parry3d/shape/voxels/
voxels_chunk.rs1use crate::bounding_volume::Aabb;
2use crate::math::{ivect_to_vect, IVector, Int, Real, Vector};
3use crate::shape::{VoxelData, VoxelState, Voxels};
4
5#[derive(Clone, Debug)]
6#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
7pub(super) struct VoxelsChunkHeader {
8 pub(super) id: usize,
9 pub(super) len: usize,
13}
14
15#[derive(Clone, Debug)]
16#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
17#[repr(C)]
18#[repr(align(64))]
19pub(super) struct VoxelsChunk {
20 #[cfg_attr(feature = "serde-serialize", serde(with = "serde_arrays"))]
21 pub(super) states: [VoxelState; VoxelsChunk::VOXELS_PER_CHUNK],
22}
23
24impl Default for VoxelsChunk {
25 fn default() -> Self {
26 Self {
27 states: [VoxelState::EMPTY; VoxelsChunk::VOXELS_PER_CHUNK],
28 }
29 }
30}
31
32#[derive(Copy, Clone, Debug, PartialEq)]
33pub struct VoxelIndex {
34 pub(super) chunk_id: usize,
35 pub(super) id_in_chunk: usize,
36}
37
38impl VoxelIndex {
39 pub fn flat_id(&self) -> usize {
40 self.chunk_id * VoxelsChunk::VOXELS_PER_CHUNK + self.id_in_chunk
41 }
42
43 pub fn from_flat_id(id: usize) -> Self {
44 Self {
45 chunk_id: id / VoxelsChunk::VOXELS_PER_CHUNK,
46 id_in_chunk: id % VoxelsChunk::VOXELS_PER_CHUNK,
47 }
48 }
49}
50
51impl VoxelsChunk {
52 #[cfg(feature = "dim2")]
55 pub(super) const VOXELS_PER_CHUNK_DIM: usize = 16;
56 #[cfg(feature = "dim3")]
57 pub(super) const VOXELS_PER_CHUNK_DIM: usize = 8;
58 #[cfg(feature = "dim2")]
59 pub(super) const VOXELS_PER_CHUNK: usize =
60 Self::VOXELS_PER_CHUNK_DIM * Self::VOXELS_PER_CHUNK_DIM;
61 #[cfg(feature = "dim3")]
62 pub(super) const VOXELS_PER_CHUNK: usize =
63 Self::VOXELS_PER_CHUNK_DIM * Self::VOXELS_PER_CHUNK_DIM * Self::VOXELS_PER_CHUNK_DIM;
64
65 #[cfg(feature = "dim2")]
66 pub(super) const INVALID_CHUNK_KEY: IVector = IVector::new(Int::MAX, Int::MAX);
67 #[cfg(feature = "dim3")]
68 pub(super) const INVALID_CHUNK_KEY: IVector = IVector::new(Int::MAX, Int::MAX, Int::MAX);
69
70 #[cfg(feature = "dim2")]
72 pub(super) fn voxel_key_at_id(chunk_key: IVector, id_in_chunk: u32) -> IVector {
73 let y = id_in_chunk as Int / Self::VOXELS_PER_CHUNK_DIM as Int;
74 let x = id_in_chunk as Int % Self::VOXELS_PER_CHUNK_DIM as Int;
75 chunk_key * (Self::VOXELS_PER_CHUNK_DIM as Int) + IVector::new(x, y)
76 }
77
78 #[cfg(feature = "dim3")]
80 pub(super) fn voxel_key_at_id(chunk_key: IVector, id_in_chunk: u32) -> IVector {
81 let d0d1 = (Self::VOXELS_PER_CHUNK_DIM * Self::VOXELS_PER_CHUNK_DIM) as u32;
82 let z = id_in_chunk / d0d1;
83 let y = (id_in_chunk - z * d0d1) / Self::VOXELS_PER_CHUNK_DIM as u32;
84 let x = id_in_chunk % Self::VOXELS_PER_CHUNK_DIM as u32;
85 chunk_key * (Self::VOXELS_PER_CHUNK_DIM as Int) + IVector::new(x as Int, y as Int, z as Int)
86 }
87
88 pub(super) fn keys_bounds(chunk_key: &IVector) -> [IVector; 2] {
90 let imins = chunk_key * Self::VOXELS_PER_CHUNK_DIM as Int;
91 let imaxs = imins + IVector::splat(Self::VOXELS_PER_CHUNK_DIM as Int);
92 [imins, imaxs]
93 }
94
95 pub(super) fn aabb(chunk_key: &IVector, voxel_size: Vector) -> Aabb {
96 let [imins, imaxs] = Self::keys_bounds(chunk_key);
97 let aabb = Aabb::new(ivect_to_vect(imins), ivect_to_vect(imaxs));
98 Aabb::new(aabb.mins * voxel_size, aabb.maxs * voxel_size)
99 }
100}
101
102#[derive(Copy, Clone)]
151pub struct VoxelsChunkRef<'a> {
152 pub my_id: usize,
154 pub parent: &'a Voxels,
156 pub states: &'a [VoxelState; VoxelsChunk::VOXELS_PER_CHUNK],
158 pub key: &'a IVector,
160}
161
162impl<'a> VoxelsChunkRef<'a> {
163 pub fn local_aabb(&self) -> Aabb {
168 VoxelsChunk::aabb(self.key, self.parent.voxel_size)
169 }
170
171 pub fn domain(&self) -> [IVector; 2] {
173 VoxelsChunk::keys_bounds(self.key)
174 }
175
176 pub fn voxel_at_point_unchecked(&self, pt: Vector) -> IVector {
178 self.parent.voxel_at_point(pt)
179 }
180
181 pub fn voxel_state(&self, voxel_key: IVector) -> Option<VoxelState> {
183 let (chunk_key, id_in_chunk) = Voxels::chunk_key_and_id_in_chunk(voxel_key);
184 if &chunk_key != self.key {
185 return None;
186 }
187 Some(self.states[id_in_chunk])
188 }
189
190 pub fn clamp_voxel(&self, voxel_key: IVector) -> IVector {
192 let [mins, maxs] = self.domain();
193 voxel_key.clamp(mins, maxs)
194 }
195
196 pub fn voxel_aabb_unchecked(&self, voxel_key: IVector) -> Aabb {
200 self.parent.voxel_aabb(voxel_key)
201 }
202
203 pub fn flat_id(&self, voxel_key: IVector) -> Option<u32> {
208 let (chunk_key, id_in_chunk) = Voxels::chunk_key_and_id_in_chunk(voxel_key);
209 if &chunk_key != self.key {
210 return None;
211 }
212
213 Some(
214 VoxelIndex {
215 chunk_id: self.my_id,
216 id_in_chunk,
217 }
218 .flat_id() as u32,
219 )
220 }
221
222 pub fn voxels(&self) -> impl Iterator<Item = VoxelData> + '_ {
227 let range = self.domain();
228 self.voxels_in_range(range[0], range[1])
229 }
230
231 #[cfg(feature = "dim2")]
236 pub fn voxels_in_range(
237 self,
238 mins: IVector,
239 maxs: IVector,
240 ) -> impl Iterator<Item = VoxelData> + use<'a> {
241 let [chunk_mins, chunk_maxs] = VoxelsChunk::keys_bounds(self.key);
242 let mins = mins.max(chunk_mins);
243 let maxs = maxs.min(chunk_maxs);
244
245 (mins[0]..maxs[0]).flat_map(move |ix| {
246 (mins[1]..maxs[1]).flat_map(move |iy| {
247 let id_in_chunk = (ix - chunk_mins[0]) as usize
248 + (iy - chunk_mins[1]) as usize * VoxelsChunk::VOXELS_PER_CHUNK_DIM;
249 let state = self.states[id_in_chunk];
250
251 if state.is_empty() {
252 return None;
253 }
254
255 let grid_coords = IVector::new(ix, iy);
256 let center =
257 Vector::new(ix as Real + 0.5, iy as Real + 0.5) * (self.parent.voxel_size);
258 Some(VoxelData {
259 linear_id: VoxelIndex {
260 chunk_id: self.my_id,
261 id_in_chunk,
262 },
263 grid_coords,
264 center,
265 state,
266 })
267 })
268 })
269 }
270
271 #[cfg(feature = "dim3")]
276 pub fn voxels_in_range(
277 self,
278 mins: IVector,
279 maxs: IVector,
280 ) -> impl Iterator<Item = VoxelData> + use<'a> {
281 let [chunk_mins, chunk_maxs] = VoxelsChunk::keys_bounds(self.key);
282 let mins = mins.max(chunk_mins);
283 let maxs = maxs.min(chunk_maxs);
284
285 (mins[0]..maxs[0]).flat_map(move |ix| {
286 (mins[1]..maxs[1]).flat_map(move |iy| {
287 (mins[2]..maxs[2]).filter_map(move |iz| {
288 let id_in_chunk = (ix - chunk_mins[0]) as usize
289 + (iy - chunk_mins[1]) as usize * VoxelsChunk::VOXELS_PER_CHUNK_DIM
290 + (iz - chunk_mins[2]) as usize
291 * VoxelsChunk::VOXELS_PER_CHUNK_DIM
292 * VoxelsChunk::VOXELS_PER_CHUNK_DIM;
293 let state = self.states[id_in_chunk];
294
295 if state.is_empty() {
296 return None;
297 }
298
299 let grid_coords = IVector::new(ix, iy, iz);
300 let center = Vector::new(ix as Real + 0.5, iy as Real + 0.5, iz as Real + 0.5)
301 * (self.parent.voxel_size);
302 Some(VoxelData {
303 linear_id: VoxelIndex {
304 chunk_id: self.my_id,
305 id_in_chunk,
306 },
307 grid_coords,
308 center,
309 state,
310 })
311 })
312 })
313 })
314 }
315}