1#[allow(dead_code)]
7pub struct DebugLine {
8 pub start: [f32; 3],
9 pub end: [f32; 3],
10 pub color: [f32; 4],
11 pub width: f32,
12}
13
14#[allow(dead_code)]
15pub struct DebugPoint {
16 pub position: [f32; 3],
17 pub color: [f32; 4],
18 pub size: f32,
19}
20
21#[allow(dead_code)]
22pub struct DebugText {
23 pub position: [f32; 3],
24 pub text: String,
25 pub color: [f32; 4],
26 pub scale: f32,
27}
28
29#[allow(dead_code)]
30pub struct DebugDraw {
31 pub lines: Vec<DebugLine>,
32 pub points: Vec<DebugPoint>,
33 pub texts: Vec<DebugText>,
34 pub enabled: bool,
35}
36
37#[allow(dead_code)]
38pub fn new_debug_draw() -> DebugDraw {
39 DebugDraw {
40 lines: Vec::new(),
41 points: Vec::new(),
42 texts: Vec::new(),
43 enabled: true,
44 }
45}
46
47#[allow(dead_code)]
48pub fn draw_line(dd: &mut DebugDraw, start: [f32; 3], end: [f32; 3], color: [f32; 4]) {
49 if !dd.enabled {
50 return;
51 }
52 dd.lines.push(DebugLine {
53 start,
54 end,
55 color,
56 width: 1.0,
57 });
58}
59
60#[allow(dead_code)]
61pub fn draw_point(dd: &mut DebugDraw, pos: [f32; 3], color: [f32; 4], size: f32) {
62 if !dd.enabled {
63 return;
64 }
65 dd.points.push(DebugPoint {
66 position: pos,
67 color,
68 size,
69 });
70}
71
72#[allow(dead_code)]
73pub fn draw_text(dd: &mut DebugDraw, pos: [f32; 3], text: &str, color: [f32; 4]) {
74 if !dd.enabled {
75 return;
76 }
77 dd.texts.push(DebugText {
78 position: pos,
79 text: text.to_string(),
80 color,
81 scale: 1.0,
82 });
83}
84
85#[allow(dead_code)]
87pub fn draw_aabb(dd: &mut DebugDraw, min: [f32; 3], max: [f32; 3], color: [f32; 4]) {
88 if !dd.enabled {
89 return;
90 }
91 let [x0, y0, z0] = min;
92 let [x1, y1, z1] = max;
93
94 let corners = [
96 [x0, y0, z0],
97 [x1, y0, z0],
98 [x1, y1, z0],
99 [x0, y1, z0], [x0, y0, z1],
101 [x1, y0, z1],
102 [x1, y1, z1],
103 [x0, y1, z1], ];
105
106 let edges: [(usize, usize); 12] = [
108 (0, 1),
109 (1, 2),
110 (2, 3),
111 (3, 0), (4, 5),
113 (5, 6),
114 (6, 7),
115 (7, 4), (0, 4),
117 (1, 5),
118 (2, 6),
119 (3, 7), ];
121
122 for (a, b) in &edges {
123 draw_line(dd, corners[*a], corners[*b], color);
124 }
125}
126
127#[allow(dead_code)]
129pub fn draw_sphere_wireframe(
130 dd: &mut DebugDraw,
131 center: [f32; 3],
132 radius: f32,
133 color: [f32; 4],
134 segments: u32,
135) {
136 if !dd.enabled {
137 return;
138 }
139 let n = segments as usize;
140 for circle in 0..3usize {
141 for i in 0..n {
142 let t0 = i as f32 / n as f32 * std::f32::consts::TAU;
143 let t1 = (i + 1) as f32 / n as f32 * std::f32::consts::TAU;
144
145 let (s0, c0) = t0.sin_cos();
146 let (s1, c1) = t1.sin_cos();
147
148 let (p0, p1) = match circle {
149 0 => (
150 [center[0] + radius * c0, center[1] + radius * s0, center[2]],
151 [center[0] + radius * c1, center[1] + radius * s1, center[2]],
152 ),
153 1 => (
154 [center[0] + radius * c0, center[1], center[2] + radius * s0],
155 [center[0] + radius * c1, center[1], center[2] + radius * s1],
156 ),
157 _ => (
158 [center[0], center[1] + radius * c0, center[2] + radius * s0],
159 [center[0], center[1] + radius * c1, center[2] + radius * s1],
160 ),
161 };
162
163 draw_line(dd, p0, p1, color);
164 }
165 }
166}
167
168#[allow(dead_code)]
169pub fn draw_normal_vectors(
170 dd: &mut DebugDraw,
171 positions: &[[f32; 3]],
172 normals: &[[f32; 3]],
173 scale: f32,
174 color: [f32; 4],
175) {
176 if !dd.enabled {
177 return;
178 }
179 for (pos, nor) in positions.iter().zip(normals.iter()) {
180 let end = [
181 pos[0] + nor[0] * scale,
182 pos[1] + nor[1] * scale,
183 pos[2] + nor[2] * scale,
184 ];
185 draw_line(dd, *pos, end, color);
186 }
187}
188
189#[allow(dead_code)]
190pub fn draw_skeleton(
191 dd: &mut DebugDraw,
192 positions: &[[f32; 3]],
193 parent_indices: &[Option<usize>],
194 color: [f32; 4],
195) {
196 if !dd.enabled {
197 return;
198 }
199 for (i, parent_opt) in parent_indices.iter().enumerate() {
200 if let Some(parent) = parent_opt {
201 if i < positions.len() && *parent < positions.len() {
202 draw_line(dd, positions[i], positions[*parent], color);
203 }
204 }
205 }
206}
207
208#[allow(dead_code)]
210pub fn draw_wireframe(
211 dd: &mut DebugDraw,
212 positions: &[[f32; 3]],
213 indices: &[u32],
214 color: [f32; 4],
215) {
216 if !dd.enabled {
217 return;
218 }
219 let tri_count = indices.len() / 3;
220 for t in 0..tri_count {
221 let i0 = indices[t * 3] as usize;
222 let i1 = indices[t * 3 + 1] as usize;
223 let i2 = indices[t * 3 + 2] as usize;
224 if i0 < positions.len() && i1 < positions.len() && i2 < positions.len() {
225 draw_line(dd, positions[i0], positions[i1], color);
226 draw_line(dd, positions[i1], positions[i2], color);
227 draw_line(dd, positions[i2], positions[i0], color);
228 }
229 }
230}
231
232#[allow(dead_code)]
233pub fn clear_debug_draw(dd: &mut DebugDraw) {
234 dd.lines.clear();
235 dd.points.clear();
236 dd.texts.clear();
237}
238
239#[allow(dead_code)]
240pub fn line_count(dd: &DebugDraw) -> usize {
241 dd.lines.len()
242}
243
244#[allow(dead_code)]
245pub fn total_primitive_count(dd: &DebugDraw) -> usize {
246 dd.lines.len() + dd.points.len() + dd.texts.len()
247}
248
249#[allow(dead_code)]
250pub fn set_enabled(dd: &mut DebugDraw, enabled: bool) {
251 dd.enabled = enabled;
252}
253
254#[cfg(test)]
257mod tests {
258 use super::*;
259
260 const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
261
262 #[test]
263 fn test_draw_line_adds_one() {
264 let mut dd = new_debug_draw();
265 draw_line(&mut dd, [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], WHITE);
266 assert_eq!(line_count(&dd), 1);
267 }
268
269 #[test]
270 fn test_draw_aabb_adds_12_lines() {
271 let mut dd = new_debug_draw();
272 draw_aabb(&mut dd, [0.0, 0.0, 0.0], [1.0, 1.0, 1.0], WHITE);
273 assert_eq!(line_count(&dd), 12);
274 }
275
276 #[test]
277 fn test_draw_sphere_wireframe_segments() {
278 let segments = 16u32;
279 let mut dd = new_debug_draw();
280 draw_sphere_wireframe(&mut dd, [0.0, 0.0, 0.0], 1.0, WHITE, segments);
281 assert_eq!(line_count(&dd), (segments * 3) as usize);
282 }
283
284 #[test]
285 fn test_draw_normal_vectors_adds_n_lines() {
286 let mut dd = new_debug_draw();
287 let positions: Vec<[f32; 3]> = (0..5).map(|i| [i as f32, 0.0, 0.0]).collect();
288 let normals: Vec<[f32; 3]> = vec![[0.0, 1.0, 0.0]; 5];
289 draw_normal_vectors(&mut dd, &positions, &normals, 0.1, WHITE);
290 assert_eq!(line_count(&dd), 5);
291 }
292
293 #[test]
294 fn test_draw_wireframe_adds_triangle_count_times_3() {
295 let mut dd = new_debug_draw();
296 let positions: Vec<[f32; 3]> = vec![
297 [0.0, 0.0, 0.0],
298 [1.0, 0.0, 0.0],
299 [0.5, 1.0, 0.0],
300 [1.5, 0.0, 0.0],
301 [2.0, 1.0, 0.0],
302 ];
303 let indices: Vec<u32> = vec![0, 1, 2, 1, 3, 4];
304 draw_wireframe(&mut dd, &positions, &indices, WHITE);
305 assert_eq!(line_count(&dd), 6); }
307
308 #[test]
309 fn test_clear_resets_counts() {
310 let mut dd = new_debug_draw();
311 draw_line(&mut dd, [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], WHITE);
312 draw_point(&mut dd, [0.0, 0.0, 0.0], WHITE, 1.0);
313 draw_text(&mut dd, [0.0, 0.0, 0.0], "hi", WHITE);
314 clear_debug_draw(&mut dd);
315 assert_eq!(total_primitive_count(&dd), 0);
316 }
317
318 #[test]
319 fn test_total_primitive_count() {
320 let mut dd = new_debug_draw();
321 draw_line(&mut dd, [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], WHITE);
322 draw_point(&mut dd, [0.0, 0.0, 0.0], WHITE, 2.0);
323 draw_text(&mut dd, [0.0, 0.0, 0.0], "test", WHITE);
324 assert_eq!(total_primitive_count(&dd), 3);
325 }
326
327 #[test]
328 fn test_draw_point_adds_one() {
329 let mut dd = new_debug_draw();
330 draw_point(&mut dd, [0.0, 0.0, 0.0], WHITE, 1.0);
331 assert_eq!(dd.points.len(), 1);
332 }
333
334 #[test]
335 fn test_draw_text_adds_one() {
336 let mut dd = new_debug_draw();
337 draw_text(&mut dd, [0.0, 0.0, 0.0], "hello", WHITE);
338 assert_eq!(dd.texts.len(), 1);
339 }
340
341 #[test]
342 fn test_set_enabled_false_no_lines() {
343 let mut dd = new_debug_draw();
344 set_enabled(&mut dd, false);
345 draw_line(&mut dd, [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], WHITE);
346 assert_eq!(line_count(&dd), 0);
347 }
348
349 #[test]
350 fn test_draw_skeleton_adds_lines() {
351 let mut dd = new_debug_draw();
352 let positions: Vec<[f32; 3]> = vec![[0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 2.0, 0.0]];
353 let parents: Vec<Option<usize>> = vec![None, Some(0), Some(1)];
354 draw_skeleton(&mut dd, &positions, &parents, WHITE);
355 assert_eq!(line_count(&dd), 2);
356 }
357
358 #[test]
359 fn test_new_debug_draw_empty() {
360 let dd = new_debug_draw();
361 assert_eq!(total_primitive_count(&dd), 0);
362 assert!(dd.enabled);
363 }
364
365 #[test]
366 fn test_line_count_direct() {
367 let mut dd = new_debug_draw();
368 for _ in 0..7 {
369 draw_line(&mut dd, [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], WHITE);
370 }
371 assert_eq!(line_count(&dd), 7);
372 }
373}