veloren_common/volumes/
dyna.rs

1use crate::vol::{
2    BaseVol, DefaultPosIterator, DefaultVolIterator, IntoPosIterator, IntoVolIterator, ReadVol,
3    SizedVol, WriteVol,
4};
5use serde::{Deserialize, Serialize};
6use vek::*;
7
8#[derive(Debug, Clone)]
9pub enum DynaError {
10    OutOfBounds,
11}
12
13/// A volume with dimensions known only at the creation of the object.
14// V = Voxel
15// S = Size (replace when const generics are a thing)
16// M = Metadata
17#[derive(Debug, Serialize, Deserialize)]
18pub struct Dyna<V, M, A: Access = ColumnAccess> {
19    vox: Vec<V>,
20    meta: M,
21    pub sz: Vec3<u32>,
22    _phantom: std::marker::PhantomData<A>,
23}
24
25impl<V: Clone, M: Clone, A: Access> Clone for Dyna<V, M, A> {
26    fn clone(&self) -> Self {
27        Self {
28            vox: self.vox.clone(),
29            meta: self.meta.clone(),
30            sz: self.sz,
31            _phantom: std::marker::PhantomData,
32        }
33    }
34}
35
36impl<V, M, A: Access> Dyna<V, M, A> {
37    /// Used to transform a voxel position in the volume into its corresponding
38    /// index in the voxel array.
39    #[inline(always)]
40    fn idx_for(sz: Vec3<u32>, pos: Vec3<i32>) -> Option<usize> {
41        if pos.map(|e| e >= 0).reduce_and() && pos.map2(sz, |e, lim| e < lim as i32).reduce_and() {
42            Some(A::idx(pos, sz))
43        } else {
44            None
45        }
46    }
47
48    pub fn map_into<W, F: FnMut(V) -> W>(self, f: F) -> Dyna<W, M, A> {
49        let Dyna {
50            vox,
51            meta,
52            sz,
53            _phantom,
54        } = self;
55        Dyna {
56            vox: vox.into_iter().map(f).collect(),
57            meta,
58            sz,
59            _phantom,
60        }
61    }
62}
63
64impl<V, M, A: Access> BaseVol for Dyna<V, M, A> {
65    type Error = DynaError;
66    type Vox = V;
67}
68
69impl<V, M, A: Access> SizedVol for Dyna<V, M, A> {
70    #[inline(always)]
71    fn lower_bound(&self) -> Vec3<i32> { Vec3::zero() }
72
73    #[inline(always)]
74    fn upper_bound(&self) -> Vec3<i32> { self.sz.map(|e| e as i32) }
75}
76
77impl<V, M, A: Access> SizedVol for &Dyna<V, M, A> {
78    #[inline(always)]
79    fn lower_bound(&self) -> Vec3<i32> { (*self).lower_bound() }
80
81    #[inline(always)]
82    fn upper_bound(&self) -> Vec3<i32> { (*self).upper_bound() }
83}
84
85impl<V, M, A: Access> ReadVol for Dyna<V, M, A> {
86    #[inline(always)]
87    fn get(&self, pos: Vec3<i32>) -> Result<&V, DynaError> {
88        Self::idx_for(self.sz, pos)
89            .and_then(|idx| self.vox.get(idx))
90            .ok_or(DynaError::OutOfBounds)
91    }
92}
93
94impl<V, M, A: Access> WriteVol for Dyna<V, M, A> {
95    #[inline(always)]
96    fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<Self::Vox, DynaError> {
97        Self::idx_for(self.sz, pos)
98            .and_then(|idx| self.vox.get_mut(idx))
99            .map(|old_vox| core::mem::replace(old_vox, vox))
100            .ok_or(DynaError::OutOfBounds)
101    }
102}
103
104impl<V, M, A: Access> IntoPosIterator for &Dyna<V, M, A> {
105    type IntoIter = DefaultPosIterator;
106
107    fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
108        Self::IntoIter::new(lower_bound, upper_bound)
109    }
110}
111
112impl<'a, V, M, A: Access> IntoVolIterator<'a> for &'a Dyna<V, M, A> {
113    type IntoIter = DefaultVolIterator<'a, Dyna<V, M, A>>;
114
115    fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
116        Self::IntoIter::new(self, lower_bound, upper_bound)
117    }
118}
119
120impl<V: Clone, M, A: Access> Dyna<V, M, A> {
121    /// Create a new `Dyna` with the provided dimensions and all voxels filled
122    /// with duplicates of the provided voxel.
123    pub fn filled(sz: Vec3<u32>, vox: V, meta: M) -> Self {
124        Self {
125            vox: vec![vox; sz.product() as usize],
126            meta,
127            sz,
128            _phantom: std::marker::PhantomData,
129        }
130    }
131
132    /// Same as [`Dyna::filled`], but with the voxel determined by the function
133    /// `f`.
134    pub fn from_fn<F: FnMut(Vec3<i32>) -> V>(sz: Vec3<u32>, meta: M, mut f: F) -> Self {
135        Self {
136            vox: (0..sz.product() as usize)
137                .map(|idx| f(A::pos(idx, sz)))
138                .collect(),
139            meta,
140            sz,
141            _phantom: std::marker::PhantomData,
142        }
143    }
144
145    /// Get a reference to the internal metadata.
146    pub fn metadata(&self) -> &M { &self.meta }
147
148    /// Get a mutable reference to the internal metadata.
149    pub fn metadata_mut(&mut self) -> &mut M { &mut self.meta }
150}
151
152pub trait Access {
153    fn idx(pos: Vec3<i32>, sz: Vec3<u32>) -> usize;
154    /// `idx` must be in range, permitted to panic otherwise.
155    fn pos(idx: usize, sz: Vec3<u32>) -> Vec3<i32>;
156}
157
158#[derive(Copy, Clone, Debug)]
159pub struct ColumnAccess;
160
161impl Access for ColumnAccess {
162    fn idx(pos: Vec3<i32>, sz: Vec3<u32>) -> usize {
163        (pos.x * sz.y as i32 * sz.z as i32 + pos.y * sz.z as i32 + pos.z) as usize
164    }
165
166    fn pos(idx: usize, sz: Vec3<u32>) -> Vec3<i32> {
167        let z = idx as u32 % sz.z;
168        let y = (idx as u32 / sz.z) % sz.y;
169        let x = idx as u32 / (sz.y * sz.z);
170        Vec3::new(x, y, z).map(|e| e as i32)
171    }
172}