rapier2d/geometry/narrow_phase/
mod.rs1mod contacts;
6mod intersections;
7mod pair_management;
8mod pair_update;
9mod queries;
10mod solver_graph;
11#[cfg(test)]
12#[cfg(feature = "f32")]
13#[cfg(feature = "dim3")]
14mod test;
15
16use crate::alloc_prelude::*;
17use crate::data::Coarena;
18use crate::dynamics::solver::solver_contact_graph::{
19 GENERIC_BUCKET, SolverContactGraph, bucket_id,
20};
21use crate::dynamics::{IslandManager, RigidBodySet};
22use crate::geometry::{
23 ColliderGraphIndex, ColliderHandle, ColliderSet, ContactData, ContactManifoldData, ContactPair,
24 InteractionGraph, IntersectionPair, SolverFlags,
25};
26use alloc::sync::Arc;
27use parry::query::{DefaultQueryDispatcher, PersistentQueryDispatcher};
28
29#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
30#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
31struct ColliderGraphIndices {
32 contact_graph_index: ColliderGraphIndex,
33 intersection_graph_index: ColliderGraphIndex,
34}
35
36impl ColliderGraphIndices {
37 fn invalid() -> Self {
38 Self {
39 contact_graph_index: InteractionGraph::<(), ()>::invalid_graph_index(),
40 intersection_graph_index: InteractionGraph::<(), ()>::invalid_graph_index(),
41 }
42 }
43}
44
45#[derive(Copy, Clone, PartialEq, Eq)]
46enum PairRemovalMode {
47 FromContactGraph,
48 FromIntersectionGraph,
49 Auto,
50}
51
52fn strong_wake_sleeping_side(
54 islands: &mut IslandManager,
55 bodies: &mut RigidBodySet,
56 h1: Option<crate::dynamics::RigidBodyHandle>,
57 h2: Option<crate::dynamics::RigidBodyHandle>,
58) {
59 for h in [h1, h2].into_iter().flatten() {
60 let sleeping_dyn = bodies
61 .get(h)
62 .is_some_and(|rb| rb.is_dynamic() && rb.activation.sleeping);
63 if sleeping_dyn {
64 islands.wake_up(bodies, h, true);
65 }
66 }
67}
68
69fn pack_color_body_info(info: Option<(u32, bool)>) -> u32 {
72 match info {
73 None => u32::MAX,
74 Some((id, fixed)) => (id << 1) | fixed as u32,
75 }
76}
77
78fn unpack_color_body_info(packed: u32) -> Option<(u32, bool)> {
80 if packed == u32::MAX {
81 None
82 } else {
83 Some((packed >> 1, packed & 1 != 0))
84 }
85}
86
87fn assign_pair_solver_color(
91 masks: &mut Vec<u128>,
92 pair: &mut ContactPair,
93 body1: Option<(u32, bool)>, body2: Option<(u32, bool)>,
95) {
96 use crate::geometry::contact_pair::{
97 SOLVER_COLOR_OVERFLOW, SOLVER_COLOR_UNCOLORED, SOLVER_DYNAMIC_COLOR_COUNT,
98 };
99
100 if pair.solver_color != SOLVER_COLOR_UNCOLORED {
101 return;
102 }
103
104 let conflicting1 = body1.filter(|(_, fixed)| !fixed).map(|(id, _)| id);
105 let conflicting2 = body2.filter(|(_, fixed)| !fixed).map(|(id, _)| id);
106 let max_id = conflicting1.max(conflicting2).map(|id| id as usize);
107
108 if let Some(max_id) = max_id {
109 if masks.len() <= max_id {
110 masks.resize(max_id + 1, 0);
111 }
112 }
113
114 let (color, bodies) = match (conflicting1, conflicting2) {
115 (Some(i1), Some(i2)) => {
116 let mask = masks[i1 as usize] | masks[i2 as usize];
120 let dynamic_free = !mask & ((1u128 << SOLVER_DYNAMIC_COLOR_COUNT) - 1);
121 (dynamic_free.trailing_zeros(), [i1, i2])
122 }
123 (Some(i1), None) => {
124 let mask = masks[i1 as usize];
125 (127u32.wrapping_sub((!mask).leading_zeros()), [i1, u32::MAX])
126 }
127 (None, Some(i2)) => {
128 let mask = masks[i2 as usize];
129 (127u32.wrapping_sub((!mask).leading_zeros()), [i2, u32::MAX])
130 }
131 (None, None) => {
132 pair.solver_color = SOLVER_COLOR_OVERFLOW;
134 pair.solver_color_bodies = [u32::MAX; 2];
135 return;
136 }
137 };
138
139 if color >= 128 {
140 pair.solver_color = SOLVER_COLOR_OVERFLOW;
142 pair.solver_color_bodies = [u32::MAX; 2];
143 return;
144 }
145
146 for id in bodies {
147 if id != u32::MAX {
148 masks[id as usize] |= 1 << color;
149 }
150 }
151
152 pair.solver_color = color as u8;
153 pair.solver_color_bodies = bodies;
154}
155
156fn clear_pair_solver_color(masks: &mut [u128], pair: &mut ContactPair) {
158 use crate::geometry::contact_pair::{SOLVER_COLOR_OVERFLOW, SOLVER_COLOR_UNCOLORED};
159
160 if pair.solver_color < SOLVER_COLOR_OVERFLOW {
161 for id in pair.solver_color_bodies {
162 if id != u32::MAX {
163 if let Some(mask) = masks.get_mut(id as usize) {
164 *mask &= !(1u128 << pair.solver_color);
165 }
166 }
167 }
168 }
169
170 pair.solver_color = SOLVER_COLOR_UNCOLORED;
171 pair.solver_color_bodies = [u32::MAX; 2];
172}
173
174fn clear_filtered_pair(pair: &mut ContactPair) -> bool {
178 let in_graph = pair
179 .solver_manifolds()
180 .iter()
181 .any(|m| m.data.graph_pos.is_some());
182 pair.clear();
183 in_graph
184}
185
186const PAIR_HINT_DYN_BIT: u16 = 1 << 15;
190const PAIR_HINT_COUNT_MASK: u16 = PAIR_HINT_DYN_BIT - 1;
192
193fn single_manifold_bucket_drift(pair: &ContactPair, selectable: bool) -> bool {
197 use crate::geometry::contact_pair::{SOLVER_COLOR_OVERFLOW, SOLVER_COLOR_UNCOLORED};
198
199 let manifold = &pair.solver_manifolds()[0];
200 let qualifies = selectable
201 && manifold
202 .data
203 .solver_flags
204 .contains(SolverFlags::COMPUTE_IMPULSES)
205 && manifold.data.num_active_contacts() != 0;
206 let pos = manifold.data.graph_pos;
207 if !qualifies {
208 return pos.is_some();
209 }
210 if !pos.is_some() {
211 return true;
212 }
213 if pos.bucket() == GENERIC_BUCKET {
216 return false;
217 }
218 let mut color = pair.solver_color;
219 if color == SOLVER_COLOR_UNCOLORED {
220 color = SOLVER_COLOR_OVERFLOW;
221 }
222 pos.bucket() != bucket_id(color)
223}
224
225fn pair_qualified_manifold_count(pair: &ContactPair) -> u16 {
228 let solver_manifolds = if pair.solver_clusters.is_empty() {
229 &pair.manifolds
230 } else {
231 &pair.solver_clusters
232 };
233
234 let mut count: u16 = 0;
235 for manifold in solver_manifolds {
236 if manifold
237 .data
238 .solver_flags
239 .contains(SolverFlags::COMPUTE_IMPULSES)
240 && manifold.data.num_active_contacts() != 0
241 {
242 count = count.saturating_add(1);
243 }
244 }
245 count.min(PAIR_HINT_COUNT_MASK)
246}
247
248fn collect_pairs_to_update<E>(
252 candidates: &mut Vec<u32>,
253 graph_indices: &Coarena<ColliderGraphIndices>,
254 graph: &crate::data::graph::Graph<ColliderHandle, E>,
255 islands: &IslandManager,
256 bodies: &RigidBodySet,
257 colliders: &ColliderSet,
258 modified_colliders: &[ColliderHandle],
259 select_graph_id: impl Fn(&ColliderGraphIndices) -> ColliderGraphIndex,
260) {
261 candidates.clear();
262
263 if graph.edges.is_empty() {
264 return;
265 }
266
267 let num_active = islands.active_bodies().count();
271 if num_active * 2 >= bodies.len() {
272 candidates.extend(0..graph.edges.len() as u32);
273 return;
274 }
275
276 let mut push_edges_of = |handle: ColliderHandle, require_change_flags: bool| {
277 let Some(co) = colliders.get(handle) else {
278 return;
279 };
280 if require_change_flags && !co.changes.needs_narrow_phase_update() {
281 return;
282 }
283 let Some(gid) = graph_indices.get(handle.0) else {
284 return;
285 };
286 for edge in graph.edges(select_graph_id(gid)) {
287 candidates.push(edge.id().index() as u32);
288 }
289 };
290
291 for handle in modified_colliders {
292 push_edges_of(*handle, true);
293 }
294
295 for body_handle in islands.active_bodies() {
299 if let Some(rb) = bodies.get(body_handle) {
300 for co_handle in rb.colliders() {
301 push_edges_of(*co_handle, false);
302 }
303 }
304 }
305
306 candidates.sort_unstable();
309 candidates.dedup();
310}
311
312#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
325#[derive(Clone)]
326pub struct NarrowPhase {
327 #[cfg_attr(
328 feature = "serde-serialize",
329 serde(skip, default = "crate::geometry::default_persistent_query_dispatcher")
330 )]
331 query_dispatcher: Arc<dyn PersistentQueryDispatcher<ContactManifoldData, ContactData>>,
332 contact_graph: InteractionGraph<ColliderHandle, ContactPair>,
333 intersection_graph: InteractionGraph<ColliderHandle, IntersectionPair>,
334 graph_indices: Coarena<ColliderGraphIndices>,
335 #[cfg_attr(feature = "serde-serialize", serde(skip))]
338 update_candidates: Vec<u32>,
339 #[cfg_attr(feature = "serde-serialize", serde(default))]
343 body_solver_color_masks: Vec<u128>,
344 #[cfg_attr(feature = "serde-serialize", serde(skip))]
348 body_qualify_info: Vec<u64>,
349 #[cfg_attr(feature = "serde-serialize", serde(skip))]
353 awake_body_mask: Vec<bool>,
354 pair_solver_hints: Vec<u16>,
358 solver_contact_graph: SolverContactGraph,
362 solver_graph_valid: bool,
366 solver_graph_epoch: u32,
370 solver_graph_mb_epoch: u32,
374 #[cfg_attr(feature = "serde-serialize", serde(skip))]
378 solver_graph_dirty: Vec<u32>,
379 force_event_pairs: Vec<u32>,
383 force_event_pos: Vec<u32>,
387 force_event_flagged: Vec<u32>,
391 force_list_valid: bool,
395 #[cfg_attr(feature = "serde-serialize", serde(skip))]
399 solver_color_todo: Vec<(u32, u32, u32)>,
400 #[cfg_attr(feature = "serde-serialize", serde(skip))]
404 retired_pairs: Vec<ContactPair>,
405}
406
407pub(crate) type ContactManifoldIndex = usize;
408
409impl Default for NarrowPhase {
410 fn default() -> Self {
411 Self::new()
412 }
413}
414
415impl NarrowPhase {
416 pub fn new() -> Self {
418 Self::with_query_dispatcher(DefaultQueryDispatcher)
419 }
420
421 pub fn with_query_dispatcher<D>(d: D) -> Self
423 where
424 D: 'static + PersistentQueryDispatcher<ContactManifoldData, ContactData>,
425 {
426 Self {
427 query_dispatcher: Arc::new(d),
428 contact_graph: InteractionGraph::new(),
429 intersection_graph: InteractionGraph::new(),
430 graph_indices: Coarena::new(),
431 update_candidates: Vec::new(),
432 retired_pairs: Vec::new(),
433 body_solver_color_masks: Vec::new(),
434 body_qualify_info: Vec::new(),
435 awake_body_mask: Vec::new(),
436 pair_solver_hints: Vec::new(),
437 solver_contact_graph: SolverContactGraph::new(),
438 solver_graph_valid: false,
439 solver_graph_epoch: 0,
440 solver_graph_mb_epoch: 0,
441 solver_graph_dirty: Vec::new(),
442 force_event_pairs: Vec::new(),
443 force_event_pos: Vec::new(),
444 force_event_flagged: Vec::new(),
445 force_list_valid: false,
446 solver_color_todo: Vec::new(),
447 }
448 }
449
450 fn refresh_awake_body_mask(&mut self, islands: &IslandManager) {
451 self.awake_body_mask.clear();
452 let len = islands
453 .active_bodies()
454 .map(|h| h.into_raw_parts().0 as usize)
455 .max()
456 .map(|m| m + 1)
457 .unwrap_or(0);
458 self.awake_body_mask.resize(len, false);
459 for handle in islands.active_bodies() {
460 self.awake_body_mask[handle.into_raw_parts().0 as usize] = true;
461 }
462 }
463}