Added vox trait

This commit is contained in:
Joshua Barretto 2019-01-14 18:49:53 +00:00
parent c5a506dad2
commit ae4f1ae2ea
12 changed files with 120 additions and 44 deletions

View File

@ -6,5 +6,6 @@ edition = "2018"
[dependencies] [dependencies]
specs = "0.14" specs = "0.14"
shred = "0.7"
vek = "0.9" vek = "0.9"
dot_vox = "1.0" dot_vox = "1.0"

View File

@ -1,6 +1,9 @@
// Library // Library
use vek::*; use vek::*;
// Crate
use crate::vol::Vox;
/// A type representing a single voxel in a figure /// A type representing a single voxel in a figure
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum Cell { pub enum Cell {
@ -9,21 +12,10 @@ pub enum Cell {
} }
impl Cell { impl Cell {
pub fn empty() -> Self {
Cell::Empty
}
pub fn new(rgb: Rgb<u8>) -> Self { pub fn new(rgb: Rgb<u8>) -> Self {
Cell::Filled(rgb.into_array()) 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<Rgb<u8>> { pub fn get_color(&self) -> Option<Rgb<u8>> {
match self { match self {
Cell::Filled(col) => Some(Rgb::from(*col)), 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,
}
}
}

View File

@ -6,7 +6,7 @@ use dot_vox::DotVoxData;
// Crate // Crate
use crate::{ use crate::{
vol::WriteVol, vol::{Vox, WriteVol},
volumes::dyna::Dyna, volumes::dyna::Dyna,
}; };

View File

@ -3,6 +3,7 @@ use std::time::Duration;
// External // External
use specs::World as EcsWorld; use specs::World as EcsWorld;
use shred::Fetch;
// Crate // Crate
use 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. /// things like entity components, terrain data, and global state like weather, time of day, etc.
pub struct State { pub struct State {
ecs_world: EcsWorld, ecs_world: EcsWorld,
terrain_map: TerrainMap,
time: f64,
} }
impl State { impl State {
@ -36,14 +35,13 @@ impl State {
// Register resources used by the ECS // Register resources used by the ECS
ecs_world.add_resource(TimeOfDay(0.0)); ecs_world.add_resource(TimeOfDay(0.0));
ecs_world.add_resource(Tick(0.0)); ecs_world.add_resource(Tick(0.0));
ecs_world.add_resource(TerrainMap::new());
// Register common components with the state // Register common components with the state
comp::register_local_components(&mut ecs_world); comp::register_local_components(&mut ecs_world);
Self { Self {
ecs_world, ecs_world,
terrain_map: TerrainMap::new(),
time: 0.0,
} }
} }
@ -61,6 +59,11 @@ impl State {
self.ecs_world.read_resource::<Tick>().0 self.ecs_world.read_resource::<Tick>().0
} }
/// Get a reference to this state's terrain.
pub fn terrain<'a>(&'a self) -> Fetch<'a, TerrainMap> {
self.ecs_world.read_resource::<TerrainMap>()
}
/// Execute a single tick, simulating the game state by the given duration. /// Execute a single tick, simulating the game state by the given duration.
pub fn tick(&mut self, dt: Duration) { pub fn tick(&mut self, dt: Duration) {
// Change the time accordingly // Change the time accordingly

View File

@ -1,5 +1,21 @@
// Crate
use crate::vol::Vox;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct Block { pub struct Block {
kind: u8, kind: u8,
color: [u8; 3], color: [u8; 3],
} }
impl Vox for Block {
fn empty() -> Self {
Self {
kind: 0,
color: [0; 3],
}
}
fn is_empty(&self) -> bool {
self.kind == 0
}
}

View File

@ -1,9 +1,15 @@
// Library // Library
use vek::*; use vek::*;
/// A voxel
pub trait Vox {
fn empty() -> Self;
fn is_empty(&self) -> bool;
}
/// A volume that contains voxel data. /// A volume that contains voxel data.
pub trait BaseVol { pub trait BaseVol {
type Vox; type Vox: Vox;
type Err; 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 { pub trait ReadVol: BaseVol {
/// Get a reference to the voxel at the provided position in the volume. /// Get a reference to the voxel at the provided position in the volume.
#[inline(always)] #[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err>; fn get(&self, pos: Vec3<i32>) -> 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<i32>) -> Result<Self::Sample, Self::Err>;
}
/// A volume that provides write access to its voxel data. /// A volume that provides write access to its voxel data.
pub trait WriteVol: BaseVol { pub trait WriteVol: BaseVol {
/// Set the voxel at the provided position in the volume to the provided value. /// Set the voxel at the provided position in the volume to the provided value.

View File

@ -6,6 +6,7 @@ use vek::*;
// Local // Local
use crate::vol::{ use crate::vol::{
Vox,
BaseVol, BaseVol,
SizedVol, SizedVol,
ReadVol, ReadVol,
@ -21,13 +22,13 @@ pub enum ChunkErr {
// V = Voxel // V = Voxel
// S = Size (replace when const generics are a thing) // S = Size (replace when const generics are a thing)
// M = Metadata // M = Metadata
pub struct Chunk<V, S: VolSize, M> { pub struct Chunk<V: Vox, S: VolSize, M> {
vox: Vec<V>, vox: Vec<V>,
meta: M, meta: M,
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
impl<V, S: VolSize, M> Chunk<V, S, M> { impl<V: Vox, S: VolSize, M> Chunk<V, S, M> {
/// Used to transform a voxel position in the volume into its corresponding index in the voxel /// Used to transform a voxel position in the volume into its corresponding index in the voxel
// array. // array.
#[inline(always)] #[inline(always)]
@ -47,17 +48,17 @@ impl<V, S: VolSize, M> Chunk<V, S, M> {
} }
} }
impl<V, S: VolSize, M> BaseVol for Chunk<V, S, M> { impl<V: Vox, S: VolSize, M> BaseVol for Chunk<V, S, M> {
type Vox = V; type Vox = V;
type Err = ChunkErr; type Err = ChunkErr;
} }
impl<V, S: VolSize, M> SizedVol for Chunk<V, S, M> { impl<V: Vox, S: VolSize, M> SizedVol for Chunk<V, S, M> {
#[inline(always)] #[inline(always)]
fn get_size(&self) -> Vec3<u32> { S::SIZE } fn get_size(&self) -> Vec3<u32> { S::SIZE }
} }
impl<V, S: VolSize, M> ReadVol for Chunk<V, S, M> { impl<V: Vox, S: VolSize, M> ReadVol for Chunk<V, S, M> {
#[inline(always)] #[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&V, ChunkErr> { fn get(&self, pos: Vec3<i32>) -> Result<&V, ChunkErr> {
Self::idx_for(pos) Self::idx_for(pos)
@ -66,7 +67,7 @@ impl<V, S: VolSize, M> ReadVol for Chunk<V, S, M> {
} }
} }
impl<V, S: VolSize, M> WriteVol for Chunk<V, S, M> { impl<V: Vox, S: VolSize, M> WriteVol for Chunk<V, S, M> {
#[inline(always)] #[inline(always)]
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), ChunkErr> { fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), ChunkErr> {
Self::idx_for(pos) Self::idx_for(pos)
@ -76,7 +77,7 @@ impl<V, S: VolSize, M> WriteVol for Chunk<V, S, M> {
} }
} }
impl<V: Clone, S: VolSize, M> Chunk<V, S, M> { impl<V: Vox + Clone, S: VolSize, M> Chunk<V, S, M> {
/// Create a new `Chunk` with the provided dimensions and all voxels filled with duplicates of /// Create a new `Chunk` with the provided dimensions and all voxels filled with duplicates of
/// the provided voxel. /// the provided voxel.
pub fn filled(vox: V, meta: M) -> Self { pub fn filled(vox: V, meta: M) -> Self {

View File

@ -3,6 +3,7 @@ use vek::*;
// Local // Local
use crate::vol::{ use crate::vol::{
Vox,
BaseVol, BaseVol,
SizedVol, SizedVol,
ReadVol, ReadVol,
@ -17,13 +18,13 @@ pub enum DynaErr {
// V = Voxel // V = Voxel
// S = Size (replace when const generics are a thing) // S = Size (replace when const generics are a thing)
// M = Metadata // M = Metadata
pub struct Dyna<V, M> { pub struct Dyna<V: Vox, M> {
vox: Vec<V>, vox: Vec<V>,
meta: M, meta: M,
sz: Vec3<u32>, sz: Vec3<u32>,
} }
impl<V, M> Dyna<V, M> { impl<V: Vox, M> Dyna<V, M> {
/// Used to transform a voxel position in the volume into its corresponding index in the voxel /// Used to transform a voxel position in the volume into its corresponding index in the voxel
// array. // array.
#[inline(always)] #[inline(always)]
@ -43,17 +44,17 @@ impl<V, M> Dyna<V, M> {
} }
} }
impl<V, M> BaseVol for Dyna<V, M> { impl<V: Vox, M> BaseVol for Dyna<V, M> {
type Vox = V; type Vox = V;
type Err = DynaErr; type Err = DynaErr;
} }
impl<V, M> SizedVol for Dyna<V, M> { impl<V: Vox, M> SizedVol for Dyna<V, M> {
#[inline(always)] #[inline(always)]
fn get_size(&self) -> Vec3<u32> { self.sz } fn get_size(&self) -> Vec3<u32> { self.sz }
} }
impl<V, M> ReadVol for Dyna<V, M> { impl<V: Vox, M> ReadVol for Dyna<V, M> {
#[inline(always)] #[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&V, DynaErr> { fn get(&self, pos: Vec3<i32>) -> Result<&V, DynaErr> {
Self::idx_for(self.sz, pos) Self::idx_for(self.sz, pos)
@ -62,7 +63,7 @@ impl<V, M> ReadVol for Dyna<V, M> {
} }
} }
impl<V, M> WriteVol for Dyna<V, M> { impl<V: Vox, M> WriteVol for Dyna<V, M> {
#[inline(always)] #[inline(always)]
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), DynaErr> { fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), DynaErr> {
Self::idx_for(self.sz, pos) Self::idx_for(self.sz, pos)
@ -72,7 +73,7 @@ impl<V, M> WriteVol for Dyna<V, M> {
} }
} }
impl<V: Clone, M> Dyna<V, M> { impl<V: Vox + Clone, M> Dyna<V, M> {
/// Create a new `Dyna` with the provided dimensions and all voxels filled with duplicates of /// Create a new `Dyna` with the provided dimensions and all voxels filled with duplicates of
/// the provided voxel. /// the provided voxel.
pub fn filled(sz: Vec3<u32>, vox: V, meta: M) -> Self { pub fn filled(sz: Vec3<u32>, vox: V, meta: M) -> Self {

View File

@ -7,27 +7,34 @@ use vek::*;
// Crate // Crate
use crate::{ use crate::{
vol::{ vol::{
Vox,
BaseVol, BaseVol,
SizedVol,
ReadVol, ReadVol,
SampleVol,
WriteVol, WriteVol,
VolSize, VolSize,
}, },
volumes::chunk::{Chunk, ChunkErr}, volumes::{
chunk::{Chunk, ChunkErr},
dyna::{Dyna, DynaErr},
},
}; };
pub enum VolMapErr { pub enum VolMapErr {
NoSuchChunk, NoSuchChunk,
ChunkErr(ChunkErr), ChunkErr(ChunkErr),
DynaErr(DynaErr),
} }
// V = Voxel // V = Voxel
// S = Size (replace with a const when const generics is a thing) // S = Size (replace with a const when const generics is a thing)
// M = Chunk metadata // M = Chunk metadata
pub struct VolMap<V, S: VolSize, M> { pub struct VolMap<V: Vox, S: VolSize, M> {
chunks: HashMap<Vec3<i32>, Chunk<V, S, M>>, chunks: HashMap<Vec3<i32>, Chunk<V, S, M>>,
} }
impl<V, S: VolSize, M> VolMap<V, S, M> { impl<V: Vox, S: VolSize, M> VolMap<V, S, M> {
#[inline(always)] #[inline(always)]
fn chunk_key(pos: Vec3<i32>) -> Vec3<i32> { fn chunk_key(pos: Vec3<i32>) -> Vec3<i32> {
pos.map2(S::SIZE, |e, sz| e.div_euclid(sz as i32)) pos.map2(S::SIZE, |e, sz| e.div_euclid(sz as i32))
@ -39,12 +46,12 @@ impl<V, S: VolSize, M> VolMap<V, S, M> {
} }
} }
impl<V, S: VolSize, M> BaseVol for VolMap<V, S, M> { impl<V: Vox, S: VolSize, M> BaseVol for VolMap<V, S, M> {
type Vox = V; type Vox = V;
type Err = VolMapErr; type Err = VolMapErr;
} }
impl<V, S: VolSize, M> ReadVol for VolMap<V, S, M> { impl<V: Vox, S: VolSize, M> ReadVol for VolMap<V, S, M> {
#[inline(always)] #[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&V, VolMapErr> { fn get(&self, pos: Vec3<i32>) -> Result<&V, VolMapErr> {
let ck = Self::chunk_key(pos); let ck = Self::chunk_key(pos);
@ -57,7 +64,29 @@ impl<V, S: VolSize, M> ReadVol for VolMap<V, S, M> {
} }
} }
impl<V, S: VolSize, M> WriteVol for VolMap<V, S, M> { impl<V: Vox + Clone, S: VolSize, M> SampleVol for VolMap<V, S, M> {
type Sample = Dyna<V, ()>;
/// 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<i32>) -> Result<Self::Sample, VolMapErr> {
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<V: Vox, S: VolSize, M> WriteVol for VolMap<V, S, M> {
#[inline(always)] #[inline(always)]
fn set(&mut self, pos: Vec3<i32>, vox: V) -> Result<(), VolMapErr> { fn set(&mut self, pos: Vec3<i32>, vox: V) -> Result<(), VolMapErr> {
let ck = Self::chunk_key(pos); let ck = Self::chunk_key(pos);
@ -70,7 +99,7 @@ impl<V, S: VolSize, M> WriteVol for VolMap<V, S, M> {
} }
} }
impl<V, S: VolSize, M> VolMap<V, S, M> { impl<V: Vox, S: VolSize, M> VolMap<V, S, M> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
chunks: HashMap::new(), chunks: HashMap::new(),

View File

@ -16,7 +16,7 @@ pub struct CharacterSkeleton {
head: Bone, head: Bone,
chest: Bone, chest: Bone,
belt: Bone, belt: Bone,
leggings: Bone, shorts: Bone,
l_hand: Bone, l_hand: Bone,
r_hand: Bone, r_hand: Bone,
l_foot: Bone, l_foot: Bone,
@ -30,7 +30,7 @@ impl CharacterSkeleton {
head: Bone::default(), head: Bone::default(),
chest: Bone::default(), chest: Bone::default(),
belt: Bone::default(), belt: Bone::default(),
leggings: Bone::default(), shorts: Bone::default(),
l_hand: Bone::default(), l_hand: Bone::default(),
r_hand: Bone::default(), r_hand: Bone::default(),
l_foot: Bone::default(), l_foot: Bone::default(),
@ -48,7 +48,7 @@ impl Skeleton for CharacterSkeleton {
FigureBoneData::new(self.head.compute_base_matrix()), FigureBoneData::new(self.head.compute_base_matrix()),
FigureBoneData::new(chest_mat), FigureBoneData::new(chest_mat),
FigureBoneData::new(self.belt.compute_base_matrix()), 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.l_hand.compute_base_matrix()),
FigureBoneData::new(self.r_hand.compute_base_matrix()), FigureBoneData::new(self.r_hand.compute_base_matrix()),
FigureBoneData::new(self.l_foot.compute_base_matrix()), FigureBoneData::new(self.l_foot.compute_base_matrix()),

View File

@ -29,8 +29,8 @@ impl Animation for RunAnimation {
skeleton.belt.offset = Vec3::unit_z() * 7.0; skeleton.belt.offset = Vec3::unit_z() * 7.0;
skeleton.belt.ori = Quaternion::rotation_z(wave * 0.3); skeleton.belt.ori = Quaternion::rotation_z(wave * 0.3);
skeleton.leggings.offset = Vec3::unit_z() * 4.0; skeleton.shorts.offset = Vec3::unit_z() * 4.0;
skeleton.leggings.ori = Quaternion::rotation_z(wave * 0.3); skeleton.shorts.ori = Quaternion::rotation_z(wave * 0.3);
skeleton.l_hand.offset = Vec3::new(-8.0, wave * 5.0, 9.0); 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); skeleton.r_hand.offset = Vec3::new(8.0, -wave * 5.0, 9.0);

View File

@ -6,6 +6,7 @@ use vek::*;
// Project // Project
use common::vol::{ use common::vol::{
Vox,
SizedVol, SizedVol,
ReadVol, ReadVol,
}; };