1#![allow(clippy::needless_range_loop)]
21
22use super::integrate::{finalize_bodies, integrate_positions, integrate_velocities};
23use super::StepContext;
24use crate::constants::GRAPH_COLOR_COUNT;
25use crate::constraint_graph::OVERFLOW_INDEX;
26use crate::contact::contact_flags;
27use crate::contact_solver::{
28 apply_restitution, prepare_contacts, solve_contacts, store_impulses, warm_start_contacts,
29 ContactConstraint,
30};
31use crate::core::NULL_INDEX;
32use crate::events::{BodyMoveEvent, ContactHitEvent, JointEvent};
33use crate::id::{BodyId, ContactId, JointId, ShapeId};
34use crate::joint::{get_joint_reaction, prepare_joint, solve_joint, warm_start_joint};
35use crate::math_functions::{make_world_transform, offset_pos, TRANSFORM_IDENTITY};
36use crate::solver_set::AWAKE_SET;
37use crate::timer::{get_milliseconds, get_milliseconds_and_reset, get_ticks};
38use crate::types::BodyType;
39use crate::world::World;
40
41const ITERATIONS: i32 = 1;
43const RELAX_ITERATIONS: i32 = 1;
44
45fn prepare_color_joints(world: &mut World, color_index: i32, context: &StepContext) {
48 let count = world.constraint_graph.colors[color_index as usize]
49 .joint_sims
50 .len();
51 for i in 0..count {
52 let mut sim = world.constraint_graph.colors[color_index as usize].joint_sims[i];
53 prepare_joint(world, &mut sim, context);
54 world.constraint_graph.colors[color_index as usize].joint_sims[i] = sim;
55 }
56}
57
58pub fn solve(world: &mut World, context: &StepContext) {
60 world.step_index += 1;
62
63 let awake_body_count = world.solver_sets[AWAKE_SET as usize].body_sims.len();
66 if awake_body_count == 0 {
67 world.broad_phase.validate_no_enlarged();
68 return;
69 }
70
71 let mut setup_ticks = get_ticks();
74
75 let mut bullet_bodies: Vec<i32> = Vec::with_capacity(awake_body_count);
77
78 world.body_move_events.resize(
80 awake_body_count,
81 BodyMoveEvent {
82 user_data: 0,
83 transform: make_world_transform(TRANSFORM_IDENTITY),
84 body_id: BodyId::default(),
85 fell_asleep: false,
86 },
87 );
88
89 let joint_id_capacity = world.joint_id_pool.id_capacity();
92 let contact_id_capacity = world.contact_id_pool.id_capacity();
93 {
94 let task_context = &mut world.task_contexts[0];
95 task_context
96 .joint_state_bit_set
97 .set_bit_count_and_clear(joint_id_capacity as u32);
98 task_context
99 .hit_event_bit_set
100 .set_bit_count_and_clear(contact_id_capacity as u32);
101 task_context.has_hit_events = false;
102 }
103
104 if world.split_island_id != NULL_INDEX {
110 let split_ticks = get_ticks();
111 let split_id = world.split_island_id;
112 crate::island::split_island(world, split_id);
113 world.split_island_id = NULL_INDEX;
114 world.profile.split_islands += get_milliseconds(split_ticks);
115 }
116
117 world.profile.solver_setup = get_milliseconds_and_reset(&mut setup_ticks);
118
119 let mut constraint_ticks = get_ticks();
122 let mut ticks = get_ticks();
123
124 for color_index in 0..OVERFLOW_INDEX {
127 prepare_color_joints(world, color_index, context);
128 }
129
130 let mut color_constraints: Vec<Vec<ContactConstraint>> =
132 (0..GRAPH_COLOR_COUNT).map(|_| Vec::new()).collect();
133 for color_index in 0..GRAPH_COLOR_COUNT as usize {
134 let count = world.constraint_graph.colors[color_index]
137 .contact_sims
138 .len();
139 color_constraints[color_index].resize(count, ContactConstraint::default());
140 }
141 for color_index in 0..OVERFLOW_INDEX as usize {
142 let contacts = &world.constraint_graph.colors[color_index].contact_sims;
143 let states = &world.solver_sets[AWAKE_SET as usize].body_states;
144 prepare_contacts(
145 &mut color_constraints[color_index],
146 contacts,
147 states,
148 context,
149 );
150 }
151
152 prepare_color_joints(world, OVERFLOW_INDEX, context);
155 {
156 let contacts = &world.constraint_graph.colors[OVERFLOW_INDEX as usize].contact_sims;
157 let states = &world.solver_sets[AWAKE_SET as usize].body_states;
158 prepare_contacts(
159 &mut color_constraints[OVERFLOW_INDEX as usize],
160 contacts,
161 states,
162 context,
163 );
164 }
165
166 world.profile.prepare_constraints += get_milliseconds_and_reset(&mut ticks);
167
168 let sub_step_count = context.sub_step_count;
170 for _sub_step_index in 0..sub_step_count {
171 integrate_velocities(world, context);
173 world.profile.integrate_velocities += get_milliseconds_and_reset(&mut ticks);
174
175 {
179 let world_parts = &mut *world;
180 let graph = &mut world_parts.constraint_graph;
181 let states = &mut world_parts.solver_sets[AWAKE_SET as usize].body_states;
182
183 for joint in graph.colors[OVERFLOW_INDEX as usize].joint_sims.iter_mut() {
184 warm_start_joint(joint, states);
185 }
186 warm_start_contacts(&mut color_constraints[OVERFLOW_INDEX as usize], states);
187
188 for color_index in 0..OVERFLOW_INDEX as usize {
189 for joint in graph.colors[color_index].joint_sims.iter_mut() {
190 warm_start_joint(joint, states);
191 }
192 warm_start_contacts(&mut color_constraints[color_index], states);
193 }
194 }
195 world.profile.warm_start += get_milliseconds_and_reset(&mut ticks);
196
197 for _ in 0..ITERATIONS {
199 let use_bias = true;
200 let world_parts = &mut *world;
201 let graph = &mut world_parts.constraint_graph;
202 let states = &mut world_parts.solver_sets[AWAKE_SET as usize].body_states;
203 let joint_state_bit_set = &mut world_parts.task_contexts[0].joint_state_bit_set;
204
205 for joint in graph.colors[OVERFLOW_INDEX as usize].joint_sims.iter_mut() {
209 solve_joint(joint, context, states, use_bias);
210 }
211 solve_contacts(
212 &mut color_constraints[OVERFLOW_INDEX as usize],
213 states,
214 context,
215 use_bias,
216 );
217
218 for color_index in 0..OVERFLOW_INDEX as usize {
219 for joint in graph.colors[color_index].joint_sims.iter_mut() {
220 solve_joint(joint, context, states, use_bias);
221
222 if (joint.force_threshold < f32::MAX || joint.torque_threshold < f32::MAX)
223 && !joint_state_bit_set.get_bit(joint.joint_id as u32)
224 {
225 let (force, torque) = get_joint_reaction(joint, context.inv_h);
226
227 if force >= joint.force_threshold || torque >= joint.torque_threshold {
230 joint_state_bit_set.set_bit(joint.joint_id as u32);
232 }
233 }
234 }
235 solve_contacts(
236 &mut color_constraints[color_index],
237 states,
238 context,
239 use_bias,
240 );
241 }
242 }
243 world.profile.solve_impulses += get_milliseconds_and_reset(&mut ticks);
244
245 integrate_positions(world, context);
247 world.profile.integrate_positions += get_milliseconds_and_reset(&mut ticks);
248
249 for _ in 0..RELAX_ITERATIONS {
251 let use_bias = false;
252 let world_parts = &mut *world;
253 let graph = &mut world_parts.constraint_graph;
254 let states = &mut world_parts.solver_sets[AWAKE_SET as usize].body_states;
255
256 for joint in graph.colors[OVERFLOW_INDEX as usize].joint_sims.iter_mut() {
257 solve_joint(joint, context, states, use_bias);
258 }
259 solve_contacts(
260 &mut color_constraints[OVERFLOW_INDEX as usize],
261 states,
262 context,
263 use_bias,
264 );
265
266 for color_index in 0..OVERFLOW_INDEX as usize {
267 for joint in graph.colors[color_index].joint_sims.iter_mut() {
268 solve_joint(joint, context, states, use_bias);
269 }
270 solve_contacts(
271 &mut color_constraints[color_index],
272 states,
273 context,
274 use_bias,
275 );
276 }
277 }
278 world.profile.relax_impulses += get_milliseconds_and_reset(&mut ticks);
279 }
280
281 {
283 let world_parts = &mut *world;
284 let states = &mut world_parts.solver_sets[AWAKE_SET as usize].body_states;
285
286 apply_restitution(
287 &mut color_constraints[OVERFLOW_INDEX as usize],
288 states,
289 context,
290 );
291 for color_index in 0..OVERFLOW_INDEX as usize {
292 apply_restitution(&mut color_constraints[color_index], states, context);
293 }
294 }
295 world.profile.apply_restitution += get_milliseconds_and_reset(&mut ticks);
296
297 {
301 let world_parts = &mut *world;
302 let graph = &mut world_parts.constraint_graph;
303 let task_context = &mut world_parts.task_contexts[0];
304 let neg_hit_threshold = -world_parts.hit_event_threshold;
305
306 store_impulses(
307 &color_constraints[OVERFLOW_INDEX as usize],
308 &mut graph.colors[OVERFLOW_INDEX as usize].contact_sims,
309 );
310
311 for color_index in 0..OVERFLOW_INDEX as usize {
312 store_impulses(
313 &color_constraints[color_index],
314 &mut graph.colors[color_index].contact_sims,
315 );
316
317 for contact_sim in &graph.colors[color_index].contact_sims {
320 if contact_sim.sim_flags & contact_flags::SIM_ENABLE_HIT_EVENT != 0 {
321 for k in 0..contact_sim.manifold.point_count as usize {
322 let mp = &contact_sim.manifold.points[k];
323
324 if mp.normal_velocity < neg_hit_threshold && mp.total_normal_impulse > 0.0 {
327 task_context
328 .hit_event_bit_set
329 .set_bit(contact_sim.contact_id as u32);
330 task_context.has_hit_events = true;
331 break;
332 }
333 }
334 }
335 }
336 }
337 }
338 world.profile.store_impulses += get_milliseconds_and_reset(&mut ticks);
339
340 world.profile.constraints = get_milliseconds_and_reset(&mut constraint_ticks);
342
343 let transform_ticks = get_ticks();
345
346 {
349 let awake_island_count = world.solver_sets[AWAKE_SET as usize].island_sims.len();
350 let task_context = &mut world.task_contexts[0];
351 task_context.sensor_hits.clear();
352 task_context
353 .enlarged_sim_bit_set
354 .set_bit_count_and_clear(awake_body_count as u32);
355 task_context
356 .awake_island_bit_set
357 .set_bit_count_and_clear(awake_island_count as u32);
358 task_context.split_island_id = NULL_INDEX;
359 task_context.split_sleep_time = 0.0;
360 }
361
362 finalize_bodies(world, context, &mut bullet_bodies);
365
366 world.profile.transforms = get_milliseconds(transform_ticks);
367
368 {
370 let joint_event_ticks = get_ticks();
371 let world_id = world.world_id;
372 let word_count = world.task_contexts[0].joint_state_bit_set.block_count();
373 for k in 0..word_count {
374 let mut word = world.task_contexts[0].joint_state_bit_set.block(k);
375 while word != 0 {
376 let ctz = word.trailing_zeros();
377 let joint_id = (64 * k + ctz) as i32;
378
379 let joint = &world.joints[joint_id as usize];
380 debug_assert!(joint.set_index == AWAKE_SET);
381
382 let event = JointEvent {
383 joint_id: JointId {
384 index1: joint_id + 1,
385 world0: world_id,
386 generation: joint.generation,
387 },
388 user_data: joint.user_data,
389 };
390
391 world.joint_events.push(event);
392
393 word &= word - 1;
395 }
396 }
397 world.profile.joint_events = get_milliseconds(joint_event_ticks);
398 }
399
400 {
402 let hit_ticks = get_ticks();
403 debug_assert!(world.contact_hit_events.is_empty());
404
405 if world.task_contexts[0].has_hit_events {
406 let threshold = world.hit_event_threshold;
407 let world_id = world.world_id;
408
409 let word_count = world.task_contexts[0].hit_event_bit_set.block_count();
410 for k in 0..word_count {
411 let mut word = world.task_contexts[0].hit_event_bit_set.block(k);
412 while word != 0 {
413 let ctz = word.trailing_zeros();
414 let contact_id = (64 * k + ctz) as i32;
415
416 let contact = world.contacts[contact_id as usize];
417 debug_assert!(
418 contact.set_index == AWAKE_SET && contact.color_index != NULL_INDEX
419 );
420
421 let contact_sim = &world.constraint_graph.colors[contact.color_index as usize]
422 .contact_sims[contact.local_index as usize];
423
424 let mut approach_speed = threshold;
425 let mut best_point: Option<usize> = None;
426 for p in 0..contact_sim.manifold.point_count as usize {
427 let mp = &contact_sim.manifold.points[p];
428 let point_approach_speed = -mp.normal_velocity;
429
430 if point_approach_speed > approach_speed && mp.total_normal_impulse > 0.0 {
433 approach_speed = point_approach_speed;
434 best_point = Some(p);
435 }
436 }
437
438 if let Some(p) = best_point {
439 let best = contact_sim.manifold.points[p];
440 let normal = contact_sim.manifold.normal;
441
442 let shape_a = &world.shapes[contact_sim.shape_id_a as usize];
443 let shape_b = &world.shapes[contact_sim.shape_id_b as usize];
444
445 let body_a = &world.bodies[shape_a.body_id as usize];
452 let body_b = &world.bodies[shape_b.body_id as usize];
453 let point = if body_a.type_ != BodyType::Static
454 && body_b.type_ == BodyType::Static
455 {
456 let body_sim_b = &world.solver_sets[body_b.set_index as usize]
457 .body_sims[body_b.local_index as usize];
458 offset_pos(body_sim_b.center, best.anchor_b)
459 } else {
460 let body_sim_a = &world.solver_sets[body_a.set_index as usize]
461 .body_sims[body_a.local_index as usize];
462 offset_pos(body_sim_a.center, best.anchor_a)
463 };
464
465 let event = ContactHitEvent {
466 shape_id_a: ShapeId {
467 index1: shape_a.id + 1,
468 world0: world_id,
469 generation: shape_a.generation,
470 },
471 shape_id_b: ShapeId {
472 index1: shape_b.id + 1,
473 world0: world_id,
474 generation: shape_b.generation,
475 },
476 contact_id: ContactId {
477 index1: contact.contact_id + 1,
478 world0: world_id,
479 padding: 0,
480 generation: contact.generation,
481 },
482 point,
483 normal,
484 approach_speed,
485 };
486
487 world.contact_hit_events.push(event);
488 }
489
490 word &= word - 1;
492 }
493 }
494 }
495 world.profile.hit_events = get_milliseconds(hit_ticks);
496 }
497
498 {
500 let refit_ticks = get_ticks();
501 world.broad_phase.validate_no_enlarged();
502
503 let word_count = world.task_contexts[0].enlarged_sim_bit_set.block_count();
509 for k in 0..word_count {
510 let mut word = world.task_contexts[0].enlarged_sim_bit_set.block(k);
511 while word != 0 {
512 let ctz = word.trailing_zeros();
513 let body_sim_index = (64 * k + ctz) as usize;
514
515 let (body_id, sim_flags) = {
516 let body_sim = &world.solver_sets[AWAKE_SET as usize].body_sims[body_sim_index];
517 (body_sim.body_id, body_sim.flags)
518 };
519
520 let mut shape_id = world.bodies[body_id as usize].head_shape_id;
521 if sim_flags
522 & (crate::body::body_flags::IS_BULLET | crate::body::body_flags::IS_FAST)
523 == (crate::body::body_flags::IS_BULLET | crate::body::body_flags::IS_FAST)
524 {
525 while shape_id != NULL_INDEX {
527 let proxy_key = world.shapes[shape_id as usize].proxy_key;
528
529 world.broad_phase.buffer_move(proxy_key);
534
535 shape_id = world.shapes[shape_id as usize].next_shape_id;
536 }
537 } else {
538 while shape_id != NULL_INDEX {
539 if world.shapes[shape_id as usize].enlarged_aabb {
545 let proxy_key = world.shapes[shape_id as usize].proxy_key;
546 let fat_aabb = world.shapes[shape_id as usize].fat_aabb;
547 world.broad_phase.enlarge_proxy(proxy_key, fat_aabb);
548 world.shapes[shape_id as usize].enlarged_aabb = false;
549 }
550
551 shape_id = world.shapes[shape_id as usize].next_shape_id;
552 }
553 }
554
555 word &= word - 1;
557 }
558 }
559
560 world.broad_phase.validate();
561 world.profile.refit = get_milliseconds(refit_ticks);
562 }
563
564 if !bullet_bodies.is_empty() {
566 let bullet_ticks = get_ticks();
567 for &sim_index in &bullet_bodies {
570 super::continuous::solve_continuous(world, sim_index);
571 }
572
573 for &sim_index in &bullet_bodies {
577 let (body_id, enlarge) = {
578 let bullet_body_sim =
579 &world.solver_sets[AWAKE_SET as usize].body_sims[sim_index as usize];
580 (
581 bullet_body_sim.body_id,
582 bullet_body_sim.flags & crate::body::body_flags::ENLARGE_BOUNDS != 0,
583 )
584 };
585 if !enlarge {
586 continue;
587 }
588
589 world.solver_sets[AWAKE_SET as usize].body_sims[sim_index as usize].flags &=
591 !crate::body::body_flags::ENLARGE_BOUNDS;
592
593 let mut shape_id = world.bodies[body_id as usize].head_shape_id;
594 while shape_id != NULL_INDEX {
595 if !world.shapes[shape_id as usize].enlarged_aabb {
596 shape_id = world.shapes[shape_id as usize].next_shape_id;
597 continue;
598 }
599
600 world.shapes[shape_id as usize].enlarged_aabb = false;
602
603 let proxy_key = world.shapes[shape_id as usize].proxy_key;
604 let proxy_id = crate::broad_phase::proxy_id(proxy_key);
605 debug_assert!(crate::broad_phase::proxy_type(proxy_key) == BodyType::Dynamic);
606
607 debug_assert!(world.broad_phase.moved_proxies[BodyType::Dynamic as usize]
609 .get_bit(proxy_id as u32));
610
611 let fat_aabb = world.shapes[shape_id as usize].fat_aabb;
612 world.broad_phase.trees[BodyType::Dynamic as usize]
613 .enlarge_proxy(proxy_id, fat_aabb);
614
615 shape_id = world.shapes[shape_id as usize].next_shape_id;
616 }
617 }
618 world.profile.bullets = get_milliseconds(bullet_ticks);
619 }
620
621 {
624 let sensor_hit_ticks = get_ticks();
625 let hits = std::mem::take(&mut world.task_contexts[0].sensor_hits);
626 for hit in hits {
627 let sensor_index = world.shapes[hit.sensor_id as usize].sensor_index;
628 let generation = world.shapes[hit.visitor_id as usize].generation;
629
630 let shape_ref = crate::sensor::Visitor {
631 shape_id: hit.visitor_id,
632 generation,
633 };
634 world.sensors[sensor_index as usize].hits.push(shape_ref);
635 }
636 world.profile.sensor_hits = get_milliseconds(sensor_hit_ticks);
637 }
638
639 if world.enable_sleep {
643 let sleep_ticks = get_ticks();
644 debug_assert!(world.split_island_id == NULL_INDEX);
647 {
648 let task_context = &world.task_contexts[0];
649 if task_context.split_island_id != NULL_INDEX && task_context.split_sleep_time >= 0.0 {
650 debug_assert!(task_context.split_sleep_time > 0.0);
651 world.split_island_id = task_context.split_island_id;
652 }
653 }
654
655 let count = world.solver_sets[AWAKE_SET as usize].island_sims.len();
658 for island_index in (0..count).rev() {
659 if world.task_contexts[0]
660 .awake_island_bit_set
661 .get_bit(island_index as u32)
662 {
663 continue;
665 }
666
667 let island_id =
668 world.solver_sets[AWAKE_SET as usize].island_sims[island_index].island_id;
669
670 crate::solver_set::try_sleep_island(world, island_id);
671 }
672
673 world.validate_solver_sets();
674 world.profile.sleep_islands = get_milliseconds(sleep_ticks);
675 }
676}