Skip to main content

bevy_rapier2d/geometry/shape_views/
voxels.rs

1use rapier::prelude::{Aabb, VoxelData, VoxelState, Voxels};
2
3use crate::math::{IVect, Vect};
4
5#[cfg(feature = "dim2")]
6use bevy::math::bounding::Aabb2d as BevyAabb;
7#[cfg(feature = "dim3")]
8use bevy::math::bounding::Aabb3d as BevyAabb;
9
10#[cfg(feature = "dim2")]
11fn aabb_na_from_bevy(aabb: &BevyAabb) -> Aabb {
12    rapier::parry::bounding_volume::Aabb::new(aabb.min, aabb.max)
13}
14
15#[cfg(feature = "dim3")]
16fn aabb_na_from_bevy(aabb: &BevyAabb) -> Aabb {
17    rapier::parry::bounding_volume::Aabb::new(aabb.min.into(), aabb.max.into())
18}
19
20#[cfg(feature = "dim2")]
21fn aabb_bevy_from_na(aabb: &Aabb) -> BevyAabb {
22    BevyAabb {
23        min: aabb.mins,
24        max: aabb.maxs,
25    }
26}
27
28#[cfg(feature = "dim3")]
29fn aabb_bevy_from_na(aabb: &Aabb) -> BevyAabb {
30    BevyAabb {
31        min: aabb.mins.into(),
32        max: aabb.maxs.into(),
33    }
34}
35
36/// Read-only access to the properties of a [`Voxels`] shape.
37#[derive(Copy, Clone)]
38pub struct VoxelsView<'a> {
39    /// The raw shape from Rapier.
40    pub raw: &'a Voxels,
41}
42
43// TODO: implement those on VoxelsViewMut too.
44macro_rules! impl_ref_methods(
45    ($View: ident) => {
46        impl<'a> $View<'a> {
47            /// Shortcut to [`Voxels::total_memory_size`].
48            pub fn total_memory_size(&self) -> usize {
49                self.raw.total_memory_size()
50            }
51
52            /// Shortcut to [`Voxels::heap_memory_size`].
53            pub fn heap_memory_size(&self) -> usize {
54                self.raw.heap_memory_size()
55            }
56
57            /// Shortcut to [`Voxels::local_aabb`].
58            pub fn extents(&self) -> Vect {
59                self.raw.local_aabb().extents()
60            }
61
62            /// Shortcut to [`Voxels::local_aabb`].
63            pub fn domain_center(&self) -> Vect {
64                self.raw.local_aabb().center()
65            }
66
67            /// Shortcut to [`Voxels::domain`].
68            pub fn is_voxel_in_bounds(&self, key: IVect) -> bool {
69                let [mins, maxs] = self.raw.domain();
70                #[cfg(feature = "dim2")]
71                {
72                    key.x >= mins.x && key.y >= mins.y && key.x < maxs.x && key.y < maxs.y
73                }
74                #[cfg(feature = "dim3")]
75                {
76                    key.x >= mins.x
77                        && key.y >= mins.y
78                        && key.z >= mins.z
79                        && key.x < maxs.x
80                        && key.y < maxs.y
81                        && key.z < maxs.z
82                }
83            }
84
85            /// Shortcut to [`Voxels::voxel_aabb`].
86            pub fn voxel_aabb(&self, key: IVect) -> BevyAabb {
87                aabb_bevy_from_na(&self.raw.voxel_aabb(key.into()))
88            }
89
90            /// Shortcut to [`Voxels::voxel_state`].
91            pub fn voxel_state(&self, key: IVect) -> Option<VoxelState> {
92                self.raw.voxel_state(key.into())
93            }
94
95            /// Shortcut to [`Voxels::voxel_at_point`].
96            pub fn voxel_at_point_unchecked(&self, point: Vect) -> IVect {
97                self.raw.voxel_at_point(point)
98            }
99
100            /// Shortcut to [`Voxels::voxel_at_point`].
101            pub fn voxel_at_point(&self, pt: Vect) -> Option<IVect> {
102                let voxel = self.voxel_at_point_unchecked(pt);
103                if self.is_voxel_in_bounds(voxel) {
104                    Some(voxel)
105                } else {
106                    None
107                }
108            }
109
110            /// Shortcut to [`Voxels::domain`].
111            pub fn clamp_voxel(&self, key: IVect) -> IVect {
112                let [mins, maxs] = self.raw.domain();
113                #[cfg(feature = "dim2")]
114                {
115                    IVect::new(
116                        key.x.clamp(mins.x, maxs.x - 1),
117                        key.y.clamp(mins.y, maxs.y - 1),
118                    )
119                }
120                #[cfg(feature = "dim3")]
121                {
122                    IVect::new(
123                        key.x.clamp(mins.x, maxs.x - 1),
124                        key.y.clamp(mins.y, maxs.y - 1),
125                        key.z.clamp(mins.z, maxs.z - 1),
126                    )
127                }
128            }
129
130            /// Shortcut to [`Voxels::voxel_range_intersecting_local_aabb`].
131            pub fn voxel_range_intersecting_local_aabb(&self, aabb: &BevyAabb) -> [IVect; 2] {
132                let res = self
133                    .raw
134                    .voxel_range_intersecting_local_aabb(&aabb_na_from_bevy(aabb));
135                [res[0].into(), res[1].into()]
136            }
137
138            /// Shortcut to [`Voxels::voxel_range_aabb`].
139            pub fn voxel_range_aabb(&self, mins: IVect, maxs: IVect) -> BevyAabb {
140                aabb_bevy_from_na(&self.raw.voxel_range_aabb(mins.into(), maxs.into()))
141            }
142
143            /// Shortcut to [`Voxels::align_aabb_to_grid`].
144            pub fn align_aabb_to_grid(&self, aabb: &BevyAabb) -> BevyAabb {
145                aabb_bevy_from_na(&self.raw.align_aabb_to_grid(&aabb_na_from_bevy(aabb)))
146            }
147
148            /// Shortcut to [`Voxels::voxels_intersecting_local_aabb`].
149            pub fn voxels_intersecting_local_aabb(
150                &self,
151                aabb: &BevyAabb,
152            ) -> impl Iterator<Item = VoxelData> + '_ {
153                self.raw
154                    .voxels_intersecting_local_aabb(&aabb_na_from_bevy(aabb))
155            }
156
157            /// Shortcut to [`Voxels::voxels`].
158            pub fn voxels(&self) -> impl Iterator<Item = VoxelData> + '_ {
159                self.raw.voxels()
160            }
161
162            /// Shortcut to [`Voxels::split_with_box`].
163            #[cfg(feature = "dim2")]
164            pub fn split_with_box(&self, aabb: &BevyAabb) -> (Option<Voxels>, Option<Voxels>) {
165                self.raw.split_with_box(&aabb_na_from_bevy(aabb))
166            }
167
168            /// Shortcut to [`Voxels::voxels_in_range`].
169            pub fn voxels_in_range(
170                &self,
171                mins: IVect,
172                maxs: IVect,
173            ) -> impl Iterator<Item = VoxelData> + '_ {
174                self.raw.voxels_in_range(mins.into(), maxs.into())
175            }
176        }
177    }
178);
179
180impl_ref_methods!(VoxelsView);
181
182/// Read-write access to the properties of a [`Voxels`].
183pub struct VoxelsViewMut<'a> {
184    /// The raw shape from Rapier.
185    pub raw: &'a mut Voxels,
186}
187
188impl_ref_methods!(VoxelsViewMut);
189
190impl<'a> VoxelsViewMut<'a> {
191    /// Shortcut to set voxel state with bounds checking.
192    pub fn try_set_voxel(&mut self, key: IVect, is_filled: bool) -> Option<VoxelState> {
193        if self.is_voxel_in_bounds(key) {
194            Some(self.raw.set_voxel(key, is_filled))
195        } else {
196            None
197        }
198    }
199
200    /// Shortcut to to [`Voxels::set_voxel`].
201    pub fn set_voxel(&mut self, key: IVect, is_filled: bool) -> VoxelState {
202        self.raw.set_voxel(key, is_filled)
203    }
204
205    /// Shortcut to [`Voxels::crop`].
206    pub fn crop(&mut self, domain_mins: IVect, domain_maxs: IVect) {
207        self.raw.crop(domain_mins, domain_maxs);
208    }
209}