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