1use crate::body::body_flags;
7use crate::collision::ShapeGeometry;
8use crate::constants::linear_slop;
9use crate::contact::{Contact, ContactSim};
10use crate::core::NULL_INDEX;
11use crate::debug_draw::{DebugDraw, HexColor};
12use crate::joint::draw_joint;
13use crate::math_functions::{
14 aabb_union, is_valid_aabb, lerp_position, mul_sv, normalize, offset_pos, right_perp, sub_pos,
15 transform_world_point, Aabb, Vec2, WorldTransform,
16};
17use crate::shape::Shape;
18use crate::solver_set::{AWAKE_SET, DISABLED_SET};
19use crate::types::{BodyType, BODY_TYPE_COUNT};
20use crate::world::World;
21
22fn draw_shape(
24 draw: &mut dyn DebugDraw,
25 shape: &Shape,
26 transform: WorldTransform,
27 color: HexColor,
28 draw_chain_normals: bool,
29) {
30 match &shape.geometry {
31 ShapeGeometry::Capsule(capsule) => {
32 let p1 = transform_world_point(transform, capsule.center1);
33 let p2 = transform_world_point(transform, capsule.center2);
34 draw.draw_solid_capsule(p1, p2, capsule.radius, color);
35 }
36
37 ShapeGeometry::Circle(circle) => {
38 draw.draw_solid_circle(transform, circle.center, circle.radius, color);
39 }
40
41 ShapeGeometry::Polygon(poly) => {
42 draw.draw_solid_polygon(
43 transform,
44 &poly.vertices[..poly.count as usize],
45 poly.radius,
46 color,
47 );
48 }
49
50 ShapeGeometry::Segment(segment) => {
51 let p1 = transform_world_point(transform, segment.point1);
52 let p2 = transform_world_point(transform, segment.point2);
53 draw.draw_line(p1, p2, color);
54 }
55
56 ShapeGeometry::ChainSegment(chain_segment) => {
57 let segment = &chain_segment.segment;
58 let p1 = transform_world_point(transform, segment.point1);
59 let p2 = transform_world_point(transform, segment.point2);
60 draw.draw_line(p1, p2, color);
61 draw.draw_point(p2, 4.0, color);
62
63 if draw_chain_normals {
64 let c = lerp_position(p1, p2, 0.5);
65 let e = normalize(sub_pos(p2, p1));
66 let n = right_perp(e);
67 let length = 0.2 * crate::core::get_length_units_per_meter();
68 draw.draw_line(c, offset_pos(c, mul_sv(length, n)), HexColor::PALE_GREEN);
69 }
70 }
71 }
72}
73
74fn get_contact_sim_ref<'a>(world: &'a World, contact: &Contact) -> &'a ContactSim {
77 if contact.set_index == AWAKE_SET && contact.color_index != NULL_INDEX {
78 &world.constraint_graph.colors[contact.color_index as usize].contact_sims
80 [contact.local_index as usize]
81 } else {
82 &world.solver_sets[contact.set_index as usize].contact_sims[contact.local_index as usize]
83 }
84}
85
86fn draw_query_callback(world: &mut World, draw: &mut dyn DebugDraw, shape_id: i32) {
89 let shape = &world.shapes[shape_id as usize];
90 debug_assert!(shape.id == shape_id);
91 let body = &world.bodies[shape.body_id as usize];
92 let body_sim = &world.solver_sets[body.set_index as usize].body_sims[body.local_index as usize];
93
94 if draw.draw_shapes() {
95 let color = if shape.material.custom_color != 0 {
96 HexColor(shape.material.custom_color)
97 } else if body.type_ == BodyType::Dynamic && body.mass == 0.0 {
98 HexColor::RED
100 } else if body.set_index == DISABLED_SET {
101 HexColor::SLATE_GRAY
102 } else if shape.sensor_index != NULL_INDEX {
103 HexColor::WHEAT
104 } else if body.flags & body_flags::HAD_TIME_OF_IMPACT != 0 {
105 HexColor::LIME
106 } else if (body_sim.flags & body_flags::IS_BULLET != 0) && body.set_index == AWAKE_SET {
107 HexColor::TURQUOISE
108 } else if body.flags & body_flags::IS_SPEED_CAPPED != 0 {
109 HexColor::YELLOW
110 } else if body_sim.flags & body_flags::IS_FAST != 0 {
111 HexColor::SALMON
112 } else if body.type_ == BodyType::Static {
113 HexColor::PALE_GREEN
114 } else if body.type_ == BodyType::Kinematic {
115 HexColor::ROYAL_BLUE
116 } else if body.set_index == AWAKE_SET {
117 HexColor::PINK
118 } else {
119 HexColor::GRAY
120 };
121
122 let draw_chain_normals = draw.draw_chain_normals();
123 draw_shape(draw, shape, body_sim.transform, color, draw_chain_normals);
124 }
125
126 if draw.draw_bounds_boxes() {
127 draw.draw_bounds(shape.fat_aabb, HexColor::GOLD);
128 }
129
130 let body_id = shape.body_id;
131 world.debug_body_set.set_bit(body_id as u32);
132}
133
134fn draw_body_joints(world: &mut World, draw: &mut dyn DebugDraw, body_id: i32) {
136 let mut joint_key = world.bodies[body_id as usize].head_joint_key;
137 while joint_key != NULL_INDEX {
138 let joint_id = joint_key >> 1;
139 let edge_index = joint_key & 1;
140
141 if !world.debug_joint_set.get_bit(joint_id as u32) {
143 let joint = &world.joints[joint_id as usize];
144 draw_joint(draw, world, joint);
145 world.debug_joint_set.set_bit(joint_id as u32);
146 }
147
148 let joint = &world.joints[joint_id as usize];
149 joint_key = joint.edges[edge_index as usize].next_key;
150 }
151}
152
153fn draw_body_contacts(world: &mut World, draw: &mut dyn DebugDraw, body_id: i32) {
155 const K_AXIS_SCALE: f32 = 0.3;
156 let speculative_color = HexColor::GAINSBORO;
157 let add_color = HexColor::GREEN;
158 let persist_color = HexColor::BLUE;
159 let normal_color = HexColor::DIM_GRAY;
160 let impulse_color = HexColor::MAGENTA;
161 let friction_color = HexColor::YELLOW;
162
163 let slop = linear_slop();
164
165 let mut contact_key = world.bodies[body_id as usize].head_contact_key;
166 while contact_key != NULL_INDEX {
167 let contact_id = contact_key >> 1;
168 let edge_index = contact_key & 1;
169 let contact = &world.contacts[contact_id as usize];
170 contact_key = contact.edges[edge_index as usize].next_key;
171
172 if !world.debug_contact_set.get_bit(contact_id as u32) {
174 let contact_sim = get_contact_sim_ref(world, contact);
175 let body_a = &world.bodies[contact.edges[0].body_id as usize];
176 let body_sim_a = &world.solver_sets[body_a.set_index as usize].body_sims
177 [body_a.local_index as usize];
178 let body_b = &world.bodies[contact.edges[1].body_id as usize];
179 let body_sim_b = &world.solver_sets[body_b.set_index as usize].body_sims
180 [body_b.local_index as usize];
181 let point_count = contact_sim.manifold.point_count;
182 let normal = contact_sim.manifold.normal;
183
184 for j in 0..point_count as usize {
185 let mp = &contact_sim.manifold.points[j];
186
187 let p = if draw.draw_anchor_a() {
188 offset_pos(body_sim_a.center, mp.anchor_a)
189 } else {
190 offset_pos(body_sim_b.center, mp.anchor_b)
191 };
192
193 if draw.draw_graph_colors() && contact.color_index != NULL_INDEX {
194 let point_size =
196 if contact.color_index == crate::constraint_graph::OVERFLOW_INDEX {
197 7.5
198 } else {
199 5.0
200 };
201 draw.draw_point(
202 p,
203 point_size,
204 crate::constraint_graph::get_graph_color(contact.color_index),
205 );
206 } else if mp.separation > slop {
207 draw.draw_point(p, 5.0, speculative_color);
209 } else if !mp.persisted {
210 draw.draw_point(p, 10.0, add_color);
212 } else {
213 draw.draw_point(p, 5.0, persist_color);
215 }
216
217 if draw.draw_contact_normals() {
218 let p1 = p;
219 let p2 = offset_pos(p1, mul_sv(K_AXIS_SCALE, normal));
220 draw.draw_line(p1, p2, normal_color);
221
222 let buffer = format!(" {:.2}", mp.separation);
223 draw.draw_string(p1, &buffer, HexColor::WHITE);
224 } else if draw.draw_contact_forces() {
225 let force = 0.5 * mp.total_normal_impulse * world.inv_dt;
228 let p1 = p;
229 let p2 = offset_pos(p1, mul_sv(draw.force_scale() * force, normal));
230 draw.draw_line(p1, p2, impulse_color);
231 let buffer = format!("{:.1}", force);
232 draw.draw_string(p1, &buffer, HexColor::WHITE);
233 }
234
235 if draw.draw_contact_features() {
236 let buffer = format!("{}", mp.id);
237 draw.draw_string(p, &buffer, HexColor::ORANGE);
238 }
239
240 if draw.draw_friction_forces() {
241 let force = 0.5 * mp.tangent_impulse * world.inv_h;
242 let tangent = right_perp(normal);
243 let p1 = p;
244 let p2 = offset_pos(p1, mul_sv(draw.force_scale() * force, tangent));
245 draw.draw_line(p1, p2, friction_color);
246 let buffer = format!("{:.1}", force);
247 draw.draw_string(p1, &buffer, HexColor::WHITE);
248 }
249 }
250
251 world.debug_contact_set.set_bit(contact_id as u32);
252 }
253 }
254}
255
256fn draw_body_island(world: &mut World, draw: &mut dyn DebugDraw, body_id: i32) {
258 let island_id = world.bodies[body_id as usize].island_id;
259 if island_id != NULL_INDEX && !world.debug_island_set.get_bit(island_id as u32) {
260 let island = &world.islands[island_id as usize];
261 if island.set_index == NULL_INDEX {
262 return;
265 }
266
267 let mut shape_count = 0;
268 let mut aabb = Aabb {
269 lower_bound: Vec2 {
270 x: f32::MAX,
271 y: f32::MAX,
272 },
273 upper_bound: Vec2 {
274 x: -f32::MAX,
275 y: -f32::MAX,
276 },
277 };
278
279 for body_index in 0..island.bodies.len() {
280 let island_body_id = island.bodies[body_index];
281 let island_body = &world.bodies[island_body_id as usize];
282 let mut shape_id = island_body.head_shape_id;
283 while shape_id != NULL_INDEX {
284 let shape = &world.shapes[shape_id as usize];
285 aabb = aabb_union(aabb, shape.fat_aabb);
286 shape_count += 1;
287 shape_id = shape.next_shape_id;
288 }
289 }
290
291 if shape_count > 0 {
292 draw.draw_bounds(aabb, HexColor::ORANGE_RED);
293 }
294
295 world.debug_island_set.set_bit(island_id as u32);
296 }
297}
298
299pub fn world_draw(world: &mut World, draw: &mut dyn DebugDraw) {
303 debug_assert!(!world.locked);
304 if world.locked {
305 return;
306 }
307
308 debug_assert!(is_valid_aabb(draw.drawing_bounds()));
309
310 let body_capacity = world.body_id_pool.id_capacity();
311 world
312 .debug_body_set
313 .set_bit_count_and_clear(body_capacity as u32);
314
315 let joint_capacity = world.joint_id_pool.id_capacity();
316 world
317 .debug_joint_set
318 .set_bit_count_and_clear(joint_capacity as u32);
319
320 let contact_capacity = world.contact_id_pool.id_capacity();
321 world
322 .debug_contact_set
323 .set_bit_count_and_clear(contact_capacity as u32);
324
325 let island_capacity = world.island_id_pool.id_capacity();
326 world
327 .debug_island_set
328 .set_bit_count_and_clear(island_capacity as u32);
329
330 for i in 0..BODY_TYPE_COUNT {
331 let mut shape_ids = Vec::new();
335 world.broad_phase.trees[i].query_all(draw.drawing_bounds(), |_, user_data| {
336 shape_ids.push(user_data as i32);
337 true
338 });
339
340 for shape_id in shape_ids {
341 draw_query_callback(world, draw, shape_id);
342 }
343 }
344
345 let word_count = world.debug_body_set.block_count as usize;
346 let words: Vec<u64> = world.debug_body_set.blocks[..word_count].to_vec();
349 for (k, word) in words.into_iter().enumerate() {
350 let mut word = word;
351 while word != 0 {
352 let ctz = word.trailing_zeros();
353 let body_id = (64 * k as u32 + ctz) as i32;
354
355 if draw.draw_body_names() && !world.bodies[body_id as usize].name.is_empty() {
356 let offset = Vec2 { x: 0.1, y: 0.1 };
357 let body = &world.bodies[body_id as usize];
358 let body_sim = &world.solver_sets[body.set_index as usize].body_sims
359 [body.local_index as usize];
360
361 let transform = WorldTransform {
362 p: body_sim.center,
363 q: body_sim.transform.q,
364 };
365 let p = transform_world_point(transform, offset);
366 let name = world.bodies[body_id as usize].name.clone();
367 draw.draw_string(p, &name, HexColor::BLUE_VIOLET);
368 }
369
370 if draw.draw_mass() && world.bodies[body_id as usize].type_ == BodyType::Dynamic {
371 let offset = Vec2 { x: 0.1, y: 0.1 };
372 let body = &world.bodies[body_id as usize];
373 let body_sim = &world.solver_sets[body.set_index as usize].body_sims
374 [body.local_index as usize];
375
376 let transform = WorldTransform {
377 p: body_sim.center,
378 q: body_sim.transform.q,
379 };
380 draw.draw_line(body_sim.center0, body_sim.center, HexColor::WHITE_SMOKE);
381 draw.draw_transform(transform);
382
383 let p = transform_world_point(transform, offset);
384 let buffer = format!(" {:.2}", world.bodies[body_id as usize].mass);
385 draw.draw_string(p, &buffer, HexColor::WHITE);
386 }
387
388 if draw.draw_joints() {
389 draw_body_joints(world, draw, body_id);
390 }
391
392 if draw.draw_contacts() && world.bodies[body_id as usize].type_ == BodyType::Dynamic {
393 draw_body_contacts(world, draw, body_id);
394 }
395
396 if draw.draw_islands() {
397 draw_body_island(world, draw, body_id);
398 }
399
400 word &= word - 1;
402 }
403 }
404}