1use super::{contact_flags, Contact, ContactSim};
7use crate::body::body_flags;
8use crate::collision::{Manifold, ShapeType};
9use crate::constants::GRAPH_COLOR_COUNT;
10use crate::core::NULL_INDEX;
11use crate::distance::SimplexCache;
12use crate::events::ContactEndTouchEvent;
13use crate::id::{ContactId, ShapeId};
14use crate::solver_set::{AWAKE_SET, DISABLED_SET, STATIC_SET};
15use crate::table::shape_pair_key;
16use crate::world::World;
17
18fn is_primary_pair(type_a: ShapeType, type_b: ShapeType) -> bool {
20 use ShapeType::*;
21 matches!(
22 (type_a, type_b),
23 (Circle, Circle)
24 | (Capsule, Circle)
25 | (Capsule, Capsule)
26 | (Polygon, Circle)
27 | (Polygon, Capsule)
28 | (Polygon, Polygon)
29 | (Segment, Circle)
30 | (Segment, Capsule)
31 | (Segment, Polygon)
32 | (ChainSegment, Circle)
33 | (ChainSegment, Capsule)
34 | (ChainSegment, Polygon)
35 )
36}
37
38pub(super) fn contact_register(type_a: ShapeType, type_b: ShapeType) -> Option<bool> {
42 if is_primary_pair(type_a, type_b) {
43 return Some(true);
44 }
45
46 if type_a != type_b && is_primary_pair(type_b, type_a) {
49 return Some(false);
50 }
51
52 None
53}
54
55pub fn can_collide(type_a: ShapeType, type_b: ShapeType) -> bool {
57 contact_register(type_a, type_b).is_some()
58}
59
60pub fn create_contact(world: &mut World, shape_id_a: i32, shape_id_b: i32) {
64 let type_a = world.shapes[shape_id_a as usize].shape_type();
65 let type_b = world.shapes[shape_id_b as usize].shape_type();
66
67 let Some(primary) = contact_register(type_a, type_b) else {
68 return;
70 };
71
72 if !primary {
73 create_contact(world, shape_id_b, shape_id_a);
75 return;
76 }
77
78 let body_id_a = world.shapes[shape_id_a as usize].body_id;
79 let body_id_b = world.shapes[shape_id_b as usize].body_id;
80
81 let set_a = world.bodies[body_id_a as usize].set_index;
82 let set_b = world.bodies[body_id_b as usize].set_index;
83 debug_assert!(set_a != DISABLED_SET && set_b != DISABLED_SET);
84 debug_assert!(set_a != STATIC_SET || set_b != STATIC_SET);
85
86 let set_index = if set_a == AWAKE_SET || set_b == AWAKE_SET {
87 AWAKE_SET
88 } else {
89 DISABLED_SET
93 };
94
95 let contact_id = world.contact_id_pool.alloc_id();
97 if contact_id == world.contacts.len() as i32 {
98 world.contacts.push(Contact::default());
99 }
100
101 let local_index = world.solver_sets[set_index as usize].contact_sims.len() as i32;
102
103 {
104 let contact = &mut world.contacts[contact_id as usize];
105 contact.contact_id = contact_id;
106 contact.generation = contact.generation.wrapping_add(1);
107 contact.set_index = set_index;
108 contact.color_index = NULL_INDEX;
109 contact.local_index = local_index;
110 contact.island_id = NULL_INDEX;
111 contact.island_index = NULL_INDEX;
112 contact.shape_id_a = shape_id_a;
113 contact.shape_id_b = shape_id_b;
114 contact.flags = 0;
115 }
116
117 if (world.bodies[body_id_a as usize].flags & body_flags::BODY_ENABLE_CONTACT_RECYCLING) != 0
119 && (world.bodies[body_id_b as usize].flags & body_flags::BODY_ENABLE_CONTACT_RECYCLING) != 0
120 {
121 world.contacts[contact_id as usize].flags |= contact_flags::RECYCLE;
122 }
123
124 debug_assert!(
125 world.shapes[shape_id_a as usize].sensor_index == NULL_INDEX
126 && world.shapes[shape_id_b as usize].sensor_index == NULL_INDEX
127 );
128
129 if world.shapes[shape_id_a as usize].enable_contact_events
130 || world.shapes[shape_id_b as usize].enable_contact_events
131 {
132 world.contacts[contact_id as usize].flags |= contact_flags::ENABLE_CONTACT_EVENTS;
133 }
134
135 {
137 let head_contact_key = world.bodies[body_id_a as usize].head_contact_key;
138 {
139 let contact = &mut world.contacts[contact_id as usize];
140 contact.edges[0].body_id = body_id_a;
141 contact.edges[0].prev_key = NULL_INDEX;
142 contact.edges[0].next_key = head_contact_key;
143 }
144
145 let key_a = contact_id << 1;
146 if head_contact_key != NULL_INDEX {
147 let head_contact = &mut world.contacts[(head_contact_key >> 1) as usize];
148 head_contact.edges[(head_contact_key & 1) as usize].prev_key = key_a;
149 }
150 let body_a = &mut world.bodies[body_id_a as usize];
151 body_a.head_contact_key = key_a;
152 body_a.contact_count += 1;
153 }
154
155 {
157 let head_contact_key = world.bodies[body_id_b as usize].head_contact_key;
158 {
159 let contact = &mut world.contacts[contact_id as usize];
160 contact.edges[1].body_id = body_id_b;
161 contact.edges[1].prev_key = NULL_INDEX;
162 contact.edges[1].next_key = head_contact_key;
163 }
164
165 let key_b = (contact_id << 1) | 1;
166 if head_contact_key != NULL_INDEX {
167 let head_contact = &mut world.contacts[(head_contact_key >> 1) as usize];
168 head_contact.edges[(head_contact_key & 1) as usize].prev_key = key_b;
169 }
170 let body_b = &mut world.bodies[body_id_b as usize];
171 body_b.head_contact_key = key_b;
172 body_b.contact_count += 1;
173 }
174
175 let pair_key = shape_pair_key(shape_id_a, shape_id_b);
177 world.broad_phase.pair_set.add_key(pair_key);
178
179 let contact_flags_now = world.contacts[contact_id as usize].flags;
182 let shape_a = &world.shapes[shape_id_a as usize];
183 let shape_b = &world.shapes[shape_id_b as usize];
184
185 let mut contact_sim = ContactSim {
186 contact_id,
187 body_id_a,
189 body_id_b,
190 body_sim_index_a: NULL_INDEX,
191 body_sim_index_b: NULL_INDEX,
192 inv_mass_a: 0.0,
193 inv_i_a: 0.0,
194 inv_mass_b: 0.0,
195 inv_i_b: 0.0,
196 shape_id_a,
197 shape_id_b,
198 cache: SimplexCache::default(),
199 manifold: Manifold::default(),
200 friction: (world.friction_callback.unwrap())(
203 shape_a.material.friction,
204 shape_a.material.user_material_id,
205 shape_b.material.friction,
206 shape_b.material.user_material_id,
207 ),
208 restitution: (world.restitution_callback.unwrap())(
209 shape_a.material.restitution,
210 shape_a.material.user_material_id,
211 shape_b.material.restitution,
212 shape_b.material.user_material_id,
213 ),
214 tangent_speed: 0.0,
215 sim_flags: contact_flags_now,
216 ..ContactSim::default()
217 };
218
219 if shape_a.enable_pre_solve_events || shape_b.enable_pre_solve_events {
220 contact_sim.sim_flags |= contact_flags::SIM_ENABLE_PRE_SOLVE_EVENTS;
221 }
222
223 world.solver_sets[set_index as usize]
224 .contact_sims
225 .push(contact_sim);
226}
227
228pub fn destroy_contact(world: &mut World, contact_id: i32, wake_bodies: bool) {
238 let (shape_id_a, shape_id_b, edge_a, edge_b, flags, generation) = {
239 let contact = &world.contacts[contact_id as usize];
240 (
241 contact.shape_id_a,
242 contact.shape_id_b,
243 contact.edges[0],
244 contact.edges[1],
245 contact.flags,
246 contact.generation,
247 )
248 };
249
250 let pair_key = shape_pair_key(shape_id_a, shape_id_b);
252 world.broad_phase.pair_set.remove_key(pair_key);
253
254 let body_id_a = edge_a.body_id;
255 let body_id_b = edge_b.body_id;
256
257 let touching = (flags & contact_flags::TOUCHING) != 0;
258
259 if touching && (flags & contact_flags::ENABLE_CONTACT_EVENTS) != 0 {
261 let world_id = world.world_id;
262 let shape_a = &world.shapes[shape_id_a as usize];
263 let shape_b = &world.shapes[shape_id_b as usize];
264
265 let event = ContactEndTouchEvent {
266 shape_id_a: ShapeId {
267 index1: shape_a.id + 1,
268 world0: world_id,
269 generation: shape_a.generation,
270 },
271 shape_id_b: ShapeId {
272 index1: shape_b.id + 1,
273 world0: world_id,
274 generation: shape_b.generation,
275 },
276 contact_id: ContactId {
277 index1: contact_id + 1,
278 world0: world_id,
279 padding: 0,
280 generation,
281 },
282 };
283
284 world.contact_end_events[world.end_event_array_index as usize].push(event);
285 }
286
287 if edge_a.prev_key != NULL_INDEX {
289 let prev_contact = &mut world.contacts[(edge_a.prev_key >> 1) as usize];
290 prev_contact.edges[(edge_a.prev_key & 1) as usize].next_key = edge_a.next_key;
291 }
292
293 if edge_a.next_key != NULL_INDEX {
294 let next_contact = &mut world.contacts[(edge_a.next_key >> 1) as usize];
295 next_contact.edges[(edge_a.next_key & 1) as usize].prev_key = edge_a.prev_key;
296 }
297
298 let edge_key_a = contact_id << 1;
299 {
300 let body_a = &mut world.bodies[body_id_a as usize];
301 if body_a.head_contact_key == edge_key_a {
302 body_a.head_contact_key = edge_a.next_key;
303 }
304 body_a.contact_count -= 1;
305 }
306
307 if edge_b.prev_key != NULL_INDEX {
309 let prev_contact = &mut world.contacts[(edge_b.prev_key >> 1) as usize];
310 prev_contact.edges[(edge_b.prev_key & 1) as usize].next_key = edge_b.next_key;
311 }
312
313 if edge_b.next_key != NULL_INDEX {
314 let next_contact = &mut world.contacts[(edge_b.next_key >> 1) as usize];
315 next_contact.edges[(edge_b.next_key & 1) as usize].prev_key = edge_b.prev_key;
316 }
317
318 let edge_key_b = (contact_id << 1) | 1;
319 {
320 let body_b = &mut world.bodies[body_id_b as usize];
321 if body_b.head_contact_key == edge_key_b {
322 body_b.head_contact_key = edge_b.next_key;
323 }
324 body_b.contact_count -= 1;
325 }
326
327 if world.contacts[contact_id as usize].island_id != NULL_INDEX {
329 crate::island::unlink_contact(world, contact_id);
330 }
331
332 let (color_index, local_index, set_index) = {
333 let contact = &world.contacts[contact_id as usize];
334 (contact.color_index, contact.local_index, contact.set_index)
335 };
336 if color_index != NULL_INDEX {
337 debug_assert!(set_index == AWAKE_SET);
339 crate::constraint_graph::remove_contact_from_graph(
340 world,
341 body_id_a,
342 body_id_b,
343 color_index,
344 local_index,
345 );
346 } else {
347 debug_assert!(
349 set_index != AWAKE_SET
350 || (world.contacts[contact_id as usize].flags & contact_flags::TOUCHING) == 0
351 );
352 let set = &mut world.solver_sets[set_index as usize];
353 let moved_index = set.contact_sims.len() as i32 - 1;
354 set.contact_sims.swap_remove(local_index as usize);
355 if moved_index != local_index {
356 let moved_contact_id =
357 world.solver_sets[set_index as usize].contact_sims[local_index as usize].contact_id;
358 world.contacts[moved_contact_id as usize].local_index = local_index;
359 }
360 }
361
362 {
364 let contact = &mut world.contacts[contact_id as usize];
365 contact.contact_id = NULL_INDEX;
366 contact.set_index = NULL_INDEX;
367 contact.color_index = NULL_INDEX;
368 contact.local_index = NULL_INDEX;
369 }
370 world.contact_id_pool.free_id(contact_id);
371
372 if wake_bodies && touching {
373 crate::body::wake_body(world, body_id_a);
374 crate::body::wake_body(world, body_id_b);
375 }
376}
377
378pub fn get_contact_full_id(world: &World, contact_id: crate::id::ContactId) -> i32 {
381 let id = contact_id.index1 - 1;
382 debug_assert!((id as usize) < world.contacts.len());
383 let contact = &world.contacts[id as usize];
384 debug_assert!(contact.contact_id == id && contact.generation == contact_id.generation);
385 id
386}
387
388pub fn get_contact_sim(world: &mut World, contact_id: i32) -> &mut ContactSim {
391 let (set_index, color_index, local_index) = {
392 let contact = &world.contacts[contact_id as usize];
393 (contact.set_index, contact.color_index, contact.local_index)
394 };
395
396 if set_index == AWAKE_SET && color_index != NULL_INDEX {
397 debug_assert!((0..GRAPH_COLOR_COUNT).contains(&color_index));
399 &mut world.constraint_graph.colors[color_index as usize].contact_sims[local_index as usize]
400 } else {
401 &mut world.solver_sets[set_index as usize].contact_sims[local_index as usize]
402 }
403}
404
405pub fn get_contact_sim_ref(world: &World, contact_id: i32) -> &ContactSim {
408 let contact = &world.contacts[contact_id as usize];
409
410 if contact.set_index == AWAKE_SET && contact.color_index != NULL_INDEX {
411 debug_assert!((0..GRAPH_COLOR_COUNT).contains(&contact.color_index));
412 &world.constraint_graph.colors[contact.color_index as usize].contact_sims
413 [contact.local_index as usize]
414 } else {
415 &world.solver_sets[contact.set_index as usize].contact_sims[contact.local_index as usize]
416 }
417}