parry2d/shape/voxels/
voxels_neighborhood.rs1use super::VoxelsChunk;
2use crate::math::{ivect_to_vect, IVector, IVectorExt, DIM};
3use crate::shape::{VoxelState, Voxels};
4
5impl Voxels {
6 #[must_use]
11 pub(super) fn update_neighbors_state(
12 &mut self,
13 key: IVector,
14 center_is_empty: bool,
15 ) -> VoxelState {
16 let mut key_data = 0;
17
18 for k in 0..DIM {
19 let mut left = key;
20 let mut right = key;
21 left.ivset(k, left.ivget(k) - 1);
22 right.ivset(k, right.ivget(k) + 1);
23
24 if let Some(left_id) = self.linear_index(left) {
28 let left_state = &mut self.chunks[left_id.chunk_id].states[left_id.id_in_chunk];
29 if !left_state.is_empty() {
30 if center_is_empty {
31 left_state.0 &= !(1 << (k * 2));
32 } else {
33 left_state.0 |= 1 << (k * 2);
34 key_data |= 1 << (k * 2 + 1);
35 }
36 }
37 }
38
39 if let Some(right_id) = self.linear_index(right) {
40 let right_state = &mut self.chunks[right_id.chunk_id].states[right_id.id_in_chunk];
41 if !right_state.is_empty() {
42 if center_is_empty {
43 right_state.0 &= !(1 << (k * 2 + 1));
44 } else {
45 right_state.0 |= 1 << (k * 2 + 1);
46 key_data |= 1 << (k * 2);
47 }
48 }
49 }
50 }
51
52 if center_is_empty {
53 VoxelState::EMPTY
54 } else {
55 VoxelState::new(key_data)
56 }
57 }
58
59 pub(super) fn recompute_all_voxels_states(&mut self) {
60 for (chunk_key, chunk_header) in self.chunk_headers.iter() {
61 for id_in_chunk in 0..VoxelsChunk::VOXELS_PER_CHUNK {
62 let voxel_key = VoxelsChunk::voxel_key_at_id(*chunk_key, id_in_chunk as u32);
63 self.chunks[chunk_header.id].states[id_in_chunk] =
64 self.compute_voxel_state(voxel_key);
65 }
66 }
67 }
68
69 fn compute_voxel_state(&self, key: IVector) -> VoxelState {
70 let Some(id) = self.linear_index(key) else {
71 return VoxelState::EMPTY;
72 };
73
74 if self.chunks[id.chunk_id].states[id.id_in_chunk].is_empty() {
75 return VoxelState::EMPTY;
76 }
77
78 self.compute_voxel_neighborhood_bits(key)
79 }
80
81 pub(super) fn compute_voxel_neighborhood_bits(&self, key: IVector) -> VoxelState {
82 let mut occupied_faces = 0;
83
84 for k in 0..DIM {
85 let (mut prev, mut next) = (key, key);
86 prev.ivset(k, prev.ivget(k) - 1);
87 next.ivset(k, next.ivget(k) + 1);
88
89 if let Some(next_id) = self.linear_index(next) {
90 if !self.chunks[next_id.chunk_id].states[next_id.id_in_chunk].is_empty() {
91 occupied_faces |= 1 << (k * 2);
92 }
93 }
94 if let Some(prev_id) = self.linear_index(prev) {
95 if !self.chunks[prev_id.chunk_id].states[prev_id.id_in_chunk].is_empty() {
96 occupied_faces |= 1 << (k * 2 + 1);
97 }
98 }
99 }
100
101 VoxelState::new(occupied_faces)
102 }
103
104 pub fn propagate_voxel_change(
112 &mut self,
113 other: &mut Self,
114 voxel: IVector,
115 origin_shift: IVector,
116 ) {
117 let center_is_empty = self
118 .voxel_state(voxel)
119 .map(|vox| vox.is_empty())
120 .unwrap_or(true);
121 let center_state_delta =
122 other.update_neighbors_state(voxel - origin_shift, center_is_empty);
123
124 if let Some(vid) = self.linear_index(voxel) {
125 self.chunks[vid.chunk_id].states[vid.id_in_chunk].0 |= center_state_delta.0;
126 }
127 }
128
129 pub fn combine_voxel_states(&mut self, other: &mut Self, origin_shift: IVector) {
141 let one = IVector::splat(1);
142 let origin_shift_worldspace = ivect_to_vect(origin_shift) * self.voxel_size;
143
144 for chunk_key in &self.chunk_keys {
145 let mut aabb = VoxelsChunk::aabb(chunk_key, self.voxel_size);
146 aabb.mins -= self.voxel_size / 2.0;
148 aabb.maxs += self.voxel_size / 2.0;
149 let shifted_aabb = aabb.translated(-origin_shift_worldspace);
151
152 if other.chunk_bvh.intersect_aabb(&shifted_aabb).any(|_| true) {
153 let mut domain = VoxelsChunk::keys_bounds(chunk_key);
161 domain[0] -= one;
163 domain[1] += one;
164
165 for i in domain[0].x..domain[1].x {
166 for j in domain[0].y..domain[1].y {
167 #[cfg(feature = "dim2")]
168 let k_range = 0..1;
169 #[cfg(feature = "dim3")]
170 let k_range = domain[0].z..domain[1].z;
171 for _k in k_range {
172 #[cfg(feature = "dim2")]
173 let key0 = IVector::new(i, j);
174 #[cfg(feature = "dim3")]
175 let key0 = IVector::new(i, j, _k);
176 let key1 = key0 - origin_shift;
177 let vox0 = self
178 .linear_index(key0)
179 .map(|id| &mut self.chunks[id.chunk_id].states[id.id_in_chunk])
180 .filter(|state| !state.is_empty());
181 let vox1 = other
182 .linear_index(key1)
183 .map(|id| &mut other.chunks[id.chunk_id].states[id.id_in_chunk])
184 .filter(|state| !state.is_empty());
185
186 match (vox0, vox1) {
187 (Some(vox0), Some(vox1)) => {
188 vox0.0 |= vox1.0;
189 vox1.0 |= vox0.0;
190 }
191 (Some(vox0), None) => {
192 vox0.0 |= other.compute_voxel_neighborhood_bits(key1).0;
193 }
194 (None, Some(vox1)) => {
195 vox1.0 |= self.compute_voxel_neighborhood_bits(key0).0;
196 }
197 (None, None) => { }
198 }
199 }
200 }
201 }
202 }
203 }
204 }
205}