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::types::BodyType;
38use crate::world::World;
39
40const ITERATIONS: i32 = 1;
42const RELAX_ITERATIONS: i32 = 1;
43
44fn prepare_color_joints(world: &mut World, color_index: i32, context: &StepContext) {
47 let count = world.constraint_graph.colors[color_index as usize]
48 .joint_sims
49 .len();
50 for i in 0..count {
51 let mut sim = world.constraint_graph.colors[color_index as usize].joint_sims[i];
52 prepare_joint(world, &mut sim, context);
53 world.constraint_graph.colors[color_index as usize].joint_sims[i] = sim;
54 }
55}
56
57pub fn solve(world: &mut World, context: &StepContext) {
59 world.step_index += 1;
61
62 let awake_body_count = world.solver_sets[AWAKE_SET as usize].body_sims.len();
65 if awake_body_count == 0 {
66 world.broad_phase.validate_no_enlarged();
67 return;
68 }
69
70 let mut bullet_bodies: Vec<i32> = Vec::with_capacity(awake_body_count);
72
73 world.body_move_events.resize(
75 awake_body_count,
76 BodyMoveEvent {
77 user_data: 0,
78 transform: make_world_transform(TRANSFORM_IDENTITY),
79 body_id: BodyId::default(),
80 fell_asleep: false,
81 },
82 );
83
84 let joint_id_capacity = world.joint_id_pool.id_capacity();
87 let contact_id_capacity = world.contact_id_pool.id_capacity();
88 {
89 let task_context = &mut world.task_contexts[0];
90 task_context
91 .joint_state_bit_set
92 .set_bit_count_and_clear(joint_id_capacity as u32);
93 task_context
94 .hit_event_bit_set
95 .set_bit_count_and_clear(contact_id_capacity as u32);
96 task_context.has_hit_events = false;
97 }
98
99 if world.split_island_id != NULL_INDEX {
103 let split_id = world.split_island_id;
104 crate::island::split_island(world, split_id);
105 world.split_island_id = NULL_INDEX;
106 }
107
108 for color_index in 0..OVERFLOW_INDEX {
111 prepare_color_joints(world, color_index, context);
112 }
113
114 let mut color_constraints: Vec<Vec<ContactConstraint>> =
116 (0..GRAPH_COLOR_COUNT).map(|_| Vec::new()).collect();
117 for color_index in 0..GRAPH_COLOR_COUNT as usize {
118 let count = world.constraint_graph.colors[color_index]
121 .contact_sims
122 .len();
123 color_constraints[color_index].resize(count, ContactConstraint::default());
124 }
125 for color_index in 0..OVERFLOW_INDEX as usize {
126 let contacts = &world.constraint_graph.colors[color_index].contact_sims;
127 let states = &world.solver_sets[AWAKE_SET as usize].body_states;
128 prepare_contacts(
129 &mut color_constraints[color_index],
130 contacts,
131 states,
132 context,
133 );
134 }
135
136 prepare_color_joints(world, OVERFLOW_INDEX, context);
139 {
140 let contacts = &world.constraint_graph.colors[OVERFLOW_INDEX as usize].contact_sims;
141 let states = &world.solver_sets[AWAKE_SET as usize].body_states;
142 prepare_contacts(
143 &mut color_constraints[OVERFLOW_INDEX as usize],
144 contacts,
145 states,
146 context,
147 );
148 }
149
150 let sub_step_count = context.sub_step_count;
152 for _sub_step_index in 0..sub_step_count {
153 integrate_velocities(world, context);
155
156 {
160 let world_parts = &mut *world;
161 let graph = &mut world_parts.constraint_graph;
162 let states = &mut world_parts.solver_sets[AWAKE_SET as usize].body_states;
163
164 for joint in graph.colors[OVERFLOW_INDEX as usize].joint_sims.iter_mut() {
165 warm_start_joint(joint, states);
166 }
167 warm_start_contacts(&mut color_constraints[OVERFLOW_INDEX as usize], states);
168
169 for color_index in 0..OVERFLOW_INDEX as usize {
170 for joint in graph.colors[color_index].joint_sims.iter_mut() {
171 warm_start_joint(joint, states);
172 }
173 warm_start_contacts(&mut color_constraints[color_index], states);
174 }
175 }
176
177 for _ in 0..ITERATIONS {
179 let use_bias = true;
180 let world_parts = &mut *world;
181 let graph = &mut world_parts.constraint_graph;
182 let states = &mut world_parts.solver_sets[AWAKE_SET as usize].body_states;
183 let joint_state_bit_set = &mut world_parts.task_contexts[0].joint_state_bit_set;
184
185 for joint in graph.colors[OVERFLOW_INDEX as usize].joint_sims.iter_mut() {
189 solve_joint(joint, context, states, use_bias);
190 }
191 solve_contacts(
192 &mut color_constraints[OVERFLOW_INDEX as usize],
193 states,
194 context,
195 use_bias,
196 );
197
198 for color_index in 0..OVERFLOW_INDEX as usize {
199 for joint in graph.colors[color_index].joint_sims.iter_mut() {
200 solve_joint(joint, context, states, use_bias);
201
202 if (joint.force_threshold < f32::MAX || joint.torque_threshold < f32::MAX)
203 && !joint_state_bit_set.get_bit(joint.joint_id as u32)
204 {
205 let (force, torque) = get_joint_reaction(joint, context.inv_h);
206
207 if force >= joint.force_threshold || torque >= joint.torque_threshold {
210 joint_state_bit_set.set_bit(joint.joint_id as u32);
212 }
213 }
214 }
215 solve_contacts(
216 &mut color_constraints[color_index],
217 states,
218 context,
219 use_bias,
220 );
221 }
222 }
223
224 integrate_positions(world, context);
226
227 for _ in 0..RELAX_ITERATIONS {
229 let use_bias = false;
230 let world_parts = &mut *world;
231 let graph = &mut world_parts.constraint_graph;
232 let states = &mut world_parts.solver_sets[AWAKE_SET as usize].body_states;
233
234 for joint in graph.colors[OVERFLOW_INDEX as usize].joint_sims.iter_mut() {
235 solve_joint(joint, context, states, use_bias);
236 }
237 solve_contacts(
238 &mut color_constraints[OVERFLOW_INDEX as usize],
239 states,
240 context,
241 use_bias,
242 );
243
244 for color_index in 0..OVERFLOW_INDEX as usize {
245 for joint in graph.colors[color_index].joint_sims.iter_mut() {
246 solve_joint(joint, context, states, use_bias);
247 }
248 solve_contacts(
249 &mut color_constraints[color_index],
250 states,
251 context,
252 use_bias,
253 );
254 }
255 }
256 }
257
258 {
260 let world_parts = &mut *world;
261 let states = &mut world_parts.solver_sets[AWAKE_SET as usize].body_states;
262
263 apply_restitution(
264 &mut color_constraints[OVERFLOW_INDEX as usize],
265 states,
266 context,
267 );
268 for color_index in 0..OVERFLOW_INDEX as usize {
269 apply_restitution(&mut color_constraints[color_index], states, context);
270 }
271 }
272
273 {
277 let world_parts = &mut *world;
278 let graph = &mut world_parts.constraint_graph;
279 let task_context = &mut world_parts.task_contexts[0];
280 let neg_hit_threshold = -world_parts.hit_event_threshold;
281
282 store_impulses(
283 &color_constraints[OVERFLOW_INDEX as usize],
284 &mut graph.colors[OVERFLOW_INDEX as usize].contact_sims,
285 );
286
287 for color_index in 0..OVERFLOW_INDEX as usize {
288 store_impulses(
289 &color_constraints[color_index],
290 &mut graph.colors[color_index].contact_sims,
291 );
292
293 for contact_sim in &graph.colors[color_index].contact_sims {
296 if contact_sim.sim_flags & contact_flags::SIM_ENABLE_HIT_EVENT != 0 {
297 for k in 0..contact_sim.manifold.point_count as usize {
298 let mp = &contact_sim.manifold.points[k];
299
300 if mp.normal_velocity < neg_hit_threshold && mp.total_normal_impulse > 0.0 {
303 task_context
304 .hit_event_bit_set
305 .set_bit(contact_sim.contact_id as u32);
306 task_context.has_hit_events = true;
307 break;
308 }
309 }
310 }
311 }
312 }
313 }
314
315 {
319 let awake_island_count = world.solver_sets[AWAKE_SET as usize].island_sims.len();
320 let task_context = &mut world.task_contexts[0];
321 task_context.sensor_hits.clear();
322 task_context
323 .enlarged_sim_bit_set
324 .set_bit_count_and_clear(awake_body_count as u32);
325 task_context
326 .awake_island_bit_set
327 .set_bit_count_and_clear(awake_island_count as u32);
328 task_context.split_island_id = NULL_INDEX;
329 task_context.split_sleep_time = 0.0;
330 }
331
332 finalize_bodies(world, context, &mut bullet_bodies);
335
336 {
338 let world_id = world.world_id;
339 let word_count = world.task_contexts[0].joint_state_bit_set.block_count();
340 for k in 0..word_count {
341 let mut word = world.task_contexts[0].joint_state_bit_set.block(k);
342 while word != 0 {
343 let ctz = word.trailing_zeros();
344 let joint_id = (64 * k + ctz) as i32;
345
346 let joint = &world.joints[joint_id as usize];
347 debug_assert!(joint.set_index == AWAKE_SET);
348
349 let event = JointEvent {
350 joint_id: JointId {
351 index1: joint_id + 1,
352 world0: world_id,
353 generation: joint.generation,
354 },
355 user_data: joint.user_data,
356 };
357
358 world.joint_events.push(event);
359
360 word &= word - 1;
362 }
363 }
364 }
365
366 {
368 debug_assert!(world.contact_hit_events.is_empty());
369
370 if world.task_contexts[0].has_hit_events {
371 let threshold = world.hit_event_threshold;
372 let world_id = world.world_id;
373
374 let word_count = world.task_contexts[0].hit_event_bit_set.block_count();
375 for k in 0..word_count {
376 let mut word = world.task_contexts[0].hit_event_bit_set.block(k);
377 while word != 0 {
378 let ctz = word.trailing_zeros();
379 let contact_id = (64 * k + ctz) as i32;
380
381 let contact = world.contacts[contact_id as usize];
382 debug_assert!(
383 contact.set_index == AWAKE_SET && contact.color_index != NULL_INDEX
384 );
385
386 let contact_sim = &world.constraint_graph.colors[contact.color_index as usize]
387 .contact_sims[contact.local_index as usize];
388
389 let mut approach_speed = threshold;
390 let mut best_point: Option<usize> = None;
391 for p in 0..contact_sim.manifold.point_count as usize {
392 let mp = &contact_sim.manifold.points[p];
393 let point_approach_speed = -mp.normal_velocity;
394
395 if point_approach_speed > approach_speed && mp.total_normal_impulse > 0.0 {
398 approach_speed = point_approach_speed;
399 best_point = Some(p);
400 }
401 }
402
403 if let Some(p) = best_point {
404 let best = contact_sim.manifold.points[p];
405 let normal = contact_sim.manifold.normal;
406
407 let shape_a = &world.shapes[contact_sim.shape_id_a as usize];
408 let shape_b = &world.shapes[contact_sim.shape_id_b as usize];
409
410 let body_a = &world.bodies[shape_a.body_id as usize];
417 let body_b = &world.bodies[shape_b.body_id as usize];
418 let point = if body_a.type_ != BodyType::Static
419 && body_b.type_ == BodyType::Static
420 {
421 let body_sim_b = &world.solver_sets[body_b.set_index as usize]
422 .body_sims[body_b.local_index as usize];
423 offset_pos(body_sim_b.center, best.anchor_b)
424 } else {
425 let body_sim_a = &world.solver_sets[body_a.set_index as usize]
426 .body_sims[body_a.local_index as usize];
427 offset_pos(body_sim_a.center, best.anchor_a)
428 };
429
430 let event = ContactHitEvent {
431 shape_id_a: ShapeId {
432 index1: shape_a.id + 1,
433 world0: world_id,
434 generation: shape_a.generation,
435 },
436 shape_id_b: ShapeId {
437 index1: shape_b.id + 1,
438 world0: world_id,
439 generation: shape_b.generation,
440 },
441 contact_id: ContactId {
442 index1: contact.contact_id + 1,
443 world0: world_id,
444 padding: 0,
445 generation: contact.generation,
446 },
447 point,
448 normal,
449 approach_speed,
450 };
451
452 world.contact_hit_events.push(event);
453 }
454
455 word &= word - 1;
457 }
458 }
459 }
460 }
461
462 {
464 world.broad_phase.validate_no_enlarged();
465
466 let word_count = world.task_contexts[0].enlarged_sim_bit_set.block_count();
472 for k in 0..word_count {
473 let mut word = world.task_contexts[0].enlarged_sim_bit_set.block(k);
474 while word != 0 {
475 let ctz = word.trailing_zeros();
476 let body_sim_index = (64 * k + ctz) as usize;
477
478 let (body_id, sim_flags) = {
479 let body_sim = &world.solver_sets[AWAKE_SET as usize].body_sims[body_sim_index];
480 (body_sim.body_id, body_sim.flags)
481 };
482
483 let mut shape_id = world.bodies[body_id as usize].head_shape_id;
484 if sim_flags
485 & (crate::body::body_flags::IS_BULLET | crate::body::body_flags::IS_FAST)
486 == (crate::body::body_flags::IS_BULLET | crate::body::body_flags::IS_FAST)
487 {
488 while shape_id != NULL_INDEX {
490 let proxy_key = world.shapes[shape_id as usize].proxy_key;
491
492 world.broad_phase.buffer_move(proxy_key);
497
498 shape_id = world.shapes[shape_id as usize].next_shape_id;
499 }
500 } else {
501 while shape_id != NULL_INDEX {
502 if world.shapes[shape_id as usize].enlarged_aabb {
508 let proxy_key = world.shapes[shape_id as usize].proxy_key;
509 let fat_aabb = world.shapes[shape_id as usize].fat_aabb;
510 world.broad_phase.enlarge_proxy(proxy_key, fat_aabb);
511 world.shapes[shape_id as usize].enlarged_aabb = false;
512 }
513
514 shape_id = world.shapes[shape_id as usize].next_shape_id;
515 }
516 }
517
518 word &= word - 1;
520 }
521 }
522
523 world.broad_phase.validate();
524 }
525
526 if !bullet_bodies.is_empty() {
528 for &sim_index in &bullet_bodies {
531 super::continuous::solve_continuous(world, sim_index);
532 }
533
534 for &sim_index in &bullet_bodies {
538 let (body_id, enlarge) = {
539 let bullet_body_sim =
540 &world.solver_sets[AWAKE_SET as usize].body_sims[sim_index as usize];
541 (
542 bullet_body_sim.body_id,
543 bullet_body_sim.flags & crate::body::body_flags::ENLARGE_BOUNDS != 0,
544 )
545 };
546 if !enlarge {
547 continue;
548 }
549
550 world.solver_sets[AWAKE_SET as usize].body_sims[sim_index as usize].flags &=
552 !crate::body::body_flags::ENLARGE_BOUNDS;
553
554 let mut shape_id = world.bodies[body_id as usize].head_shape_id;
555 while shape_id != NULL_INDEX {
556 if !world.shapes[shape_id as usize].enlarged_aabb {
557 shape_id = world.shapes[shape_id as usize].next_shape_id;
558 continue;
559 }
560
561 world.shapes[shape_id as usize].enlarged_aabb = false;
563
564 let proxy_key = world.shapes[shape_id as usize].proxy_key;
565 let proxy_id = crate::broad_phase::proxy_id(proxy_key);
566 debug_assert!(crate::broad_phase::proxy_type(proxy_key) == BodyType::Dynamic);
567
568 debug_assert!(world.broad_phase.moved_proxies[BodyType::Dynamic as usize]
570 .get_bit(proxy_id as u32));
571
572 let fat_aabb = world.shapes[shape_id as usize].fat_aabb;
573 world.broad_phase.trees[BodyType::Dynamic as usize]
574 .enlarge_proxy(proxy_id, fat_aabb);
575
576 shape_id = world.shapes[shape_id as usize].next_shape_id;
577 }
578 }
579 }
580
581 {
584 let hits = std::mem::take(&mut world.task_contexts[0].sensor_hits);
585 for hit in hits {
586 let sensor_index = world.shapes[hit.sensor_id as usize].sensor_index;
587 let generation = world.shapes[hit.visitor_id as usize].generation;
588
589 let shape_ref = crate::sensor::Visitor {
590 shape_id: hit.visitor_id,
591 generation,
592 };
593 world.sensors[sensor_index as usize].hits.push(shape_ref);
594 }
595 }
596
597 if world.enable_sleep {
601 debug_assert!(world.split_island_id == NULL_INDEX);
604 {
605 let task_context = &world.task_contexts[0];
606 if task_context.split_island_id != NULL_INDEX && task_context.split_sleep_time >= 0.0 {
607 debug_assert!(task_context.split_sleep_time > 0.0);
608 world.split_island_id = task_context.split_island_id;
609 }
610 }
611
612 let count = world.solver_sets[AWAKE_SET as usize].island_sims.len();
615 for island_index in (0..count).rev() {
616 if world.task_contexts[0]
617 .awake_island_bit_set
618 .get_bit(island_index as u32)
619 {
620 continue;
622 }
623
624 let island_id =
625 world.solver_sets[AWAKE_SET as usize].island_sims[island_index].island_id;
626
627 crate::solver_set::try_sleep_island(world, island_id);
628 }
629
630 world.validate_solver_sets();
631 }
632}