diff --git a/common/Cargo.toml b/common/Cargo.toml index d35d5f094a..b07fcfde69 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -6,5 +6,6 @@ edition = "2018" [dependencies] specs = "0.14" +shred = "0.7" vek = "0.9" dot_vox = "1.0" diff --git a/common/src/figure/cell.rs b/common/src/figure/cell.rs index c6e1d79cc4..2d445dcf3d 100644 --- a/common/src/figure/cell.rs +++ b/common/src/figure/cell.rs @@ -1,6 +1,9 @@ // Library use vek::*; +// Crate +use crate::vol::Vox; + /// A type representing a single voxel in a figure #[derive(Copy, Clone, Debug)] pub enum Cell { @@ -9,21 +12,10 @@ pub enum Cell { } impl Cell { - pub fn empty() -> Self { - Cell::Empty - } - pub fn new(rgb: Rgb) -> Self { Cell::Filled(rgb.into_array()) } - pub fn is_empty(&self) -> bool { - match self { - Cell::Filled(_) => false, - Cell::Empty => true, - } - } - pub fn get_color(&self) -> Option> { match self { Cell::Filled(col) => Some(Rgb::from(*col)), @@ -31,3 +23,16 @@ impl Cell { } } } + +impl Vox for Cell { + fn empty() -> Self { + Cell::Empty + } + + fn is_empty(&self) -> bool { + match self { + Cell::Filled(_) => false, + Cell::Empty => true, + } + } +} diff --git a/common/src/figure/mod.rs b/common/src/figure/mod.rs index cd39161bcf..1d59de63b1 100644 --- a/common/src/figure/mod.rs +++ b/common/src/figure/mod.rs @@ -6,7 +6,7 @@ use dot_vox::DotVoxData; // Crate use crate::{ - vol::WriteVol, + vol::{Vox, WriteVol}, volumes::dyna::Dyna, }; diff --git a/common/src/state.rs b/common/src/state.rs index 084b701da6..71a7e741c2 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -3,6 +3,7 @@ use std::time::Duration; // External use specs::World as EcsWorld; +use shred::Fetch; // Crate use crate::{ @@ -24,8 +25,6 @@ struct Tick(f64); /// things like entity components, terrain data, and global state like weather, time of day, etc. pub struct State { ecs_world: EcsWorld, - terrain_map: TerrainMap, - time: f64, } impl State { @@ -36,14 +35,13 @@ impl State { // Register resources used by the ECS ecs_world.add_resource(TimeOfDay(0.0)); ecs_world.add_resource(Tick(0.0)); + ecs_world.add_resource(TerrainMap::new()); // Register common components with the state comp::register_local_components(&mut ecs_world); Self { ecs_world, - terrain_map: TerrainMap::new(), - time: 0.0, } } @@ -61,6 +59,11 @@ impl State { self.ecs_world.read_resource::().0 } + /// Get a reference to this state's terrain. + pub fn terrain<'a>(&'a self) -> Fetch<'a, TerrainMap> { + self.ecs_world.read_resource::() + } + /// Execute a single tick, simulating the game state by the given duration. pub fn tick(&mut self, dt: Duration) { // Change the time accordingly diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index 0b45fdcf8a..18d8b1d760 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -1,5 +1,21 @@ +// Crate +use crate::vol::Vox; + #[derive(Copy, Clone, Debug)] pub struct Block { kind: u8, color: [u8; 3], } + +impl Vox for Block { + fn empty() -> Self { + Self { + kind: 0, + color: [0; 3], + } + } + + fn is_empty(&self) -> bool { + self.kind == 0 + } +} diff --git a/common/src/vol.rs b/common/src/vol.rs index bb49a86423..5a3afdb314 100644 --- a/common/src/vol.rs +++ b/common/src/vol.rs @@ -1,9 +1,15 @@ // Library use vek::*; +/// A voxel +pub trait Vox { + fn empty() -> Self; + fn is_empty(&self) -> bool; +} + /// A volume that contains voxel data. pub trait BaseVol { - type Vox; + type Vox: Vox; type Err; } @@ -53,13 +59,26 @@ pub trait SizedVol: BaseVol { } } -/// A volume that provided read access to its voxel data. +/// 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. #[inline(always)] fn get(&self, pos: Vec3) -> Result<&Self::Vox, Self::Err>; } +/// A volume that provides the ability to sample (i.e: clone a section of) its voxel data. +pub trait SampleVol: BaseVol where Self::Vox: Clone { + type Sample: BaseVol + ReadVol; + /// Take a sample of the volume by cloning voxels within the provided range. + /// + /// Note that value and accessibility of voxels outside the bounds of the sample is + /// implementation-defined and should not be used. + /// + /// Note that the resultant volume has a coordinate space relative to the sample, not the + /// original volume. + fn sample(&self, range: Aabb) -> 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. diff --git a/common/src/volumes/chunk.rs b/common/src/volumes/chunk.rs index fcd0912873..97fbdc7368 100644 --- a/common/src/volumes/chunk.rs +++ b/common/src/volumes/chunk.rs @@ -6,6 +6,7 @@ use vek::*; // Local use crate::vol::{ + Vox, BaseVol, SizedVol, ReadVol, @@ -21,13 +22,13 @@ pub enum ChunkErr { // V = Voxel // S = Size (replace when const generics are a thing) // M = Metadata -pub struct Chunk { +pub struct Chunk { vox: Vec, meta: M, phantom: PhantomData, } -impl Chunk { +impl Chunk { /// Used to transform a voxel position in the volume into its corresponding index in the voxel // array. #[inline(always)] @@ -47,17 +48,17 @@ impl Chunk { } } -impl BaseVol for Chunk { +impl BaseVol for Chunk { type Vox = V; type Err = ChunkErr; } -impl SizedVol for Chunk { +impl SizedVol for Chunk { #[inline(always)] fn get_size(&self) -> Vec3 { S::SIZE } } -impl ReadVol for Chunk { +impl ReadVol for Chunk { #[inline(always)] fn get(&self, pos: Vec3) -> Result<&V, ChunkErr> { Self::idx_for(pos) @@ -66,7 +67,7 @@ impl ReadVol for Chunk { } } -impl WriteVol for Chunk { +impl WriteVol for Chunk { #[inline(always)] fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), ChunkErr> { Self::idx_for(pos) @@ -76,7 +77,7 @@ impl WriteVol for Chunk { } } -impl Chunk { +impl Chunk { /// Create a new `Chunk` with the provided dimensions and all voxels filled with duplicates of /// the provided voxel. pub fn filled(vox: V, meta: M) -> Self { diff --git a/common/src/volumes/dyna.rs b/common/src/volumes/dyna.rs index f975b7e02a..ee51bcbb25 100644 --- a/common/src/volumes/dyna.rs +++ b/common/src/volumes/dyna.rs @@ -3,6 +3,7 @@ use vek::*; // Local use crate::vol::{ + Vox, BaseVol, SizedVol, ReadVol, @@ -17,13 +18,13 @@ pub enum DynaErr { // V = Voxel // S = Size (replace when const generics are a thing) // M = Metadata -pub struct Dyna { +pub struct Dyna { vox: Vec, meta: M, sz: Vec3, } -impl Dyna { +impl Dyna { /// Used to transform a voxel position in the volume into its corresponding index in the voxel // array. #[inline(always)] @@ -43,17 +44,17 @@ impl Dyna { } } -impl BaseVol for Dyna { +impl BaseVol for Dyna { type Vox = V; type Err = DynaErr; } -impl SizedVol for Dyna { +impl SizedVol for Dyna { #[inline(always)] fn get_size(&self) -> Vec3 { self.sz } } -impl ReadVol for Dyna { +impl ReadVol for Dyna { #[inline(always)] fn get(&self, pos: Vec3) -> Result<&V, DynaErr> { Self::idx_for(self.sz, pos) @@ -62,7 +63,7 @@ impl ReadVol for Dyna { } } -impl WriteVol for Dyna { +impl WriteVol for Dyna { #[inline(always)] fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), DynaErr> { Self::idx_for(self.sz, pos) @@ -72,7 +73,7 @@ impl WriteVol for Dyna { } } -impl Dyna { +impl Dyna { /// Create a new `Dyna` with the provided dimensions and all voxels filled with duplicates of /// the provided voxel. pub fn filled(sz: Vec3, vox: V, meta: M) -> Self { diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs index c3c2ff0834..33674d4e33 100644 --- a/common/src/volumes/vol_map.rs +++ b/common/src/volumes/vol_map.rs @@ -7,27 +7,34 @@ use vek::*; // Crate use crate::{ vol::{ + Vox, BaseVol, + SizedVol, ReadVol, + SampleVol, WriteVol, VolSize, }, - volumes::chunk::{Chunk, ChunkErr}, + volumes::{ + chunk::{Chunk, ChunkErr}, + dyna::{Dyna, DynaErr}, + }, }; pub enum VolMapErr { NoSuchChunk, ChunkErr(ChunkErr), + DynaErr(DynaErr), } // V = Voxel // S = Size (replace with a const when const generics is a thing) // M = Chunk metadata -pub struct VolMap { +pub struct VolMap { chunks: HashMap, Chunk>, } -impl VolMap { +impl VolMap { #[inline(always)] fn chunk_key(pos: Vec3) -> Vec3 { pos.map2(S::SIZE, |e, sz| e.div_euclid(sz as i32)) @@ -39,12 +46,12 @@ impl VolMap { } } -impl BaseVol for VolMap { +impl BaseVol for VolMap { type Vox = V; type Err = VolMapErr; } -impl ReadVol for VolMap { +impl ReadVol for VolMap { #[inline(always)] fn get(&self, pos: Vec3) -> Result<&V, VolMapErr> { let ck = Self::chunk_key(pos); @@ -57,7 +64,29 @@ impl ReadVol for VolMap { } } -impl WriteVol for VolMap { +impl SampleVol for VolMap { + type Sample = Dyna; + + /// 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: Aabb) -> Result { + let mut sample = Dyna::filled( + range.size().map(|e| e as u32).into(), + V::empty(), + (), + ); + + for pos in sample.iter_positions() { + sample.set(pos, self.get(range.min + pos)?.clone()) + .map_err(|err| VolMapErr::DynaErr(err))?; + } + + Ok(sample) + } +} + +impl WriteVol for VolMap { #[inline(always)] fn set(&mut self, pos: Vec3, vox: V) -> Result<(), VolMapErr> { let ck = Self::chunk_key(pos); @@ -70,7 +99,7 @@ impl WriteVol for VolMap { } } -impl VolMap { +impl VolMap { pub fn new() -> Self { Self { chunks: HashMap::new(), diff --git a/voxygen/src/anim/character/mod.rs b/voxygen/src/anim/character/mod.rs index 0e63aecf31..367cdf32ed 100644 --- a/voxygen/src/anim/character/mod.rs +++ b/voxygen/src/anim/character/mod.rs @@ -16,7 +16,7 @@ pub struct CharacterSkeleton { head: Bone, chest: Bone, belt: Bone, - leggings: Bone, + shorts: Bone, l_hand: Bone, r_hand: Bone, l_foot: Bone, @@ -30,7 +30,7 @@ impl CharacterSkeleton { head: Bone::default(), chest: Bone::default(), belt: Bone::default(), - leggings: Bone::default(), + shorts: Bone::default(), l_hand: Bone::default(), r_hand: Bone::default(), l_foot: Bone::default(), @@ -48,7 +48,7 @@ impl Skeleton for CharacterSkeleton { FigureBoneData::new(self.head.compute_base_matrix()), FigureBoneData::new(chest_mat), FigureBoneData::new(self.belt.compute_base_matrix()), - FigureBoneData::new(self.leggings.compute_base_matrix()), + FigureBoneData::new(self.shorts.compute_base_matrix()), FigureBoneData::new(self.l_hand.compute_base_matrix()), FigureBoneData::new(self.r_hand.compute_base_matrix()), FigureBoneData::new(self.l_foot.compute_base_matrix()), diff --git a/voxygen/src/anim/character/run.rs b/voxygen/src/anim/character/run.rs index 472ae57923..f1bedf8c07 100644 --- a/voxygen/src/anim/character/run.rs +++ b/voxygen/src/anim/character/run.rs @@ -29,8 +29,8 @@ impl Animation for RunAnimation { skeleton.belt.offset = Vec3::unit_z() * 7.0; skeleton.belt.ori = Quaternion::rotation_z(wave * 0.3); - skeleton.leggings.offset = Vec3::unit_z() * 4.0; - skeleton.leggings.ori = Quaternion::rotation_z(wave * 0.3); + skeleton.shorts.offset = Vec3::unit_z() * 4.0; + skeleton.shorts.ori = Quaternion::rotation_z(wave * 0.3); skeleton.l_hand.offset = Vec3::new(-8.0, wave * 5.0, 9.0); skeleton.r_hand.offset = Vec3::new(8.0, -wave * 5.0, 9.0); diff --git a/voxygen/src/mesh/segment.rs b/voxygen/src/mesh/segment.rs index 4bb540afb5..0980528190 100644 --- a/voxygen/src/mesh/segment.rs +++ b/voxygen/src/mesh/segment.rs @@ -6,6 +6,7 @@ use vek::*; // Project use common::vol::{ + Vox, SizedVol, ReadVol, };