box3d_rust/
constraint_graph.rs1use crate::bitset::BitSet;
14use crate::constants::GRAPH_COLOR_COUNT;
15use crate::contact::ContactSpec;
16use crate::joint::JointSim;
17use crate::math_functions::max_int;
18
19pub const OVERFLOW_INDEX: i32 = GRAPH_COLOR_COUNT - 1;
21
22pub const DYNAMIC_COLOR_COUNT: i32 = GRAPH_COLOR_COUNT - 4;
25
26#[derive(Debug, Clone, Default)]
28pub struct GraphColor {
29 pub body_set: BitSet,
32
33 pub joint_sims: Vec<JointSim>,
35
36 pub convex_contacts: Vec<i32>,
37 pub contacts: Vec<ContactSpec>,
38}
39
40#[derive(Debug, Clone, Default)]
42pub struct ConstraintGraph {
43 pub colors: Vec<GraphColor>,
45}
46
47impl ConstraintGraph {
48 pub fn new(body_capacity: i32) -> ConstraintGraph {
50 const _: () = assert!(GRAPH_COLOR_COUNT >= 2, "must have at least two colors");
51 const _: () = assert!(
52 OVERFLOW_INDEX == GRAPH_COLOR_COUNT - 1,
53 "bad overflow index"
54 );
55
56 let body_capacity = max_int(body_capacity, 8);
57
58 let mut colors = Vec::with_capacity(GRAPH_COLOR_COUNT as usize);
59 for i in 0..GRAPH_COLOR_COUNT {
61 let mut color = GraphColor::default();
62 if i < OVERFLOW_INDEX {
63 color.body_set = BitSet::new(body_capacity as u32);
64 color.body_set.set_bit_count_and_clear(body_capacity as u32);
65 }
66 colors.push(color);
67 }
68
69 ConstraintGraph { colors }
70 }
71}
72
73pub fn add_contact_to_graph(world: &mut crate::world::World, contact_id: i32) {
76 use crate::contact::contact_flags;
77 use crate::core::NULL_INDEX;
78 use crate::types::BodyType;
79
80 let contact = &world.contacts[contact_id as usize];
81 debug_assert!(contact.manifold_count() > 0);
82 debug_assert!((contact.flags & contact_flags::TOUCHING) != 0);
83
84 let body_id_a = contact.edges[0].body_id;
85 let body_id_b = contact.edges[1].body_id;
86 let type_a = world.bodies[body_id_a as usize].type_;
87 let type_b = world.bodies[body_id_b as usize].type_;
88 debug_assert!(type_a == BodyType::Dynamic || type_b == BodyType::Dynamic);
89
90 let mut color_index = OVERFLOW_INDEX;
91
92 if type_a == BodyType::Dynamic && type_b == BodyType::Dynamic {
93 for i in 0..DYNAMIC_COLOR_COUNT {
94 let color = &world.constraint_graph.colors[i as usize];
95 if color.body_set.get_bit(body_id_a as u32) || color.body_set.get_bit(body_id_b as u32)
96 {
97 continue;
98 }
99 world.constraint_graph.colors[i as usize]
100 .body_set
101 .set_bit_grow(body_id_a as u32);
102 world.constraint_graph.colors[i as usize]
103 .body_set
104 .set_bit_grow(body_id_b as u32);
105 color_index = i;
106 break;
107 }
108 } else if type_a == BodyType::Dynamic {
109 for i in (1..OVERFLOW_INDEX).rev() {
110 if world.constraint_graph.colors[i as usize]
111 .body_set
112 .get_bit(body_id_a as u32)
113 {
114 continue;
115 }
116 world.constraint_graph.colors[i as usize]
117 .body_set
118 .set_bit_grow(body_id_a as u32);
119 color_index = i;
120 break;
121 }
122 } else if type_b == BodyType::Dynamic {
123 for i in (1..OVERFLOW_INDEX).rev() {
124 if world.constraint_graph.colors[i as usize]
125 .body_set
126 .get_bit(body_id_b as u32)
127 {
128 continue;
129 }
130 world.constraint_graph.colors[i as usize]
131 .body_set
132 .set_bit_grow(body_id_b as u32);
133 color_index = i;
134 break;
135 }
136 }
137
138 let is_mesh =
139 (world.contacts[contact_id as usize].flags & contact_flags::SIM_MESH_CONTACT) != 0;
140 let is_scalar = is_mesh || color_index == OVERFLOW_INDEX;
141 let local_index = if is_scalar {
142 world.constraint_graph.colors[color_index as usize]
143 .contacts
144 .len() as i32
145 } else {
146 world.constraint_graph.colors[color_index as usize]
147 .convex_contacts
148 .len() as i32
149 };
150
151 let local_a = world.bodies[body_id_a as usize].local_index;
152 let local_b = world.bodies[body_id_b as usize].local_index;
153 let manifold_count = world.contacts[contact_id as usize].manifold_count();
154
155 {
156 let contact = &mut world.contacts[contact_id as usize];
157 contact.color_index = color_index;
158 contact.local_index = local_index;
159 contact.body_sim_index_a = if type_a == BodyType::Static {
160 NULL_INDEX
161 } else {
162 local_a
163 };
164 contact.body_sim_index_b = if type_b == BodyType::Static {
165 NULL_INDEX
166 } else {
167 local_b
168 };
169 }
170
171 let color = &mut world.constraint_graph.colors[color_index as usize];
172 if is_scalar {
173 debug_assert!(manifold_count < u16::MAX as i32);
174 color.contacts.push(ContactSpec {
175 contact_id,
176 manifold_start: 0,
177 manifold_count: manifold_count as u16,
178 });
179 } else {
180 color.convex_contacts.push(contact_id);
181 }
182}
183
184fn assign_joint_color(
189 graph: &mut ConstraintGraph,
190 body_id_a: i32,
191 body_id_b: i32,
192 type_a: crate::types::BodyType,
193 type_b: crate::types::BodyType,
194) -> i32 {
195 use crate::types::BodyType;
196
197 debug_assert!(type_a == BodyType::Dynamic || type_b == BodyType::Dynamic);
198
199 if type_a == BodyType::Dynamic && type_b == BodyType::Dynamic {
200 for i in 0..DYNAMIC_COLOR_COUNT {
202 let color = &graph.colors[i as usize];
203 if color.body_set.get_bit(body_id_a as u32) || color.body_set.get_bit(body_id_b as u32)
204 {
205 continue;
206 }
207
208 let color = &mut graph.colors[i as usize];
209 color.body_set.set_bit_grow(body_id_a as u32);
210 color.body_set.set_bit_grow(body_id_b as u32);
211 return i;
212 }
213 } else if type_a == BodyType::Dynamic {
214 for i in (1..OVERFLOW_INDEX).rev() {
216 let color = &graph.colors[i as usize];
217 if color.body_set.get_bit(body_id_a as u32) {
218 continue;
219 }
220
221 graph.colors[i as usize]
222 .body_set
223 .set_bit_grow(body_id_a as u32);
224 return i;
225 }
226 } else if type_b == BodyType::Dynamic {
227 for i in (1..OVERFLOW_INDEX).rev() {
229 let color = &graph.colors[i as usize];
230 if color.body_set.get_bit(body_id_b as u32) {
231 continue;
232 }
233
234 graph.colors[i as usize]
235 .body_set
236 .set_bit_grow(body_id_b as u32);
237 return i;
238 }
239 }
240
241 OVERFLOW_INDEX
242}
243
244pub fn create_joint_in_graph(world: &mut crate::world::World, joint_id: i32) -> (i32, i32) {
248 let body_id_a = world.joints[joint_id as usize].edges[0].body_id;
249 let body_id_b = world.joints[joint_id as usize].edges[1].body_id;
250 let type_a = world.bodies[body_id_a as usize].type_;
251 let type_b = world.bodies[body_id_b as usize].type_;
252
253 let color_index = assign_joint_color(
254 &mut world.constraint_graph,
255 body_id_a,
256 body_id_b,
257 type_a,
258 type_b,
259 );
260
261 let color = &mut world.constraint_graph.colors[color_index as usize];
262 let local_index = color.joint_sims.len() as i32;
263 color.joint_sims.push(crate::joint::JointSim::default());
264
265 let joint = &mut world.joints[joint_id as usize];
266 joint.color_index = color_index;
267 joint.local_index = local_index;
268 (color_index, local_index)
269}
270
271pub fn add_joint_to_graph(
273 world: &mut crate::world::World,
274 joint_sim: crate::joint::JointSim,
275 joint_id: i32,
276) {
277 let (color_index, local_index) = create_joint_in_graph(world, joint_id);
278 world.constraint_graph.colors[color_index as usize].joint_sims[local_index as usize] =
279 joint_sim;
280}
281
282pub fn remove_joint_from_graph(
284 world: &mut crate::world::World,
285 body_id_a: i32,
286 body_id_b: i32,
287 color_index: i32,
288 local_index: i32,
289) {
290 debug_assert!(0 <= color_index && color_index < GRAPH_COLOR_COUNT);
291
292 if color_index != OVERFLOW_INDEX {
293 let color = &mut world.constraint_graph.colors[color_index as usize];
295 color.body_set.clear_bit(body_id_a as u32);
296 color.body_set.clear_bit(body_id_b as u32);
297 }
298
299 let color = &mut world.constraint_graph.colors[color_index as usize];
300 let moved_index = color.joint_sims.len() as i32 - 1;
301 color.joint_sims.swap_remove(local_index as usize);
302 if moved_index != local_index {
303 let moved_id = color.joint_sims[local_index as usize].joint_id;
305 let moved_joint = &mut world.joints[moved_id as usize];
306 debug_assert!(moved_joint.set_index == crate::solver_set::AWAKE_SET);
307 debug_assert!(moved_joint.color_index == color_index);
308 debug_assert!(moved_joint.local_index == moved_index);
309 moved_joint.local_index = local_index;
310 }
311}
312
313pub fn remove_contact_from_graph(
315 world: &mut crate::world::World,
316 body_id_a: i32,
317 body_id_b: i32,
318 color_index: i32,
319 local_index: i32,
320 mesh_contact: bool,
321) {
322 debug_assert!(0 <= color_index && color_index < GRAPH_COLOR_COUNT);
323
324 if color_index != OVERFLOW_INDEX {
325 let color = &mut world.constraint_graph.colors[color_index as usize];
326 color.body_set.clear_bit(body_id_a as u32);
327 color.body_set.clear_bit(body_id_b as u32);
328 }
329
330 let color = &mut world.constraint_graph.colors[color_index as usize];
331 if mesh_contact || color_index == OVERFLOW_INDEX {
332 let moved_index = color.contacts.len() as i32 - 1;
333 color.contacts.swap_remove(local_index as usize);
334 if moved_index != local_index {
335 let moved_contact_id = color.contacts[local_index as usize].contact_id;
336 let moved = &mut world.contacts[moved_contact_id as usize];
337 debug_assert!(moved.set_index == crate::solver_set::AWAKE_SET);
338 debug_assert!(moved.color_index == color_index);
339 debug_assert!(moved.local_index == moved_index);
340 moved.local_index = local_index;
341 }
342 } else {
343 let moved_index = color.convex_contacts.len() as i32 - 1;
344 color.convex_contacts.swap_remove(local_index as usize);
345 if moved_index != local_index {
346 let moved_contact_id = color.convex_contacts[local_index as usize];
347 let moved = &mut world.contacts[moved_contact_id as usize];
348 debug_assert!(moved.set_index == crate::solver_set::AWAKE_SET);
349 debug_assert!(moved.color_index == color_index);
350 debug_assert!(moved.local_index == moved_index);
351 debug_assert!((moved.flags & crate::contact::contact_flags::SIM_MESH_CONTACT) == 0);
352 moved.local_index = local_index;
353 }
354 }
355}