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