1use azalea_core::{
2 bitset::BitSet,
3 direction::{Axis, AxisCycle},
4};
5
6use super::mergers::IndexMerger;
7
8pub trait IntLineConsumer = FnMut(u32, u32, u32, u32, u32, u32);
9
10#[derive(Clone, PartialEq, Eq, Debug)]
11pub enum DiscreteVoxelShape {
12 BitSet(BitSetDiscreteVoxelShape),
13}
14
15impl DiscreteVoxelShape {
16 #[inline]
17 pub fn size(&self, axis: Axis) -> u32 {
18 match self {
19 DiscreteVoxelShape::BitSet(shape) => shape.size(axis),
20 }
21 }
22
23 pub fn first_full(&self, axis: Axis) -> i32 {
24 match self {
25 DiscreteVoxelShape::BitSet(shape) => shape.first_full(axis),
26 }
27 }
28
29 pub fn last_full(&self, axis: Axis) -> i32 {
30 match self {
31 DiscreteVoxelShape::BitSet(shape) => shape.last_full(axis),
32 }
33 }
34
35 pub fn is_empty(&self) -> bool {
36 if self.first_full(Axis::X) >= self.last_full(Axis::X) {
37 return true;
38 }
39 if self.first_full(Axis::Y) >= self.last_full(Axis::Y) {
40 return true;
41 }
42 if self.first_full(Axis::Z) >= self.last_full(Axis::Z) {
43 return true;
44 }
45 false
46 }
47
48 pub fn is_full_wide(&self, x: i32, y: i32, z: i32) -> bool {
49 if x < 0 || y < 0 || z < 0 {
50 return false;
51 }
52 let (x, y, z) = (x as u32, y as u32, z as u32);
53
54 (x < self.size(Axis::X) && y < self.size(Axis::Y) && z < self.size(Axis::Z))
55 && (self.is_full(x, y, z))
56 }
57
58 pub fn is_full_wide_axis_cycle(&self, axis_cycle: AxisCycle, x: i32, y: i32, z: i32) -> bool {
59 self.is_full_wide(
60 axis_cycle.cycle_xyz(x, y, z, Axis::X),
61 axis_cycle.cycle_xyz(x, y, z, Axis::Y),
62 axis_cycle.cycle_xyz(x, y, z, Axis::Z),
63 )
64 }
65
66 pub fn is_full(&self, x: u32, y: u32, z: u32) -> bool {
67 match self {
68 DiscreteVoxelShape::BitSet(shape) => shape.is_full(x, y, z),
69 }
70 }
71
72 pub fn for_all_boxes(&self, consumer: impl IntLineConsumer, swap: bool) {
73 BitSetDiscreteVoxelShape::for_all_boxes(self, consumer, swap);
74 }
75}
76
77#[derive(Default, Clone, PartialEq, Eq, Debug)]
78pub struct BitSetDiscreteVoxelShape {
79 x_size: u32,
80 y_size: u32,
81 z_size: u32,
82
83 storage: BitSet,
84 x_min: i32,
85 y_min: i32,
86 z_min: i32,
87 x_max: i32,
88 y_max: i32,
89 z_max: i32,
90}
91
92impl BitSetDiscreteVoxelShape {
93 pub fn new(x_min: u32, y_min: u32, z_min: u32) -> Self {
94 BitSetDiscreteVoxelShape {
95 x_size: x_min,
96 y_size: y_min,
97 z_size: z_min,
98
99 storage: BitSet::new((x_min * y_min * z_min).try_into().unwrap()),
100 x_min: z_min.try_into().unwrap(),
101 y_min: z_min.try_into().unwrap(),
102 z_min: z_min.try_into().unwrap(),
103 x_max: 0,
104 y_max: 0,
105 z_max: 0,
106 }
107 }
108
109 #[allow(clippy::too_many_arguments)]
111 pub fn with_filled_bounds(
112 x_size: u32,
113 y_size: u32,
114 z_size: u32,
115 x_min: i32,
116 y_min: i32,
117 z_min: i32,
118 x_max: i32,
119 y_max: i32,
120 z_max: i32,
121 ) -> Self {
122 let mut shape = BitSetDiscreteVoxelShape::new(x_size, y_size, z_size);
123 shape.x_min = x_min;
124 shape.y_min = y_min;
125 shape.z_min = z_min;
126 shape.x_max = x_max;
127 shape.y_max = y_max;
128 shape.z_max = z_max;
129
130 for x in x_min..x_max {
131 for y in y_min..y_max {
132 for z in z_min..z_max {
133 shape.fill_update_bounds(
134 x.try_into().unwrap(),
135 y.try_into().unwrap(),
136 z.try_into().unwrap(),
137 false,
138 );
139 }
140 }
141 }
142
143 shape
144 }
145
146 fn fill_update_bounds(&mut self, x: u32, y: u32, z: u32, update: bool) {
147 self.storage.set(self.get_index(x, y, z));
148 if update {
149 self.x_min = std::cmp::min(self.x_min, x as i32);
150 self.y_min = std::cmp::min(self.y_min, y as i32);
151 self.z_min = std::cmp::min(self.z_min, z as i32);
152 self.x_max = std::cmp::max(self.x_max, (x + 1) as i32);
153 self.y_max = std::cmp::max(self.y_max, (y + 1) as i32);
154 self.z_max = std::cmp::max(self.z_max, (z + 1) as i32);
155 }
156 }
157
158 pub fn fill(&mut self, x: u32, y: u32, z: u32) {
159 self.fill_update_bounds(x, y, z, true);
160 }
161
162 fn get_index_from_size(x: u32, y: u32, z: u32, y_size: u32, z_size: u32) -> usize {
163 ((x * y_size + y) * z_size + z) as usize
164 }
165 fn get_index(&self, x: u32, y: u32, z: u32) -> usize {
166 Self::get_index_from_size(x, y, z, self.y_size, self.z_size)
167 }
168
169 pub fn join(
170 var0: &DiscreteVoxelShape,
171 var1: &DiscreteVoxelShape,
172 var2: &IndexMerger,
173 var3: &IndexMerger,
174 var4: &IndexMerger,
175 var5: impl Fn(bool, bool) -> bool,
176 ) -> Self {
177 let mut var6 = BitSetDiscreteVoxelShape::new(
178 (var2.size() - 1) as u32,
179 (var3.size() - 1) as u32,
180 (var4.size() - 1) as u32,
181 );
182 let mut var7: [i32; 6] = [
183 2147483647,
184 2147483647,
185 2147483647,
186 -2147483648,
187 -2147483648,
188 -2147483648,
189 ];
190 var2.for_merged_indexes(|var7x: i32, var8: i32, var9: i32| {
191 let mut var10 = [false];
192 var3.for_merged_indexes(|var10x: i32, var11: i32, var12: i32| {
193 let mut var13 = [false];
194 var4.for_merged_indexes(|var12x: i32, var13x: i32, var14: i32| {
195 if var5(
196 var0.is_full_wide(var7x, var10x, var12x),
197 var1.is_full_wide(var8, var11, var13x),
198 ) {
199 var6.storage.set(var6.get_index(
200 var9.try_into().unwrap(),
201 var12.try_into().unwrap(),
202 var14.try_into().unwrap(),
203 ));
204 var7[2] = std::cmp::min(var7[2], var14);
205 var7[5] = std::cmp::max(var7[5], var14);
206 var13[0] = true;
207 }
208
209 true
210 });
211 if var13[0] {
212 var7[1] = std::cmp::min(var7[1], var12);
213 var7[4] = std::cmp::max(var7[4], var12);
214 var10[0] = true;
215 }
216
217 true
218 });
219 if var10[0] {
220 var7[0] = std::cmp::min(var7[0], var9);
221 var7[3] = std::cmp::max(var7[3], var9);
222 }
223
224 true
225 });
226 var6.x_min = var7[0];
227 var6.y_min = var7[1];
228 var6.z_min = var7[2];
229 var6.x_max = var7[3] + 1;
230 var6.y_max = var7[4] + 1;
231 var6.z_max = var7[5] + 1;
232 var6
233 }
234
235 pub fn for_all_boxes(
236 var0: &DiscreteVoxelShape,
237 mut consumer: impl IntLineConsumer,
238 var2: bool,
239 ) {
240 let mut var3 = BitSetDiscreteVoxelShape::from(var0);
241 for y in 0..var3.y_size {
242 for x in 0..var3.x_size {
243 let mut var6 = None;
244 for z in 0..=var3.z_size {
245 if var3.is_full_wide(x, y, z) {
246 if var2 {
247 if var6.is_none() {
248 var6 = Some(z);
249 }
250 } else {
251 consumer(x, y, z, x + 1, y + 1, z + 1);
252 }
253 } else if var6.is_some() {
254 let mut var8 = x;
255 let mut var9 = y;
256 var3.clear_z_strip(var6.unwrap(), z, x, y);
257 while var3.is_z_strip_full(var6.unwrap(), z, var8 + 1, y) {
258 var3.clear_z_strip(var6.unwrap(), z, var8 + 1, y);
259 var8 += 1;
260 }
261 while var3.is_xz_rectangle_full(x, var8 + 1, var6.unwrap(), z, var9 + 1) {
262 for var10 in x..=var8 {
263 var3.clear_z_strip(var6.unwrap(), z, var10, var9 + 1);
264 }
265 var9 += 1;
266 }
267 consumer(x, y, var6.unwrap(), var8 + 1, var9 + 1, z);
268 var6 = None;
269 }
270 }
271 }
272 }
273 }
274
275 fn is_z_strip_full(&self, var1: u32, var2: u32, var3: u32, var4: u32) -> bool {
276 if var3 < self.x_size && var4 < self.y_size {
277 self.storage
278 .next_clear_bit(self.get_index(var3, var4, var1))
279 >= self.get_index(var3, var4, var2)
280 } else {
281 false
282 }
283 }
284
285 fn is_xz_rectangle_full(&self, var1: u32, var2: u32, var3: u32, var4: u32, var5: u32) -> bool {
286 for var6 in var1..var2 {
287 if !self.is_z_strip_full(var3, var4, var6, var5) {
288 return false;
289 }
290 }
291 true
292 }
293
294 fn clear_z_strip(&mut self, var1: u32, var2: u32, var3: u32, var4: u32) {
295 self.storage.clear(
296 self.get_index(var3, var4, var1),
297 self.get_index(var3, var4, var2),
298 );
299 }
300}
301
302impl BitSetDiscreteVoxelShape {
303 #[inline]
304 fn size(&self, axis: Axis) -> u32 {
305 axis.choose(self.x_size, self.y_size, self.z_size)
306 }
307
308 fn first_full(&self, axis: Axis) -> i32 {
309 axis.choose(self.x_min, self.y_min, self.z_min)
310 }
311
312 fn last_full(&self, axis: Axis) -> i32 {
313 axis.choose(self.x_max, self.y_max, self.z_max)
314 }
315
316 fn is_full(&self, x: u32, y: u32, z: u32) -> bool {
317 self.storage.index(self.get_index(x, y, z))
318 }
319
320 fn is_full_wide(&self, x: u32, y: u32, z: u32) -> bool {
321 (x < self.size(Axis::X) && y < self.size(Axis::Y) && z < self.size(Axis::Z))
322 && (self.is_full(x, y, z))
323 }
324}
325
326impl From<&DiscreteVoxelShape> for BitSetDiscreteVoxelShape {
327 fn from(shape: &DiscreteVoxelShape) -> Self {
328 let x_size = shape.size(Axis::X);
329 let y_size = shape.size(Axis::Y);
330 let z_size = shape.size(Axis::Z);
331 let mut storage;
332 #[allow(irrefutable_let_patterns)]
334 if let DiscreteVoxelShape::BitSet(shape) = shape {
335 storage = shape.storage.clone();
336 } else {
337 storage = BitSet::new((x_size * y_size * z_size) as usize);
338 for x in 0..x_size {
339 for y in 0..y_size {
340 for z in 0..z_size {
341 if shape.is_full(x, y, z) {
342 storage.set(Self::get_index_from_size(x, y, z, y_size, z_size));
343 }
344 }
345 }
346 }
347 }
348
349 Self {
350 x_size,
351 y_size,
352 z_size,
353 storage,
354 x_min: shape.first_full(Axis::X),
355 y_min: shape.first_full(Axis::Y),
356 z_min: shape.first_full(Axis::Z),
357 x_max: shape.last_full(Axis::X),
358 y_max: shape.last_full(Axis::Y),
359 z_max: shape.last_full(Axis::Z),
360 }
361 }
362}