parry3d/shape/voxels/
voxels_chunk.rs1use crate::bounding_volume::Aabb;
2use crate::math::{Point, Real, Vector};
3use crate::shape::{VoxelData, VoxelState, Voxels};
4use na::point;
5
6#[derive(Clone, Debug)]
7#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
8pub(super) struct VoxelsChunkHeader {
9 pub(super) id: usize,
10 pub(super) len: usize,
14}
15
16#[derive(Clone, Debug)]
17#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
18#[repr(C)]
19#[repr(align(64))]
20pub(super) struct VoxelsChunk {
21 #[cfg_attr(feature = "serde-serialize", serde(with = "serde_arrays"))]
22 pub(super) states: [VoxelState; VoxelsChunk::VOXELS_PER_CHUNK],
23}
24
25impl Default for VoxelsChunk {
26 fn default() -> Self {
27 Self {
28 states: [VoxelState::EMPTY; VoxelsChunk::VOXELS_PER_CHUNK],
29 }
30 }
31}
32
33#[derive(Copy, Clone, Debug, PartialEq)]
34pub struct VoxelIndex {
35 pub(super) chunk_id: usize,
36 pub(super) id_in_chunk: usize,
37}
38
39impl VoxelIndex {
40 pub fn flat_id(&self) -> usize {
41 self.chunk_id * VoxelsChunk::VOXELS_PER_CHUNK + self.id_in_chunk
42 }
43
44 pub fn from_flat_id(id: usize) -> Self {
45 Self {
46 chunk_id: id / VoxelsChunk::VOXELS_PER_CHUNK,
47 id_in_chunk: id % VoxelsChunk::VOXELS_PER_CHUNK,
48 }
49 }
50}
51
52impl VoxelsChunk {
53 #[cfg(feature = "dim2")]
56 pub(super) const VOXELS_PER_CHUNK_DIM: usize = 16;
57 #[cfg(feature = "dim3")]
58 pub(super) const VOXELS_PER_CHUNK_DIM: usize = 8;
59 #[cfg(feature = "dim2")]
60 pub(super) const VOXELS_PER_CHUNK: usize =
61 Self::VOXELS_PER_CHUNK_DIM * Self::VOXELS_PER_CHUNK_DIM;
62 #[cfg(feature = "dim3")]
63 pub(super) const VOXELS_PER_CHUNK: usize =
64 Self::VOXELS_PER_CHUNK_DIM * Self::VOXELS_PER_CHUNK_DIM * Self::VOXELS_PER_CHUNK_DIM;
65
66 #[cfg(feature = "dim2")]
67 pub(super) const INVALID_CHUNK_KEY: Point<i32> = point![i32::MAX, i32::MAX];
68 #[cfg(feature = "dim3")]
69 pub(super) const INVALID_CHUNK_KEY: Point<i32> = point![i32::MAX, i32::MAX, i32::MAX];
70
71 #[cfg(feature = "dim2")]
73 pub(super) fn voxel_key_at_id(chunk_key: Point<i32>, id_in_chunk: u32) -> Point<i32> {
74 let y = id_in_chunk as i32 / Self::VOXELS_PER_CHUNK_DIM as i32;
75 let x = id_in_chunk as i32 % Self::VOXELS_PER_CHUNK_DIM as i32;
76 chunk_key * (Self::VOXELS_PER_CHUNK_DIM as i32) + Vector::new(x, y)
77 }
78
79 #[cfg(feature = "dim3")]
81 pub(super) fn voxel_key_at_id(chunk_key: Point<i32>, id_in_chunk: u32) -> Point<i32> {
82 let d0d1 = (Self::VOXELS_PER_CHUNK_DIM * Self::VOXELS_PER_CHUNK_DIM) as u32;
83 let z = id_in_chunk / d0d1;
84 let y = (id_in_chunk - z * d0d1) / Self::VOXELS_PER_CHUNK_DIM as u32;
85 let x = id_in_chunk % Self::VOXELS_PER_CHUNK_DIM as u32;
86 chunk_key * (Self::VOXELS_PER_CHUNK_DIM as i32) + Vector::new(x as i32, y as i32, z as i32)
87 }
88
89 pub(super) fn keys_bounds(chunk_key: &Point<i32>) -> [Point<i32>; 2] {
91 let imins = chunk_key * Self::VOXELS_PER_CHUNK_DIM as i32;
92 let imaxs = imins + Vector::repeat(Self::VOXELS_PER_CHUNK_DIM as i32);
93 [imins, imaxs]
94 }
95
96 pub(super) fn aabb(chunk_key: &Point<i32>, voxel_size: &Vector<Real>) -> Aabb {
97 let [imins, imaxs] = Self::keys_bounds(chunk_key);
98 let mut aabb = Aabb::new(imins.cast(), imaxs.cast());
99 aabb.mins.coords.component_mul_assign(voxel_size);
100 aabb.maxs.coords.component_mul_assign(voxel_size);
101 aabb
102 }
103}
104
105#[derive(Copy, Clone)]
154pub struct VoxelsChunkRef<'a> {
155 pub my_id: usize,
157 pub parent: &'a Voxels,
159 pub states: &'a [VoxelState; VoxelsChunk::VOXELS_PER_CHUNK],
161 pub key: &'a Point<i32>,
163}
164
165impl<'a> VoxelsChunkRef<'a> {
166 pub fn local_aabb(&self) -> Aabb {
171 VoxelsChunk::aabb(self.key, &self.parent.voxel_size)
172 }
173
174 pub fn domain(&self) -> [Point<i32>; 2] {
176 VoxelsChunk::keys_bounds(self.key)
177 }
178
179 pub fn voxel_at_point_unchecked(&self, pt: Point<Real>) -> Point<i32> {
181 self.parent.voxel_at_point(pt)
182 }
183
184 pub fn voxel_state(&self, voxel_key: Point<i32>) -> Option<VoxelState> {
186 let (chunk_key, id_in_chunk) = Voxels::chunk_key_and_id_in_chunk(voxel_key);
187 if &chunk_key != self.key {
188 return None;
189 }
190 Some(self.states[id_in_chunk])
191 }
192
193 pub fn clamp_voxel(&self, voxel_key: Point<i32>) -> Point<i32> {
195 let [mins, maxs] = self.domain();
196 voxel_key
197 .coords
198 .zip_zip_map(&mins.coords, &maxs.coords, |k, min, max| k.clamp(min, max))
199 .into()
200 }
201
202 pub fn voxel_aabb_unchecked(&self, voxel_key: Point<i32>) -> Aabb {
206 self.parent.voxel_aabb(voxel_key)
207 }
208
209 pub fn flat_id(&self, voxel_key: Point<i32>) -> Option<u32> {
214 let (chunk_key, id_in_chunk) = Voxels::chunk_key_and_id_in_chunk(voxel_key);
215 if &chunk_key != self.key {
216 return None;
217 }
218
219 Some(
220 VoxelIndex {
221 chunk_id: self.my_id,
222 id_in_chunk,
223 }
224 .flat_id() as u32,
225 )
226 }
227
228 pub fn voxels(&self) -> impl Iterator<Item = VoxelData> + '_ {
233 let range = self.domain();
234 self.voxels_in_range(range[0], range[1])
235 }
236
237 #[cfg(feature = "dim2")]
242 pub fn voxels_in_range(
243 self,
244 mins: Point<i32>,
245 maxs: Point<i32>,
246 ) -> impl Iterator<Item = VoxelData> + use<'a> {
247 let [chunk_mins, chunk_maxs] = VoxelsChunk::keys_bounds(self.key);
248 let mins = mins.coords.sup(&chunk_mins.coords);
249 let maxs = maxs.coords.inf(&chunk_maxs.coords);
250
251 (mins[0]..maxs[0]).flat_map(move |ix| {
252 (mins[1]..maxs[1]).flat_map(move |iy| {
253 let id_in_chunk = (ix - chunk_mins[0]) as usize
254 + (iy - chunk_mins[1]) as usize * VoxelsChunk::VOXELS_PER_CHUNK_DIM;
255 let state = self.states[id_in_chunk];
256
257 if state.is_empty() {
258 return None;
259 }
260
261 let grid_coords = Point::new(ix, iy);
262 let center = Vector::new(ix as Real + 0.5, iy as Real + 0.5)
263 .component_mul(&self.parent.voxel_size);
264 Some(VoxelData {
265 linear_id: VoxelIndex {
266 chunk_id: self.my_id,
267 id_in_chunk,
268 },
269 grid_coords,
270 center: center.into(),
271 state,
272 })
273 })
274 })
275 }
276
277 #[cfg(feature = "dim3")]
282 pub fn voxels_in_range(
283 self,
284 mins: Point<i32>,
285 maxs: Point<i32>,
286 ) -> impl Iterator<Item = VoxelData> + use<'a> {
287 let [chunk_mins, chunk_maxs] = VoxelsChunk::keys_bounds(self.key);
288 let mins = mins.coords.sup(&chunk_mins.coords);
289 let maxs = maxs.coords.inf(&chunk_maxs.coords);
290
291 (mins[0]..maxs[0]).flat_map(move |ix| {
292 (mins[1]..maxs[1]).flat_map(move |iy| {
293 (mins[2]..maxs[2]).filter_map(move |iz| {
294 let id_in_chunk = (ix - chunk_mins[0]) as usize
295 + (iy - chunk_mins[1]) as usize * VoxelsChunk::VOXELS_PER_CHUNK_DIM
296 + (iz - chunk_mins[2]) as usize
297 * VoxelsChunk::VOXELS_PER_CHUNK_DIM
298 * VoxelsChunk::VOXELS_PER_CHUNK_DIM;
299 let state = self.states[id_in_chunk];
300
301 if state.is_empty() {
302 return None;
303 }
304
305 let grid_coords = Point::new(ix, iy, iz);
306 let center = Vector::new(ix as Real + 0.5, iy as Real + 0.5, iz as Real + 0.5)
307 .component_mul(&self.parent.voxel_size);
308 Some(VoxelData {
309 linear_id: VoxelIndex {
310 chunk_id: self.my_id,
311 id_in_chunk,
312 },
313 grid_coords,
314 center: center.into(),
315 state,
316 })
317 })
318 })
319 })
320 }
321}