diff --git a/client/src/lib.rs b/client/src/lib.rs index 37fec85ef5..4b7550585c 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -13,7 +13,7 @@ use common::{ net::PostBox, state::{State, Uid}, terrain::{block::Block, chonk::ChonkMetrics, TerrainChunk, TerrainChunkSize}, - vol::VolSize, + vol::RectVolSize, ChatType, }; use hashbrown::HashMap; @@ -210,7 +210,7 @@ impl Client { .cloned()? .0, ) - .map2(Vec2::from(TerrainChunkSize::SIZE), |e: f32, sz| { + .map2(TerrainChunkSize::RECT_SIZE, |e: f32, sz| { (e as u32).div_euclid(sz) as i32 }); diff --git a/common/src/figure/mod.rs b/common/src/figure/mod.rs index 9d73be8c8f..eda0bc23cf 100644 --- a/common/src/figure/mod.rs +++ b/common/src/figure/mod.rs @@ -5,7 +5,7 @@ pub use mat_cell::Material; use self::cell::Cell; use self::mat_cell::MatCell; use crate::{ - vol::{ReadVol, SizedVol, Vox, WriteVol}, + vol::{IntoFullPosIterator, IntoFullVolIterator, ReadVol, SizedVol, Vox, WriteVol}, volumes::dyna::Dyna, }; use dot_vox::DotVoxData; @@ -52,7 +52,7 @@ impl From<&DotVoxData> for Segment { impl Segment { /// Transform cells pub fn map(mut self, transform: impl Fn(Cell) -> Option) -> Self { - for pos in self.iter_positions() { + for pos in self.full_pos_iter() { if let Some(new) = transform(*self.get(pos).unwrap()) { self.set(pos, new).unwrap(); } @@ -91,9 +91,9 @@ impl DynaUnionizer { // Determine size of the new Dyna let mut min_point = self.0[0].1; - let mut max_point = self.0[0].1 + self.0[0].0.get_size().map(|e| e as i32); + let mut max_point = self.0[0].1 + self.0[0].0.size().map(|e| e as i32); for (dyna, offset) in self.0.iter().skip(1) { - let size = dyna.get_size().map(|e| e as i32); + let size = dyna.size().map(|e| e as i32); min_point = min_point.map2(*offset, std::cmp::min); max_point = max_point.map2(offset + size, std::cmp::max); } @@ -103,8 +103,7 @@ impl DynaUnionizer { // Copy segments into combined let origin = min_point.map(|e| e * -1); for (dyna, offset) in self.0 { - for pos in dyna.iter_positions() { - let vox = dyna.get(pos).unwrap(); + for (pos, vox) in dyna.full_vol_iter() { if !vox.is_empty() { combined.set(origin + offset + pos, *vox).unwrap(); } @@ -119,9 +118,9 @@ pub type MatSegment = Dyna; impl MatSegment { pub fn to_segment(&self, map: impl Fn(Material) -> Rgb) -> Segment { - let mut vol = Dyna::filled(self.get_size(), Cell::empty(), ()); - for pos in self.iter_positions() { - let rgb = match self.get(pos).unwrap() { + let mut vol = Dyna::filled(self.size(), Cell::empty(), ()); + for (pos, vox) in self.full_vol_iter() { + let rgb = match vox { MatCell::None => continue, MatCell::Mat(mat) => map(*mat), MatCell::Normal(rgb) => *rgb, diff --git a/common/src/ray.rs b/common/src/ray.rs index 741581cbac..a236a07f9d 100644 --- a/common/src/ray.rs +++ b/common/src/ray.rs @@ -53,7 +53,7 @@ impl<'a, V: ReadVol, F: RayUntil, G: RayForEach> Ray<'a, V, F, G> { self } - pub fn cast(mut self) -> (f32, Result, V::Err>) { + pub fn cast(mut self) -> (f32, Result, V::Error>) { // TODO: Fully test this! const PLANCK: f32 = 0.001; diff --git a/common/src/state.rs b/common/src/state.rs index 43c9d5a9ba..e87e6c91e3 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -6,7 +6,7 @@ use crate::{ event::{EventBus, LocalEvent, ServerEvent}, msg::{EcsCompPacket, EcsResPacket}, sys, - terrain::{Block, TerrainChunk, TerrainMap}, + terrain::{Block, TerrainChunk, TerrainGrid}, vol::WriteVol, }; use hashbrown::{HashMap, HashSet}; @@ -150,7 +150,7 @@ impl State { // Register unsynced resources used by the ECS. ecs.add_resource(Time(0.0)); ecs.add_resource(DeltaTime(0.0)); - ecs.add_resource(TerrainMap::new().unwrap()); + ecs.add_resource(TerrainGrid::new().unwrap()); ecs.add_resource(BlockChange::default()); ecs.add_resource(TerrainChanges::default()); ecs.add_resource(EventBus::::default()); @@ -217,12 +217,12 @@ impl State { } /// Get a reference to this state's terrain. - pub fn terrain(&self) -> Fetch { + pub fn terrain(&self) -> Fetch { self.ecs.read_resource() } /// Get a writable reference to this state's terrain. - pub fn terrain_mut(&self) -> FetchMut { + pub fn terrain_mut(&self) -> FetchMut { self.ecs.write_resource() } @@ -248,7 +248,7 @@ impl State { pub fn insert_chunk(&mut self, key: Vec2, chunk: TerrainChunk) { if self .ecs - .write_resource::() + .write_resource::() .insert(key, Arc::new(chunk)) .is_some() { @@ -268,7 +268,7 @@ impl State { pub fn remove_chunk(&mut self, key: Vec2) { if self .ecs - .write_resource::() + .write_resource::() .remove(key) .is_some() { @@ -299,7 +299,7 @@ impl State { self.ecs.maintain(); // Apply terrain changes - let mut terrain = self.ecs.write_resource::(); + let mut terrain = self.ecs.write_resource::(); self.ecs .read_resource::() .blocks diff --git a/common/src/sys/movement.rs b/common/src/sys/movement.rs index 6372c03372..cd657704b9 100644 --- a/common/src/sys/movement.rs +++ b/common/src/sys/movement.rs @@ -4,7 +4,7 @@ use crate::{ Stats, Vel, }, state::DeltaTime, - terrain::TerrainMap, + terrain::TerrainGrid, }; use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage}; use std::time::Duration; @@ -30,7 +30,7 @@ pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0; pub struct Sys; impl<'a> System<'a> for Sys { type SystemData = ( - ReadExpect<'a, TerrainMap>, + ReadExpect<'a, TerrainGrid>, Read<'a, DeltaTime>, ReadStorage<'a, Stats>, ReadStorage<'a, Controller>, diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 9b9aab55b1..84f3b993ed 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -3,7 +3,7 @@ use { comp::{Body, Ori, PhysicsState, Pos, Scale, Vel}, event::{EventBus, LocalEvent}, state::DeltaTime, - terrain::TerrainMap, + terrain::TerrainGrid, vol::ReadVol, }, specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage}, @@ -32,7 +32,7 @@ pub struct Sys; impl<'a> System<'a> for Sys { type SystemData = ( Entities<'a>, - ReadExpect<'a, TerrainMap>, + ReadExpect<'a, TerrainGrid>, Read<'a, DeltaTime>, Read<'a, EventBus>, ReadStorage<'a, Scale>, diff --git a/common/src/terrain/chonk.rs b/common/src/terrain/chonk.rs index 099ae323ed..9c7acf04bb 100644 --- a/common/src/terrain/chonk.rs +++ b/common/src/terrain/chonk.rs @@ -1,7 +1,7 @@ use super::{block::Block, TerrainChunkMeta, TerrainChunkSize}; use crate::{ - vol::{BaseVol, ReadVol, VolSize, WriteVol}, - volumes::chunk::{Chunk, ChunkErr}, + vol::{BaseVol, ReadVol, RectRasterableVol, RectVolSize, VolSize, WriteVol}, + volumes::chunk::{Chunk, ChunkError}, }; use hashbrown::HashMap; use serde_derive::{Deserialize, Serialize}; @@ -10,7 +10,7 @@ use vek::*; #[derive(Debug)] pub enum ChonkError { - ChunkError(ChunkErr), + ChunkError(ChunkError), OutOfBounds, } @@ -21,8 +21,8 @@ pub struct SubChunkSize; impl VolSize for SubChunkSize { const SIZE: Vec3 = Vec3 { - x: TerrainChunkSize::SIZE.x, - y: TerrainChunkSize::SIZE.y, + x: TerrainChunkSize::RECT_SIZE.x, + y: TerrainChunkSize::RECT_SIZE.y, z: SUB_CHUNK_HEIGHT, }; } @@ -111,7 +111,11 @@ impl Chonk { impl BaseVol for Chonk { type Vox = Block; - type Err = ChonkError; + type Error = ChonkError; +} + +impl RectRasterableVol for Chonk { + const RECT_SIZE: Vec2 = TerrainChunkSize::RECT_SIZE; } impl ReadVol for Chonk { diff --git a/common/src/terrain/mod.rs b/common/src/terrain/mod.rs index 480bf285fe..43bb15ebf3 100644 --- a/common/src/terrain/mod.rs +++ b/common/src/terrain/mod.rs @@ -10,7 +10,7 @@ pub use self::{ structure::Structure, }; -use crate::{vol::VolSize, volumes::vol_map_2d::VolMap2d}; +use crate::{vol::RectVolSize, volumes::vol_grid_2d::VolGrid2d}; use serde_derive::{Deserialize, Serialize}; use vek::*; @@ -19,12 +19,8 @@ use vek::*; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TerrainChunkSize; -impl VolSize for TerrainChunkSize { - const SIZE: Vec3 = Vec3 { - x: 32, - y: 32, - z: std::i32::MAX as u32, - }; +impl RectVolSize for TerrainChunkSize { + const RECT_SIZE: Vec2 = Vec2 { x: 32, y: 32 }; } // TerrainChunkMeta @@ -61,5 +57,5 @@ impl TerrainChunkMeta { // Terrain type aliases -pub type TerrainChunk = chonk::Chonk; //Chunk; -pub type TerrainMap = VolMap2d; +pub type TerrainChunk = chonk::Chonk; +pub type TerrainGrid = VolGrid2d; diff --git a/common/src/terrain/structure.rs b/common/src/terrain/structure.rs index 34af563d79..78b0a9521f 100644 --- a/common/src/terrain/structure.rs +++ b/common/src/terrain/structure.rs @@ -2,14 +2,14 @@ use super::BlockKind; use crate::{ assets::{self, Asset}, vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol}, - volumes::dyna::{Dyna, DynaErr}, + volumes::dyna::{Dyna, DynaError}, }; use dot_vox::DotVoxData; use std::fs::File; use std::io::BufReader; use vek::*; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq)] pub enum StructureBlock { None, TemperateLeaves, @@ -63,7 +63,7 @@ impl Structure { pub fn get_bounds(&self) -> Aabb { Aabb { min: -self.center, - max: self.vol.get_size().map(|e| e as i32) - self.center, + max: self.vol.size().map(|e| e as i32) - self.center, } } @@ -74,7 +74,7 @@ impl Structure { impl BaseVol for Structure { type Vox = StructureBlock; - type Err = StructureError; + type Error = StructureError; } impl ReadVol for Structure { @@ -82,7 +82,7 @@ impl ReadVol for Structure { fn get(&self, pos: Vec3) -> Result<&Self::Vox, StructureError> { match self.vol.get(pos + self.center) { Ok(block) => Ok(block), - Err(DynaErr::OutOfBounds) => Ok(&self.empty), + Err(DynaError::OutOfBounds) => Ok(&self.empty), } } } diff --git a/common/src/vol.rs b/common/src/vol.rs index f77e696bc4..16a43b33d6 100644 --- a/common/src/vol.rs +++ b/common/src/vol.rs @@ -2,8 +2,18 @@ use crate::ray::Ray; use std::fmt::Debug; use vek::*; +/// Used to specify a volume's compile-time size. This exists as a substitute until const generics +/// are implemented. +pub trait VolSize: Clone { + const SIZE: Vec3; +} + +pub trait RectVolSize: Clone { + const RECT_SIZE: Vec2; +} + /// A voxel. -pub trait Vox: Sized { +pub trait Vox: Sized + Clone + PartialEq { fn empty() -> Self; fn is_empty(&self) -> bool; @@ -19,64 +29,88 @@ pub trait Vox: Sized { /// A volume that contains voxel data. pub trait BaseVol { type Vox: Vox; - type Err: Debug; + type Error: Debug; +} + +/// Implementing `BaseVol` for any `&'a BaseVol` makes it possible to implement +/// `IntoVolIterator` for references. +impl<'a, T: BaseVol> BaseVol for &'a T { + type Vox = T::Vox; + type Error = T::Error; } // Utility types -pub struct VoxPosIter { - pos: Vec3, - sz: Vec3, -} +/// A volume that is a cuboid. +pub trait SizedVol: BaseVol { + /// Returns the (inclusive) lower bound of the volume. + fn lower_bound(&self) -> Vec3; -impl Iterator for VoxPosIter { - type Item = Vec3; + /// Returns the (exclusive) upper bound of the volume. + fn upper_bound(&self) -> Vec3; - fn next(&mut self) -> Option { - let mut old_pos = self.pos; - - if old_pos.z == self.sz.z { - old_pos.z = 0; - old_pos.y += 1; - if old_pos.y == self.sz.y { - old_pos.y = 0; - old_pos.x += 1; - if old_pos.x == self.sz.x { - return None; - } - } - } - - self.pos = old_pos + Vec3::unit_z(); - - Some(old_pos.map(|e| e as i32)) + /// Returns the size of the volume. + fn size(&self) -> Vec3 { + (self.upper_bound() - self.lower_bound()).map(|e| e as u32) } } -/// A volume that has a finite size. -pub trait SizedVol: BaseVol { - /// Get the size of the volume. - fn get_size(&self) -> Vec3; +/// A volume that is compile-time sized and has its lower bound at `(0, 0, 0)`. +/// The name `RasterableVol` was chosen because such a volume can be used with +/// `VolGrid3d`. +pub trait RasterableVol: BaseVol { + const SIZE: Vec3; +} - /// Iterate through all potential voxel positions in this volume. - fn iter_positions(&self) -> VoxPosIter { - VoxPosIter { - pos: Vec3::zero(), - sz: self.get_size(), - } +impl SizedVol for V { + fn lower_bound(&self) -> Vec3 { + Vec3::zero() + } + + fn upper_bound(&self) -> Vec3 { + V::SIZE.map(|e| e as i32) + } +} + +/// A volume whose cross section with the XY-plane is a rectangle. +pub trait RectSizedVol: BaseVol { + fn lower_bound_xy(&self) -> Vec2; + + fn upper_bound_xy(&self) -> Vec2; + + fn size_xy(&self) -> Vec2 { + (self.upper_bound_xy() - self.lower_bound_xy()).map(|e| e as u32) + } +} + +/// A volume that is compile-time sized in x and y direction and has its lower +/// bound at `(0, 0, z)`. In z direction there's no restriction on the lower +/// or upper bound. The name `RectRasterableVol` was chosen because such a +/// volume can be used with `VolGrid2d`. +pub trait RectRasterableVol: BaseVol { + const RECT_SIZE: Vec2; +} + +impl RectSizedVol for V { + fn lower_bound_xy(&self) -> Vec2 { + Vec2::zero() + } + + fn upper_bound_xy(&self) -> Vec2 { + V::RECT_SIZE.map(|e| e as i32) } } /// A volume that provides read access to its voxel data. pub trait ReadVol: BaseVol { /// Get a reference to the voxel at the provided position in the volume. - fn get(&self, pos: Vec3) -> Result<&Self::Vox, Self::Err>; + fn get<'a>(&'a self, pos: Vec3) -> Result<&'a Self::Vox, Self::Error>; - fn ray( - &self, + fn ray<'a>( + &'a self, from: Vec3, to: Vec3, - ) -> Ray bool, fn(Vec3)> + ) -> Ray<'a, Self, fn(&Self::Vox) -> bool, fn(Vec3)> where Self: Sized, { @@ -85,6 +119,8 @@ pub trait ReadVol: BaseVol { } /// A volume that provides the ability to sample (i.e., clone a section of) its voxel data. +/// +/// TODO (haslersn): Do we still need this now that we have `IntoVolIterator`? pub trait SampleVol: BaseVol { type Sample: BaseVol + ReadVol; /// Take a sample of the volume by cloning voxels within the provided range. @@ -94,19 +130,142 @@ pub trait SampleVol: BaseVol { /// /// Note that the resultant volume has a coordinate space relative to the sample, not the /// original volume. - fn sample(&self, range: I) -> Result; + fn sample(&self, range: I) -> Result; } /// A volume that provides write access to its voxel data. pub trait WriteVol: BaseVol { /// Set the voxel at the provided position in the volume to the provided value. - fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), Self::Err>; + fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), Self::Error>; } -// Utility traits +/// A volume (usually rather a reference to a volume) that is convertible into +/// an iterator to a cuboid subsection of the volume. +pub trait IntoVolIterator<'a>: BaseVol +where + Self::Vox: 'a, +{ + type IntoIter: Iterator, &'a Self::Vox)>; -/// Used to specify a volume's compile-time size. This exists as a substitute until const generics -/// are implemented. -pub trait VolSize { - const SIZE: Vec3; + fn vol_iter(self, lower_bound: Vec3, upper_bound: Vec3) -> Self::IntoIter; +} + +pub trait IntoPosIterator: BaseVol { + type IntoIter: Iterator>; + + fn pos_iter(self, lower_bound: Vec3, upper_bound: Vec3) -> Self::IntoIter; +} + +// Helpers + +/// A volume (usually rather a reference to a volume) that is convertible into +/// an iterator. +pub trait IntoFullVolIterator<'a>: BaseVol +where + Self::Vox: 'a, +{ + type IntoIter: Iterator, &'a Self::Vox)>; + + fn full_vol_iter(self) -> Self::IntoIter; +} + +/// For any `&'a SizedVol: IntoVolIterator` we implement `IntoFullVolIterator`. +/// Unfortunately we can't just implement `IntoIterator` in this generic way +/// because it's defined in another crate. That's actually the only reason why +/// the trait `IntoFullVolIterator` exists. +impl<'a, T: 'a + SizedVol> IntoFullVolIterator<'a> for &'a T +where + Self: IntoVolIterator<'a>, +{ + type IntoIter = >::IntoIter; + + fn full_vol_iter(self) -> Self::IntoIter { + self.vol_iter(self.lower_bound(), self.upper_bound()) + } +} + +pub trait IntoFullPosIterator: BaseVol { + type IntoIter: Iterator>; + + fn full_pos_iter(self) -> Self::IntoIter; +} + +impl<'a, T: 'a + SizedVol> IntoFullPosIterator for &'a T +where + Self: IntoPosIterator, +{ + type IntoIter = ::IntoIter; + + fn full_pos_iter(self) -> Self::IntoIter { + self.pos_iter(self.lower_bound(), self.upper_bound()) + } +} + +// Defaults + +/// Convenience iterator type that can be used to quickly implement +/// `IntoPosIterator`. +pub struct DefaultPosIterator { + current: Vec3, + begin: Vec2, + end: Vec3, +} + +impl DefaultPosIterator { + pub fn new(lower_bound: Vec3, upper_bound: Vec3) -> Self { + Self { + current: lower_bound, + begin: From::from(lower_bound), + end: upper_bound, + } + } +} + +impl Iterator for DefaultPosIterator { + type Item = Vec3; + + fn next(&mut self) -> Option> { + self.current.x += (self.current.x < self.end.x) as i32; + if self.current.x == self.end.x { + self.current.x = self.begin.x; + self.current.y += (self.current.y < self.end.y) as i32; + if self.current.y == self.end.y { + self.current.y = self.begin.y; + self.current.z += (self.current.z < self.end.z) as i32; + if self.current.z == self.end.z { + return None; + } + } + } + Some(self.current) + } +} + +/// Convenience iterator type that can be used to quickly implement +/// `IntoVolIterator`. +pub struct DefaultVolIterator<'a, T: ReadVol> { + vol: &'a T, + pos_iter: DefaultPosIterator, +} + +impl<'a, T: ReadVol> DefaultVolIterator<'a, T> { + pub fn new(vol: &'a T, lower_bound: Vec3, upper_bound: Vec3) -> Self { + Self { + vol, + pos_iter: DefaultPosIterator::new(lower_bound, upper_bound), + } + } +} + +impl<'a, T: ReadVol> Iterator for DefaultVolIterator<'a, T> { + type Item = (Vec3, &'a T::Vox); + + fn next(&mut self) -> Option<(Vec3, &'a T::Vox)> { + while let Some(pos) = self.pos_iter.next() { + if let Ok(vox) = self.vol.get(pos) { + return Some((pos, vox)); + } + } + return None; + } } diff --git a/common/src/volumes/chunk.rs b/common/src/volumes/chunk.rs index 0168686278..dbe0f069b9 100644 --- a/common/src/volumes/chunk.rs +++ b/common/src/volumes/chunk.rs @@ -4,7 +4,7 @@ use std::marker::PhantomData; use vek::*; #[derive(Debug)] -pub enum ChunkErr { +pub enum ChunkError { OutOfBounds, } @@ -43,32 +43,37 @@ impl Chunk { impl BaseVol for Chunk { type Vox = V; - type Err = ChunkErr; + type Error = ChunkError; } impl SizedVol for Chunk { #[inline(always)] - fn get_size(&self) -> Vec3 { - S::SIZE + fn lower_bound(&self) -> Vec3 { + Vec3::zero() + } + + #[inline(always)] + fn upper_bound(&self) -> Vec3 { + S::SIZE.map(|e| e as i32) } } impl ReadVol for Chunk { #[inline(always)] - fn get(&self, pos: Vec3) -> Result<&V, ChunkErr> { + fn get(&self, pos: Vec3) -> Result<&V, ChunkError> { Self::idx_for(pos) .and_then(|idx| self.vox.get(idx)) - .ok_or(ChunkErr::OutOfBounds) + .ok_or(ChunkError::OutOfBounds) } } impl WriteVol for Chunk { #[inline(always)] - fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), ChunkErr> { + fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), ChunkError> { Self::idx_for(pos) .and_then(|idx| self.vox.get_mut(idx)) .map(|old_vox| *old_vox = vox) - .ok_or(ChunkErr::OutOfBounds) + .ok_or(ChunkError::OutOfBounds) } } diff --git a/common/src/volumes/dyna.rs b/common/src/volumes/dyna.rs index 4acebe6f1e..9ad587ccee 100644 --- a/common/src/volumes/dyna.rs +++ b/common/src/volumes/dyna.rs @@ -1,9 +1,12 @@ -use crate::vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol}; +use crate::vol::{ + BaseVol, DefaultPosIterator, DefaultVolIterator, IntoPosIterator, IntoVolIterator, ReadVol, + SizedVol, Vox, WriteVol, +}; use serde_derive::{Deserialize, Serialize}; use vek::*; #[derive(Debug, Clone)] -pub enum DynaErr { +pub enum DynaError { OutOfBounds, } @@ -40,32 +43,53 @@ impl Dyna { impl BaseVol for Dyna { type Vox = V; - type Err = DynaErr; + type Error = DynaError; } impl SizedVol for Dyna { #[inline(always)] - fn get_size(&self) -> Vec3 { - self.sz + fn lower_bound(&self) -> Vec3 { + Vec3::zero() + } + + #[inline(always)] + fn upper_bound(&self) -> Vec3 { + self.sz.map(|e| e as i32) } } impl ReadVol for Dyna { #[inline(always)] - fn get(&self, pos: Vec3) -> Result<&V, DynaErr> { + fn get(&self, pos: Vec3) -> Result<&V, DynaError> { Self::idx_for(self.sz, pos) .and_then(|idx| self.vox.get(idx)) - .ok_or(DynaErr::OutOfBounds) + .ok_or(DynaError::OutOfBounds) } } impl WriteVol for Dyna { #[inline(always)] - fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), DynaErr> { + fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), DynaError> { Self::idx_for(self.sz, pos) .and_then(|idx| self.vox.get_mut(idx)) .map(|old_vox| *old_vox = vox) - .ok_or(DynaErr::OutOfBounds) + .ok_or(DynaError::OutOfBounds) + } +} + +impl<'a, V: Vox, M> IntoPosIterator for &'a Dyna { + type IntoIter = DefaultPosIterator; + + fn pos_iter(self, lower_bound: Vec3, upper_bound: Vec3) -> Self::IntoIter { + Self::IntoIter::new(lower_bound, upper_bound) + } +} + +impl<'a, V: Vox, M> IntoVolIterator<'a> for &'a Dyna { + type IntoIter = DefaultVolIterator<'a, Dyna>; + + fn vol_iter(self, lower_bound: Vec3, upper_bound: Vec3) -> Self::IntoIter { + Self::IntoIter::new(self, lower_bound, upper_bound) } } diff --git a/common/src/volumes/mod.rs b/common/src/volumes/mod.rs index 56a27bcf2e..b84e75b7c8 100644 --- a/common/src/volumes/mod.rs +++ b/common/src/volumes/mod.rs @@ -1,4 +1,4 @@ pub mod chunk; pub mod dyna; -pub mod vol_map_2d; -pub mod vol_map_3d; +pub mod vol_grid_2d; +pub mod vol_grid_3d; diff --git a/common/src/volumes/vol_map_2d.rs b/common/src/volumes/vol_grid_2d.rs similarity index 67% rename from common/src/volumes/vol_map_2d.rs rename to common/src/volumes/vol_grid_2d.rs index f7458d46a5..9ce00cef7b 100644 --- a/common/src/volumes/vol_map_2d.rs +++ b/common/src/volumes/vol_grid_2d.rs @@ -1,16 +1,16 @@ use crate::{ - vol::{BaseVol, ReadVol, SampleVol, VolSize, WriteVol}, - volumes::dyna::DynaErr, + vol::{BaseVol, ReadVol, RectRasterableVol, SampleVol, WriteVol}, + volumes::dyna::DynaError, }; use hashbrown::{hash_map, HashMap}; -use std::{fmt::Debug, marker::PhantomData, sync::Arc}; +use std::{fmt::Debug, sync::Arc}; use vek::*; #[derive(Debug, Clone)] -pub enum VolMap2dErr { +pub enum VolGrid2dError { NoSuchChunk, - ChunkErr(V::Err), - DynaErr(DynaErr), + ChunkError(V::Error), + DynaError(DynaError), InvalidChunkSize, } @@ -18,56 +18,55 @@ pub enum VolMap2dErr { // S = Size (replace with a const when const generics is a thing) // M = Chunk metadata #[derive(Clone)] -pub struct VolMap2d { +pub struct VolGrid2d { chunks: HashMap, Arc>, - phantom: PhantomData, } -impl VolMap2d { +impl VolGrid2d { #[inline(always)] pub fn chunk_key>>(pos: P) -> Vec2 { pos.into() - .map2(S::SIZE.into(), |e, sz: u32| e >> (sz - 1).count_ones()) + .map2(V::RECT_SIZE, |e, sz: u32| e >> (sz - 1).count_ones()) } #[inline(always)] pub fn chunk_offs(pos: Vec3) -> Vec3 { - let offs = pos.map2(S::SIZE, |e, sz| e & (sz - 1) as i32); + let offs = Vec2::::from(pos).map2(V::RECT_SIZE, |e, sz| e & (sz - 1) as i32); Vec3::new(offs.x, offs.y, pos.z) } } -impl BaseVol for VolMap2d { +impl BaseVol for VolGrid2d { type Vox = V::Vox; - type Err = VolMap2dErr; + type Error = VolGrid2dError; } -impl ReadVol for VolMap2d { +impl ReadVol for VolGrid2d { #[inline(always)] - fn get(&self, pos: Vec3) -> Result<&V::Vox, VolMap2dErr> { + fn get(&self, pos: Vec3) -> Result<&V::Vox, VolGrid2dError> { let ck = Self::chunk_key(pos); self.chunks .get(&ck) - .ok_or(VolMap2dErr::NoSuchChunk) + .ok_or(VolGrid2dError::NoSuchChunk) .and_then(|chunk| { let co = Self::chunk_offs(pos); - chunk.get(co).map_err(VolMap2dErr::ChunkErr) + chunk.get(co).map_err(VolGrid2dError::ChunkError) }) } } // TODO: This actually breaks the API: samples are supposed to have an offset of zero! // TODO: Should this be changed, perhaps? -impl>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol for VolMap2d { - type Sample = VolMap2d; +impl>, V: RectRasterableVol + ReadVol + Debug> SampleVol for VolGrid2d { + type Sample = VolGrid2d; /// Take a sample of the terrain by cloning the voxels within the provided range. /// /// Note that the resultant volume does not carry forward metadata from the original chunks. - fn sample(&self, range: I) -> Result> { + fn sample(&self, range: I) -> Result> { let range = range.into(); - let mut sample = VolMap2d::new()?; + let mut sample = VolGrid2d::new()?; let chunk_min = Self::chunk_key(range.min); let chunk_max = Self::chunk_key(range.max); for x in chunk_min.x..=chunk_max.x { @@ -86,39 +85,38 @@ impl>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol } } -impl WriteVol for VolMap2d { +impl WriteVol for VolGrid2d { #[inline(always)] - fn set(&mut self, pos: Vec3, vox: V::Vox) -> Result<(), VolMap2dErr> { + fn set(&mut self, pos: Vec3, vox: V::Vox) -> Result<(), VolGrid2dError> { let ck = Self::chunk_key(pos); self.chunks .get_mut(&ck) - .ok_or(VolMap2dErr::NoSuchChunk) + .ok_or(VolGrid2dError::NoSuchChunk) .and_then(|chunk| { let co = Self::chunk_offs(pos); Arc::make_mut(chunk) .set(co, vox) - .map_err(VolMap2dErr::ChunkErr) + .map_err(VolGrid2dError::ChunkError) }) } } -impl VolMap2d { - pub fn new() -> Result> { +impl VolGrid2d { + pub fn new() -> Result> { if Self::chunk_size() .map(|e| e.is_power_of_two() && e > 0) .reduce_and() { Ok(Self { chunks: HashMap::default(), - phantom: PhantomData, }) } else { - Err(VolMap2dErr::InvalidChunkSize) + Err(VolGrid2dError::InvalidChunkSize) } } pub fn chunk_size() -> Vec2 { - S::SIZE.into() + V::RECT_SIZE } pub fn insert(&mut self, key: Vec2, chunk: Arc) -> Option> { @@ -149,7 +147,7 @@ impl VolMap2d { } pub fn key_pos(&self, key: Vec2) -> Vec2 { - key * Vec2::::from(S::SIZE).map(|e| e as i32) + key * V::RECT_SIZE.map(|e| e as i32) } pub fn pos_key(&self, pos: Vec3) -> Vec2 { @@ -163,11 +161,11 @@ impl VolMap2d { } } -pub struct ChunkIter<'a, V: BaseVol> { +pub struct ChunkIter<'a, V: RectRasterableVol> { iter: hash_map::Iter<'a, Vec2, Arc>, } -impl<'a, V: BaseVol> Iterator for ChunkIter<'a, V> { +impl<'a, V: RectRasterableVol> Iterator for ChunkIter<'a, V> { type Item = (Vec2, &'a Arc); fn next(&mut self) -> Option { diff --git a/common/src/volumes/vol_map_3d.rs b/common/src/volumes/vol_grid_3d.rs similarity index 70% rename from common/src/volumes/vol_map_3d.rs rename to common/src/volumes/vol_grid_3d.rs index b1105d8cb7..627d1aeb42 100644 --- a/common/src/volumes/vol_map_3d.rs +++ b/common/src/volumes/vol_grid_3d.rs @@ -1,16 +1,16 @@ use crate::{ - vol::{BaseVol, ReadVol, SampleVol, VolSize, WriteVol}, - volumes::dyna::DynaErr, + vol::{BaseVol, RasterableVol, ReadVol, SampleVol, WriteVol}, + volumes::dyna::DynaError, }; use hashbrown::{hash_map, HashMap}; -use std::{fmt::Debug, marker::PhantomData, sync::Arc}; +use std::{fmt::Debug, sync::Arc}; use vek::*; #[derive(Debug)] -pub enum VolMap3dErr { +pub enum VolGrid3dError { NoSuchChunk, - ChunkErr(V::Err), - DynaErr(DynaErr), + ChunkErr(V::Error), + DynaError(DynaError), InvalidChunkSize, } @@ -18,15 +18,14 @@ pub enum VolMap3dErr { // S = Size (replace with a const when const generics is a thing) // M = Chunk metadata #[derive(Clone)] -pub struct VolMap3d { +pub struct VolGrid3d { chunks: HashMap, Arc>, - phantom: PhantomData, } -impl VolMap3d { +impl VolGrid3d { #[inline(always)] pub fn chunk_key(pos: Vec3) -> Vec3 { - pos.map2(S::SIZE, |e, sz| { + pos.map2(V::SIZE, |e, sz| { // Horrid, but it's faster than a cheetah with a red bull blood transfusion let log2 = (sz - 1).count_ones(); ((((i64::from(e) + (1 << 32)) as u64) >> log2) - (1 << (32 - log2))) as i32 @@ -35,43 +34,43 @@ impl VolMap3d { #[inline(always)] pub fn chunk_offs(pos: Vec3) -> Vec3 { - pos.map2(S::SIZE, |e, sz| { + pos.map2(V::SIZE, |e, sz| { // Horrid, but it's even faster than the aforementioned cheetah (((i64::from(e) + (1 << 32)) as u64) & u64::from(sz - 1)) as i32 }) } } -impl BaseVol for VolMap3d { +impl BaseVol for VolGrid3d { type Vox = V::Vox; - type Err = VolMap3dErr; + type Error = VolGrid3dError; } -impl ReadVol for VolMap3d { +impl ReadVol for VolGrid3d { #[inline(always)] - fn get(&self, pos: Vec3) -> Result<&V::Vox, VolMap3dErr> { + fn get(&self, pos: Vec3) -> Result<&V::Vox, VolGrid3dError> { let ck = Self::chunk_key(pos); self.chunks .get(&ck) - .ok_or(VolMap3dErr::NoSuchChunk) + .ok_or(VolGrid3dError::NoSuchChunk) .and_then(|chunk| { let co = Self::chunk_offs(pos); - chunk.get(co).map_err(VolMap3dErr::ChunkErr) + chunk.get(co).map_err(VolGrid3dError::ChunkErr) }) } } // TODO: This actually breaks the API: samples are supposed to have an offset of zero! // TODO: Should this be changed, perhaps? -impl>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol for VolMap3d { - type Sample = VolMap3d; +impl>, V: RasterableVol + ReadVol + Debug> SampleVol for VolGrid3d { + type Sample = VolGrid3d; /// Take a sample of the terrain by cloning the voxels within the provided range. /// /// Note that the resultant volume does not carry forward metadata from the original chunks. - fn sample(&self, range: I) -> Result> { + fn sample(&self, range: I) -> Result> { let range = range.into(); - let mut sample = VolMap3d::new()?; + let mut sample = VolGrid3d::new()?; let chunk_min = Self::chunk_key(range.min); let chunk_max = Self::chunk_key(range.max); for x in chunk_min.x..=chunk_max.x { @@ -92,39 +91,38 @@ impl>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol } } -impl WriteVol for VolMap3d { +impl WriteVol for VolGrid3d { #[inline(always)] - fn set(&mut self, pos: Vec3, vox: V::Vox) -> Result<(), VolMap3dErr> { + fn set(&mut self, pos: Vec3, vox: V::Vox) -> Result<(), VolGrid3dError> { let ck = Self::chunk_key(pos); self.chunks .get_mut(&ck) - .ok_or(VolMap3dErr::NoSuchChunk) + .ok_or(VolGrid3dError::NoSuchChunk) .and_then(|chunk| { let co = Self::chunk_offs(pos); Arc::make_mut(chunk) .set(co, vox) - .map_err(VolMap3dErr::ChunkErr) + .map_err(VolGrid3dError::ChunkErr) }) } } -impl VolMap3d { - pub fn new() -> Result> { +impl VolGrid3d { + pub fn new() -> Result> { if Self::chunk_size() .map(|e| e.is_power_of_two() && e > 0) .reduce_and() { Ok(Self { chunks: HashMap::new(), - phantom: PhantomData, }) } else { - Err(VolMap3dErr::InvalidChunkSize) + Err(VolGrid3dError::InvalidChunkSize) } } pub fn chunk_size() -> Vec3 { - S::SIZE + V::SIZE } pub fn insert(&mut self, key: Vec3, chunk: Arc) -> Option> { @@ -147,7 +145,7 @@ impl VolMap3d { } pub fn key_pos(&self, key: Vec3) -> Vec3 { - key * S::SIZE.map(|e| e as i32) + key * V::SIZE.map(|e| e as i32) } pub fn pos_key(&self, pos: Vec3) -> Vec3 { @@ -161,11 +159,11 @@ impl VolMap3d { } } -pub struct ChunkIter<'a, V: BaseVol> { +pub struct ChunkIter<'a, V: RasterableVol> { iter: hash_map::Iter<'a, Vec3, Arc>, } -impl<'a, V: BaseVol> Iterator for ChunkIter<'a, V> { +impl<'a, V: RasterableVol> Iterator for ChunkIter<'a, V> { type Item = (Vec3, &'a Arc); fn next(&mut self) -> Option { diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs index e69de29bb2..8b13789179 100644 --- a/common/src/volumes/vol_map.rs +++ b/common/src/volumes/vol_map.rs @@ -0,0 +1 @@ + diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 8edb5c6e69..7eaf39a2aa 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -846,7 +846,7 @@ fn handle_debug_column(server: &mut Server, entity: EcsEntity, args: String, act let sim = server.world.sim(); if let Ok((x, y)) = scan_fmt!(&args, action.arg_fmt, i32, i32) { let wpos = Vec2::new(x, y); - /* let chunk_pos = wpos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { + /* let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| { e / sz as i32 }); */ diff --git a/server/src/lib.rs b/server/src/lib.rs index c1ebb8d86b..48d44fa1fd 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -22,9 +22,8 @@ use common::{ msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg}, net::PostOffice, state::{BlockChange, State, TimeOfDay, Uid}, - terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainMap}, - vol::Vox, - vol::{ReadVol, VolSize}, + terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainGrid}, + vol::{ReadVol, RectVolSize, Vox}, }; use crossbeam::channel; use hashbrown::HashSet; @@ -261,7 +260,7 @@ impl Server { let mut block_change = ecs.write_resource::(); let _ = ecs - .read_resource::() + .read_resource::() .ray(pos, pos + dir * radius) .until(|_| rand::random::() < 0.05) .for_each(|pos| block_change.set(pos, Block::empty())) @@ -479,7 +478,7 @@ impl Server { fn chunk_in_vd( player_pos: Vec3, chunk_pos: Vec2, - terrain: &TerrainMap, + terrain: &TerrainGrid, vd: u32, ) -> bool { let player_chunk_pos = terrain.pos_key(player_pos.map(|e| e as i32)); @@ -1085,8 +1084,8 @@ impl Server { ) { { // Check if the entity is in the client's range - (pos.0 - client_pos.0) - .map2(TerrainChunkSize::SIZE, |d, sz| { + Vec2::from(pos.0 - client_pos.0) + .map2(TerrainChunkSize::RECT_SIZE, |d: f32, sz| { (d.abs() as u32 / sz).checked_sub(2).unwrap_or(0) }) .magnitude_squared() diff --git a/voxygen/src/anim/character/crun.rs b/voxygen/src/anim/character/crun.rs index def3c9c8d5..5e69198d89 100644 --- a/voxygen/src/anim/character/crun.rs +++ b/voxygen/src/anim/character/crun.rs @@ -40,7 +40,6 @@ impl Animation for WieldAnimation { * 0.1, ); - match Tool::Hammer { //TODO: Inventory Tool::Sword => { diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 8ff3e1676e..19567bf182 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -39,7 +39,7 @@ use crate::{ GlobalState, }; use client::{Client, Event as ClientEvent}; -use common::{comp, terrain::TerrainChunkSize, vol::VolSize}; +use common::{comp, terrain::TerrainChunk, vol::RectRasterableVol}; use conrod_core::{ text::cursor::Index, widget::{self, Button, Image, Rectangle, Text}, @@ -482,8 +482,10 @@ impl Hud { .filter(|(entity, _, stats, _, _)| *entity != me && !stats.is_dead) // Don't process nametags outside the vd (visibility further limited by ui backend) .filter(|(_, pos, _, _, _)| { - (pos.0 - player_pos) - .map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32) + Vec2::from(pos.0 - player_pos) + .map2(TerrainChunk::RECT_SIZE, |d: f32, sz| { + d.abs() as f32 / sz as f32 + }) .magnitude() < view_distance as f32 }) @@ -523,8 +525,10 @@ impl Hud { }) // Don't process health bars outside the vd (visibility further limited by ui backend) .filter(|(_, pos, _, _)| { - (pos.0 - player_pos) - .map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32) + Vec2::from(pos.0 - player_pos) + .map2(TerrainChunk::RECT_SIZE, |d: f32, sz| { + d.abs() as f32 / sz as f32 + }) .magnitude() < view_distance as f32 }) diff --git a/voxygen/src/mesh/segment.rs b/voxygen/src/mesh/segment.rs index 268d1e16f9..90a54e5292 100644 --- a/voxygen/src/mesh/segment.rs +++ b/voxygen/src/mesh/segment.rs @@ -5,7 +5,7 @@ use crate::{ use common::{ figure::Segment, util::{linear_to_srgb, srgb_to_linear}, - vol::{ReadVol, SizedVol, Vox}, + vol::{IntoFullVolIterator, Vox}, }; use vek::*; @@ -23,8 +23,8 @@ impl Meshable for Segment { ) -> (Mesh, Mesh) { let mut mesh = Mesh::new(); - for pos in self.iter_positions() { - if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) { + for (pos, vox) in self.full_vol_iter() { + if let Some(col) = vox.get_color() { let col = col.map(|e| e as f32 / 255.0); vol::push_vox_verts( @@ -64,8 +64,8 @@ impl Meshable for Segment { ) -> (Mesh, Mesh) { let mut mesh = Mesh::new(); - for pos in self.iter_positions() { - if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) { + for (pos, vox) in self.full_vol_iter() { + if let Some(col) = vox.get_color() { let col = col.map(|e| e as f32 / 255.0); vol::push_vox_verts( diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index d3543d7aad..656a09b114 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -4,8 +4,8 @@ use crate::{ }; use common::{ terrain::{Block, BlockKind}, - vol::{BaseVol, ReadVol, VolSize}, - volumes::vol_map_2d::VolMap2d, + vol::{ReadVol, RectRasterableVol}, + volumes::vol_grid_2d::VolGrid2d, }; use std::fmt::Debug; use vek::*; @@ -24,8 +24,8 @@ fn block_shadow_density(kind: BlockKind) -> (f32, f32) { } } -impl + ReadVol + Debug, S: VolSize + Clone> - Meshable for VolMap2d +impl + ReadVol + Debug> Meshable + for VolGrid2d { type Pipeline = TerrainPipeline; type TranslucentPipeline = FluidPipeline; @@ -126,7 +126,7 @@ impl + ReadVol + Debug, S: VolSize + Clone> } /* -impl + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap3d { +impl + ReadVol + Debug> Meshable for VolGrid3d { type Pipeline = TerrainPipeline; type Supplement = Aabb; diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index e6bc82d680..b62bffc3ba 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -17,8 +17,8 @@ use common::{ comp::{ ActionState::*, Body, CharacterState, Last, MovementState::*, Ori, Pos, Scale, Stats, Vel, }, - terrain::TerrainChunkSize, - vol::VolSize, + terrain::TerrainChunk, + vol::RectRasterableVol, }; use hashbrown::HashMap; use log::debug; @@ -77,8 +77,10 @@ impl FigureMgr { .join() { // Don't process figures outside the vd - let vd_frac = (pos.0 - player_pos) - .map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32) + let vd_frac = Vec2::from(pos.0 - player_pos) + .map2(TerrainChunk::RECT_SIZE, |d: f32, sz| { + d.abs() as f32 / sz as f32 + }) .magnitude() / view_distance as f32; // Keep from re-adding/removing entities on the border of the vd diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 5d00b99698..74677adfe4 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -10,9 +10,9 @@ use client::Client; use common::{ assets, figure::Segment, - terrain::{Block, BlockKind, TerrainChunkSize, TerrainMap}, - vol::{ReadVol, SampleVol, VolSize, Vox}, - volumes::vol_map_2d::VolMap2dErr, + terrain::{Block, BlockKind, TerrainChunkSize, TerrainGrid}, + vol::{ReadVol, RectVolSize, SampleVol, Vox}, + volumes::vol_grid_2d::VolGrid2dError, }; use crossbeam::channel; use dot_vox::DotVoxData; @@ -139,7 +139,7 @@ fn mesh_worker( pos: Vec2, z_bounds: (f32, f32), started_tick: u64, - volume: >>::Sample, + volume: >>::Sample, range: Aabb, ) -> MeshWorkerResponse { let (opaque_mesh, fluid_mesh) = volume.generate_mesh(range); @@ -152,11 +152,11 @@ fn mesh_worker( sprite_instances: { let mut instances = HashMap::new(); - for x in 0..TerrainChunkSize::SIZE.x as i32 { - for y in 0..TerrainChunkSize::SIZE.y as i32 { + for x in 0..TerrainChunkSize::RECT_SIZE.x as i32 { + for y in 0..TerrainChunkSize::RECT_SIZE.y as i32 { for z in z_bounds.0 as i32..z_bounds.1 as i32 + 1 { let wpos = Vec3::from( - pos * Vec2::from(TerrainChunkSize::SIZE).map(|e: u32| e as i32), + pos * Vec2::from(TerrainChunkSize::RECT_SIZE).map(|e: u32| e as i32), ) + Vec3::new(x, y, z); let kind = volume.get(wpos).unwrap_or(&Block::empty()).kind(); @@ -728,10 +728,10 @@ impl Terrain { let aabr = Aabr { min: todo .pos - .map2(TerrainMap::chunk_size(), |e, sz| e * sz as i32 - 1), + .map2(TerrainGrid::chunk_size(), |e, sz| e * sz as i32 - 1), max: todo .pos - .map2(TerrainMap::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1), + .map2(TerrainGrid::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1), }; // Copy out the chunk data we need to perform the meshing. We do this by taking a @@ -740,7 +740,7 @@ impl Terrain { Ok(sample) => sample, // Either this chunk or its neighbours doesn't yet exist, so we keep it in the // queue to be processed at a later date when we have its neighbours. - Err(VolMap2dErr::NoSuchChunk) => return, + Err(VolGrid2dError::NoSuchChunk) => return, _ => panic!("Unhandled edge case"), }; @@ -807,7 +807,7 @@ impl Terrain { locals: renderer .create_consts(&[TerrainLocals { model_offs: Vec3::from( - response.pos.map2(TerrainMap::chunk_size(), |e, sz| { + response.pos.map2(TerrainGrid::chunk_size(), |e, sz| { e as f32 * sz as f32 }), ) @@ -836,7 +836,7 @@ impl Terrain { ); // Update chunk visibility - let chunk_sz = TerrainChunkSize::SIZE.x as f32; + let chunk_sz = TerrainChunkSize::RECT_SIZE.x as f32; for (pos, chunk) in &mut self.chunks { let chunk_pos = pos.map(|e| e as f32 * chunk_sz); @@ -886,9 +886,10 @@ impl Terrain { if chunk.visible { const SPRITE_RENDER_DISTANCE: f32 = 128.0; - let chunk_center = pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { - (e as f32 + 0.5) * sz as f32 - }); + let chunk_center = pos + .map2(Vec2::from(TerrainChunkSize::RECT_SIZE), |e, sz: u32| { + (e as f32 + 0.5) * sz as f32 + }); if Vec2::from(focus_pos).distance_squared(chunk_center) < SPRITE_RENDER_DISTANCE * SPRITE_RENDER_DISTANCE { diff --git a/voxygen/src/ui/graphic/renderer.rs b/voxygen/src/ui/graphic/renderer.rs index ecd6a8ebb5..c33bdd5a8b 100644 --- a/voxygen/src/ui/graphic/renderer.rs +++ b/voxygen/src/ui/graphic/renderer.rs @@ -1,7 +1,7 @@ use common::{ figure::Segment, util::{linear_to_srgba, srgba_to_linear}, - vol::{ReadVol, SizedVol, Vox}, + vol::{IntoFullVolIterator, ReadVol, SizedVol, Vox}, }; use euc::{buffer::Buffer2d, rasterizer, Pipeline}; use image::{DynamicImage, RgbaImage}; @@ -69,7 +69,7 @@ pub fn draw_vox( let mut color = Buffer2d::new(dims, [0; 4]); let mut depth = Buffer2d::new(dims, 1.0); - let (w, h, d) = segment.get_size().map(|e| e as f32).into_tuple(); + let (w, h, d) = segment.size().map(|e| e as f32).into_tuple(); let mvp = Mat4::::orthographic_rh_no(FrustumPlanes { left: -1.0, @@ -155,8 +155,8 @@ fn create_quad( fn generate_mesh(segment: &Segment, offs: Vec3) -> Vec { let mut vertices = Vec::new(); - for pos in segment.iter_positions() { - if let Some(col) = segment.get(pos).ok().and_then(|vox| vox.get_color()) { + for (pos, vox) in segment.full_vol_iter() { + if let Some(col) = vox.get_color() { let col = col.map(|e| e as f32 / 255.0); let is_empty = |pos| segment.get(pos).map(|v| v.is_empty()).unwrap_or(true); diff --git a/world/src/column/mod.rs b/world/src/column/mod.rs index 376efd16d1..5dc71d7ba0 100644 --- a/world/src/column/mod.rs +++ b/world/src/column/mod.rs @@ -9,7 +9,7 @@ use crate::{ use common::{ assets, terrain::{BlockKind, Structure, TerrainChunkSize}, - vol::VolSize, + vol::RectVolSize, }; use lazy_static::lazy_static; use noise::NoiseFn; @@ -71,9 +71,7 @@ impl<'a> ColumnGen<'a> { .min_by_key(|(pos, _)| pos.distance_squared(wpos)) .unwrap(); - let chunk_pos = pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { - e / sz as i32 - }); + let chunk_pos = pos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32); let chunk = self.sim.get(chunk_pos)?; if seed % 5 == 2 @@ -126,9 +124,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> { fn get(&self, wpos: Vec2) -> Option> { let wposf = wpos.map(|e| e as f64); - let chunk_pos = wpos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { - e / sz as i32 - }); + let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32); let sim = &self.sim; diff --git a/world/src/generator/town/vol.rs b/world/src/generator/town/vol.rs index 1a630ed3e0..a3b0ddb6aa 100644 --- a/world/src/generator/town/vol.rs +++ b/world/src/generator/town/vol.rs @@ -34,13 +34,13 @@ impl TownColumn { } } -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub struct Module { pub vol_idx: usize, pub dir: usize, } -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum CellKind { Empty, Park, @@ -50,7 +50,7 @@ pub enum CellKind { House(usize), } -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub struct TownCell { pub kind: CellKind, pub module: Option, @@ -200,11 +200,11 @@ impl TownVol { impl BaseVol for TownVol { type Vox = TownCell; - type Err = TownError; + type Error = TownError; } impl ReadVol for TownVol { - fn get(&self, pos: Vec3) -> Result<&Self::Vox, Self::Err> { + fn get(&self, pos: Vec3) -> Result<&Self::Vox, Self::Error> { match self.grid.get(Vec2::from(pos)) { Some((base, _, cells)) => cells .get((pos.z + UNDERGROUND_DEPTH - *base) as usize) @@ -215,7 +215,7 @@ impl ReadVol for TownVol { } impl WriteVol for TownVol { - fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), Self::Err> { + fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), Self::Error> { match self.grid.get_mut(Vec2::from(pos)) { Some((base, _, cells)) => cells .get_mut((pos.z + UNDERGROUND_DEPTH - *base) as usize) diff --git a/world/src/lib.rs b/world/src/lib.rs index 5cd9a8916b..f0ce7896c7 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -25,7 +25,7 @@ use crate::{ }; use common::{ terrain::{Block, BlockKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize}, - vol::{ReadVol, VolSize, Vox, WriteVol}, + vol::{ReadVol, RectVolSize, Vox, WriteVol}, }; use rand::Rng; use std::time::Duration; @@ -70,7 +70,7 @@ impl World { let stone = Block::new(BlockKind::Dense, Rgb::new(200, 220, 255)); let water = Block::new(BlockKind::Water, Rgb::new(60, 90, 190)); - let chunk_size2d = Vec2::from(TerrainChunkSize::SIZE); + let chunk_size2d = TerrainChunkSize::RECT_SIZE; let (base_z, sim_chunk) = match self .sim .get_interpolated( @@ -96,13 +96,13 @@ impl World { let meta = TerrainChunkMeta::new(sim_chunk.get_name(&self.sim), sim_chunk.get_biome()); let mut sampler = self.sample_blocks(); - let chunk_block_pos = Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32); + let chunk_block_pos = Vec3::from(chunk_pos) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32); let mut chunk = TerrainChunk::new(base_z, stone, air, meta); - for x in 0..TerrainChunkSize::SIZE.x as i32 { - for y in 0..TerrainChunkSize::SIZE.y as i32 { + for x in 0..TerrainChunkSize::RECT_SIZE.x as i32 { + for y in 0..TerrainChunkSize::RECT_SIZE.y as i32 { let wpos2d = Vec2::new(x, y) - + Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32); + + Vec2::from(chunk_pos) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32); let z_cache = match sampler.get_z_cache(wpos2d) { Some(z_cache) => z_cache, @@ -127,7 +127,7 @@ impl World { } let gen_entity_pos = || { - let lpos2d = Vec2::from(TerrainChunkSize::SIZE) + let lpos2d = TerrainChunkSize::RECT_SIZE .map(|sz| rand::thread_rng().gen::().rem_euclid(sz)); let mut lpos = Vec3::new(lpos2d.x as i32, lpos2d.y as i32, 0); diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index c6d10bcca8..7467a1d3b4 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -18,7 +18,7 @@ use crate::{ }; use common::{ terrain::{BiomeKind, TerrainChunkSize}, - vol::VolSize, + vol::RectVolSize, }; use noise::{ BasicMulti, Billow, HybridMulti, MultiFractal, NoiseFn, RidgedMulti, Seedable, SuperSimplex, @@ -328,7 +328,7 @@ impl WorldSim { self.rng.gen::() % grid_size.y, ); let wpos = (cell_pos * cell_size + cell_size / 2) - .map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { + .map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| { e as i32 * sz as i32 + sz as i32 / 2 }); @@ -378,8 +378,8 @@ impl WorldSim { for j in 0..WORLD_SIZE.y { let chunk_pos = Vec2::new(i as i32, j as i32); let block_pos = Vec2::new( - chunk_pos.x * TerrainChunkSize::SIZE.x as i32, - chunk_pos.y * TerrainChunkSize::SIZE.y as i32, + chunk_pos.x * TerrainChunkSize::RECT_SIZE.x as i32, + chunk_pos.y * TerrainChunkSize::RECT_SIZE.y as i32, ); let _cell_pos = Vec2::new(i / cell_size, j / cell_size); @@ -389,9 +389,8 @@ impl WorldSim { .iter() .map(|(pos, seed)| RegionInfo { chunk_pos: *pos, - block_pos: pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { - e * sz as i32 - }), + block_pos: pos + .map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e * sz as i32), dist: (pos - chunk_pos).map(|e| e as f32).magnitude(), seed: *seed, }) @@ -429,7 +428,7 @@ impl WorldSim { for i in 0..WORLD_SIZE.x { for j in 0..WORLD_SIZE.y { let chunk_pos = Vec2::new(i as i32, j as i32); - let wpos = chunk_pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { + let wpos = chunk_pos.map2(Vec2::from(TerrainChunkSize::RECT_SIZE), |e, sz: u32| { e * sz as i32 + sz as i32 / 2 }); @@ -474,9 +473,11 @@ impl WorldSim { } pub fn get_wpos(&self, wpos: Vec2) -> Option<&SimChunk> { - self.get(wpos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { - e / sz as i32 - })) + self.get( + wpos.map2(Vec2::from(TerrainChunkSize::RECT_SIZE), |e, sz: u32| { + e / sz as i32 + }), + ) } pub fn get_mut(&mut self, chunk_pos: Vec2) -> Option<&mut SimChunk> { @@ -509,7 +510,7 @@ impl WorldSim { T: Copy + Default + Add + Mul, F: FnMut(&SimChunk) -> T, { - let pos = pos.map2(TerrainChunkSize::SIZE.into(), |e, sz: u32| { + let pos = pos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| { e as f64 / sz as f64 }); @@ -579,7 +580,7 @@ pub struct Structures { impl SimChunk { fn generate(posi: usize, gen_ctx: &mut GenCtx, gen_cdf: &GenCdf) -> Self { let pos = uniform_idx_as_vec2(posi); - let wposf = (pos * TerrainChunkSize::SIZE.map(|e| e as i32)).map(|e| e as f64); + let wposf = (pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32)).map(|e| e as f64); let (_, alt_base) = gen_cdf.alt_base[posi]; let map_edge_factor = map_edge_factor(posi); diff --git a/world/src/sim/util.rs b/world/src/sim/util.rs index 48aa836665..6080d98024 100644 --- a/world/src/sim/util.rs +++ b/world/src/sim/util.rs @@ -1,5 +1,5 @@ use super::WORLD_SIZE; -use common::{terrain::TerrainChunkSize, vol::VolSize}; +use common::{terrain::TerrainChunkSize, vol::RectVolSize}; use vek::*; /// Computes the cumulative distribution function of the weighted sum of k independent, @@ -141,7 +141,7 @@ pub fn uniform_noise(f: impl Fn(usize, Vec2) -> Option) -> InverseCdf .filter_map(|i| { (f( i, - (uniform_idx_as_vec2(i) * TerrainChunkSize::SIZE.map(|e| e as i32)) + (uniform_idx_as_vec2(i) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32)) .map(|e| e as f64), ) .map(|res| (i, res)))