1#![allow(clippy::needless_range_loop)]
8
9use super::continuous::solve_continuous;
10use super::integrate::{finalize_bodies, integrate_positions, integrate_velocities};
11use super::StepContext;
12use crate::body::body_flags;
13use crate::broad_phase::{proxy_id, proxy_type};
14use crate::constants::{GRAPH_COLOR_COUNT, RELAX_ITERATIONS, SOLVER_ITERATIONS};
15use crate::constraint_graph::OVERFLOW_INDEX;
16use crate::contact_solver::{
17 apply_restitution, apply_restitution_convex, flag_hit_events, prepare_color_contacts,
18 solve_contacts, solve_contacts_convex, store_impulses, warm_start_contacts,
19 warm_start_contacts_convex, ContactConstraint,
20};
21use crate::core::NULL_INDEX;
22use crate::events::{BodyMoveEvent, JointEvent};
23use crate::id::{BodyId, JointId};
24use crate::island::split_island;
25use crate::joint::{get_joint_reaction, prepare_joint, solve_joint, warm_start_joint};
26use crate::math_functions::WORLD_TRANSFORM_IDENTITY;
27use crate::shape::shape_flags;
28use crate::solver_set::{try_sleep_island, AWAKE_SET};
29use crate::types::BodyType;
30use crate::world::World;
31
32fn solve_joints_then_contacts(
36 world: &mut World,
37 color_constraints: &mut [Vec<ContactConstraint>],
38 convex_counts: &[usize],
39 context: &StepContext,
40 use_bias: bool,
41) {
42 {
44 let mut joint_sims =
45 std::mem::take(&mut world.constraint_graph.colors[OVERFLOW_INDEX as usize].joint_sims);
46 {
47 let states = &mut world.solver_sets[AWAKE_SET as usize].body_states;
48 for joint in &mut joint_sims {
49 solve_joint(joint, context, states, use_bias);
50 }
51 }
52 if use_bias {
53 for joint in &mut joint_sims {
54 maybe_flag_joint_reaction(world, joint, context.inv_h);
55 }
56 }
57 world.constraint_graph.colors[OVERFLOW_INDEX as usize].joint_sims = joint_sims;
58
59 let states = &mut world.solver_sets[AWAKE_SET as usize].body_states;
60 debug_assert_eq!(convex_counts[OVERFLOW_INDEX as usize], 0);
61 solve_contacts(
62 &mut color_constraints[OVERFLOW_INDEX as usize],
63 states,
64 context,
65 use_bias,
66 );
67 }
68
69 for color_index in 0..OVERFLOW_INDEX as usize {
70 let mut joint_sims =
71 std::mem::take(&mut world.constraint_graph.colors[color_index].joint_sims);
72 {
73 let states = &mut world.solver_sets[AWAKE_SET as usize].body_states;
74 for joint in &mut joint_sims {
75 solve_joint(joint, context, states, use_bias);
76 }
77 }
78 if use_bias {
79 for joint in &mut joint_sims {
80 maybe_flag_joint_reaction(world, joint, context.inv_h);
81 }
82 }
83 world.constraint_graph.colors[color_index].joint_sims = joint_sims;
84
85 let states = &mut world.solver_sets[AWAKE_SET as usize].body_states;
86 let convex_count = convex_counts[color_index];
87 let (convex, mesh) = color_constraints[color_index].split_at_mut(convex_count);
88 solve_contacts_convex(convex, states, context, use_bias);
90 solve_contacts(mesh, states, context, use_bias);
91 }
92}
93
94fn maybe_flag_joint_reaction(world: &mut World, joint: &crate::joint::JointSim, inv_h: f32) {
95 if !(joint.force_threshold < f32::MAX || joint.torque_threshold < f32::MAX) {
96 return;
97 }
98 if world.task_contexts[0]
99 .joint_state_bit_set
100 .get_bit(joint.joint_id as u32)
101 {
102 return;
103 }
104
105 let (force, torque) = get_joint_reaction(world, joint, inv_h);
106
107 if force >= joint.force_threshold || torque >= joint.torque_threshold {
109 world.task_contexts[0]
110 .joint_state_bit_set
111 .set_bit(joint.joint_id as u32);
112 }
113}
114
115pub fn solve(world: &mut World, context: &StepContext) {
119 let awake_body_count = world.solver_sets[AWAKE_SET as usize].body_sims.len();
120 if awake_body_count == 0 {
121 world.broad_phase.validate_no_enlarged();
122 return;
123 }
124
125 world.body_move_events.resize(
126 awake_body_count,
127 BodyMoveEvent {
128 user_data: 0,
129 transform: WORLD_TRANSFORM_IDENTITY,
130 body_id: BodyId::default(),
131 fell_asleep: false,
132 },
133 );
134
135 let contact_id_capacity = world.contact_id_pool.id_capacity();
136 let joint_id_capacity = world.joint_id_pool.id_capacity();
137 {
138 let task_context = &mut world.task_contexts[0];
139 task_context
140 .hit_event_bit_set
141 .set_bit_count_and_clear(contact_id_capacity as u32);
142 task_context.has_hit_events = false;
143 task_context
144 .joint_state_bit_set
145 .set_bit_count_and_clear(joint_id_capacity as u32);
146 }
147
148 if world.split_island_id != NULL_INDEX {
155 split_island(world, world.split_island_id);
156 world.split_island_id = NULL_INDEX;
157 }
158
159 for color_index in 0..GRAPH_COLOR_COUNT as usize {
162 let mut joint_sims =
163 std::mem::take(&mut world.constraint_graph.colors[color_index].joint_sims);
164 for joint in &mut joint_sims {
165 prepare_joint(world, joint, context);
166 }
167 world.constraint_graph.colors[color_index].joint_sims = joint_sims;
168 }
169
170 let mut color_constraints: Vec<Vec<ContactConstraint>> = (0..GRAPH_COLOR_COUNT as usize)
172 .map(|_| Vec::new())
173 .collect();
174 let mut convex_counts = vec![0usize; GRAPH_COLOR_COUNT as usize];
175
176 for color_index in 0..GRAPH_COLOR_COUNT as usize {
177 let convex_ids = world.constraint_graph.colors[color_index]
178 .convex_contacts
179 .clone();
180 let mesh_specs = world.constraint_graph.colors[color_index].contacts.clone();
181 let contacts = &world.contacts;
182 let sims = &world.solver_sets[AWAKE_SET as usize].body_sims;
183 let states = &world.solver_sets[AWAKE_SET as usize].body_states;
184 convex_counts[color_index] = prepare_color_contacts(
185 &mut color_constraints[color_index],
186 &convex_ids,
187 &mesh_specs,
188 contacts,
189 sims,
190 states,
191 context,
192 );
193 }
194
195 let sub_step_count = context.sub_step_count;
197 for _sub_step_index in 0..sub_step_count {
198 integrate_velocities(world, context);
199
200 {
203 let World {
204 constraint_graph,
205 solver_sets,
206 ..
207 } = world;
208 let states = &mut solver_sets[AWAKE_SET as usize].body_states;
209 for joint in &mut constraint_graph.colors[OVERFLOW_INDEX as usize].joint_sims {
210 warm_start_joint(joint, states);
211 }
212 warm_start_contacts(&mut color_constraints[OVERFLOW_INDEX as usize], states);
213 for color_index in 0..OVERFLOW_INDEX as usize {
214 for joint in &mut constraint_graph.colors[color_index].joint_sims {
215 warm_start_joint(joint, states);
216 }
217 let convex_count = convex_counts[color_index];
218 let (convex, mesh) = color_constraints[color_index].split_at_mut(convex_count);
219 warm_start_contacts_convex(convex, states);
220 warm_start_contacts(mesh, states);
221 }
222 }
223
224 for _ in 0..SOLVER_ITERATIONS {
225 let use_bias = true;
226 solve_joints_then_contacts(
227 world,
228 &mut color_constraints,
229 &convex_counts,
230 context,
231 use_bias,
232 );
233 }
234
235 integrate_positions(world, context);
236
237 for _ in 0..RELAX_ITERATIONS {
238 let use_bias = false;
239 solve_joints_then_contacts(
240 world,
241 &mut color_constraints,
242 &convex_counts,
243 context,
244 use_bias,
245 );
246 }
247 }
248
249 {
251 let states = &mut world.solver_sets[AWAKE_SET as usize].body_states;
252 apply_restitution(
254 &mut color_constraints[OVERFLOW_INDEX as usize],
255 states,
256 context,
257 );
258 for color_index in 0..OVERFLOW_INDEX as usize {
259 let convex_count = convex_counts[color_index];
260 let (convex, mesh) = color_constraints[color_index].split_at_mut(convex_count);
261 apply_restitution_convex(convex, states, context);
262 apply_restitution(mesh, states, context);
263 }
264 }
265
266 {
268 store_impulses(
269 &color_constraints[OVERFLOW_INDEX as usize],
270 &mut world.contacts,
271 );
272
273 for color_index in 0..OVERFLOW_INDEX as usize {
274 store_impulses(&color_constraints[color_index], &mut world.contacts);
275 }
276
277 let neg_hit_threshold = -world.hit_event_threshold;
278 let mut has_hit = world.task_contexts[0].has_hit_events;
279 for color_index in 0..OVERFLOW_INDEX as usize {
280 flag_hit_events(
281 &color_constraints[color_index],
282 &world.contacts,
283 &mut world.task_contexts[0].hit_event_bit_set,
284 &mut has_hit,
285 neg_hit_threshold,
286 );
287 }
288 world.task_contexts[0].has_hit_events = has_hit;
289 }
290
291 let mut bullet_bodies: Vec<i32> = Vec::with_capacity(awake_body_count);
293 {
294 let awake_island_count = world.solver_sets[AWAKE_SET as usize].island_sims.len();
295 let task_context = &mut world.task_contexts[0];
296 task_context.sensor_hits.clear();
297 task_context
298 .enlarged_sim_bit_set
299 .set_bit_count_and_clear(awake_body_count as u32);
300 task_context
301 .awake_island_bit_set
302 .set_bit_count_and_clear(awake_island_count as u32);
303 task_context.split_island_id = NULL_INDEX;
304 task_context.split_sleep_time = 0.0;
305 }
306
307 finalize_bodies(world, context, &mut bullet_bodies);
308
309 {
311 debug_assert!(world.joint_events.is_empty());
312 let world_id = world.world_id;
313 let word_count = world.task_contexts[0].joint_state_bit_set.block_count();
314 for k in 0..word_count {
315 let mut word = world.task_contexts[0].joint_state_bit_set.block(k);
316 while word != 0 {
317 let ctz = word.trailing_zeros();
318 let joint_id = (64 * k + ctz) as i32;
319
320 debug_assert!((joint_id as usize) < world.joints.len());
321
322 let joint = &world.joints[joint_id as usize];
323 debug_assert!(joint.set_index == AWAKE_SET);
324
325 world.joint_events.push(JointEvent {
326 joint_id: JointId {
327 index1: joint_id + 1,
328 world0: world_id,
329 generation: joint.generation,
330 },
331 user_data: joint.user_data,
332 });
333
334 word &= word - 1;
335 }
336 }
337 }
338
339 {
342 use crate::events::ContactHitEvent;
343 use crate::id::{ContactId, ShapeId};
344 use crate::math_functions::{lerp, lerp_position, offset_pos, VEC3_ZERO};
345
346 debug_assert!(world.contact_hit_events.is_empty());
347
348 if world.task_contexts[0].has_hit_events {
351 let threshold = world.hit_event_threshold;
352 let world_id = world.world_id;
353
354 let word_count = world.task_contexts[0].hit_event_bit_set.block_count();
355 for k in 0..word_count {
356 let mut word = world.task_contexts[0].hit_event_bit_set.block(k);
357 while word != 0 {
358 let ctz = word.trailing_zeros();
359 let contact_id = (64 * k + ctz) as i32;
360
361 let contact = &world.contacts[contact_id as usize];
362 debug_assert!(
363 contact.set_index == AWAKE_SET && contact.color_index != NULL_INDEX
364 );
365
366 let shape_a = &world.shapes[contact.shape_id_a as usize];
367 let shape_b = &world.shapes[contact.shape_id_b as usize];
368 let body_a = &world.bodies[shape_a.body_id as usize];
369 let body_b = &world.bodies[shape_b.body_id as usize];
370 let sim_a = &world.solver_sets[body_a.set_index as usize].body_sims
372 [body_a.local_index as usize];
373 let sim_b = &world.solver_sets[body_b.set_index as usize].body_sims
374 [body_b.local_index as usize];
375 let mid_center = lerp_position(sim_a.center, sim_b.center, 0.5);
376
377 let mut approach_speed = threshold;
378 let mut point = mid_center;
379 let mut normal = VEC3_ZERO;
380 let mut found = false;
381 let mut triangle_index = 0;
382 for manifold in &contact.manifolds {
383 for p in 0..manifold.point_count as usize {
384 let mp = &manifold.points[p];
385 let mp_approach_speed = -mp.normal_velocity;
386
387 if mp_approach_speed > approach_speed && mp.total_normal_impulse > 0.0 {
389 approach_speed = mp_approach_speed;
390 point = offset_pos(mid_center, lerp(mp.anchor_a, mp.anchor_b, 0.5));
391 normal = manifold.normal;
392 triangle_index = mp.triangle_index;
393 found = true;
394 }
395 }
396 }
397
398 if found {
399 let event = ContactHitEvent {
400 shape_id_a: ShapeId {
401 index1: shape_a.id + 1,
402 world0: world_id,
403 generation: shape_a.generation,
404 },
405 shape_id_b: ShapeId {
406 index1: shape_b.id + 1,
407 world0: world_id,
408 generation: shape_b.generation,
409 },
410 contact_id: ContactId {
411 index1: contact.contact_id + 1,
412 world0: world_id,
413 padding: 0,
414 generation: contact.generation,
415 },
416 point,
417 normal,
418 approach_speed,
419 user_material_id_a: shape_a
422 .get_shape_user_material_id(contact.child_index, triangle_index),
423 user_material_id_b: shape_b
424 .get_shape_user_material_id(0, triangle_index),
425 };
426 world.contact_hit_events.push(event);
427 }
428
429 word &= word - 1;
430 }
431 }
432 }
433 }
434
435 {
438 world.broad_phase.validate_no_enlarged();
439
440 let word_count = world.task_contexts[0].enlarged_sim_bit_set.block_count();
441 for k in 0..word_count {
442 let mut word = world.task_contexts[0].enlarged_sim_bit_set.block(k);
443 while word != 0 {
444 let ctz = word.trailing_zeros();
445 let body_sim_index = (64 * k + ctz) as usize;
446
447 let body_sim = world.solver_sets[AWAKE_SET as usize].body_sims[body_sim_index];
448 let body_id = body_sim.body_id;
449 let mut shape_id = world.bodies[body_id as usize].head_shape_id;
450
451 if (body_sim.flags & (body_flags::IS_BULLET | body_flags::IS_FAST))
452 == (body_flags::IS_BULLET | body_flags::IS_FAST)
453 {
454 while shape_id != NULL_INDEX {
455 let proxy_key = world.shapes[shape_id as usize].proxy_key;
456 world.broad_phase.buffer_move(proxy_key);
457 shape_id = world.shapes[shape_id as usize].next_shape_id;
458 }
459 } else {
460 while shape_id != NULL_INDEX {
461 if (world.shapes[shape_id as usize].flags & shape_flags::ENLARGED_AABB) != 0
462 {
463 let proxy_key = world.shapes[shape_id as usize].proxy_key;
464 let fat_aabb = world.shapes[shape_id as usize].fat_aabb;
465 world.broad_phase.enlarge_proxy(proxy_key, fat_aabb);
466 world.shapes[shape_id as usize].flags &= !shape_flags::ENLARGED_AABB;
467 }
468 shape_id = world.shapes[shape_id as usize].next_shape_id;
469 }
470 }
471
472 word &= word - 1;
473 }
474 }
475
476 world.broad_phase.validate();
477 }
478
479 if !bullet_bodies.is_empty() {
481 for &sim_index in &bullet_bodies {
482 solve_continuous(world, sim_index);
483 }
484
485 let dynamic_tree = BodyType::Dynamic as usize;
486 for &sim_index in &bullet_bodies {
487 let bullet_sim =
488 &mut world.solver_sets[AWAKE_SET as usize].body_sims[sim_index as usize];
489 if (bullet_sim.flags & body_flags::ENLARGE_BOUNDS) == 0 {
490 continue;
491 }
492 bullet_sim.flags &= !body_flags::ENLARGE_BOUNDS;
493 let body_id = bullet_sim.body_id;
494
495 let mut shape_id = world.bodies[body_id as usize].head_shape_id;
496 while shape_id != NULL_INDEX {
497 if (world.shapes[shape_id as usize].flags & shape_flags::ENLARGED_AABB) == 0 {
498 shape_id = world.shapes[shape_id as usize].next_shape_id;
499 continue;
500 }
501 world.shapes[shape_id as usize].flags &= !shape_flags::ENLARGED_AABB;
502
503 let proxy_key = world.shapes[shape_id as usize].proxy_key;
504 let proxy_id_ = proxy_id(proxy_key);
505 debug_assert!(proxy_type(proxy_key) == BodyType::Dynamic);
506 debug_assert!(
507 world.broad_phase.moved_proxies[dynamic_tree].get_bit(proxy_id_ as u32)
508 );
509
510 let fat_aabb = world.shapes[shape_id as usize].fat_aabb;
511 world.broad_phase.trees[dynamic_tree].enlarge_proxy(proxy_id_, fat_aabb);
512
513 shape_id = world.shapes[shape_id as usize].next_shape_id;
514 }
515 }
516 }
517
518 {
520 let mut drained: Vec<(i32, i32, u16)> = Vec::new();
521 for task_context in &world.task_contexts {
522 for hit in &task_context.sensor_hits {
523 let sensor_index = world.shapes[hit.sensor_id as usize].sensor_index;
524 let generation = world.shapes[hit.visitor_id as usize].generation;
525 drained.push((sensor_index, hit.visitor_id, generation));
526 }
527 }
528 for (sensor_index, visitor_id, generation) in drained {
529 world.sensors[sensor_index as usize]
530 .hits
531 .push(crate::sensor::Visitor {
532 shape_id: visitor_id,
533 generation,
534 });
535 }
536 }
537
538 if world.enable_sleep {
541 debug_assert!(world.split_island_id == NULL_INDEX);
543 let mut split_sleep_timer = 0.0f32;
544 {
545 let task_context = &world.task_contexts[0];
546 if task_context.split_island_id != NULL_INDEX
547 && task_context.split_sleep_time >= split_sleep_timer
548 {
549 debug_assert!(task_context.split_sleep_time > 0.0);
550
551 let tied_but_smaller = task_context.split_sleep_time == split_sleep_timer
555 && task_context.split_island_id < world.split_island_id;
556 if !tied_but_smaller {
557 world.split_island_id = task_context.split_island_id;
558 split_sleep_timer = task_context.split_sleep_time;
559 }
560 }
561 }
562 let _ = split_sleep_timer;
563
564 let count = world.solver_sets[AWAKE_SET as usize].island_sims.len();
566 for island_index in (0..count).rev() {
567 if world.task_contexts[0]
568 .awake_island_bit_set
569 .get_bit(island_index as u32)
570 {
571 continue;
573 }
574
575 let island_id =
576 world.solver_sets[AWAKE_SET as usize].island_sims[island_index].island_id;
577
578 try_sleep_island(world, island_id);
579 }
580
581 world.validate_solver_sets();
582 }
583}