parry2d/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)]
107pub struct VoxelsChunkRef<'a> {
108 pub my_id: usize,
110 pub parent: &'a Voxels,
112 pub states: &'a [VoxelState; VoxelsChunk::VOXELS_PER_CHUNK],
114 pub key: &'a Point<i32>,
116}
117
118impl<'a> VoxelsChunkRef<'a> {
119 pub fn local_aabb(&self) -> Aabb {
124 VoxelsChunk::aabb(self.key, &self.parent.voxel_size)
125 }
126
127 pub fn domain(&self) -> [Point<i32>; 2] {
129 VoxelsChunk::keys_bounds(self.key)
130 }
131
132 pub fn voxel_at_point_unchecked(&self, pt: Point<Real>) -> Point<i32> {
134 self.parent.voxel_at_point(pt)
135 }
136
137 pub fn voxel_state(&self, voxel_key: Point<i32>) -> Option<VoxelState> {
139 let (chunk_key, id_in_chunk) = Voxels::chunk_key_and_id_in_chunk(voxel_key);
140 if &chunk_key != self.key {
141 return None;
142 }
143 Some(self.states[id_in_chunk])
144 }
145
146 pub fn clamp_voxel(&self, voxel_key: Point<i32>) -> Point<i32> {
148 let [mins, maxs] = self.domain();
149 voxel_key
150 .coords
151 .zip_zip_map(&mins.coords, &maxs.coords, |k, min, max| k.clamp(min, max))
152 .into()
153 }
154
155 pub fn voxel_aabb_unchecked(&self, voxel_key: Point<i32>) -> Aabb {
159 self.parent.voxel_aabb(voxel_key)
160 }
161
162 pub fn flat_id(&self, voxel_key: Point<i32>) -> Option<u32> {
167 let (chunk_key, id_in_chunk) = Voxels::chunk_key_and_id_in_chunk(voxel_key);
168 if &chunk_key != self.key {
169 return None;
170 }
171
172 Some(
173 VoxelIndex {
174 chunk_id: self.my_id,
175 id_in_chunk,
176 }
177 .flat_id() as u32,
178 )
179 }
180
181 pub fn voxels(&self) -> impl Iterator<Item = VoxelData> + '_ {
186 let range = self.domain();
187 self.voxels_in_range(range[0], range[1])
188 }
189
190 #[cfg(feature = "dim2")]
195 pub fn voxels_in_range(
196 self,
197 mins: Point<i32>,
198 maxs: Point<i32>,
199 ) -> impl Iterator<Item = VoxelData> + use<'a> {
200 let [chunk_mins, chunk_maxs] = VoxelsChunk::keys_bounds(self.key);
201 let mins = mins.coords.sup(&chunk_mins.coords);
202 let maxs = maxs.coords.inf(&chunk_maxs.coords);
203
204 (mins[0]..maxs[0]).flat_map(move |ix| {
205 (mins[1]..maxs[1]).flat_map(move |iy| {
206 let id_in_chunk = (ix - chunk_mins[0]) as usize
207 + (iy - chunk_mins[1]) as usize * VoxelsChunk::VOXELS_PER_CHUNK_DIM;
208 let state = self.states[id_in_chunk];
209
210 if state.is_empty() {
211 return None;
212 }
213
214 let grid_coords = Point::new(ix, iy);
215 let center = Vector::new(ix as Real + 0.5, iy as Real + 0.5)
216 .component_mul(&self.parent.voxel_size);
217 Some(VoxelData {
218 linear_id: VoxelIndex {
219 chunk_id: self.my_id,
220 id_in_chunk,
221 },
222 grid_coords,
223 center: center.into(),
224 state,
225 })
226 })
227 })
228 }
229
230 #[cfg(feature = "dim3")]
235 pub fn voxels_in_range(
236 self,
237 mins: Point<i32>,
238 maxs: Point<i32>,
239 ) -> impl Iterator<Item = VoxelData> + use<'a> {
240 let [chunk_mins, chunk_maxs] = VoxelsChunk::keys_bounds(self.key);
241 let mins = mins.coords.sup(&chunk_mins.coords);
242 let maxs = maxs.coords.inf(&chunk_maxs.coords);
243
244 (mins[0]..maxs[0]).flat_map(move |ix| {
245 (mins[1]..maxs[1]).flat_map(move |iy| {
246 (mins[2]..maxs[2]).filter_map(move |iz| {
247 let id_in_chunk = (ix - chunk_mins[0]) as usize
248 + (iy - chunk_mins[1]) as usize * VoxelsChunk::VOXELS_PER_CHUNK_DIM
249 + (iz - chunk_mins[2]) as usize
250 * VoxelsChunk::VOXELS_PER_CHUNK_DIM
251 * VoxelsChunk::VOXELS_PER_CHUNK_DIM;
252 let state = self.states[id_in_chunk];
253
254 if state.is_empty() {
255 return None;
256 }
257
258 let grid_coords = Point::new(ix, iy, iz);
259 let center = Vector::new(ix as Real + 0.5, iy as Real + 0.5, iz as Real + 0.5)
260 .component_mul(&self.parent.voxel_size);
261 Some(VoxelData {
262 linear_id: VoxelIndex {
263 chunk_id: self.my_id,
264 id_in_chunk,
265 },
266 grid_coords,
267 center: center.into(),
268 state,
269 })
270 })
271 })
272 })
273 }
274}