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