1use crate::body::{body_flags, remove_body_sim, BodySim, BodyState, IDENTITY_BODY_STATE};
7use crate::constants::GRAPH_COLOR_COUNT;
8use crate::constraint_graph::{
9 add_contact_to_graph, add_joint_to_graph, remove_joint_from_graph, OVERFLOW_INDEX,
10};
11use crate::contact::{contact_flags, ContactSim};
12use crate::core::NULL_INDEX;
13use crate::island::IslandSim;
14use crate::joint::JointSim;
15use crate::world::World;
16
17pub const STATIC_SET: i32 = 0;
21pub const DISABLED_SET: i32 = 1;
23pub const AWAKE_SET: i32 = 2;
26pub const FIRST_SLEEPING_SET: i32 = 3;
30
31#[derive(Debug, Clone, Default)]
40pub struct SolverSet {
41 pub body_sims: Vec<BodySim>,
43
44 pub body_states: Vec<BodyState>,
46
47 pub joint_sims: Vec<JointSim>,
49
50 pub contact_sims: Vec<ContactSim>,
53
54 pub island_sims: Vec<IslandSim>,
59
60 pub set_index: i32,
63}
64
65pub fn destroy_solver_set(world: &mut World, set_index: i32) {
67 let set = &mut world.solver_sets[set_index as usize];
68 *set = SolverSet::default();
69 set.set_index = NULL_INDEX;
70 world.solver_set_id_pool.free_id(set_index);
71}
72
73pub fn wake_solver_set(world: &mut World, set_index: i32) {
82 debug_assert!(set_index >= FIRST_SLEEPING_SET);
83
84 let body_count = world.solver_sets[set_index as usize].body_sims.len();
85 for i in 0..body_count {
86 let sim_src = world.solver_sets[set_index as usize].body_sims[i];
87 let body_id = sim_src.body_id;
88
89 debug_assert!(world.bodies[body_id as usize].set_index == set_index);
90 let awake_body_count = world.solver_sets[AWAKE_SET as usize].body_sims.len() as i32;
91 let flags = {
92 let body = &mut world.bodies[body_id as usize];
93 body.set_index = AWAKE_SET;
94 body.local_index = awake_body_count;
95
96 body.sleep_time = 0.0;
98 body.flags
99 };
100
101 world.solver_sets[AWAKE_SET as usize]
102 .body_sims
103 .push(sim_src);
104
105 let mut state = IDENTITY_BODY_STATE;
106 state.flags = flags;
107 world.solver_sets[AWAKE_SET as usize]
108 .body_states
109 .push(state);
110
111 let mut contact_key = world.bodies[body_id as usize].head_contact_key;
113 while contact_key != NULL_INDEX {
114 let edge_index = contact_key & 1;
115 let contact_id = contact_key >> 1;
116
117 contact_key = world.contacts[contact_id as usize].edges[edge_index as usize].next_key;
118
119 if world.contacts[contact_id as usize].set_index != DISABLED_SET {
120 debug_assert!(
121 world.contacts[contact_id as usize].set_index == AWAKE_SET
122 || world.contacts[contact_id as usize].set_index == set_index
123 );
124 continue;
125 }
126
127 let local_index = world.contacts[contact_id as usize].local_index;
128 let contact_sim =
129 world.solver_sets[DISABLED_SET as usize].contact_sims[local_index as usize];
130
131 debug_assert!(
132 (world.contacts[contact_id as usize].flags & contact_flags::TOUCHING) == 0
133 && contact_sim.manifold.point_count == 0
134 );
135
136 let awake_contact_count =
137 world.solver_sets[AWAKE_SET as usize].contact_sims.len() as i32;
138 {
139 let contact = &mut world.contacts[contact_id as usize];
140 contact.set_index = AWAKE_SET;
141 contact.local_index = awake_contact_count;
142 }
143 world.solver_sets[AWAKE_SET as usize]
144 .contact_sims
145 .push(contact_sim);
146
147 let moved_index =
148 world.solver_sets[DISABLED_SET as usize].contact_sims.len() as i32 - 1;
149 world.solver_sets[DISABLED_SET as usize]
150 .contact_sims
151 .swap_remove(local_index as usize);
152 if moved_index != local_index {
153 let moved_id = world.solver_sets[DISABLED_SET as usize].contact_sims
155 [local_index as usize]
156 .contact_id;
157 let moved_contact = &mut world.contacts[moved_id as usize];
158 debug_assert!(moved_contact.local_index == moved_index);
159 moved_contact.local_index = local_index;
160 }
161 }
162 }
163
164 {
166 let contact_count = world.solver_sets[set_index as usize].contact_sims.len();
167 for i in 0..contact_count {
168 let contact_sim = world.solver_sets[set_index as usize].contact_sims[i];
169 let contact_id = contact_sim.contact_id;
170 debug_assert!(world.contacts[contact_id as usize].flags & contact_flags::TOUCHING != 0);
171 debug_assert!(contact_sim.sim_flags & contact_flags::SIM_TOUCHING != 0);
172 debug_assert!(contact_sim.manifold.point_count > 0);
173 debug_assert!(world.contacts[contact_id as usize].set_index == set_index);
174 world.contacts[contact_id as usize].set_index = AWAKE_SET;
175 add_contact_to_graph(world, contact_sim, contact_id);
176 }
177 }
178
179 {
181 let joint_count = world.solver_sets[set_index as usize].joint_sims.len();
182 for i in 0..joint_count {
183 let joint_sim = world.solver_sets[set_index as usize].joint_sims[i];
184 let joint_id = joint_sim.joint_id;
185 debug_assert!(world.joints[joint_id as usize].set_index == set_index);
186 add_joint_to_graph(world, joint_sim, joint_id);
187 world.joints[joint_id as usize].set_index = AWAKE_SET;
188 }
189 }
190
191 {
196 let island_count = world.solver_sets[set_index as usize].island_sims.len();
197 for i in 0..island_count {
198 let island_src = world.solver_sets[set_index as usize].island_sims[i];
199 let awake_island_count = world.solver_sets[AWAKE_SET as usize].island_sims.len() as i32;
200 {
201 let island = &mut world.islands[island_src.island_id as usize];
202 island.set_index = AWAKE_SET;
203 island.local_index = awake_island_count;
204 }
205 world.solver_sets[AWAKE_SET as usize]
206 .island_sims
207 .push(island_src);
208 }
209 }
210
211 destroy_solver_set(world, set_index);
213}
214
215pub fn try_sleep_island(world: &mut World, island_id: i32) {
219 debug_assert!(world.islands[island_id as usize].set_index == AWAKE_SET);
220
221 if world.islands[island_id as usize].constraint_remove_count > 0
224 && world.islands[island_id as usize].bodies.len() > 1
225 {
226 return;
227 }
228
229 let sleep_set_id = world.solver_set_id_pool.alloc_id();
237 if sleep_set_id == world.solver_sets.len() as i32 {
238 let set = SolverSet {
239 set_index: NULL_INDEX,
240 ..SolverSet::default()
241 };
242 world.solver_sets.push(set);
243 }
244
245 {
246 let (body_cap, contact_cap, joint_cap) = {
247 let island = &world.islands[island_id as usize];
248 (
249 island.bodies.len(),
250 island.contacts.len(),
251 island.joints.len(),
252 )
253 };
254 let sleep_set = &mut world.solver_sets[sleep_set_id as usize];
255 *sleep_set = SolverSet::default();
256 sleep_set.set_index = sleep_set_id;
257 sleep_set.body_sims.reserve(body_cap);
258 sleep_set.contact_sims.reserve(contact_cap);
259 sleep_set.joint_sims.reserve(joint_cap);
260 }
261
262 debug_assert!({
263 let local = world.islands[island_id as usize].local_index;
264 0 <= local && local < world.solver_sets[AWAKE_SET as usize].island_sims.len() as i32
265 });
266
267 {
270 let island_body_count = world.islands[island_id as usize].bodies.len();
271 for i in 0..island_body_count {
272 let body_id = world.islands[island_id as usize].bodies[i];
273 debug_assert!(world.bodies[body_id as usize].set_index == AWAKE_SET);
274 debug_assert!(world.bodies[body_id as usize].island_id == island_id);
275 debug_assert!(world.bodies[body_id as usize].island_index == i as i32);
276
277 let body_move_index = world.bodies[body_id as usize].body_move_index;
280 if body_move_index != NULL_INDEX {
281 let move_event = &mut world.body_move_events[body_move_index as usize];
282 debug_assert!(move_event.body_id.index1 - 1 == body_id);
283 debug_assert!(
284 move_event.body_id.generation == world.bodies[body_id as usize].generation
285 );
286 move_event.fell_asleep = true;
287 world.bodies[body_id as usize].body_move_index = NULL_INDEX;
288 }
289
290 let awake_body_index = world.bodies[body_id as usize].local_index;
291 let awake_sim =
292 world.solver_sets[AWAKE_SET as usize].body_sims[awake_body_index as usize];
293
294 let sleep_body_index = world.solver_sets[sleep_set_id as usize].body_sims.len() as i32;
296 world.solver_sets[sleep_set_id as usize]
297 .body_sims
298 .push(awake_sim);
299
300 remove_body_sim(
301 &mut world.solver_sets[AWAKE_SET as usize].body_sims,
302 &mut world.bodies,
303 awake_body_index,
304 );
305
306 world.solver_sets[AWAKE_SET as usize]
308 .body_states
309 .swap_remove(awake_body_index as usize);
310
311 {
312 let body = &mut world.bodies[body_id as usize];
313 body.set_index = sleep_set_id;
314 body.local_index = sleep_body_index;
315 }
316
317 let mut contact_key = world.bodies[body_id as usize].head_contact_key;
321 while contact_key != NULL_INDEX {
322 let contact_id = contact_key >> 1;
323 let edge_index = contact_key & 1;
324
325 debug_assert!(
326 world.contacts[contact_id as usize].set_index == AWAKE_SET
327 || world.contacts[contact_id as usize].set_index == DISABLED_SET
328 );
329 contact_key =
330 world.contacts[contact_id as usize].edges[edge_index as usize].next_key;
331
332 if world.contacts[contact_id as usize].set_index == DISABLED_SET {
333 continue;
335 }
336
337 if world.contacts[contact_id as usize].color_index != NULL_INDEX {
338 debug_assert!(
340 world.contacts[contact_id as usize].flags & contact_flags::TOUCHING != 0
341 );
342 continue;
343 }
344
345 let other_edge_index = edge_index ^ 1;
349 let other_body_id =
350 world.contacts[contact_id as usize].edges[other_edge_index as usize].body_id;
351 if world.bodies[other_body_id as usize].set_index == AWAKE_SET {
352 continue;
353 }
354
355 let local_index = world.contacts[contact_id as usize].local_index;
356 let contact_sim =
357 world.solver_sets[AWAKE_SET as usize].contact_sims[local_index as usize];
358
359 debug_assert!(contact_sim.manifold.point_count == 0);
360 debug_assert!(
361 world.contacts[contact_id as usize].flags & contact_flags::TOUCHING == 0
362 );
363
364 let disabled_count =
366 world.solver_sets[DISABLED_SET as usize].contact_sims.len() as i32;
367 {
368 let contact = &mut world.contacts[contact_id as usize];
369 contact.set_index = DISABLED_SET;
370 contact.local_index = disabled_count;
371 }
372 world.solver_sets[DISABLED_SET as usize]
373 .contact_sims
374 .push(contact_sim);
375
376 let moved_index =
377 world.solver_sets[AWAKE_SET as usize].contact_sims.len() as i32 - 1;
378 world.solver_sets[AWAKE_SET as usize]
379 .contact_sims
380 .swap_remove(local_index as usize);
381 if moved_index != local_index {
382 let moved_id = world.solver_sets[AWAKE_SET as usize].contact_sims
384 [local_index as usize]
385 .contact_id;
386 let moved_contact = &mut world.contacts[moved_id as usize];
387 debug_assert!(moved_contact.local_index == moved_index);
388 moved_contact.local_index = local_index;
389 }
390 }
391 }
392 }
393
394 {
397 let island_contact_count = world.islands[island_id as usize].contacts.len();
398 for i in 0..island_contact_count {
399 let contact_id = world.islands[island_id as usize].contacts[i].contact_id;
400 let (color_index, local_index, body_id_a, body_id_b) = {
401 let contact = &world.contacts[contact_id as usize];
402 debug_assert!(contact.set_index == AWAKE_SET);
403 debug_assert!(contact.island_id == island_id);
404 (
405 contact.color_index,
406 contact.local_index,
407 contact.edges[0].body_id,
408 contact.edges[1].body_id,
409 )
410 };
411 debug_assert!((0..GRAPH_COLOR_COUNT).contains(&color_index));
412
413 if color_index != OVERFLOW_INDEX {
415 let color = &mut world.constraint_graph.colors[color_index as usize];
417 color.body_set.clear_bit(body_id_a as u32);
418 color.body_set.clear_bit(body_id_b as u32);
419 }
420
421 let awake_contact_sim = world.constraint_graph.colors[color_index as usize]
422 .contact_sims[local_index as usize];
423
424 let sleep_contact_index =
425 world.solver_sets[sleep_set_id as usize].contact_sims.len() as i32;
426 world.solver_sets[sleep_set_id as usize]
427 .contact_sims
428 .push(awake_contact_sim);
429
430 let moved_index = world.constraint_graph.colors[color_index as usize]
431 .contact_sims
432 .len() as i32
433 - 1;
434 world.constraint_graph.colors[color_index as usize]
435 .contact_sims
436 .swap_remove(local_index as usize);
437 if moved_index != local_index {
438 let moved_id = world.constraint_graph.colors[color_index as usize].contact_sims
440 [local_index as usize]
441 .contact_id;
442 let moved_contact = &mut world.contacts[moved_id as usize];
443 debug_assert!(moved_contact.local_index == moved_index);
444 moved_contact.local_index = local_index;
445 }
446
447 let contact = &mut world.contacts[contact_id as usize];
448 contact.set_index = sleep_set_id;
449 contact.color_index = NULL_INDEX;
450 contact.local_index = sleep_contact_index;
451 }
452 }
453
454 {
457 let island_joint_count = world.islands[island_id as usize].joints.len();
458 for i in 0..island_joint_count {
459 let joint_id = world.islands[island_id as usize].joints[i].joint_id;
460 let (color_index, local_index, body_id_a, body_id_b) = {
461 let joint = &world.joints[joint_id as usize];
462 debug_assert!(joint.set_index == AWAKE_SET);
463 debug_assert!(joint.island_id == island_id);
464 (
465 joint.color_index,
466 joint.local_index,
467 joint.edges[0].body_id,
468 joint.edges[1].body_id,
469 )
470 };
471 debug_assert!((0..GRAPH_COLOR_COUNT).contains(&color_index));
472
473 if color_index != OVERFLOW_INDEX {
474 let color = &mut world.constraint_graph.colors[color_index as usize];
476 color.body_set.clear_bit(body_id_a as u32);
477 color.body_set.clear_bit(body_id_b as u32);
478 }
479
480 let awake_joint_sim = world.constraint_graph.colors[color_index as usize].joint_sims
481 [local_index as usize];
482
483 let sleep_joint_index =
484 world.solver_sets[sleep_set_id as usize].joint_sims.len() as i32;
485 world.solver_sets[sleep_set_id as usize]
486 .joint_sims
487 .push(awake_joint_sim);
488
489 let moved_index = world.constraint_graph.colors[color_index as usize]
490 .joint_sims
491 .len() as i32
492 - 1;
493 world.constraint_graph.colors[color_index as usize]
494 .joint_sims
495 .swap_remove(local_index as usize);
496 if moved_index != local_index {
497 let moved_id = world.constraint_graph.colors[color_index as usize].joint_sims
499 [local_index as usize]
500 .joint_id;
501 let moved_joint = &mut world.joints[moved_id as usize];
502 debug_assert!(moved_joint.local_index == moved_index);
503 moved_joint.local_index = local_index;
504 }
505
506 let joint = &mut world.joints[joint_id as usize];
507 joint.set_index = sleep_set_id;
508 joint.color_index = NULL_INDEX;
509 joint.local_index = sleep_joint_index;
510 }
511 }
512
513 {
515 debug_assert!(world.islands[island_id as usize].set_index == AWAKE_SET);
516
517 let island_index = world.islands[island_id as usize].local_index;
518 world.solver_sets[sleep_set_id as usize]
519 .island_sims
520 .push(IslandSim { island_id });
521
522 let moved_island_index = world.solver_sets[AWAKE_SET as usize].island_sims.len() as i32 - 1;
523 world.solver_sets[AWAKE_SET as usize]
524 .island_sims
525 .swap_remove(island_index as usize);
526 if moved_island_index != island_index {
527 let moved_island_id =
529 world.solver_sets[AWAKE_SET as usize].island_sims[island_index as usize].island_id;
530 let moved_island = &mut world.islands[moved_island_id as usize];
531 debug_assert!(moved_island.local_index == moved_island_index);
532 moved_island.local_index = island_index;
533 }
534
535 let island = &mut world.islands[island_id as usize];
536 island.set_index = sleep_set_id;
537 island.local_index = 0;
538 }
539
540 if world.split_island_id == island_id {
541 world.split_island_id = NULL_INDEX;
542 }
543
544 world.validate_solver_sets();
545}
546
547pub fn merge_solver_sets(world: &mut World, set_id1: i32, set_id2: i32) {
552 debug_assert!(set_id1 >= FIRST_SLEEPING_SET);
553 debug_assert!(set_id2 >= FIRST_SLEEPING_SET);
554
555 let (set_id1, set_id2) = {
557 let count1 = world.solver_sets[set_id1 as usize].body_sims.len();
558 let count2 = world.solver_sets[set_id2 as usize].body_sims.len();
559 if count1 < count2 {
560 (set_id2, set_id1)
561 } else {
562 (set_id1, set_id2)
563 }
564 };
565
566 {
568 let body_count = world.solver_sets[set_id2 as usize].body_sims.len();
569 for i in 0..body_count {
570 let sim_src = world.solver_sets[set_id2 as usize].body_sims[i];
571 let target_count = world.solver_sets[set_id1 as usize].body_sims.len() as i32;
572 {
573 let body = &mut world.bodies[sim_src.body_id as usize];
574 debug_assert!(body.set_index == set_id2);
575 body.set_index = set_id1;
576 body.local_index = target_count;
577 }
578 world.solver_sets[set_id1 as usize].body_sims.push(sim_src);
579 }
580 }
581
582 {
584 let contact_count = world.solver_sets[set_id2 as usize].contact_sims.len();
585 for i in 0..contact_count {
586 let contact_src = world.solver_sets[set_id2 as usize].contact_sims[i];
587 let target_count = world.solver_sets[set_id1 as usize].contact_sims.len() as i32;
588 {
589 let contact = &mut world.contacts[contact_src.contact_id as usize];
590 debug_assert!(contact.set_index == set_id2);
591 contact.set_index = set_id1;
592 contact.local_index = target_count;
593 }
594 world.solver_sets[set_id1 as usize]
595 .contact_sims
596 .push(contact_src);
597 }
598 }
599
600 {
602 let joint_count = world.solver_sets[set_id2 as usize].joint_sims.len();
603 for i in 0..joint_count {
604 let joint_src = world.solver_sets[set_id2 as usize].joint_sims[i];
605 let target_count = world.solver_sets[set_id1 as usize].joint_sims.len() as i32;
606 {
607 let joint = &mut world.joints[joint_src.joint_id as usize];
608 debug_assert!(joint.set_index == set_id2);
609 joint.set_index = set_id1;
610 joint.local_index = target_count;
611 }
612 world.solver_sets[set_id1 as usize]
613 .joint_sims
614 .push(joint_src);
615 }
616 }
617
618 {
620 let island_count = world.solver_sets[set_id2 as usize].island_sims.len();
621 for i in 0..island_count {
622 let island_src = world.solver_sets[set_id2 as usize].island_sims[i];
623 let target_count = world.solver_sets[set_id1 as usize].island_sims.len() as i32;
624 {
625 let island = &mut world.islands[island_src.island_id as usize];
626 island.set_index = set_id1;
627 island.local_index = target_count;
628 }
629 world.solver_sets[set_id1 as usize]
630 .island_sims
631 .push(island_src);
632 }
633 }
634
635 destroy_solver_set(world, set_id2);
637
638 world.validate_solver_sets();
639}
640
641pub fn transfer_body(
645 world: &mut World,
646 target_set_index: i32,
647 source_set_index: i32,
648 body_id: i32,
649) {
650 if target_set_index == source_set_index {
651 return;
652 }
653
654 let source_index = world.bodies[body_id as usize].local_index;
655 let mut sim = world.solver_sets[source_set_index as usize].body_sims[source_index as usize];
656
657 let target_index = world.solver_sets[target_set_index as usize].body_sims.len() as i32;
658
659 sim.flags &=
661 !(body_flags::IS_FAST | body_flags::IS_SPEED_CAPPED | body_flags::HAD_TIME_OF_IMPACT);
662 world.solver_sets[target_set_index as usize]
663 .body_sims
664 .push(sim);
665
666 remove_body_sim(
668 &mut world.solver_sets[source_set_index as usize].body_sims,
669 &mut world.bodies,
670 source_index,
671 );
672
673 if source_set_index == AWAKE_SET {
674 world.solver_sets[AWAKE_SET as usize]
675 .body_states
676 .swap_remove(source_index as usize);
677 } else if target_set_index == AWAKE_SET {
678 let mut state = IDENTITY_BODY_STATE;
679 state.flags = world.bodies[body_id as usize].flags;
680 world.solver_sets[AWAKE_SET as usize]
681 .body_states
682 .push(state);
683 }
684
685 let body = &mut world.bodies[body_id as usize];
686 body.set_index = target_set_index;
687 body.local_index = target_index;
688}
689
690pub fn transfer_joint(
694 world: &mut World,
695 target_set_index: i32,
696 source_set_index: i32,
697 joint_id: i32,
698) {
699 if target_set_index == source_set_index {
700 return;
701 }
702
703 let (local_index, color_index) = {
704 let joint = &world.joints[joint_id as usize];
705 (joint.local_index, joint.color_index)
706 };
707
708 let source_sim = if source_set_index == AWAKE_SET {
710 debug_assert!((0..GRAPH_COLOR_COUNT).contains(&color_index));
711 world.constraint_graph.colors[color_index as usize].joint_sims[local_index as usize]
712 } else {
713 debug_assert!(color_index == NULL_INDEX);
714 world.solver_sets[source_set_index as usize].joint_sims[local_index as usize]
715 };
716
717 if target_set_index == AWAKE_SET {
719 add_joint_to_graph(world, source_sim, joint_id);
720 world.joints[joint_id as usize].set_index = AWAKE_SET;
721 } else {
722 let target_local = world.solver_sets[target_set_index as usize]
723 .joint_sims
724 .len() as i32;
725 {
726 let joint = &mut world.joints[joint_id as usize];
727 joint.set_index = target_set_index;
728 joint.local_index = target_local;
729 joint.color_index = NULL_INDEX;
730 }
731 world.solver_sets[target_set_index as usize]
732 .joint_sims
733 .push(source_sim);
734 }
735
736 if source_set_index == AWAKE_SET {
738 let (body_id_a, body_id_b) = {
739 let joint = &world.joints[joint_id as usize];
740 (joint.edges[0].body_id, joint.edges[1].body_id)
741 };
742 remove_joint_from_graph(world, body_id_a, body_id_b, color_index, local_index);
743 } else {
744 let moved_index = world.solver_sets[source_set_index as usize]
745 .joint_sims
746 .len() as i32
747 - 1;
748 world.solver_sets[source_set_index as usize]
749 .joint_sims
750 .swap_remove(local_index as usize);
751 if moved_index != local_index {
752 let moved_id = world.solver_sets[source_set_index as usize].joint_sims
754 [local_index as usize]
755 .joint_id;
756 world.joints[moved_id as usize].local_index = local_index;
757 }
758 }
759}