Skip to main content

bevy_rapier3d/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::shape::Aabb2d as BevyAabb;
7#[cfg(feature = "dim3")]
8use bevy::shape::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::voxel_size`].
58            pub fn voxel_size(&self) -> Vect {
59                self.raw.voxel_size()
60            }
61
62            /// Shortcut to [`Voxels::voxel_center`].
63            pub fn voxel_center(&self, key: IVect) -> Vect {
64                self.raw.voxel_center(key)
65            }
66
67            /// Shortcut to [`Voxels::cropped`].
68            ///
69            /// Returns `None` if no filled voxel lies in the `[domain_mins, domain_maxs]` range.
70            pub fn cropped(&self, domain_mins: IVect, domain_maxs: IVect) -> Option<Voxels> {
71                self.raw.cropped(domain_mins, domain_maxs)
72            }
73
74            /// Shortcut to [`Voxels::local_aabb`].
75            pub fn extents(&self) -> Vect {
76                self.raw.local_aabb().extents()
77            }
78
79            /// Shortcut to [`Voxels::local_aabb`].
80            pub fn domain_center(&self) -> Vect {
81                self.raw.local_aabb().center()
82            }
83
84            /// Shortcut to [`Voxels::domain`].
85            pub fn is_voxel_in_bounds(&self, key: IVect) -> bool {
86                let [mins, maxs] = self.raw.domain();
87                #[cfg(feature = "dim2")]
88                {
89                    key.x >= mins.x && key.y >= mins.y && key.x < maxs.x && key.y < maxs.y
90                }
91                #[cfg(feature = "dim3")]
92                {
93                    key.x >= mins.x
94                        && key.y >= mins.y
95                        && key.z >= mins.z
96                        && key.x < maxs.x
97                        && key.y < maxs.y
98                        && key.z < maxs.z
99                }
100            }
101
102            /// Shortcut to [`Voxels::voxel_aabb`].
103            pub fn voxel_aabb(&self, key: IVect) -> BevyAabb {
104                aabb_bevy_from_na(&self.raw.voxel_aabb(key.into()))
105            }
106
107            /// Shortcut to [`Voxels::voxel_state`].
108            pub fn voxel_state(&self, key: IVect) -> Option<VoxelState> {
109                self.raw.voxel_state(key.into())
110            }
111
112            /// Shortcut to [`Voxels::voxel_at_point`].
113            pub fn voxel_at_point_unchecked(&self, point: Vect) -> IVect {
114                self.raw.voxel_at_point(point)
115            }
116
117            /// Shortcut to [`Voxels::voxel_at_point`].
118            pub fn voxel_at_point(&self, pt: Vect) -> Option<IVect> {
119                let voxel = self.voxel_at_point_unchecked(pt);
120                if self.is_voxel_in_bounds(voxel) {
121                    Some(voxel)
122                } else {
123                    None
124                }
125            }
126
127            /// Shortcut to [`Voxels::domain`].
128            pub fn clamp_voxel(&self, key: IVect) -> IVect {
129                let [mins, maxs] = self.raw.domain();
130                #[cfg(feature = "dim2")]
131                {
132                    IVect::new(
133                        key.x.clamp(mins.x, maxs.x - 1),
134                        key.y.clamp(mins.y, maxs.y - 1),
135                    )
136                }
137                #[cfg(feature = "dim3")]
138                {
139                    IVect::new(
140                        key.x.clamp(mins.x, maxs.x - 1),
141                        key.y.clamp(mins.y, maxs.y - 1),
142                        key.z.clamp(mins.z, maxs.z - 1),
143                    )
144                }
145            }
146
147            /// Shortcut to [`Voxels::voxel_range_intersecting_local_aabb`].
148            pub fn voxel_range_intersecting_local_aabb(&self, aabb: &BevyAabb) -> [IVect; 2] {
149                let res = self
150                    .raw
151                    .voxel_range_intersecting_local_aabb(&aabb_na_from_bevy(aabb));
152                [res[0].into(), res[1].into()]
153            }
154
155            /// Shortcut to [`Voxels::voxel_range_aabb`].
156            pub fn voxel_range_aabb(&self, mins: IVect, maxs: IVect) -> BevyAabb {
157                aabb_bevy_from_na(&self.raw.voxel_range_aabb(mins.into(), maxs.into()))
158            }
159
160            /// Shortcut to [`Voxels::align_aabb_to_grid`].
161            pub fn align_aabb_to_grid(&self, aabb: &BevyAabb) -> BevyAabb {
162                aabb_bevy_from_na(&self.raw.align_aabb_to_grid(&aabb_na_from_bevy(aabb)))
163            }
164
165            /// Shortcut to [`Voxels::voxels_intersecting_local_aabb`].
166            pub fn voxels_intersecting_local_aabb(
167                &self,
168                aabb: &BevyAabb,
169            ) -> impl Iterator<Item = VoxelData> + '_ {
170                self.raw
171                    .voxels_intersecting_local_aabb(&aabb_na_from_bevy(aabb))
172            }
173
174            /// Shortcut to [`Voxels::voxels`].
175            pub fn voxels(&self) -> impl Iterator<Item = VoxelData> + '_ {
176                self.raw.voxels()
177            }
178
179            /// Shortcut to [`Voxels::split_with_box`].
180            pub fn split_with_box(&self, aabb: &BevyAabb) -> (Option<Voxels>, Option<Voxels>) {
181                self.raw.split_with_box(&aabb_na_from_bevy(aabb))
182            }
183
184            /// Shortcut to [`Voxels::voxels_in_range`].
185            pub fn voxels_in_range(
186                &self,
187                mins: IVect,
188                maxs: IVect,
189            ) -> impl Iterator<Item = VoxelData> + '_ {
190                self.raw.voxels_in_range(mins.into(), maxs.into())
191            }
192        }
193    }
194);
195
196impl_ref_methods!(VoxelsView);
197
198/// Read-write access to the properties of a [`Voxels`].
199pub struct VoxelsViewMut<'a> {
200    /// The raw shape from Rapier.
201    pub raw: &'a mut Voxels,
202}
203
204impl_ref_methods!(VoxelsViewMut);
205
206impl<'a> VoxelsViewMut<'a> {
207    /// Shortcut to set voxel state with bounds checking.
208    pub fn try_set_voxel(&mut self, key: IVect, is_filled: bool) -> Option<VoxelState> {
209        if self.is_voxel_in_bounds(key) {
210            Some(self.raw.set_voxel(key, is_filled))
211        } else {
212            None
213        }
214    }
215
216    /// Shortcut to to [`Voxels::set_voxel`].
217    pub fn set_voxel(&mut self, key: IVect, is_filled: bool) -> VoxelState {
218        self.raw.set_voxel(key, is_filled)
219    }
220
221    /// Shortcut to [`Voxels::crop`].
222    pub fn crop(&mut self, domain_mins: IVect, domain_maxs: IVect) {
223        self.raw.crop(domain_mins, domain_maxs);
224    }
225
226    /// Shortcut to [`Voxels::set_voxel_size`].
227    pub fn set_voxel_size(&mut self, new_size: Vect) {
228        self.raw.set_voxel_size(new_size);
229    }
230
231    /// Shortcut to [`Voxels::combine_voxel_states`].
232    ///
233    /// Makes the voxels of `self` and `other` aware of their neighbors from the other shape, so
234    /// that contacts transition smoothly across their boundary. A voxel with coordinates `key`
235    /// in `other` has coordinates `key + origin_shift` in `self`.
236    pub fn combine_voxel_states(&mut self, other: &mut VoxelsViewMut<'_>, origin_shift: IVect) {
237        self.raw.combine_voxel_states(other.raw, origin_shift);
238    }
239
240    /// Shortcut to [`Voxels::propagate_voxel_change`].
241    ///
242    /// Same as [`Self::combine_voxel_states`] but restricted to the given `voxel` of `self` (and
243    /// its neighbors), after it was modified with [`Self::set_voxel`].
244    pub fn propagate_voxel_change(
245        &mut self,
246        other: &mut VoxelsViewMut<'_>,
247        voxel: IVect,
248        origin_shift: IVect,
249    ) {
250        self.raw
251            .propagate_voxel_change(other.raw, voxel, origin_shift);
252    }
253}