Skip to main content

box3d_rust/
debug_draw.rs

1//! Debug draw interface (`b3DebugDraw`), color palette (`b3HexColor`), and
2//! debug-material packing from `types.h` / `types.c`.
3//!
4//! SPDX-FileCopyrightText: 2025 Erin Catto
5//! SPDX-License-Identifier: MIT
6
7use crate::core::get_length_units_per_meter;
8use crate::geometry::ShapeType;
9use crate::id::ShapeId;
10use crate::math_functions::{Aabb, Pos, Vec3, WorldTransform};
11use crate::shape::ShapeGeometry;
12
13/// Color for debug drawing, packed 0xRRGGBB (b3HexColor). C treats the enum as
14/// a plain integer (shape custom colors are arbitrary u32 values), so the Rust
15/// port is a newtype over u32 with the named palette as associated constants.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct HexColor(pub u32);
18
19impl HexColor {
20    pub const ALICE_BLUE: HexColor = HexColor(0xF0F8FF);
21    pub const ANTIQUE_WHITE: HexColor = HexColor(0xFAEBD7);
22    pub const AQUA: HexColor = HexColor(0x00FFFF);
23    pub const AQUAMARINE: HexColor = HexColor(0x7FFFD4);
24    pub const AZURE: HexColor = HexColor(0xF0FFFF);
25    pub const BEIGE: HexColor = HexColor(0xF5F5DC);
26    pub const BISQUE: HexColor = HexColor(0xFFE4C4);
27    pub const BLACK: HexColor = HexColor(0x000000);
28    pub const BLANCHED_ALMOND: HexColor = HexColor(0xFFEBCD);
29    pub const BLUE: HexColor = HexColor(0x0000FF);
30    pub const BLUE_VIOLET: HexColor = HexColor(0x8A2BE2);
31    pub const BROWN: HexColor = HexColor(0xA52A2A);
32    pub const BURLYWOOD: HexColor = HexColor(0xDEB887);
33    pub const CADET_BLUE: HexColor = HexColor(0x5F9EA0);
34    pub const CHARTREUSE: HexColor = HexColor(0x7FFF00);
35    pub const CHOCOLATE: HexColor = HexColor(0xD2691E);
36    pub const CORAL: HexColor = HexColor(0xFF7F50);
37    pub const CORNFLOWER_BLUE: HexColor = HexColor(0x6495ED);
38    pub const CORNSILK: HexColor = HexColor(0xFFF8DC);
39    pub const CRIMSON: HexColor = HexColor(0xDC143C);
40    pub const CYAN: HexColor = HexColor(0x00FFFF);
41    pub const DARK_BLUE: HexColor = HexColor(0x00008B);
42    pub const DARK_CYAN: HexColor = HexColor(0x008B8B);
43    pub const DARK_GOLDEN_ROD: HexColor = HexColor(0xB8860B);
44    pub const DARK_GRAY: HexColor = HexColor(0xA9A9A9);
45    pub const DARK_GREEN: HexColor = HexColor(0x006400);
46    pub const DARK_KHAKI: HexColor = HexColor(0xBDB76B);
47    pub const DARK_MAGENTA: HexColor = HexColor(0x8B008B);
48    pub const DARK_OLIVE_GREEN: HexColor = HexColor(0x556B2F);
49    pub const DARK_ORANGE: HexColor = HexColor(0xFF8C00);
50    pub const DARK_ORCHID: HexColor = HexColor(0x9932CC);
51    pub const DARK_RED: HexColor = HexColor(0x8B0000);
52    pub const DARK_SALMON: HexColor = HexColor(0xE9967A);
53    pub const DARK_SEA_GREEN: HexColor = HexColor(0x8FBC8F);
54    pub const DARK_SLATE_BLUE: HexColor = HexColor(0x483D8B);
55    pub const DARK_SLATE_GRAY: HexColor = HexColor(0x2F4F4F);
56    pub const DARK_TURQUOISE: HexColor = HexColor(0x00CED1);
57    pub const DARK_VIOLET: HexColor = HexColor(0x9400D3);
58    pub const DEEP_PINK: HexColor = HexColor(0xFF1493);
59    pub const DEEP_SKY_BLUE: HexColor = HexColor(0x00BFFF);
60    pub const DIM_GRAY: HexColor = HexColor(0x696969);
61    pub const DODGER_BLUE: HexColor = HexColor(0x1E90FF);
62    pub const FIRE_BRICK: HexColor = HexColor(0xB22222);
63    pub const FLORAL_WHITE: HexColor = HexColor(0xFFFAF0);
64    pub const FOREST_GREEN: HexColor = HexColor(0x228B22);
65    pub const FUCHSIA: HexColor = HexColor(0xFF00FF);
66    pub const GAINSBORO: HexColor = HexColor(0xDCDCDC);
67    pub const GHOST_WHITE: HexColor = HexColor(0xF8F8FF);
68    pub const GOLD: HexColor = HexColor(0xFFD700);
69    pub const GOLDEN_ROD: HexColor = HexColor(0xDAA520);
70    pub const GRAY: HexColor = HexColor(0x808080);
71    pub const GREEN: HexColor = HexColor(0x008000);
72    pub const GREEN_YELLOW: HexColor = HexColor(0xADFF2F);
73    pub const HONEY_DEW: HexColor = HexColor(0xF0FFF0);
74    pub const HOT_PINK: HexColor = HexColor(0xFF69B4);
75    pub const INDIAN_RED: HexColor = HexColor(0xCD5C5C);
76    pub const INDIGO: HexColor = HexColor(0x4B0082);
77    pub const IVORY: HexColor = HexColor(0xFFFFF0);
78    pub const KHAKI: HexColor = HexColor(0xF0E68C);
79    pub const LAVENDER: HexColor = HexColor(0xE6E6FA);
80    pub const LAVENDER_BLUSH: HexColor = HexColor(0xFFF0F5);
81    pub const LAWN_GREEN: HexColor = HexColor(0x7CFC00);
82    pub const LEMON_CHIFFON: HexColor = HexColor(0xFFFACD);
83    pub const LIGHT_BLUE: HexColor = HexColor(0xADD8E6);
84    pub const LIGHT_CORAL: HexColor = HexColor(0xF08080);
85    pub const LIGHT_CYAN: HexColor = HexColor(0xE0FFFF);
86    pub const LIGHT_GOLDEN_ROD_YELLOW: HexColor = HexColor(0xFAFAD2);
87    pub const LIGHT_GRAY: HexColor = HexColor(0xD3D3D3);
88    pub const LIGHT_GREEN: HexColor = HexColor(0x90EE90);
89    pub const LIGHT_PINK: HexColor = HexColor(0xFFB6C1);
90    pub const LIGHT_SALMON: HexColor = HexColor(0xFFA07A);
91    pub const LIGHT_SEA_GREEN: HexColor = HexColor(0x20B2AA);
92    pub const LIGHT_SKY_BLUE: HexColor = HexColor(0x87CEFA);
93    pub const LIGHT_SLATE_GRAY: HexColor = HexColor(0x778899);
94    pub const LIGHT_STEEL_BLUE: HexColor = HexColor(0xB0C4DE);
95    pub const LIGHT_YELLOW: HexColor = HexColor(0xFFFFE0);
96    pub const LIME: HexColor = HexColor(0x00FF00);
97    pub const LIME_GREEN: HexColor = HexColor(0x32CD32);
98    pub const LINEN: HexColor = HexColor(0xFAF0E6);
99    pub const MAGENTA: HexColor = HexColor(0xFF00FF);
100    pub const MAROON: HexColor = HexColor(0x800000);
101    pub const MEDIUM_AQUA_MARINE: HexColor = HexColor(0x66CDAA);
102    pub const MEDIUM_BLUE: HexColor = HexColor(0x0000CD);
103    pub const MEDIUM_ORCHID: HexColor = HexColor(0xBA55D3);
104    pub const MEDIUM_PURPLE: HexColor = HexColor(0x9370DB);
105    pub const MEDIUM_SEA_GREEN: HexColor = HexColor(0x3CB371);
106    pub const MEDIUM_SLATE_BLUE: HexColor = HexColor(0x7B68EE);
107    pub const MEDIUM_SPRING_GREEN: HexColor = HexColor(0x00FA9A);
108    pub const MEDIUM_TURQUOISE: HexColor = HexColor(0x48D1CC);
109    pub const MEDIUM_VIOLET_RED: HexColor = HexColor(0xC71585);
110    pub const MIDNIGHT_BLUE: HexColor = HexColor(0x191970);
111    pub const MINT_CREAM: HexColor = HexColor(0xF5FFFA);
112    pub const MISTY_ROSE: HexColor = HexColor(0xFFE4E1);
113    pub const MOCCASIN: HexColor = HexColor(0xFFE4B5);
114    pub const NAVAJO_WHITE: HexColor = HexColor(0xFFDEAD);
115    pub const NAVY: HexColor = HexColor(0x000080);
116    pub const OLD_LACE: HexColor = HexColor(0xFDF5E6);
117    pub const OLIVE: HexColor = HexColor(0x808000);
118    pub const OLIVE_DRAB: HexColor = HexColor(0x6B8E23);
119    pub const ORANGE: HexColor = HexColor(0xFFA500);
120    pub const ORANGE_RED: HexColor = HexColor(0xFF4500);
121    pub const ORCHID: HexColor = HexColor(0xDA70D6);
122    pub const PALE_GOLDEN_ROD: HexColor = HexColor(0xEEE8AA);
123    pub const PALE_GREEN: HexColor = HexColor(0x98FB98);
124    pub const PALE_TURQUOISE: HexColor = HexColor(0xAFEEEE);
125    pub const PALE_VIOLET_RED: HexColor = HexColor(0xDB7093);
126    pub const PAPAYA_WHIP: HexColor = HexColor(0xFFEFD5);
127    pub const PEACH_PUFF: HexColor = HexColor(0xFFDAB9);
128    pub const PERU: HexColor = HexColor(0xCD853F);
129    pub const PINK: HexColor = HexColor(0xFFC0CB);
130    pub const PLUM: HexColor = HexColor(0xDDA0DD);
131    pub const POWDER_BLUE: HexColor = HexColor(0xB0E0E6);
132    pub const PURPLE: HexColor = HexColor(0x800080);
133    pub const REBECCA_PURPLE: HexColor = HexColor(0x663399);
134    pub const RED: HexColor = HexColor(0xFF0000);
135    pub const ROSY_BROWN: HexColor = HexColor(0xBC8F8F);
136    pub const ROYAL_BLUE: HexColor = HexColor(0x4169E1);
137    pub const SADDLE_BROWN: HexColor = HexColor(0x8B4513);
138    pub const SALMON: HexColor = HexColor(0xFA8072);
139    pub const SANDY_BROWN: HexColor = HexColor(0xF4A460);
140    pub const SEA_GREEN: HexColor = HexColor(0x2E8B57);
141    pub const SEA_SHELL: HexColor = HexColor(0xFFF5EE);
142    pub const SIENNA: HexColor = HexColor(0xA0522D);
143    pub const SILVER: HexColor = HexColor(0xC0C0C0);
144    pub const SKY_BLUE: HexColor = HexColor(0x87CEEB);
145    pub const SLATE_BLUE: HexColor = HexColor(0x6A5ACD);
146    pub const SLATE_GRAY: HexColor = HexColor(0x708090);
147    pub const SNOW: HexColor = HexColor(0xFFFAFA);
148    pub const SPRING_GREEN: HexColor = HexColor(0x00FF7F);
149    pub const STEEL_BLUE: HexColor = HexColor(0x4682B4);
150    pub const TAN: HexColor = HexColor(0xD2B48C);
151    pub const TEAL: HexColor = HexColor(0x008080);
152    pub const THISTLE: HexColor = HexColor(0xD8BFD8);
153    pub const TOMATO: HexColor = HexColor(0xFF6347);
154    pub const TURQUOISE: HexColor = HexColor(0x40E0D0);
155    pub const VIOLET: HexColor = HexColor(0xEE82EE);
156    pub const WHEAT: HexColor = HexColor(0xF5DEB3);
157    pub const WHITE: HexColor = HexColor(0xFFFFFF);
158    pub const WHITE_SMOKE: HexColor = HexColor(0xF5F5F5);
159    pub const YELLOW: HexColor = HexColor(0xFFFF00);
160    pub const YELLOW_GREEN: HexColor = HexColor(0x9ACD32);
161    pub const BOX2D_RED: HexColor = HexColor(0xDC3132);
162    pub const BOX2D_BLUE: HexColor = HexColor(0x30AEBF);
163    pub const BOX2D_GREEN: HexColor = HexColor(0x8CC924);
164    pub const BOX2D_YELLOW: HexColor = HexColor(0xFFEE8C);
165}
166
167/// Debug draw material preset packed into the high byte of a color.
168/// (`b3DebugMaterial`)
169#[derive(Debug, Clone, Copy, PartialEq, Eq)]
170#[repr(u32)]
171pub enum DebugMaterial {
172    Default = 0,
173    Matte = 1,
174    Soft = 2,
175    Dead = 3,
176    Glossy = 4,
177    Metallic = 5,
178}
179
180/// Pack an RGB color with a material preset. (`b3MakeDebugColor`)
181pub fn make_debug_color(rgb: HexColor, material: DebugMaterial) -> HexColor {
182    HexColor((rgb.0 & 0x00FF_FFFF) | ((material as u32) << 24))
183}
184
185/// Geometry snapshot passed to [`CreateDebugShapeCallback`]. (`b3DebugShape`)
186#[derive(Debug, Clone, Copy)]
187pub struct DebugShape<'a> {
188    pub shape_id: ShapeId,
189    pub shape_type: ShapeType,
190    pub geometry: &'a ShapeGeometry,
191}
192
193/// WorldDef / World callback that builds a GPU (or test) shape handle.
194/// (`b3CreateDebugShapeCallback`)
195pub type CreateDebugShapeCallback = fn(&DebugShape<'_>, u64) -> u64;
196
197/// Destroys a user shape handle when the physics shape is destroyed or changed.
198/// (`b3DestroyDebugShapeCallback`)
199pub type DestroyDebugShapeCallback = fn(u64, u64);
200
201/// Debug drawing callbacks and options (`b3DebugDraw`).
202///
203/// Defaults match `b3DefaultDebugDraw`: draw callbacks are no-ops, option flags
204/// are off, `drawing_bounds` is a cube of half-extent `100 * lengthUnits`, and
205/// force/joint scales are 1.
206pub trait DebugDraw {
207    /// Draws a previously created user shape. (`DrawShapeFcn`)
208    /// Returns whether drawing should continue (unused by `world_draw` today).
209    fn draw_shape(&mut self, user_shape: u64, transform: WorldTransform, color: HexColor) -> bool {
210        let _ = (user_shape, transform, color);
211        true
212    }
213
214    /// Draw a line segment. (`DrawSegmentFcn`)
215    fn draw_segment(&mut self, p1: Pos, p2: Pos, color: HexColor) {
216        let _ = (p1, p2, color);
217    }
218
219    /// Draw a transform; choose your own length scale. (`DrawTransformFcn`)
220    fn draw_transform(&mut self, transform: WorldTransform) {
221        let _ = transform;
222    }
223
224    /// Draw a point. (`DrawPointFcn`)
225    fn draw_point(&mut self, p: Pos, size: f32, color: HexColor) {
226        let _ = (p, size, color);
227    }
228
229    /// Draw a sphere. (`DrawSphereFcn`)
230    fn draw_sphere(&mut self, p: Pos, radius: f32, color: HexColor, alpha: f32) {
231        let _ = (p, radius, color, alpha);
232    }
233
234    /// Draw a capsule. (`DrawCapsuleFcn`)
235    fn draw_capsule(&mut self, p1: Pos, p2: Pos, radius: f32, color: HexColor, alpha: f32) {
236        let _ = (p1, p2, radius, color, alpha);
237    }
238
239    /// Draw a bounding box. (`DrawBoundsFcn`)
240    fn draw_bounds(&mut self, aabb: Aabb, color: HexColor) {
241        let _ = (aabb, color);
242    }
243
244    /// Draw an oriented box. (`DrawBoxFcn`)
245    fn draw_box(&mut self, extents: Vec3, transform: WorldTransform, color: HexColor) {
246        let _ = (extents, transform, color);
247    }
248
249    /// Draw a string in world space. (`DrawStringFcn`)
250    fn draw_string(&mut self, p: Pos, s: &str, color: HexColor) {
251        let _ = (p, s, color);
252    }
253
254    /// World bounds used for culling. (`drawingBounds`)
255    fn drawing_bounds(&self) -> Aabb {
256        let h = 100.0 * get_length_units_per_meter();
257        Aabb {
258            lower_bound: Vec3 {
259                x: -h,
260                y: -h,
261                z: -h,
262            },
263            upper_bound: Vec3 { x: h, y: h, z: h },
264        }
265    }
266
267    /// Scale for drawing forces. (`forceScale`)
268    fn force_scale(&self) -> f32 {
269        1.0
270    }
271
272    /// Global scaling for joint drawing. (`jointScale`)
273    fn joint_scale(&self) -> f32 {
274        1.0
275    }
276
277    fn draw_shapes(&self) -> bool {
278        false
279    }
280    fn draw_joints(&self) -> bool {
281        false
282    }
283    fn draw_joint_extras(&self) -> bool {
284        false
285    }
286    fn draw_bounds_boxes(&self) -> bool {
287        false
288    }
289    fn draw_mass(&self) -> bool {
290        false
291    }
292    fn draw_sleep(&self) -> bool {
293        false
294    }
295    fn draw_body_names(&self) -> bool {
296        false
297    }
298    fn draw_contacts(&self) -> bool {
299        false
300    }
301    /// Draw contact anchor A instead of B. (`drawAnchorA`)
302    fn draw_anchor_a(&self) -> bool {
303        false
304    }
305    fn draw_graph_colors(&self) -> bool {
306        false
307    }
308    fn draw_contact_features(&self) -> bool {
309        false
310    }
311    fn draw_contact_normals(&self) -> bool {
312        false
313    }
314    fn draw_contact_forces(&self) -> bool {
315        false
316    }
317    fn draw_friction_forces(&self) -> bool {
318        false
319    }
320    fn draw_islands(&self) -> bool {
321        false
322    }
323}
324
325/// Internal solver debug point drawn at the end of `world_draw`. (`b3DebugPoint`)
326#[derive(Debug, Clone, Copy)]
327pub struct DebugPoint {
328    pub p: Pos,
329    pub color: HexColor,
330    pub label: i32,
331    pub value: f32,
332}
333
334impl Default for DebugPoint {
335    fn default() -> Self {
336        DebugPoint {
337            p: Pos::default(),
338            color: HexColor::BLACK,
339            label: 0,
340            value: 0.0,
341        }
342    }
343}
344
345/// Internal solver debug line drawn at the end of `world_draw`. (`b3DebugLine`)
346#[derive(Debug, Clone, Copy)]
347pub struct DebugLine {
348    pub p1: Pos,
349    pub p2: Pos,
350    pub color: HexColor,
351    pub label: i32,
352}
353
354impl Default for DebugLine {
355    fn default() -> Self {
356        DebugLine {
357            p1: Pos::default(),
358            p2: Pos::default(),
359            color: HexColor::BLACK,
360            label: 0,
361        }
362    }
363}
364
365/// (`B3_DEBUG_POINT_CAPACITY`)
366pub const DEBUG_POINT_CAPACITY: usize = 64;
367/// (`B3_DEBUG_LINE_CAPACITY`)
368pub const DEBUG_LINE_CAPACITY: usize = 64;