1use super::World;
14use crate::broad_phase::update_broad_phase_pairs;
15use crate::constants::{speculative_distance, GRAPH_COLOR_COUNT};
16use crate::contact::{contact_flags, update_contact, Contact, ContactSim, ContactUpdateContext};
17use crate::core::NULL_INDEX;
18use crate::events::{ContactBeginTouchEvent, ContactEndTouchEvent};
19use crate::id::{ContactId, ShapeId};
20use crate::math_functions::{
21 aabb_overlaps, abs_float, distance, dot, inv_mul_rot, inv_mul_world_transforms, invert_rot,
22 is_valid_float, max_float, min_float, mul_rot, rotate_vector, sub, sub_pos, Rot,
23};
24use crate::sensor::overlap_sensors;
25use crate::solver::{make_soft, solve, StepContext};
26use crate::solver_set::{AWAKE_SET, FIRST_SLEEPING_SET, STATIC_SET};
27use crate::types::BodyType;
28
29fn relative_cos(a: Rot, b: Rot) -> f32 {
31 a.c * b.c + a.s * b.s
32}
33
34#[derive(Clone, Copy)]
38struct ContactSimLocation {
39 color_index: i32,
40 local_index: i32,
41}
42
43fn get_located_sim(world: &World, location: ContactSimLocation) -> ContactSim {
44 if location.color_index != NULL_INDEX {
45 world.constraint_graph.colors[location.color_index as usize].contact_sims
46 [location.local_index as usize]
47 } else {
48 world.solver_sets[AWAKE_SET as usize].contact_sims[location.local_index as usize]
49 }
50}
51
52fn put_located_sim(world: &mut World, location: ContactSimLocation, sim: ContactSim) {
53 if location.color_index != NULL_INDEX {
54 world.constraint_graph.colors[location.color_index as usize].contact_sims
55 [location.local_index as usize] = sim;
56 } else {
57 world.solver_sets[AWAKE_SET as usize].contact_sims[location.local_index as usize] = sim;
58 }
59}
60
61fn collide_contact(
63 world: &mut World,
64 location: ContactSimLocation,
65 update_context: &ContactUpdateContext,
66) {
67 let recycle_distance = world.contact_recycle_distance;
68 let speculative_distance_ = speculative_distance();
69 let recycle_distance_non_touching = min_float(recycle_distance, speculative_distance_);
70
71 let mut contact_sim = get_located_sim(world, location);
72
73 let contact_id = contact_sim.contact_id;
74
75 let overlap = {
77 let shape_a = &world.shapes[contact_sim.shape_id_a as usize];
78 let shape_b = &world.shapes[contact_sim.shape_id_b as usize];
79 aabb_overlaps(shape_a.fat_aabb, shape_b.fat_aabb)
80 };
81
82 if !overlap {
83 contact_sim.sim_flags |= contact_flags::SIM_DISJOINT;
84 contact_sim.sim_flags &= !contact_flags::SIM_TOUCHING;
85 put_located_sim(world, location, contact_sim);
86 world.task_contexts[0]
87 .contact_state_bit_set
88 .set_bit(contact_id as u32);
89 return;
90 }
91
92 let was_touching = contact_sim.sim_flags & contact_flags::SIM_TOUCHING != 0;
93
94 let (shape_body_id_a, shape_body_id_b) = {
96 let shape_a = &world.shapes[contact_sim.shape_id_a as usize];
97 let shape_b = &world.shapes[contact_sim.shape_id_b as usize];
98 (shape_a.body_id, shape_b.body_id)
99 };
100
101 let body_a = &world.bodies[shape_body_id_a as usize];
102 let body_b = &world.bodies[shape_body_id_b as usize];
103 let body_sim_a =
104 world.solver_sets[body_a.set_index as usize].body_sims[body_a.local_index as usize];
105 let body_sim_b =
106 world.solver_sets[body_b.set_index as usize].body_sims[body_b.local_index as usize];
107 let transform_a = body_sim_a.transform;
108 let transform_b = body_sim_b.transform;
109
110 contact_sim.body_sim_index_a = if body_a.set_index == AWAKE_SET {
112 body_a.local_index
113 } else {
114 NULL_INDEX
115 };
116 contact_sim.inv_mass_a = body_sim_a.inv_mass;
117 contact_sim.inv_i_a = body_sim_a.inv_inertia;
118
119 contact_sim.body_sim_index_b = if body_b.set_index == AWAKE_SET {
120 body_b.local_index
121 } else {
122 NULL_INDEX
123 };
124 contact_sim.inv_mass_b = body_sim_b.inv_mass;
125 contact_sim.inv_i_b = body_sim_b.inv_inertia;
126
127 let type_a = body_a.type_;
128 let type_b = body_b.type_;
129
130 if recycle_distance > 0.0
135 && contact_sim.sim_flags & contact_flags::SIM_RELATIVE_TRANSFORM_VALID != 0
136 && contact_sim.sim_flags & contact_flags::RECYCLE != 0
137 {
138 let cached_q_a = contact_sim.cached_rotation_a;
139 let cached_q_b = contact_sim.cached_rotation_b;
140 let xfc = contact_sim.cached_relative_pose;
141 let xf = inv_mul_world_transforms(transform_a, transform_b);
142
143 let cos_a = relative_cos(transform_a.q, cached_q_a);
144 let cos_b = relative_cos(transform_b.q, cached_q_b);
145 let min_cos = min_float(cos_a, cos_b);
146
147 let max_extent_a = if type_a == BodyType::Static {
148 0.0
149 } else {
150 body_sim_a.max_extent
151 };
152 let max_extent_b = if type_b == BodyType::Static {
153 0.0
154 } else {
155 body_sim_b.max_extent
156 };
157 let max_extent = max_float(max_extent_a, max_extent_b);
158 let distance_ = distance(xf.p, xfc.p);
159 let qr = inv_mul_rot(xf.q, xfc.q);
160
161 let tolerance = if was_touching {
166 recycle_distance
167 } else {
168 recycle_distance_non_touching
169 };
170
171 if min_cos > crate::constants::CONTACT_RECYCLE_COS_ANGLE
172 && distance_ + max_extent * abs_float(qr.s) < tolerance
173 {
174 let dq_a = mul_rot(transform_a.q, invert_rot(cached_q_a));
175 let dq_b = mul_rot(transform_b.q, invert_rot(cached_q_b));
176 let normal = contact_sim.manifold.normal;
177
178 let dc = sub_pos(body_sim_b.center, body_sim_a.center);
180
181 for i in 0..contact_sim.manifold.point_count as usize {
182 let mp = &mut contact_sim.manifold.points[i];
185 let r_a = rotate_vector(dq_a, mp.anchor_a);
186 let r_b = rotate_vector(dq_b, mp.anchor_b);
187 let dp = crate::math_functions::add(dc, sub(r_b, r_a));
188 mp.separation = mp.base_separation + dot(dp, normal);
189 mp.persisted = true;
190 }
191
192 world.task_contexts[0].recycled_contact_count += 1;
193
194 put_located_sim(world, location, contact_sim);
197 return;
198 }
199 }
200
201 contact_sim.cached_rotation_a = transform_a.q;
203 contact_sim.cached_rotation_b = transform_b.q;
204 contact_sim.cached_relative_pose = inv_mul_world_transforms(transform_a, transform_b);
205 contact_sim.sim_flags |= contact_flags::SIM_RELATIVE_TRANSFORM_VALID;
206
207 let center_offset_a = rotate_vector(transform_a.q, body_sim_a.local_center);
208 let center_offset_b = rotate_vector(transform_b.q, body_sim_b.local_center);
209
210 let touching = {
212 let shape_a = &world.shapes[contact_sim.shape_id_a as usize];
213 let shape_b = &world.shapes[contact_sim.shape_id_b as usize];
214 update_contact(
215 update_context,
216 &mut contact_sim,
217 shape_a,
218 transform_a,
219 center_offset_a,
220 shape_b,
221 transform_b,
222 center_offset_b,
223 )
224 };
225
226 if touching && !was_touching {
229 contact_sim.sim_flags |= contact_flags::SIM_STARTED_TOUCHING;
230 world.task_contexts[0]
231 .contact_state_bit_set
232 .set_bit(contact_id as u32);
233 } else if !touching && was_touching {
234 contact_sim.sim_flags |= contact_flags::SIM_STOPPED_TOUCHING;
235 world.task_contexts[0]
236 .contact_state_bit_set
237 .set_bit(contact_id as u32);
238 }
239
240 for i in 0..contact_sim.manifold.point_count as usize {
241 let mp = &mut contact_sim.manifold.points[i];
242 mp.base_separation = mp.separation;
243 }
244
245 put_located_sim(world, location, contact_sim);
246}
247
248fn add_non_touching_contact(world: &mut World, contact_id: i32, contact_sim: ContactSim) {
250 debug_assert!(world.contacts[contact_id as usize].set_index == AWAKE_SET);
251 let local_index = world.solver_sets[AWAKE_SET as usize].contact_sims.len() as i32;
252 {
253 let contact = &mut world.contacts[contact_id as usize];
254 contact.color_index = NULL_INDEX;
255 contact.local_index = local_index;
256 }
257 world.solver_sets[AWAKE_SET as usize]
258 .contact_sims
259 .push(contact_sim);
260}
261
262fn remove_non_touching_contact(world: &mut World, set_index: i32, local_index: i32) {
264 let set = &mut world.solver_sets[set_index as usize];
265 let moved_index = set.contact_sims.len() as i32 - 1;
266 set.contact_sims.swap_remove(local_index as usize);
267 if moved_index != local_index {
268 let moved_contact_id =
269 world.solver_sets[set_index as usize].contact_sims[local_index as usize].contact_id;
270 let moved_contact = &mut world.contacts[moved_contact_id as usize];
271 debug_assert!(moved_contact.set_index == set_index);
272 debug_assert!(moved_contact.local_index == moved_index);
273 debug_assert!(moved_contact.color_index == NULL_INDEX);
274 moved_contact.local_index = local_index;
275 }
276}
277
278fn collide(world: &mut World, _context: &StepContext) {
280 let mut locations: Vec<ContactSimLocation> = Vec::new();
283 for color_index in 0..GRAPH_COLOR_COUNT {
284 let count = world.constraint_graph.colors[color_index as usize]
285 .contact_sims
286 .len();
287 for local_index in 0..count as i32 {
288 locations.push(ContactSimLocation {
289 color_index,
290 local_index,
291 });
292 }
293 }
294 {
295 let count = world.solver_sets[AWAKE_SET as usize].contact_sims.len();
296 for local_index in 0..count as i32 {
297 locations.push(ContactSimLocation {
298 color_index: NULL_INDEX,
299 local_index,
300 });
301 }
302 }
303
304 if locations.is_empty() {
305 return;
306 }
307
308 let contact_id_capacity = world.contact_id_pool.id_capacity();
311 {
312 let task_context = &mut world.task_contexts[0];
313 task_context
314 .contact_state_bit_set
315 .set_bit_count_and_clear(contact_id_capacity as u32);
316 task_context.recycled_contact_count = 0;
317 }
318
319 let update_context = ContactUpdateContext::new(world);
321 for &location in &locations {
322 collide_contact(world, location, &update_context);
323 }
324
325 let end_event_array_index = world.end_event_array_index as usize;
328 let world_id = world.world_id;
329
330 let block_count = world.task_contexts[0].contact_state_bit_set.block_count();
331 for k in 0..block_count {
332 let mut bits = world.task_contexts[0].contact_state_bit_set.block(k);
333 while bits != 0 {
334 let ctz = bits.trailing_zeros();
335 let contact_id = (64 * k + ctz) as i32;
336
337 let (color_index, local_index, flags, generation, shape_id_a, shape_id_b) = {
338 let contact: &Contact = &world.contacts[contact_id as usize];
339 debug_assert!(contact.set_index == AWAKE_SET);
340 (
341 contact.color_index,
342 contact.local_index,
343 contact.flags,
344 contact.generation,
345 contact.shape_id_a,
346 contact.shape_id_b,
347 )
348 };
349
350 let sim_flags = if color_index != NULL_INDEX {
351 debug_assert!((0..GRAPH_COLOR_COUNT).contains(&color_index));
353 world.constraint_graph.colors[color_index as usize].contact_sims
354 [local_index as usize]
355 .sim_flags
356 } else {
357 world.solver_sets[AWAKE_SET as usize].contact_sims[local_index as usize].sim_flags
358 };
359
360 let (shape_id_a_full, shape_id_b_full) = {
361 let shape_a = &world.shapes[shape_id_a as usize];
362 let shape_b = &world.shapes[shape_id_b as usize];
363 (
364 ShapeId {
365 index1: shape_a.id + 1,
366 world0: world_id,
367 generation: shape_a.generation,
368 },
369 ShapeId {
370 index1: shape_b.id + 1,
371 world0: world_id,
372 generation: shape_b.generation,
373 },
374 )
375 };
376 let contact_full_id = ContactId {
377 index1: contact_id + 1,
378 world0: world_id,
379 padding: 0,
380 generation,
381 };
382
383 if sim_flags & contact_flags::SIM_DISJOINT != 0 {
384 crate::contact::destroy_contact(world, contact_id, false);
386 } else if sim_flags & contact_flags::SIM_STARTED_TOUCHING != 0 {
387 debug_assert!(world.contacts[contact_id as usize].island_id == NULL_INDEX);
388
389 if flags & contact_flags::ENABLE_CONTACT_EVENTS != 0 {
390 world.contact_begin_events.push(ContactBeginTouchEvent {
391 shape_id_a: shape_id_a_full,
392 shape_id_b: shape_id_b_full,
393 contact_id: contact_full_id,
394 });
395 }
396
397 debug_assert!(color_index == NULL_INDEX);
398 debug_assert!(
399 world.solver_sets[AWAKE_SET as usize].contact_sims[local_index as usize]
400 .manifold
401 .point_count
402 > 0
403 );
404
405 world.contacts[contact_id as usize].flags |= contact_flags::TOUCHING;
408 crate::island::link_contact(world, contact_id);
409
410 debug_assert!(world.contacts[contact_id as usize].color_index == NULL_INDEX);
412 debug_assert!(world.contacts[contact_id as usize].local_index == local_index);
413
414 let mut contact_sim =
416 world.solver_sets[AWAKE_SET as usize].contact_sims[local_index as usize];
417 contact_sim.sim_flags &= !contact_flags::SIM_STARTED_TOUCHING;
418
419 crate::constraint_graph::add_contact_to_graph(world, contact_sim, contact_id);
421
422 remove_non_touching_contact(world, AWAKE_SET, local_index);
424 } else if sim_flags & contact_flags::SIM_STOPPED_TOUCHING != 0 {
425 debug_assert!(color_index != NULL_INDEX);
426 let contact_sim = {
427 let sim = &mut world.constraint_graph.colors[color_index as usize].contact_sims
428 [local_index as usize];
429 sim.sim_flags &= !contact_flags::SIM_STOPPED_TOUCHING;
430 *sim
431 };
432 world.contacts[contact_id as usize].flags &= !contact_flags::TOUCHING;
433
434 if flags & contact_flags::ENABLE_CONTACT_EVENTS != 0 {
435 world.contact_end_events[end_event_array_index].push(ContactEndTouchEvent {
436 shape_id_a: shape_id_a_full,
437 shape_id_b: shape_id_b_full,
438 contact_id: contact_full_id,
439 });
440 }
441
442 debug_assert!(contact_sim.manifold.point_count == 0);
443
444 crate::island::unlink_contact(world, contact_id);
445 let body_id_a = world.contacts[contact_id as usize].edges[0].body_id;
446 let body_id_b = world.contacts[contact_id as usize].edges[1].body_id;
447
448 add_non_touching_contact(world, contact_id, contact_sim);
450 crate::constraint_graph::remove_contact_from_graph(
451 world,
452 body_id_a,
453 body_id_b,
454 color_index,
455 local_index,
456 );
457 }
458
459 bits &= bits - 1;
461 }
462 }
463
464 world.validate_solver_sets();
465 world.validate_contacts();
466}
467
468impl World {
469 pub fn validate_contacts(&self) {
472 if !cfg!(debug_assertions) {
473 return;
474 }
475
476 let contact_count = self.contacts.len() as i32;
477 debug_assert!(contact_count == self.contact_id_pool.id_capacity());
478 let mut allocated_contact_count = 0;
479
480 for contact_index in 0..contact_count {
481 let contact = &self.contacts[contact_index as usize];
482 if contact.contact_id == NULL_INDEX {
483 continue;
484 }
485
486 debug_assert!(contact.contact_id == contact_index);
487
488 allocated_contact_count += 1;
489
490 let touching = contact.flags & contact_flags::TOUCHING != 0;
491
492 let set_id = contact.set_index;
493
494 if set_id == AWAKE_SET {
495 if touching {
496 debug_assert!(
497 0 <= contact.color_index && contact.color_index < GRAPH_COLOR_COUNT
498 );
499 } else {
500 debug_assert!(contact.color_index == NULL_INDEX);
501 }
502 } else if set_id >= FIRST_SLEEPING_SET {
503 debug_assert!(touching);
505 } else {
506 debug_assert!(!touching && set_id == crate::solver_set::DISABLED_SET);
508 }
509
510 let contact_sim = if set_id == AWAKE_SET && contact.color_index != NULL_INDEX {
511 &self.constraint_graph.colors[contact.color_index as usize].contact_sims
512 [contact.local_index as usize]
513 } else {
514 &self.solver_sets[set_id as usize].contact_sims[contact.local_index as usize]
515 };
516 debug_assert!(contact_sim.contact_id == contact_index);
517 debug_assert!(contact_sim.body_id_a == contact.edges[0].body_id);
518 debug_assert!(contact_sim.body_id_b == contact.edges[1].body_id);
519
520 let sim_touching = contact_sim.sim_flags & contact_flags::SIM_TOUCHING != 0;
521 debug_assert!(touching == sim_touching);
522
523 debug_assert!(
524 0 <= contact_sim.manifold.point_count && contact_sim.manifold.point_count <= 2
525 );
526 }
527
528 let contact_id_count = self.contact_id_pool.id_count();
529 debug_assert!(allocated_contact_count == contact_id_count);
530 let _ = allocated_contact_count;
531 }
532}
533
534pub fn world_step(world: &mut World, time_step: f32, sub_step_count: i32) {
537 debug_assert!(is_valid_float(time_step));
538 debug_assert!(0 < sub_step_count);
539
540 debug_assert!(!world.locked);
541 if world.locked {
542 return;
543 }
544
545 world.body_move_events.clear();
548 world.sensor_begin_events.clear();
549 world.contact_begin_events.clear();
550 world.contact_hit_events.clear();
551 world.joint_events.clear();
552
553 world.profile = super::Profile::default();
554
555 world.locked = true;
556
557 {
558 let static_shape_count = world.broad_phase.trees[BodyType::Static as usize].proxy_count();
559 let dynamic_shape_count = world.broad_phase.trees[BodyType::Dynamic as usize].proxy_count();
560 let static_body_count = world.solver_sets[STATIC_SET as usize].body_sims.len() as i32;
561 let total_body_count = world.body_id_pool.id_count();
563 let total_contact_count = world.contact_id_pool.id_count();
564
565 let c = &mut world.max_capacity;
566 c.static_shape_count =
567 crate::math_functions::max_int(c.static_shape_count, static_shape_count);
568 c.dynamic_shape_count =
569 crate::math_functions::max_int(c.dynamic_shape_count, dynamic_shape_count);
570 c.static_body_count =
571 crate::math_functions::max_int(c.static_body_count, static_body_count);
572 c.dynamic_body_count = crate::math_functions::max_int(
573 c.dynamic_body_count,
574 total_body_count - static_body_count,
575 );
576 c.contact_count = crate::math_functions::max_int(c.contact_count, total_contact_count);
577 }
578
579 update_broad_phase_pairs(world);
581
582 let sub_step_count = crate::math_functions::max_int(1, sub_step_count);
583 let mut context = StepContext {
584 dt: time_step,
585 sub_step_count,
586 ..StepContext::default()
587 };
588
589 if time_step > 0.0 {
590 context.inv_dt = 1.0 / time_step;
591 context.h = time_step / sub_step_count as f32;
592 context.inv_h = sub_step_count as f32 * context.inv_dt;
593 } else {
594 context.inv_dt = 0.0;
595 context.h = 0.0;
596 context.inv_h = 0.0;
597 }
598
599 world.inv_h = context.inv_h;
600 world.inv_dt = context.inv_dt;
601
602 let contact_hertz = min_float(world.contact_hertz, 0.125 * context.inv_h);
604 context.contact_softness = make_soft(contact_hertz, world.contact_damping_ratio, context.h);
605 context.static_softness =
606 make_soft(2.0 * contact_hertz, world.contact_damping_ratio, context.h);
607
608 context.restitution_threshold = world.restitution_threshold;
609 context.max_linear_velocity = world.max_linear_speed;
610 context.contact_speed = world.contact_speed;
611 context.enable_warm_starting = world.enable_warm_starting;
612
613 collide(world, &context);
615
616 if time_step > 0.0 {
619 solve(world, &context);
620 }
621
622 overlap_sensors(world);
624
625 world.locked = false;
626
627 world.end_event_array_index = 1 - world.end_event_array_index;
629 world.sensor_end_events[world.end_event_array_index as usize].clear();
630 world.contact_end_events[world.end_event_array_index as usize].clear();
631}
632
633#[cfg(test)]
634mod tests {
635 use super::*;
636 use crate::body::{create_body, get_body_full_id, get_body_transform};
637 use crate::geometry::make_box;
638 use crate::math_functions::{rot_get_angle, to_pos, Vec2};
639 use crate::shape::create_polygon_shape;
640 use crate::types::{default_body_def, default_shape_def, default_world_def};
641
642 #[test]
645 fn hello_world() {
646 let mut world_def = default_world_def();
649 world_def.gravity = Vec2 { x: 0.0, y: -10.0 };
650
651 let mut world = World::new(&world_def);
652
653 let mut ground_body_def = default_body_def();
655 ground_body_def.position = to_pos(Vec2 { x: 0.0, y: -10.0 });
656
657 let ground_id = create_body(&mut world, &ground_body_def);
658
659 let ground_box = make_box(50.0, 10.0);
662
663 let ground_shape_def = default_shape_def();
665 create_polygon_shape(&mut world, ground_id, &ground_shape_def, &ground_box);
666
667 let mut body_def = default_body_def();
670 body_def.type_ = crate::types::BodyType::Dynamic;
671 body_def.position = to_pos(Vec2 { x: 0.0, y: 4.0 });
672
673 let body_id = create_body(&mut world, &body_def);
674 let body_index = get_body_full_id(&world, body_id);
675
676 let dynamic_box = make_box(1.0, 1.0);
678
679 let mut shape_def = default_shape_def();
682 shape_def.density = 1.0;
683 shape_def.material.friction = 0.3;
684
685 create_polygon_shape(&mut world, body_id, &shape_def, &dynamic_box);
686
687 let time_step = 1.0 / 60.0;
691 let sub_step_count = 4;
692
693 for _ in 0..90 {
695 world_step(&mut world, time_step, sub_step_count);
698 }
699
700 let transform = get_body_transform(&world, body_index);
701 let position = transform.p;
702 let rotation = transform.q;
703
704 assert!(abs_float(position.x as f32) < 0.01);
705 assert!(abs_float(position.y as f32 - 1.00) < 0.01);
706 assert!(abs_float(rot_get_angle(rotation)) < 0.01);
707 }
708
709 #[test]
711 fn empty_world() {
712 let world_def = default_world_def();
713 let mut world = World::new(&world_def);
714
715 let time_step = 1.0 / 60.0;
716 let sub_step_count = 1;
717
718 for _ in 0..60 {
719 world_step(&mut world, time_step, sub_step_count);
720 }
721
722 assert_eq!(world.step_index, 60);
724 }
725}