1use crate::bounding_volume::{self, BoundingVolume, AABB};
2use crate::math::Isometry;
3use crate::pipeline::broad_phase::BroadPhaseProxyHandle;
4use crate::pipeline::narrow_phase::CollisionObjectGraphIndex;
5use crate::pipeline::object::CollisionGroups;
6use crate::pipeline::object::GeometricQueryType;
7use crate::shape::{Shape, ShapeHandle};
8use simba::scalar::RealField;
910bitflags! {
11#[derive(Default)]
12/// Flags indicating what changed in a collision object since the last collision world update.
13pub struct CollisionObjectUpdateFlags: u8 {
14/// Indicate that the collision object's position changed.
15const POSITION_CHANGED = 0b00000001;
16/// Indicate that the collision object's predicted position changed.
17const PREDICTED_POSITION_CHANGED = 0b00000010;
18/// Indicate that the collision object's shape changed.
19const SHAPE_CHANGED = 0b000100;
20/// Indicate that the collision object's collision group changed.
21const COLLISION_GROUPS_CHANGED = 0b001000;
22/// Indicate that the collision object's geometric query type changed.
23const QUERY_TYPE_CHANGED = 0b0010000;
24 }
25}
2627impl CollisionObjectUpdateFlags {
28/// Checks if the collision object has been changed in a way that justify a broad-phase update.
29pub fn needs_broad_phase_update(&self) -> bool {
30 !self.is_empty()
31 }
3233/// Checks if the collision object has been changed in a way that justify a narrow-phase update.
34pub fn needs_narrow_phase_update(&self) -> bool {
35// The only change that does not trigger an update
36 // is a change on predicted position.
37self.intersects(
38Self::POSITION_CHANGED
39 | Self::SHAPE_CHANGED
40 | Self::COLLISION_GROUPS_CHANGED
41 | Self::QUERY_TYPE_CHANGED,
42 )
43 }
4445/// Checks if the collision object has been changed in a way that justify an update of its bounding volume.
46pub fn needs_bounding_volume_update(&self) -> bool {
47// NOTE: the QUERY_TYPE_CHANGED is included here because the
48 // prediction margin may have changed.
49self.intersects(Self::POSITION_CHANGED | Self::SHAPE_CHANGED | Self::QUERY_TYPE_CHANGED)
50 }
5152/// Checks if the collision object has been changed in a way that justify that the broad-phase
53 /// recompute all potential proximity pairs for this collision objects.
54pub fn needs_broad_phase_redispatch(&self) -> bool {
55self.intersects(
56Self::SHAPE_CHANGED | Self::COLLISION_GROUPS_CHANGED | Self::QUERY_TYPE_CHANGED,
57 )
58 }
59}
6061/// Trait implemented by collision objects.
62pub trait CollisionObjectRef<N: RealField + Copy> {
63/// The interaction graph index of this collision object, if it has been registered into an interaction graph.
64 ///
65 /// Se the `glue::create_proxies` for more details.
66fn graph_index(&self) -> Option<CollisionObjectGraphIndex>;
67/// The broad-phase proxy handle of this collision object, if it has been registered into a broad-phase.
68 ///
69 /// Se the `glue::create_proxies` for more details.
70fn proxy_handle(&self) -> Option<BroadPhaseProxyHandle>;
71/// The position of this collision object.
72fn position(&self) -> &Isometry<N>;
73/// The expected position of this collision object in the next updates.
74 ///
75 /// This is used to enlarge the collision object bounding volume such that at yields more potential interaction pairs.
76 /// This is typically needed for CCD (continuous collision detection) to be sure the broad-phase does not miss pential
77 /// interactions in-between two discontinuous positions of the collision object.
78fn predicted_position(&self) -> Option<&Isometry<N>>;
79/// The shape of this collision object.
80fn shape(&self) -> &dyn Shape<N>;
81/// The collision groups of this collision object.
82fn collision_groups(&self) -> &CollisionGroups;
83/// The type of geometric queries this collision object is subjected to.
84fn query_type(&self) -> GeometricQueryType<N>;
85/// Flags indicating what changed in this collision object.
86fn update_flags(&self) -> CollisionObjectUpdateFlags;
8788/// Computes the AABB of this collision object, ignoring `self.predicted_position()`.
89fn compute_aabb(&self) -> AABB<N> {
90let mut aabb = bounding_volume::aabb(self.shape(), self.position());
91 aabb.loosen(self.query_type().query_limit());
92 aabb
93 }
9495/// Computes the swept AABB of this collision object, taking `self.predict_position()` into account.
96 ///
97 /// Given the AABB of this collision object at the position `self.position()’, and the AABB of
98 /// this collision object at the position `self.predicted_position()`, this returns an AABB that
99 /// bounds both.
100fn compute_swept_aabb(&self) -> AABB<N> {
101if let Some(predicted_pos) = self.predicted_position() {
102let shape = self.shape();
103let mut aabb1 = bounding_volume::aabb(shape, self.position());
104let mut aabb2 = bounding_volume::aabb(shape, predicted_pos);
105let margin = self.query_type().query_limit();
106 aabb1.loosen(margin);
107 aabb2.loosen(margin);
108 aabb1.merge(&aabb2);
109 aabb1
110 } else {
111self.compute_aabb()
112 }
113 }
114}
115116/// The unique identifier of a collision object stored in a `CollisionObjectSlab` structure.
117#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
118#[repr(transparent)]
119#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
120pub struct CollisionObjectSlabHandle(pub usize);
121122impl CollisionObjectSlabHandle {
123/// The unique identifier corresponding to this handle.
124#[inline]
125pub fn uid(&self) -> usize {
126self.0
127}
128}
129130/// A stand-alone object that has a position and a shape.
131pub struct CollisionObject<N: RealField + Copy, T> {
132 proxy_handle: Option<BroadPhaseProxyHandle>,
133 graph_index: Option<CollisionObjectGraphIndex>,
134 position: Isometry<N>,
135 predicted_position: Option<Isometry<N>>,
136 shape: ShapeHandle<N>,
137 collision_groups: CollisionGroups,
138 query_type: GeometricQueryType<N>,
139 update_flags: CollisionObjectUpdateFlags,
140 data: T,
141}
142143impl<N: RealField + Copy, T> CollisionObject<N, T> {
144/// Creates a new collision object.
145pub fn new(
146 proxy_handle: Option<BroadPhaseProxyHandle>,
147 graph_index: Option<CollisionObjectGraphIndex>,
148 position: Isometry<N>,
149 shape: ShapeHandle<N>,
150 groups: CollisionGroups,
151 query_type: GeometricQueryType<N>,
152 data: T,
153 ) -> CollisionObject<N, T> {
154 CollisionObject {
155 proxy_handle,
156 graph_index,
157 position,
158 predicted_position: None,
159 shape,
160 collision_groups: groups,
161 data,
162 query_type,
163 update_flags: CollisionObjectUpdateFlags::all(),
164 }
165 }
166167/// The collision object non-stable graph index.
168 ///
169 /// This index may change whenever a collision object is removed from the world.
170#[inline]
171pub fn graph_index(&self) -> Option<CollisionObjectGraphIndex> {
172self.graph_index
173 }
174175/// Sets the collision object unique but non-stable graph index.
176#[inline]
177pub fn set_graph_index(&mut self, index: Option<CollisionObjectGraphIndex>) {
178self.graph_index = index
179 }
180181/// Mutable reference to this collision object's update flags.
182pub fn update_flags_mut(&mut self) -> &mut CollisionObjectUpdateFlags {
183&mut self.update_flags
184 }
185186/// Clears the update flags of this collision object.
187pub fn clear_update_flags(&mut self) {
188self.update_flags = CollisionObjectUpdateFlags::empty()
189 }
190191/// The collision object's broad phase proxy unique identifier.
192#[inline]
193pub fn proxy_handle(&self) -> Option<BroadPhaseProxyHandle> {
194self.proxy_handle
195 }
196197/// Set collision object's broad phase proxy unique identifier.
198#[inline]
199pub fn set_proxy_handle(&mut self, handle: Option<BroadPhaseProxyHandle>) {
200self.proxy_handle = handle
201 }
202203/// The collision object position.
204#[inline]
205pub fn position(&self) -> &Isometry<N> {
206&self.position
207 }
208209/// The predicted collision object position.
210#[inline]
211pub fn predicted_position(&self) -> Option<&Isometry<N>> {
212self.predicted_position.as_ref()
213 }
214215/// Sets the position of the collision object and resets the predicted position to None.
216#[inline]
217pub fn set_position(&mut self, pos: Isometry<N>) {
218self.update_flags |= CollisionObjectUpdateFlags::POSITION_CHANGED;
219self.update_flags |= CollisionObjectUpdateFlags::PREDICTED_POSITION_CHANGED;
220self.position = pos;
221self.predicted_position = None;
222 }
223224/// Sets the position of the collision object and resets the predicted position.
225#[inline]
226pub fn set_position_with_prediction(&mut self, pos: Isometry<N>, prediction: Isometry<N>) {
227self.update_flags |= CollisionObjectUpdateFlags::POSITION_CHANGED;
228self.update_flags |= CollisionObjectUpdateFlags::PREDICTED_POSITION_CHANGED;
229self.position = pos;
230self.predicted_position = Some(prediction);
231 }
232233/// Sets the predicted position of the collision object.
234#[inline]
235pub fn set_predicted_position(&mut self, pos: Option<Isometry<N>>) {
236self.update_flags |= CollisionObjectUpdateFlags::PREDICTED_POSITION_CHANGED;
237self.predicted_position = pos;
238 }
239240/// Deforms the underlying shape if possible.
241 ///
242 /// Panics if the shape is not deformable.
243#[inline]
244pub fn set_deformations(&mut self, coords: &[N]) {
245self.update_flags |= CollisionObjectUpdateFlags::POSITION_CHANGED;
246self.shape
247 .make_mut()
248 .as_deformable_shape_mut()
249 .expect("Attempting to deform a non-deformable shape.")
250 .set_deformations(coords)
251 }
252253/// The collision object shape.
254#[inline]
255pub fn shape(&self) -> &ShapeHandle<N> {
256&self.shape
257 }
258259/// Set the collision object shape.
260#[inline]
261pub fn set_shape(&mut self, shape: ShapeHandle<N>) {
262self.update_flags |= CollisionObjectUpdateFlags::SHAPE_CHANGED;
263self.shape = shape
264 }
265266/// The collision groups of the collision object.
267#[inline]
268pub fn collision_groups(&self) -> &CollisionGroups {
269&self.collision_groups
270 }
271272/// Sets the collision groups of this collision object.
273#[inline]
274pub fn set_collision_groups(&mut self, groups: CollisionGroups) {
275self.update_flags |= CollisionObjectUpdateFlags::COLLISION_GROUPS_CHANGED;
276self.collision_groups = groups
277 }
278279/// The kind of queries this collision object is expected to .
280#[inline]
281pub fn query_type(&self) -> GeometricQueryType<N> {
282self.query_type
283 }
284285/// Sets the `GeometricQueryType` of the collision object.
286 /// Use `CollisionWorld::set_query_type` to use this method.
287#[inline]
288pub fn set_query_type(&mut self, query_type: GeometricQueryType<N>) {
289self.update_flags |= CollisionObjectUpdateFlags::QUERY_TYPE_CHANGED;
290self.query_type = query_type;
291 }
292293/// Reference to the user-defined data associated to this object.
294#[inline]
295pub fn data(&self) -> &T {
296&self.data
297 }
298299/// Mutable reference to the user-defined data associated to this object.
300#[inline]
301pub fn data_mut(&mut self) -> &mut T {
302&mut self.data
303 }
304}
305306impl<N: RealField + Copy, T> CollisionObjectRef<N> for CollisionObject<N, T> {
307fn graph_index(&self) -> Option<CollisionObjectGraphIndex> {
308self.graph_index()
309 }
310311fn proxy_handle(&self) -> Option<BroadPhaseProxyHandle> {
312self.proxy_handle()
313 }
314315fn position(&self) -> &Isometry<N> {
316self.position()
317 }
318319fn predicted_position(&self) -> Option<&Isometry<N>> {
320self.predicted_position()
321 }
322323fn shape(&self) -> &dyn Shape<N> {
324self.shape().as_ref()
325 }
326327fn collision_groups(&self) -> &CollisionGroups {
328self.collision_groups()
329 }
330331fn query_type(&self) -> GeometricQueryType<N> {
332self.query_type()
333 }
334335fn update_flags(&self) -> CollisionObjectUpdateFlags {
336self.update_flags
337 }
338}