azalea_physics/collision/
discrete_voxel_shape.rs

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    // yeah don't really feel like fixing this one
110    #[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        // more things could be added to DiscreteVoxelShape in the future
333        #[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}