veloren_common/
vol.rs

1use crate::{ray::Ray, volumes::scaled::Scaled};
2use std::fmt::Debug;
3use vek::*;
4
5/// Used to specify a volume's compile-time size. This exists as a substitute
6/// until const generics are implemented.
7pub trait VolSize: Clone {
8    const SIZE: Vec3<u32>;
9}
10
11pub trait RectVolSize: Clone {
12    const RECT_SIZE: Vec2<u32>;
13}
14
15/// A voxel.
16pub trait FilledVox: Sized + Clone + PartialEq {
17    fn default_non_filled() -> Self;
18    fn is_filled(&self) -> bool;
19
20    #[must_use]
21    fn or(self, other: Self) -> Self { if self.is_filled() { self } else { other } }
22}
23
24/// A volume that contains voxel data.
25pub trait BaseVol {
26    type Vox;
27    type Error: Debug;
28
29    fn scaled_by(self, scale: Vec3<f32>) -> Scaled<Self>
30    where
31        Self: Sized,
32    {
33        Scaled { inner: self, scale }
34    }
35}
36
37/// Implementing `BaseVol` for any `&'a BaseVol` makes it possible to implement
38/// `IntoVolIterator` for references.
39impl<T: BaseVol> BaseVol for &T {
40    type Error = T::Error;
41    type Vox = T::Vox;
42}
43
44// Utility types
45
46/// A volume that is a cuboid.
47pub trait SizedVol: BaseVol {
48    /// Returns the (inclusive) lower bound of the volume.
49    fn lower_bound(&self) -> Vec3<i32>;
50
51    /// Returns the (exclusive) upper bound of the volume.
52    fn upper_bound(&self) -> Vec3<i32>;
53
54    /// Returns the size of the volume.
55    fn size(&self) -> Vec3<u32> { (self.upper_bound() - self.lower_bound()).map(|e| e as u32) }
56}
57
58/// A volume that is compile-time sized and has its lower bound at `(0, 0, 0)`.
59/// The name `RasterableVol` was chosen because such a volume can be used with
60/// `VolGrid3d`.
61pub trait RasterableVol: BaseVol {
62    const SIZE: Vec3<u32>;
63}
64
65impl<V: RasterableVol> SizedVol for V {
66    fn lower_bound(&self) -> Vec3<i32> { Vec3::zero() }
67
68    fn upper_bound(&self) -> Vec3<i32> { V::SIZE.map(|e| e as i32) }
69}
70
71/// A volume whose cross section with the XY-plane is a rectangle.
72pub trait RectSizedVol: BaseVol {
73    fn lower_bound_xy(&self) -> Vec2<i32>;
74
75    fn upper_bound_xy(&self) -> Vec2<i32>;
76
77    fn size_xy(&self) -> Vec2<u32> {
78        (self.upper_bound_xy() - self.lower_bound_xy()).map(|e| e as u32)
79    }
80}
81
82/// A volume that is compile-time sized in x and y direction and has its lower
83/// bound at `(0, 0, z)`. In z direction there's no restriction on the lower
84/// or upper bound. The name `RectRasterableVol` was chosen because such a
85/// volume can be used with `VolGrid2d`.
86pub trait RectRasterableVol: BaseVol {
87    const RECT_SIZE: Vec2<u32>;
88}
89
90impl<V: RectRasterableVol> RectSizedVol for V {
91    fn lower_bound_xy(&self) -> Vec2<i32> { Vec2::zero() }
92
93    fn upper_bound_xy(&self) -> Vec2<i32> { V::RECT_SIZE.map(|e| e as i32) }
94}
95
96/// A volume that provides read access to its voxel data.
97pub trait ReadVol: BaseVol {
98    /// Get a reference to the voxel at the provided position in the volume.
99    fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Error>;
100
101    /// Get a reference to the voxel at the provided position in the volume.
102    /// Many volumes provide a fast path, provided the position is always
103    /// in-bounds. Note that this function is still safe.
104    fn get_unchecked(&self, pos: Vec3<i32>) -> &Self::Vox { self.get(pos).unwrap() }
105
106    /// NOTE: By default, this ray will simply run from `from` to `to` without
107    /// stopping.  To make something interesting happen, call `until` or
108    /// `for_each`.
109    fn ray(
110        &self,
111        from: Vec3<f32>,
112        to: Vec3<f32>,
113    ) -> Ray<Self, fn(&Self::Vox) -> bool, fn(&Self::Vox, Vec3<i32>)>
114    where
115        Self: Sized,
116    {
117        Ray::new(self, from, to, |_| false)
118    }
119
120    /// Call provided closure with each block in the supplied Aabb
121    /// Portions of the Aabb outside the volume are ignored
122    fn for_each_in(&self, aabb: Aabb<i32>, mut f: impl FnMut(Vec3<i32>, Self::Vox))
123    where
124        Self::Vox: Copy,
125    {
126        for z in aabb.min.z..aabb.max.z + 1 {
127            for y in aabb.min.y..aabb.max.y + 1 {
128                for x in aabb.min.x..aabb.max.x + 1 {
129                    if let Ok(block) = self.get(Vec3::new(x, y, z)) {
130                        f(Vec3::new(x, y, z), *block);
131                    }
132                }
133            }
134        }
135    }
136}
137
138/// A volume that provides the ability to sample (i.e., clone a section of) its
139/// voxel data.
140///
141/// TODO (haslersn): Do we still need this now that we have `IntoVolIterator`?
142pub trait SampleVol<I>: BaseVol {
143    type Sample: BaseVol + ReadVol;
144    /// Take a sample of the volume by cloning voxels within the provided range.
145    ///
146    /// Note that value and accessibility of voxels outside the bounds of the
147    /// sample is implementation-defined and should not be used.
148    ///
149    /// Note that the resultant volume has a coordinate space relative to the
150    /// sample, not the original volume.
151    fn sample(&self, range: I) -> Result<Self::Sample, Self::Error>;
152}
153
154/// A volume that provides write access to its voxel data.
155pub trait WriteVol: BaseVol {
156    /// Set the voxel at the provided position in the volume to the provided
157    /// value.
158    fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<Self::Vox, Self::Error>;
159
160    /// Map a voxel to another using the provided function.
161    // TODO: Is `map` the right name? Implies a change in type.
162    fn map<F: FnOnce(Self::Vox) -> Self::Vox>(
163        &mut self,
164        pos: Vec3<i32>,
165        f: F,
166    ) -> Result<Self::Vox, Self::Error>
167    where
168        Self: ReadVol,
169        Self::Vox: Clone,
170    {
171        // This is *deliberately* not using a get_mut since this might trigger a
172        // repr change of the underlying volume
173        self.set(pos, f(self.get(pos)?.clone()))
174    }
175}
176
177/// A volume (usually rather a reference to a volume) that is convertible into
178/// an iterator to a cuboid subsection of the volume.
179pub trait IntoVolIterator<'a>: BaseVol
180where
181    Self::Vox: 'a,
182{
183    type IntoIter: Iterator<Item = (Vec3<i32>, &'a Self::Vox)>;
184
185    fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter;
186}
187
188pub trait IntoPosIterator: BaseVol {
189    type IntoIter: Iterator<Item = Vec3<i32>>;
190
191    fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter;
192}
193
194// Helpers
195
196/// A volume (usually rather a reference to a volume) that is convertible into
197/// an iterator.
198pub trait IntoFullVolIterator<'a>: BaseVol
199where
200    Self::Vox: 'a,
201{
202    type IntoIter: Iterator<Item = (Vec3<i32>, &'a Self::Vox)>;
203
204    fn full_vol_iter(self) -> Self::IntoIter;
205}
206
207/// For any `&'a SizedVol: IntoVolIterator` we implement `IntoFullVolIterator`.
208/// Unfortunately we can't just implement `IntoIterator` in this generic way
209/// because it's defined in another crate. That's actually the only reason why
210/// the trait `IntoFullVolIterator` exists.
211// TODO: See whether relaxed orphan rules permit this to be replaced now
212impl<'a, T: 'a + SizedVol> IntoFullVolIterator<'a> for &'a T
213where
214    Self: IntoVolIterator<'a>,
215{
216    type IntoIter = <Self as IntoVolIterator<'a>>::IntoIter;
217
218    fn full_vol_iter(self) -> Self::IntoIter {
219        self.vol_iter(self.lower_bound(), self.upper_bound())
220    }
221}
222
223pub trait IntoFullPosIterator: BaseVol {
224    type IntoIter: Iterator<Item = Vec3<i32>>;
225
226    fn full_pos_iter(self) -> Self::IntoIter;
227}
228
229impl<'a, T: 'a + SizedVol> IntoFullPosIterator for &'a T
230where
231    Self: IntoPosIterator,
232{
233    type IntoIter = <Self as IntoPosIterator>::IntoIter;
234
235    fn full_pos_iter(self) -> Self::IntoIter {
236        self.pos_iter(self.lower_bound(), self.upper_bound())
237    }
238}
239
240// Defaults
241
242/// Convenience iterator type that can be used to quickly implement
243/// `IntoPosIterator`.
244#[derive(Clone)]
245pub struct DefaultPosIterator {
246    current: Vec3<i32>,
247    begin: Vec2<i32>,
248    end: Vec3<i32>,
249}
250
251impl DefaultPosIterator {
252    pub fn new(lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self {
253        debug_assert!(lower_bound.map2(upper_bound, |l, u| l <= u).reduce_and());
254        let end = if lower_bound.map2(upper_bound, |l, u| l < u).reduce_and() {
255            upper_bound
256        } else {
257            // Special case because our implementation doesn't handle empty ranges for x or
258            // y:
259            lower_bound
260        };
261        Self {
262            current: lower_bound,
263            begin: From::from(lower_bound),
264            end,
265        }
266    }
267}
268
269impl Iterator for DefaultPosIterator {
270    type Item = Vec3<i32>;
271
272    fn next(&mut self) -> Option<Vec3<i32>> {
273        if self.current.z == self.end.z {
274            return None;
275        }
276        let ret = self.current;
277        self.current.x += 1;
278        if self.current.x == self.end.x {
279            self.current.x = self.begin.x;
280            self.current.y += 1;
281            if self.current.y == self.end.y {
282                self.current.y = self.begin.y;
283                self.current.z += 1;
284            }
285        }
286        Some(ret)
287    }
288}
289
290/// Convenience iterator type that can be used to quickly implement
291/// `IntoVolIterator`.
292#[derive(Clone)]
293pub struct DefaultVolIterator<'a, T: ReadVol> {
294    vol: &'a T,
295    pos_iter: DefaultPosIterator,
296}
297
298impl<'a, T: ReadVol> DefaultVolIterator<'a, T> {
299    pub fn new(vol: &'a T, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self {
300        Self {
301            vol,
302            pos_iter: DefaultPosIterator::new(lower_bound, upper_bound),
303        }
304    }
305}
306
307impl<'a, T: ReadVol> Iterator for DefaultVolIterator<'a, T> {
308    type Item = (Vec3<i32>, &'a T::Vox);
309
310    fn next(&mut self) -> Option<(Vec3<i32>, &'a T::Vox)> {
311        for pos in &mut self.pos_iter {
312            if let Ok(vox) = self.vol.get(pos) {
313                return Some((pos, vox));
314            }
315        }
316        None
317    }
318}
319
320impl<T: ReadVol> ReadVol for &T {
321    #[inline(always)]
322    fn get(&self, pos: Vec3<i32>) -> Result<&'_ Self::Vox, Self::Error> { (*self).get(pos) }
323}