1use crate::alloc_prelude::*;
4
5use crate::dynamics::{
6 ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet, RigidBodyChanges,
7};
8use crate::geometry::{
9 BroadPhaseBvh, BroadPhasePairEvent, ColliderChanges, ColliderHandle, ModifiedColliders,
10 NarrowPhase,
11};
12use crate::math::Real;
13use crate::pipeline::{EventHandler, PhysicsHooks};
14use crate::prelude::ModifiedRigidBodies;
15use crate::{dynamics::RigidBodySet, geometry::ColliderSet};
16
17pub struct CollisionPipeline {
37 broad_phase_events: Vec<BroadPhasePairEvent>,
38}
39
40#[allow(dead_code)]
41fn check_pipeline_send_sync() {
42 fn do_test<T: Sync>() {}
43 do_test::<CollisionPipeline>();
44}
45
46impl Default for CollisionPipeline {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52impl CollisionPipeline {
53 pub fn new() -> CollisionPipeline {
55 CollisionPipeline {
56 broad_phase_events: Vec::new(),
57 }
58 }
59
60 fn detect_collisions(
61 &mut self,
62 prediction_distance: Real,
63 islands: &mut IslandManager,
64 broad_phase: &mut BroadPhaseBvh,
65 narrow_phase: &mut NarrowPhase,
66 bodies: &mut RigidBodySet,
67 colliders: &mut ColliderSet,
68 modified_colliders: &[ColliderHandle],
69 removed_colliders: &[ColliderHandle],
70 hooks: &dyn PhysicsHooks,
71 events: &dyn EventHandler,
72 handle_user_changes: bool,
73 ) {
74 self.broad_phase_events.clear();
76
77 let params = IntegrationParameters {
78 normalized_prediction_distance: prediction_distance,
79 dt: 0.0,
80 ..Default::default()
81 };
82
83 broad_phase.update(
84 ¶ms,
85 colliders,
86 bodies,
87 modified_colliders,
88 removed_colliders,
89 &mut self.broad_phase_events,
90 );
91
92 if handle_user_changes {
94 narrow_phase.handle_user_changes(
95 None,
96 modified_colliders,
97 removed_colliders,
98 colliders,
99 bodies,
100 events,
101 );
102 }
103
104 narrow_phase.register_pairs(None, colliders, bodies, &self.broad_phase_events, events);
105 narrow_phase.compute_contacts(
106 prediction_distance,
107 0.0,
108 false,
109 0.0,
110 islands,
111 bodies,
112 colliders,
113 &ImpulseJointSet::new(),
114 &MultibodyJointSet::new(),
115 modified_colliders,
116 hooks,
117 events,
118 None,
119 );
120 narrow_phase.compute_intersections(
121 islands,
122 bodies,
123 colliders,
124 modified_colliders,
125 hooks,
126 events,
127 );
128 }
129
130 fn clear_modified_colliders(
131 &mut self,
132 colliders: &mut ColliderSet,
133 modified_colliders: &mut ModifiedColliders,
134 ) {
135 for handle in modified_colliders.iter() {
136 if let Some(co) = colliders.get_mut_internal(*handle) {
137 co.changes = ColliderChanges::empty();
138 }
139 }
140
141 modified_colliders.clear();
142 }
143
144 fn clear_modified_bodies(
145 &mut self,
146 bodies: &mut RigidBodySet,
147 modified_bodies: &mut ModifiedRigidBodies,
148 ) {
149 for handle in modified_bodies.iter() {
153 if let Some(rb) = bodies.get_mut_internal(*handle) {
154 rb.changes = RigidBodyChanges::empty();
155 }
156 }
157
158 modified_bodies.clear();
159 }
160
161 pub fn step(
163 &mut self,
164 prediction_distance: Real,
165 islands: &mut IslandManager,
166 broad_phase: &mut BroadPhaseBvh,
167 narrow_phase: &mut NarrowPhase,
168 bodies: &mut RigidBodySet,
169 colliders: &mut ColliderSet,
170 hooks: &dyn PhysicsHooks,
171 events: &dyn EventHandler,
172 ) {
173 let mut modified_bodies = bodies.take_modified();
174 let mut modified_colliders = colliders.take_modified();
175 let mut removed_colliders = colliders.take_removed();
176
177 super::user_changes::handle_user_changes_to_colliders(
178 bodies,
179 colliders,
180 &modified_colliders[..],
181 );
182 super::user_changes::handle_user_changes_to_rigid_bodies(
183 None,
184 bodies,
185 colliders,
186 &mut ImpulseJointSet::new(),
187 &mut MultibodyJointSet::new(),
188 &modified_bodies,
189 &mut modified_colliders,
190 );
191
192 removed_colliders.extend(
194 modified_colliders
195 .iter()
196 .copied()
197 .filter(|h| colliders.get(*h).map(|c| !c.is_enabled()).unwrap_or(false)),
198 );
199
200 self.detect_collisions(
201 prediction_distance,
202 islands,
203 broad_phase,
204 narrow_phase,
205 bodies,
206 colliders,
207 &modified_colliders[..],
208 &removed_colliders,
209 hooks,
210 events,
211 true,
212 );
213
214 self.clear_modified_colliders(colliders, &mut modified_colliders);
215 self.clear_modified_bodies(bodies, &mut modified_bodies);
216 removed_colliders.clear();
217 }
218}
219
220#[cfg(test)]
221mod tests {
222
223 #[test]
224 #[cfg(feature = "dim3")]
225 pub fn test_no_rigid_bodies() {
226 use crate::prelude::*;
227 let mut rigid_body_set = RigidBodySet::new();
228 let mut collider_set = ColliderSet::new();
229
230 let collider_a = ColliderBuilder::cuboid(1.0, 1.0, 1.0)
232 .active_collision_types(ActiveCollisionTypes::all())
233 .sensor(true)
234 .active_events(ActiveEvents::COLLISION_EVENTS)
235 .build();
236
237 let a_handle = collider_set.insert(collider_a);
238
239 let collider_b = ColliderBuilder::cuboid(1.0, 1.0, 1.0)
240 .active_collision_types(ActiveCollisionTypes::all())
241 .sensor(true)
242 .active_events(ActiveEvents::COLLISION_EVENTS)
243 .build();
244
245 let _ = collider_set.insert(collider_b);
246
247 let integration_parameters = IntegrationParameters::default();
248 let mut islands = IslandManager::new();
249 let mut broad_phase = BroadPhaseBvh::new();
250 let mut narrow_phase = NarrowPhase::new();
251 let mut collision_pipeline = CollisionPipeline::new();
252 let physics_hooks = ();
253
254 collision_pipeline.step(
255 integration_parameters.prediction_distance(),
256 &mut islands,
257 &mut broad_phase,
258 &mut narrow_phase,
259 &mut rigid_body_set,
260 &mut collider_set,
261 &physics_hooks,
262 &(),
263 );
264
265 let mut hit = false;
266
267 for (_, _, intersecting) in narrow_phase.intersection_pairs_with(a_handle) {
268 if intersecting {
269 hit = true;
270 }
271 }
272
273 assert!(hit, "No hit found");
274 }
275
276 #[test]
277 #[cfg(feature = "dim2")]
278 pub fn test_no_rigid_bodies() {
279 use crate::prelude::*;
280 let mut rigid_body_set = RigidBodySet::new();
281 let mut collider_set = ColliderSet::new();
282
283 let collider_a = ColliderBuilder::cuboid(1.0, 1.0)
285 .active_collision_types(ActiveCollisionTypes::all())
286 .sensor(true)
287 .active_events(ActiveEvents::COLLISION_EVENTS)
288 .build();
289
290 let a_handle = collider_set.insert(collider_a);
291
292 let collider_b = ColliderBuilder::cuboid(1.0, 1.0)
293 .active_collision_types(ActiveCollisionTypes::all())
294 .sensor(true)
295 .active_events(ActiveEvents::COLLISION_EVENTS)
296 .build();
297
298 let _ = collider_set.insert(collider_b);
299
300 let integration_parameters = IntegrationParameters::default();
301 let mut islands = IslandManager::new();
302 let mut broad_phase = BroadPhaseBvh::new();
303 let mut narrow_phase = NarrowPhase::new();
304 let mut collision_pipeline = CollisionPipeline::new();
305 let physics_hooks = ();
306
307 collision_pipeline.step(
308 integration_parameters.prediction_distance(),
309 &mut islands,
310 &mut broad_phase,
311 &mut narrow_phase,
312 &mut rigid_body_set,
313 &mut collider_set,
314 &physics_hooks,
315 &(),
316 );
317
318 let mut hit = false;
319
320 for (_, _, intersecting) in narrow_phase.intersection_pairs_with(a_handle) {
321 if intersecting {
322 hit = true;
323 }
324 }
325
326 assert!(hit, "No hit found");
327 }
328}