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