parry2d/shape/voxels/
voxels_neighborhood.rs1use super::VoxelsChunk;
2use crate::math::{Point, Vector, DIM};
3use crate::shape::{VoxelState, Voxels};
4
5impl Voxels {
6 #[must_use]
11 pub(super) fn update_neighbors_state(
12 &mut self,
13 key: Point<i32>,
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[k] -= 1;
22 right[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: Point<i32>) -> 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: Point<i32>) -> VoxelState {
82 let mut occupied_faces = 0;
83
84 for k in 0..DIM {
85 let (mut prev, mut next) = (key, key);
86 prev[k] -= 1;
87 next[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: Point<i32>,
115 origin_shift: Vector<i32>,
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: Vector<i32>) {
141 let one = Vector::repeat(1);
142
143 let [my_domain_mins, my_domain_maxs] = self.domain();
145 let [other_domain_mins, other_domain_maxs] = other.domain();
146 let d0 = [my_domain_mins - one, my_domain_maxs + one * 2];
147 let d1 = [
148 other_domain_mins - one + origin_shift,
149 other_domain_maxs + one * 2 + origin_shift,
150 ];
151
152 let d01 = [d0[0].sup(&d1[0]), d0[1].inf(&d1[1])];
153 for i in d01[0].x..d01[1].x {
159 for j in d01[0].y..d01[1].y {
160 #[cfg(feature = "dim2")]
161 let k_range = 0..1;
162 #[cfg(feature = "dim3")]
163 let k_range = d01[0].z..d01[1].z;
164 for _k in k_range {
165 #[cfg(feature = "dim2")]
166 let key0 = Point::new(i, j);
167 #[cfg(feature = "dim3")]
168 let key0 = Point::new(i, j, _k);
169 let key1 = key0 - origin_shift;
170 let vox0 = self
171 .linear_index(key0)
172 .map(|id| &mut self.chunks[id.chunk_id].states[id.id_in_chunk])
173 .filter(|state| !state.is_empty());
174 let vox1 = other
175 .linear_index(key1)
176 .map(|id| &mut other.chunks[id.chunk_id].states[id.id_in_chunk])
177 .filter(|state| !state.is_empty());
178
179 match (vox0, vox1) {
180 (Some(vox0), Some(vox1)) => {
181 vox0.0 |= vox1.0;
182 vox1.0 |= vox0.0;
183 }
184 (Some(vox0), None) => {
185 vox0.0 |= other.compute_voxel_neighborhood_bits(key1).0;
186 }
187 (None, Some(vox1)) => {
188 vox1.0 |= self.compute_voxel_neighborhood_bits(key0).0;
189 }
190 (None, None) => { }
191 }
192 }
193 }
194 }
195 }
196}