rapier2d/geometry/narrow_phase/
mod.rs1mod contacts;
6mod intersections;
7mod pair_management;
8mod pair_update;
9mod queries;
10pub(crate) mod soft_contacts;
11mod solver_graph;
12#[cfg(test)]
13#[cfg(feature = "f32")]
14#[cfg(feature = "dim3")]
15mod test;
16
17use crate::alloc_prelude::*;
18use crate::data::Coarena;
19use crate::dynamics::solver::solver_contact_graph::{
20 GENERIC_BUCKET, SolverContactGraph, bucket_id,
21};
22use crate::dynamics::{IslandManager, RigidBodySet};
23use crate::geometry::{
24 ColliderGraphIndex, ColliderHandle, ColliderSet, ContactData, ContactManifoldData, ContactPair,
25 InteractionGraph, IntersectionPair, SolverFlags,
26};
27use alloc::sync::Arc;
28use parry::query::{DefaultQueryDispatcher, PersistentQueryDispatcher};
29
30#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
31#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
32struct ColliderGraphIndices {
33 contact_graph_index: ColliderGraphIndex,
34 intersection_graph_index: ColliderGraphIndex,
35}
36
37impl ColliderGraphIndices {
38 fn invalid() -> Self {
39 Self {
40 contact_graph_index: InteractionGraph::<(), ()>::invalid_graph_index(),
41 intersection_graph_index: InteractionGraph::<(), ()>::invalid_graph_index(),
42 }
43 }
44}
45
46#[derive(Copy, Clone, PartialEq, Eq)]
47enum PairRemovalMode {
48 FromContactGraph,
49 FromIntersectionGraph,
50 Auto,
51}
52
53fn strong_wake_sleeping_side(
55 islands: &mut IslandManager,
56 bodies: &mut RigidBodySet,
57 h1: Option<crate::dynamics::RigidBodyHandle>,
58 h2: Option<crate::dynamics::RigidBodyHandle>,
59) {
60 for h in [h1, h2].into_iter().flatten() {
61 let sleeping_dyn = bodies
62 .get(h)
63 .is_some_and(|rb| rb.is_dynamic() && rb.activation.sleeping);
64 if sleeping_dyn {
65 islands.wake_up(bodies, h, true);
66 }
67 }
68}
69
70fn pack_color_body_info(info: Option<(u32, bool)>) -> u32 {
73 match info {
74 None => u32::MAX,
75 Some((id, fixed)) => (id << 1) | fixed as u32,
76 }
77}
78
79fn unpack_color_body_info(packed: u32) -> Option<(u32, bool)> {
81 if packed == u32::MAX {
82 None
83 } else {
84 Some((packed >> 1, packed & 1 != 0))
85 }
86}
87
88fn assign_pair_solver_color(
92 masks: &mut Vec<u128>,
93 pair: &mut ContactPair,
94 body1: Option<(u32, bool)>, body2: Option<(u32, bool)>,
96) {
97 use crate::geometry::contact_pair::{
98 SOLVER_COLOR_OVERFLOW, SOLVER_COLOR_UNCOLORED, SOLVER_DYNAMIC_COLOR_COUNT,
99 };
100
101 let Some(pair) = pair.rigid_mut() else {
103 return;
104 };
105 if pair.solver_color != SOLVER_COLOR_UNCOLORED {
106 return;
107 }
108
109 let conflicting1 = body1.filter(|(_, fixed)| !fixed).map(|(id, _)| id);
110 let conflicting2 = body2.filter(|(_, fixed)| !fixed).map(|(id, _)| id);
111 let max_id = conflicting1.max(conflicting2).map(|id| id as usize);
112
113 if let Some(max_id) = max_id {
114 if masks.len() <= max_id {
115 masks.resize(max_id + 1, 0);
116 }
117 }
118
119 let (color, bodies) = match (conflicting1, conflicting2) {
120 (Some(i1), Some(i2)) => {
121 let mask = masks[i1 as usize] | masks[i2 as usize];
125 let dynamic_free = !mask & ((1u128 << SOLVER_DYNAMIC_COLOR_COUNT) - 1);
126 (dynamic_free.trailing_zeros(), [i1, i2])
127 }
128 (Some(i1), None) => {
129 let mask = masks[i1 as usize];
130 (127u32.wrapping_sub((!mask).leading_zeros()), [i1, u32::MAX])
131 }
132 (None, Some(i2)) => {
133 let mask = masks[i2 as usize];
134 (127u32.wrapping_sub((!mask).leading_zeros()), [i2, u32::MAX])
135 }
136 (None, None) => {
137 pair.solver_color = SOLVER_COLOR_OVERFLOW;
139 pair.solver_color_bodies = [u32::MAX; 2];
140 return;
141 }
142 };
143
144 if color >= 128 {
145 pair.solver_color = SOLVER_COLOR_OVERFLOW;
147 pair.solver_color_bodies = [u32::MAX; 2];
148 return;
149 }
150
151 for id in bodies {
152 if id != u32::MAX {
153 masks[id as usize] |= 1 << color;
154 }
155 }
156
157 pair.solver_color = color as u8;
158 pair.solver_color_bodies = bodies;
159}
160
161fn clear_pair_solver_color(masks: &mut [u128], pair: &mut ContactPair) {
163 use crate::geometry::contact_pair::{SOLVER_COLOR_OVERFLOW, SOLVER_COLOR_UNCOLORED};
164
165 let Some(pair) = pair.rigid_mut() else {
166 return;
167 };
168 if pair.solver_color < SOLVER_COLOR_OVERFLOW {
169 for id in pair.solver_color_bodies {
170 if id != u32::MAX {
171 if let Some(mask) = masks.get_mut(id as usize) {
172 *mask &= !(1u128 << pair.solver_color);
173 }
174 }
175 }
176 }
177
178 pair.solver_color = SOLVER_COLOR_UNCOLORED;
179 pair.solver_color_bodies = [u32::MAX; 2];
180}
181
182fn clear_filtered_pair(pair: &mut ContactPair) -> bool {
186 let in_graph = pair
187 .solver_manifolds()
188 .iter()
189 .any(|m| m.data.graph_pos.is_some());
190 pair.clear();
191 in_graph
192}
193
194const PAIR_HINT_DYN_BIT: u16 = 1 << 15;
198const PAIR_HINT_COUNT_MASK: u16 = PAIR_HINT_DYN_BIT - 1;
200
201fn single_manifold_bucket_drift(pair: &ContactPair, selectable: bool) -> bool {
205 use crate::geometry::contact_pair::{SOLVER_COLOR_OVERFLOW, SOLVER_COLOR_UNCOLORED};
206
207 let manifold = &pair.solver_manifolds()[0];
208 let qualifies = selectable
209 && manifold
210 .data
211 .solver_flags
212 .contains(SolverFlags::COMPUTE_RIGID_IMPULSES)
213 && manifold.data.num_active_contacts() != 0;
214 let pos = manifold.data.graph_pos;
215 if !qualifies {
216 return pos.is_some();
217 }
218 if !pos.is_some() {
219 return true;
220 }
221 if pos.bucket() == GENERIC_BUCKET {
224 return false;
225 }
226 let mut color = pair.solver_color();
227 if color == SOLVER_COLOR_UNCOLORED {
228 color = SOLVER_COLOR_OVERFLOW;
229 }
230 pos.bucket() != bucket_id(color)
231}
232
233fn pair_qualified_manifold_count(pair: &ContactPair) -> u16 {
236 let mut count: u16 = 0;
237 for manifold in pair.solver_manifolds() {
238 if manifold
239 .data
240 .solver_flags
241 .contains(SolverFlags::COMPUTE_RIGID_IMPULSES)
242 && manifold.data.num_active_contacts() != 0
243 {
244 count = count.saturating_add(1);
245 }
246 }
247 count.min(PAIR_HINT_COUNT_MASK)
248}
249
250fn collect_pairs_to_update<E>(
254 candidates: &mut Vec<u32>,
255 graph_indices: &Coarena<ColliderGraphIndices>,
256 graph: &crate::data::graph::Graph<ColliderHandle, E>,
257 islands: &IslandManager,
258 bodies: &RigidBodySet,
259 colliders: &ColliderSet,
260 modified_colliders: &[ColliderHandle],
261 select_graph_id: impl Fn(&ColliderGraphIndices) -> ColliderGraphIndex,
262) {
263 candidates.clear();
264
265 if graph.edges.is_empty() {
266 return;
267 }
268
269 let num_active = islands.active_bodies().count();
273 if num_active * 2 >= bodies.len() {
274 candidates.extend(0..graph.edges.len() as u32);
275 return;
276 }
277
278 let mut push_edges_of = |handle: ColliderHandle, require_change_flags: bool| {
279 let Some(co) = colliders.get(handle) else {
280 return;
281 };
282 if require_change_flags && !co.changes.needs_narrow_phase_update() {
283 return;
284 }
285 let Some(gid) = graph_indices.get(handle.0) else {
286 return;
287 };
288 for edge in graph.edges(select_graph_id(gid)) {
289 candidates.push(edge.id().index() as u32);
290 }
291 };
292
293 for handle in modified_colliders {
294 push_edges_of(*handle, true);
295 }
296
297 for body_handle in islands.active_bodies() {
301 if let Some(rb) = bodies.get(body_handle) {
302 for co_handle in rb.colliders() {
303 push_edges_of(*co_handle, false);
304 }
305 }
306 }
307
308 candidates.sort_unstable();
311 candidates.dedup();
312}
313
314#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
327#[derive(Clone)]
328pub struct NarrowPhase {
329 #[cfg_attr(
330 feature = "serde-serialize",
331 serde(skip, default = "crate::geometry::default_persistent_query_dispatcher")
332 )]
333 query_dispatcher: Arc<dyn PersistentQueryDispatcher<ContactManifoldData, ContactData>>,
334 contact_graph: InteractionGraph<ColliderHandle, ContactPair>,
335 intersection_graph: InteractionGraph<ColliderHandle, IntersectionPair>,
336 graph_indices: Coarena<ColliderGraphIndices>,
337 #[cfg_attr(feature = "serde-serialize", serde(skip))]
340 update_candidates: Vec<u32>,
341 #[cfg_attr(feature = "serde-serialize", serde(default))]
345 body_solver_color_masks: Vec<u128>,
346 #[cfg_attr(feature = "serde-serialize", serde(skip))]
350 body_qualify_info: Vec<u64>,
351 #[cfg_attr(feature = "serde-serialize", serde(skip))]
355 awake_body_mask: Vec<bool>,
356 pair_solver_hints: Vec<u16>,
360 solver_contact_graph: SolverContactGraph,
364 solver_graph_valid: bool,
368 solver_graph_epoch: u32,
372 solver_graph_mb_epoch: u32,
376 #[cfg_attr(feature = "serde-serialize", serde(skip))]
380 solver_graph_dirty: Vec<u32>,
381 force_event_pairs: Vec<u32>,
385 force_event_pos: Vec<u32>,
389 force_event_flagged: Vec<u32>,
393 force_list_valid: bool,
397 #[cfg_attr(feature = "serde-serialize", serde(skip))]
401 solver_color_todo: Vec<(u32, u32, u32)>,
402 #[cfg_attr(feature = "serde-serialize", serde(skip))]
405 soft_self: parry::utils::hashmap::HashMap<ColliderHandle, soft_contacts::SoftSelfContacts>,
406 #[cfg_attr(feature = "serde-serialize", serde(skip))]
410 retired_pairs: Vec<ContactPair>,
411}
412
413pub(crate) type ContactManifoldIndex = usize;
414
415impl Default for NarrowPhase {
416 fn default() -> Self {
417 Self::new()
418 }
419}
420
421impl NarrowPhase {
422 pub fn new() -> Self {
424 Self::with_query_dispatcher(DefaultQueryDispatcher)
425 }
426
427 pub fn with_query_dispatcher<D>(d: D) -> Self
429 where
430 D: 'static + PersistentQueryDispatcher<ContactManifoldData, ContactData>,
431 {
432 Self {
433 query_dispatcher: Arc::new(d),
434 contact_graph: InteractionGraph::new(),
435 intersection_graph: InteractionGraph::new(),
436 graph_indices: Coarena::new(),
437 update_candidates: Vec::new(),
438 retired_pairs: Vec::new(),
439 body_solver_color_masks: Vec::new(),
440 body_qualify_info: Vec::new(),
441 awake_body_mask: Vec::new(),
442 pair_solver_hints: Vec::new(),
443 solver_contact_graph: SolverContactGraph::new(),
444 solver_graph_valid: false,
445 solver_graph_epoch: 0,
446 solver_graph_mb_epoch: 0,
447 solver_graph_dirty: Vec::new(),
448 force_event_pairs: Vec::new(),
449 force_event_pos: Vec::new(),
450 force_event_flagged: Vec::new(),
451 force_list_valid: false,
452 solver_color_todo: Vec::new(),
453 soft_self: Default::default(),
454 }
455 }
456
457 pub fn set_query_dispatcher<D>(&mut self, d: D)
459 where
460 D: 'static + PersistentQueryDispatcher<ContactManifoldData, ContactData>,
461 {
462 self.query_dispatcher = Arc::new(d);
463 }
464
465 fn update_awake_body_mask(&mut self, islands: &IslandManager) {
466 self.awake_body_mask.clear();
467 let len = islands
468 .active_bodies()
469 .map(|h| h.into_raw_parts().0 as usize)
470 .max()
471 .map(|m| m + 1)
472 .unwrap_or(0);
473 self.awake_body_mask.resize(len, false);
474 for handle in islands.active_bodies() {
475 self.awake_body_mask[handle.into_raw_parts().0 as usize] = true;
476 }
477 }
478}