box2d_rust/
constraint_graph.rs1use crate::bitset::BitSet;
14use crate::constants::GRAPH_COLOR_COUNT;
15use crate::contact::ContactSim;
16use crate::joint::JointSim;
17
18pub const OVERFLOW_INDEX: i32 = GRAPH_COLOR_COUNT - 1;
21
22pub const DYNAMIC_COLOR_COUNT: i32 = GRAPH_COLOR_COUNT - 4;
26
27#[derive(Debug, Clone, Default)]
29pub struct GraphColor {
30 pub body_set: BitSet,
34
35 pub contact_sims: Vec<ContactSim>,
37 pub joint_sims: Vec<JointSim>,
38}
39
40#[derive(Debug, Clone, Default)]
42pub struct ConstraintGraph {
43 pub colors: Vec<GraphColor>,
45}
46
47use crate::math_functions::max_int;
48use crate::solver_set::AWAKE_SET;
49use crate::types::{BodyType, Capacity};
50use crate::world::World;
51
52impl ConstraintGraph {
53 pub fn new(capacity: &Capacity) -> ConstraintGraph {
55 const _: () = assert!(GRAPH_COLOR_COUNT >= 2, "must have at least two colors");
56 const _: () = assert!(DYNAMIC_COLOR_COUNT >= 2, "need more dynamic colors");
57
58 let body_capacity = max_int(capacity.static_body_count + capacity.dynamic_body_count, 16);
59
60 let mut colors = Vec::with_capacity(GRAPH_COLOR_COUNT as usize);
61 for i in 0..GRAPH_COLOR_COUNT {
63 let mut color = GraphColor::default();
64 if i < OVERFLOW_INDEX {
65 color.body_set = BitSet::new(body_capacity as u32);
66 color.body_set.set_bit_count_and_clear(body_capacity as u32);
67 color.contact_sims.reserve(16);
68 }
69 colors.push(color);
70 }
71
72 ConstraintGraph { colors }
73 }
74}
75
76pub fn add_contact_to_graph(world: &mut World, contact_sim: ContactSim, contact_id: i32) {
79 use crate::contact::contact_flags::{SIM_TOUCHING, TOUCHING};
80
81 debug_assert!(contact_sim.manifold.point_count > 0);
82 debug_assert!(contact_sim.sim_flags & SIM_TOUCHING != 0);
83 debug_assert!(world.contacts[contact_id as usize].flags & TOUCHING != 0);
84
85 let mut color_index = OVERFLOW_INDEX;
86
87 let (body_id_a, body_id_b) = {
88 let contact = &world.contacts[contact_id as usize];
89 (contact.edges[0].body_id, contact.edges[1].body_id)
90 };
91 let type_a = world.bodies[body_id_a as usize].type_;
92 let type_b = world.bodies[body_id_b as usize].type_;
93 debug_assert!(type_a == BodyType::Dynamic || type_b == BodyType::Dynamic);
94
95 if type_a == BodyType::Dynamic && type_b == BodyType::Dynamic {
97 for i in 0..DYNAMIC_COLOR_COUNT {
100 let color = &mut world.constraint_graph.colors[i as usize];
101 if color.body_set.get_bit(body_id_a as u32) || color.body_set.get_bit(body_id_b as u32)
102 {
103 continue;
104 }
105
106 color.body_set.set_bit_grow(body_id_a as u32);
107 color.body_set.set_bit_grow(body_id_b as u32);
108 color_index = i;
109 break;
110 }
111 } else if type_a == BodyType::Dynamic {
112 let mut i = OVERFLOW_INDEX - 1;
115 while i >= 1 {
116 let color = &mut world.constraint_graph.colors[i as usize];
117 if !color.body_set.get_bit(body_id_a as u32) {
118 color.body_set.set_bit_grow(body_id_a as u32);
119 color_index = i;
120 break;
121 }
122 i -= 1;
123 }
124 } else if type_b == BodyType::Dynamic {
125 let mut i = OVERFLOW_INDEX - 1;
126 while i >= 1 {
127 let color = &mut world.constraint_graph.colors[i as usize];
128 if !color.body_set.get_bit(body_id_b as u32) {
129 color.body_set.set_bit_grow(body_id_b as u32);
130 color_index = i;
131 break;
132 }
133 i -= 1;
134 }
135 }
136
137 let local_index = world.constraint_graph.colors[color_index as usize]
138 .contact_sims
139 .len() as i32;
140 {
141 let contact = &mut world.contacts[contact_id as usize];
142 contact.color_index = color_index;
143 contact.local_index = local_index;
144 }
145
146 let mut new_contact = contact_sim;
147
148 if type_a == BodyType::Static {
149 new_contact.body_sim_index_a = crate::core::NULL_INDEX;
150 new_contact.inv_mass_a = 0.0;
151 new_contact.inv_i_a = 0.0;
152 } else {
153 debug_assert!(world.bodies[body_id_a as usize].set_index == AWAKE_SET);
154 let local = world.bodies[body_id_a as usize].local_index;
155 new_contact.body_sim_index_a = local;
156
157 let body_sim_a = &world.solver_sets[AWAKE_SET as usize].body_sims[local as usize];
158 new_contact.inv_mass_a = body_sim_a.inv_mass;
159 new_contact.inv_i_a = body_sim_a.inv_inertia;
160 }
161
162 if type_b == BodyType::Static {
163 new_contact.body_sim_index_b = crate::core::NULL_INDEX;
164 new_contact.inv_mass_b = 0.0;
165 new_contact.inv_i_b = 0.0;
166 } else {
167 debug_assert!(world.bodies[body_id_b as usize].set_index == AWAKE_SET);
168 let local = world.bodies[body_id_b as usize].local_index;
169 new_contact.body_sim_index_b = local;
170
171 let body_sim_b = &world.solver_sets[AWAKE_SET as usize].body_sims[local as usize];
172 new_contact.inv_mass_b = body_sim_b.inv_mass;
173 new_contact.inv_i_b = body_sim_b.inv_inertia;
174 }
175
176 world.constraint_graph.colors[color_index as usize]
177 .contact_sims
178 .push(new_contact);
179}
180
181pub fn remove_contact_from_graph(
183 world: &mut World,
184 body_id_a: i32,
185 body_id_b: i32,
186 color_index: i32,
187 local_index: i32,
188) {
189 debug_assert!((0..GRAPH_COLOR_COUNT).contains(&color_index));
190 let color = &mut world.constraint_graph.colors[color_index as usize];
191
192 if color_index != OVERFLOW_INDEX {
193 color.body_set.clear_bit(body_id_a as u32);
196 color.body_set.clear_bit(body_id_b as u32);
197 }
198
199 let moved_index = color.contact_sims.len() as i32 - 1;
200 color.contact_sims.swap_remove(local_index as usize);
201 if moved_index != local_index {
202 let moved_id = color.contact_sims[local_index as usize].contact_id;
204 let moved_contact = &mut world.contacts[moved_id as usize];
205 debug_assert!(moved_contact.set_index == AWAKE_SET);
206 debug_assert!(moved_contact.color_index == color_index);
207 debug_assert!(moved_contact.local_index == moved_index);
208 moved_contact.local_index = local_index;
209 }
210}
211
212fn assign_joint_color(
216 graph: &mut ConstraintGraph,
217 body_id_a: i32,
218 body_id_b: i32,
219 type_a: BodyType,
220 type_b: BodyType,
221) -> i32 {
222 debug_assert!(type_a == BodyType::Dynamic || type_b == BodyType::Dynamic);
223
224 if type_a == BodyType::Dynamic && type_b == BodyType::Dynamic {
225 for i in 0..DYNAMIC_COLOR_COUNT {
226 let color = &mut graph.colors[i as usize];
227 if color.body_set.get_bit(body_id_a as u32) || color.body_set.get_bit(body_id_b as u32)
228 {
229 continue;
230 }
231
232 color.body_set.set_bit_grow(body_id_a as u32);
233 color.body_set.set_bit_grow(body_id_b as u32);
234 return i;
235 }
236 } else if type_a == BodyType::Dynamic {
237 let mut i = OVERFLOW_INDEX - 1;
238 while i >= 1 {
239 let color = &mut graph.colors[i as usize];
240 if !color.body_set.get_bit(body_id_a as u32) {
241 color.body_set.set_bit_grow(body_id_a as u32);
242 return i;
243 }
244 i -= 1;
245 }
246 } else if type_b == BodyType::Dynamic {
247 let mut i = OVERFLOW_INDEX - 1;
248 while i >= 1 {
249 let color = &mut graph.colors[i as usize];
250 if !color.body_set.get_bit(body_id_b as u32) {
251 color.body_set.set_bit_grow(body_id_b as u32);
252 return i;
253 }
254 i -= 1;
255 }
256 }
257
258 OVERFLOW_INDEX
259}
260
261pub fn create_joint_in_graph(world: &mut World, joint_id: i32) -> (i32, i32) {
265 let (body_id_a, body_id_b) = {
266 let joint = &world.joints[joint_id as usize];
267 (joint.edges[0].body_id, joint.edges[1].body_id)
268 };
269 let type_a = world.bodies[body_id_a as usize].type_;
270 let type_b = world.bodies[body_id_b as usize].type_;
271
272 let color_index = assign_joint_color(
273 &mut world.constraint_graph,
274 body_id_a,
275 body_id_b,
276 type_a,
277 type_b,
278 );
279
280 world.constraint_graph.colors[color_index as usize]
281 .joint_sims
282 .push(JointSim::default());
283 let local_index = world.constraint_graph.colors[color_index as usize]
284 .joint_sims
285 .len() as i32
286 - 1;
287
288 let joint = &mut world.joints[joint_id as usize];
289 joint.color_index = color_index;
290 joint.local_index = local_index;
291 (color_index, local_index)
292}
293
294pub fn add_joint_to_graph(world: &mut World, joint_sim: JointSim, joint_id: i32) {
296 let (color_index, local_index) = create_joint_in_graph(world, joint_id);
297 world.constraint_graph.colors[color_index as usize].joint_sims[local_index as usize] =
298 joint_sim;
299}
300
301pub fn remove_joint_from_graph(
303 world: &mut World,
304 body_id_a: i32,
305 body_id_b: i32,
306 color_index: i32,
307 local_index: i32,
308) {
309 debug_assert!((0..GRAPH_COLOR_COUNT).contains(&color_index));
310 let color = &mut world.constraint_graph.colors[color_index as usize];
311
312 if color_index != OVERFLOW_INDEX {
313 color.body_set.clear_bit(body_id_a as u32);
315 color.body_set.clear_bit(body_id_b as u32);
316 }
317
318 let moved_index = color.joint_sims.len() as i32 - 1;
319 color.joint_sims.swap_remove(local_index as usize);
320 if moved_index != local_index {
321 let moved_id = color.joint_sims[local_index as usize].joint_id;
323 let moved_joint = &mut world.joints[moved_id as usize];
324 debug_assert!(moved_joint.set_index == AWAKE_SET);
325 debug_assert!(moved_joint.color_index == color_index);
326 debug_assert!(moved_joint.local_index == moved_index);
327 moved_joint.local_index = local_index;
328 }
329}
330
331const GRAPH_COLORS: [crate::debug_draw::HexColor; GRAPH_COLOR_COUNT as usize] = {
334 use crate::debug_draw::HexColor;
335 [
336 HexColor::RED,
337 HexColor::ORANGE,
338 HexColor::YELLOW,
339 HexColor::LIME_GREEN,
340 HexColor::SPRING_GREEN,
341 HexColor::AQUA,
342 HexColor::DODGER_BLUE,
343 HexColor::BLUE_VIOLET,
344 HexColor::MAGENTA,
345 HexColor::DEEP_PINK,
346 HexColor::CRIMSON,
347 HexColor::CORAL,
348 HexColor::GOLD,
349 HexColor::GREEN_YELLOW,
350 HexColor::MEDIUM_SEA_GREEN,
351 HexColor::TURQUOISE,
352 HexColor::DEEP_SKY_BLUE,
353 HexColor::CORNFLOWER_BLUE,
354 HexColor::MEDIUM_SLATE_BLUE,
355 HexColor::MEDIUM_ORCHID,
356 HexColor::HOT_PINK,
357 HexColor::TOMATO,
358 HexColor::KHAKI,
359 HexColor::SILVER,
360 ]
361};
362
363pub fn get_graph_color(index: i32) -> crate::debug_draw::HexColor {
366 debug_assert!((0..GRAPH_COLOR_COUNT).contains(&index));
367 GRAPH_COLORS[index as usize]
368}