1use crate::core::{
26 algebra::{Matrix4, Point3, UnitQuaternion, Vector2, Vector3},
27 color::{Color, Hsl},
28 math::{aabb::AxisAlignedBoundingBox, frustum::Frustum, Matrix4Ext},
29};
30use rapier2d::math::Vector;
31use rapier2d::pipeline::{DebugColor, DebugRenderObject};
32use std::ops::Range;
33
34#[derive(Clone, Debug)]
36pub struct Line {
37 pub begin: Vector3<f32>,
39 pub end: Vector3<f32>,
41 pub color: Color,
43}
44
45#[derive(Default, Clone, Debug)]
90pub struct SceneDrawingContext {
91 pub lines: Vec<Line>,
93}
94
95impl rapier2d::pipeline::DebugRenderBackend for SceneDrawingContext {
96 fn draw_line(&mut self, _object: DebugRenderObject, a: Vector, b: Vector, color: DebugColor) {
97 self.add_line(Line {
98 begin: Vector3::new(a.x, a.y, 0.0),
99 end: Vector3::new(b.x, b.y, 0.0),
100 color: Color::from(Hsl::new(color[0], color[1], color[2])),
101 })
102 }
103}
104
105impl rapier3d::pipeline::DebugRenderBackend for SceneDrawingContext {
106 fn draw_line(
107 &mut self,
108 _object: rapier3d::pipeline::DebugRenderObject,
109 a: rapier3d::math::Vector,
110 b: rapier3d::math::Vector,
111 color: rapier3d::pipeline::DebugColor,
112 ) {
113 self.add_line(Line {
114 begin: a.into(),
115 end: b.into(),
116 color: Color::from(Hsl::new(color[0], color[1], color[2])),
117 })
118 }
119}
120
121impl SceneDrawingContext {
122 pub fn draw_frustum(&mut self, frustum: &Frustum, color: Color) {
124 let left_top_front = frustum.left_top_front_corner();
125 let left_bottom_front = frustum.left_bottom_front_corner();
126 let right_bottom_front = frustum.right_bottom_front_corner();
127 let right_top_front = frustum.right_top_front_corner();
128
129 let left_top_back = frustum.left_top_back_corner();
130 let left_bottom_back = frustum.left_bottom_back_corner();
131 let right_bottom_back = frustum.right_bottom_back_corner();
132 let right_top_back = frustum.right_top_back_corner();
133
134 self.add_line(Line {
136 begin: left_top_front,
137 end: right_top_front,
138 color,
139 });
140 self.add_line(Line {
141 begin: right_top_front,
142 end: right_bottom_front,
143 color,
144 });
145 self.add_line(Line {
146 begin: right_bottom_front,
147 end: left_bottom_front,
148 color,
149 });
150 self.add_line(Line {
151 begin: left_bottom_front,
152 end: left_top_front,
153 color,
154 });
155
156 self.add_line(Line {
158 begin: left_top_back,
159 end: right_top_back,
160 color,
161 });
162 self.add_line(Line {
163 begin: right_top_back,
164 end: right_bottom_back,
165 color,
166 });
167 self.add_line(Line {
168 begin: right_bottom_back,
169 end: left_bottom_back,
170 color,
171 });
172 self.add_line(Line {
173 begin: left_bottom_back,
174 end: left_top_back,
175 color,
176 });
177
178 self.add_line(Line {
180 begin: left_top_front,
181 end: left_top_back,
182 color,
183 });
184 self.add_line(Line {
185 begin: right_top_front,
186 end: right_top_back,
187 color,
188 });
189 self.add_line(Line {
190 begin: right_bottom_front,
191 end: right_bottom_back,
192 color,
193 });
194 self.add_line(Line {
195 begin: left_bottom_front,
196 end: left_bottom_back,
197 color,
198 });
199 }
200
201 pub fn draw_aabb(&mut self, aabb: &AxisAlignedBoundingBox, color: Color) {
203 let left_bottom_front = Vector3::new(aabb.min.x, aabb.min.y, aabb.max.z);
204 let left_top_front = Vector3::new(aabb.min.x, aabb.max.y, aabb.max.z);
205 let right_top_front = Vector3::new(aabb.max.x, aabb.max.y, aabb.max.z);
206 let right_bottom_front = Vector3::new(aabb.max.x, aabb.min.y, aabb.max.z);
207
208 let left_bottom_back = Vector3::new(aabb.min.x, aabb.min.y, aabb.min.z);
209 let left_top_back = Vector3::new(aabb.min.x, aabb.max.y, aabb.min.z);
210 let right_top_back = Vector3::new(aabb.max.x, aabb.max.y, aabb.min.z);
211 let right_bottom_back = Vector3::new(aabb.max.x, aabb.min.y, aabb.min.z);
212
213 self.add_line(Line {
215 begin: left_top_front,
216 end: right_top_front,
217 color,
218 });
219 self.add_line(Line {
220 begin: right_top_front,
221 end: right_bottom_front,
222 color,
223 });
224 self.add_line(Line {
225 begin: right_bottom_front,
226 end: left_bottom_front,
227 color,
228 });
229 self.add_line(Line {
230 begin: left_bottom_front,
231 end: left_top_front,
232 color,
233 });
234
235 self.add_line(Line {
237 begin: left_top_back,
238 end: right_top_back,
239 color,
240 });
241 self.add_line(Line {
242 begin: right_top_back,
243 end: right_bottom_back,
244 color,
245 });
246 self.add_line(Line {
247 begin: right_bottom_back,
248 end: left_bottom_back,
249 color,
250 });
251 self.add_line(Line {
252 begin: left_bottom_back,
253 end: left_top_back,
254 color,
255 });
256
257 self.add_line(Line {
259 begin: left_top_front,
260 end: left_top_back,
261 color,
262 });
263 self.add_line(Line {
264 begin: right_top_front,
265 end: right_top_back,
266 color,
267 });
268 self.add_line(Line {
269 begin: right_bottom_front,
270 end: right_bottom_back,
271 color,
272 });
273 self.add_line(Line {
274 begin: left_bottom_front,
275 end: left_bottom_back,
276 color,
277 });
278 }
279
280 pub fn draw_oob(
282 &mut self,
283 aabb: &AxisAlignedBoundingBox,
284 transform: Matrix4<f32>,
285 color: Color,
286 ) {
287 let left_bottom_front = transform
288 .transform_point(&Point3::new(aabb.min.x, aabb.min.y, aabb.max.z))
289 .coords;
290 let left_top_front = transform
291 .transform_point(&Point3::new(aabb.min.x, aabb.max.y, aabb.max.z))
292 .coords;
293 let right_top_front = transform
294 .transform_point(&Point3::new(aabb.max.x, aabb.max.y, aabb.max.z))
295 .coords;
296 let right_bottom_front = transform
297 .transform_point(&Point3::new(aabb.max.x, aabb.min.y, aabb.max.z))
298 .coords;
299
300 let left_bottom_back = transform
301 .transform_point(&Point3::new(aabb.min.x, aabb.min.y, aabb.min.z))
302 .coords;
303 let left_top_back = transform
304 .transform_point(&Point3::new(aabb.min.x, aabb.max.y, aabb.min.z))
305 .coords;
306 let right_top_back = transform
307 .transform_point(&Point3::new(aabb.max.x, aabb.max.y, aabb.min.z))
308 .coords;
309 let right_bottom_back = transform
310 .transform_point(&Point3::new(aabb.max.x, aabb.min.y, aabb.min.z))
311 .coords;
312
313 self.add_line(Line {
315 begin: left_top_front,
316 end: right_top_front,
317 color,
318 });
319 self.add_line(Line {
320 begin: right_top_front,
321 end: right_bottom_front,
322 color,
323 });
324 self.add_line(Line {
325 begin: right_bottom_front,
326 end: left_bottom_front,
327 color,
328 });
329 self.add_line(Line {
330 begin: left_bottom_front,
331 end: left_top_front,
332 color,
333 });
334
335 self.add_line(Line {
337 begin: left_top_back,
338 end: right_top_back,
339 color,
340 });
341 self.add_line(Line {
342 begin: right_top_back,
343 end: right_bottom_back,
344 color,
345 });
346 self.add_line(Line {
347 begin: right_bottom_back,
348 end: left_bottom_back,
349 color,
350 });
351 self.add_line(Line {
352 begin: left_bottom_back,
353 end: left_top_back,
354 color,
355 });
356
357 self.add_line(Line {
359 begin: left_top_front,
360 end: left_top_back,
361 color,
362 });
363 self.add_line(Line {
364 begin: right_top_front,
365 end: right_top_back,
366 color,
367 });
368 self.add_line(Line {
369 begin: right_bottom_front,
370 end: right_bottom_back,
371 color,
372 });
373 self.add_line(Line {
374 begin: left_bottom_front,
375 end: left_bottom_back,
376 color,
377 });
378 }
379
380 pub fn draw_transform(&mut self, matrix: Matrix4<f32>) {
382 let x = matrix.transform_vector(&Vector3::x());
383 let y = matrix.transform_vector(&Vector3::y());
384 let z = matrix.transform_vector(&Vector3::z());
385 let origin = matrix.position();
386 self.add_line(Line {
387 begin: origin,
388 end: origin + x,
389 color: Color::RED,
390 });
391 self.add_line(Line {
392 begin: origin,
393 end: origin + y,
394 color: Color::GREEN,
395 });
396 self.add_line(Line {
397 begin: origin,
398 end: origin + z,
399 color: Color::BLUE,
400 });
401 }
402
403 pub fn draw_triangle(
405 &mut self,
406 a: Vector3<f32>,
407 b: Vector3<f32>,
408 c: Vector3<f32>,
409 color: Color,
410 ) {
411 self.add_line(Line {
412 begin: a,
413 end: b,
414 color,
415 });
416 self.add_line(Line {
417 begin: b,
418 end: c,
419 color,
420 });
421 self.add_line(Line {
422 begin: c,
423 end: a,
424 color,
425 });
426 }
427
428 pub fn draw_pyramid(
430 &mut self,
431 top: Vector3<f32>,
432 a: Vector3<f32>,
433 b: Vector3<f32>,
434 c: Vector3<f32>,
435 d: Vector3<f32>,
436 color: Color,
437 transform: Matrix4<f32>,
438 ) {
439 let top = transform.position() + transform.transform_vector(&top);
440 let a = transform.position() + transform.transform_vector(&a);
441 let b = transform.position() + transform.transform_vector(&b);
442 let c = transform.position() + transform.transform_vector(&c);
443 let d = transform.position() + transform.transform_vector(&d);
444 self.draw_triangle(top, a, b, color);
445 self.draw_triangle(top, b, c, color);
446 self.draw_triangle(top, c, d, color);
447 self.draw_triangle(top, d, a, color);
448 }
449
450 pub fn draw_wire_sphere(
452 &mut self,
453 position: Vector3<f32>,
454 radius: f32,
455 segments: usize,
456 color: Color,
457 ) {
458 let translation = Matrix4::new_translation(&position);
459 self.draw_circle(Default::default(), radius, segments, translation, color);
460 self.draw_circle(
461 Default::default(),
462 radius,
463 segments,
464 translation
465 * UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 90.0f32.to_radians())
466 .to_homogeneous(),
467 color,
468 );
469 self.draw_circle(
470 Default::default(),
471 radius,
472 segments,
473 translation
474 * UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 90.0f32.to_radians())
475 .to_homogeneous(),
476 color,
477 );
478 }
479
480 pub fn draw_circle(
483 &mut self,
484 position: Vector3<f32>,
485 radius: f32,
486 segments: usize,
487 transform: Matrix4<f32>,
488 color: Color,
489 ) {
490 let d_phi = 2.0 * std::f32::consts::PI / segments as f32;
491 for i in 0..segments {
492 let x1 = position.x + radius * (d_phi * i as f32).cos();
493 let y1 = position.y + radius * (d_phi * i as f32).sin();
494 let x2 = position.x + radius * (d_phi * (i + 1) as f32).cos();
495 let y2 = position.y + radius * (d_phi * (i + 1) as f32).sin();
496
497 self.add_line(Line {
498 begin: transform.transform_point(&Point3::new(x1, y1, 0.0)).coords,
499 end: transform.transform_point(&Point3::new(x2, y2, 0.0)).coords,
500 color,
501 })
502 }
503 }
504
505 pub fn draw_circle_segment(
508 &mut self,
509 position: Vector3<f32>,
510 radius: f32,
511 segments: usize,
512 begin_angle: f32,
513 end_angle: f32,
514 transform: Matrix4<f32>,
515 color: Color,
516 ) {
517 let d_angle = 2.0 * std::f32::consts::PI / segments as f32;
518 let mut angle = begin_angle;
519 while angle < end_angle {
520 let x1 = position.x + radius * (angle).cos();
521 let y1 = position.y + radius * (angle).sin();
522 let x2 = position.x + radius * (angle + d_angle).cos();
523 let y2 = position.y + radius * (angle + d_angle).sin();
524
525 self.add_line(Line {
526 begin: transform.transform_point(&Point3::new(x1, y1, 0.0)).coords,
527 end: transform.transform_point(&Point3::new(x2, y2, 0.0)).coords,
528 color,
529 });
530
531 angle += d_angle;
532 }
533 }
534
535 pub fn draw_rectangle(
537 &mut self,
538 half_width: f32,
539 half_height: f32,
540 transform: Matrix4<f32>,
541 color: Color,
542 ) {
543 let a = transform
544 .transform_point(&Point3::new(-half_width, half_height, 0.0))
545 .coords;
546 let b = transform
547 .transform_point(&Point3::new(half_width, half_height, 0.0))
548 .coords;
549 let c = transform
550 .transform_point(&Point3::new(half_width, -half_height, 0.0))
551 .coords;
552 let d = transform
553 .transform_point(&Point3::new(-half_width, -half_height, 0.0))
554 .coords;
555 self.add_line(Line {
556 begin: a,
557 end: b,
558 color,
559 });
560 self.add_line(Line {
561 begin: b,
562 end: c,
563 color,
564 });
565 self.add_line(Line {
566 begin: c,
567 end: d,
568 color,
569 });
570 self.add_line(Line {
571 begin: d,
572 end: a,
573 color,
574 });
575 }
576
577 pub fn draw_sphere(
579 &mut self,
580 position: Vector3<f32>,
581 slices: usize,
582 stacks: usize,
583 radius: f32,
584 color: Color,
585 ) {
586 let d_theta = std::f32::consts::PI / slices as f32;
587 let d_phi = 2.0 * std::f32::consts::PI / stacks as f32;
588
589 for i in 0..stacks {
590 for j in 0..slices {
591 let nj = j + 1;
592 let ni = i + 1;
593
594 let k0 = radius * (d_theta * i as f32).sin();
595 let k1 = (d_phi * j as f32).cos();
596 let k2 = (d_phi * j as f32).sin();
597 let k3 = radius * (d_theta * i as f32).cos();
598
599 let k4 = radius * (d_theta * ni as f32).sin();
600 let k5 = (d_phi * nj as f32).cos();
601 let k6 = (d_phi * nj as f32).sin();
602 let k7 = radius * (d_theta * ni as f32).cos();
603
604 if i != (stacks - 1) {
605 self.draw_triangle(
606 position + Vector3::new(k0 * k1, k0 * k2, k3),
607 position + Vector3::new(k4 * k1, k4 * k2, k7),
608 position + Vector3::new(k4 * k5, k4 * k6, k7),
609 color,
610 );
611 }
612
613 if i != 0 {
614 self.draw_triangle(
615 position + Vector3::new(k4 * k5, k4 * k6, k7),
616 position + Vector3::new(k0 * k5, k0 * k6, k3),
617 position + Vector3::new(k0 * k1, k0 * k2, k3),
618 color,
619 );
620 }
621 }
622 }
623 }
624
625 pub fn draw_sphere_section(
627 &mut self,
628 radius: f32,
629 theta_range: Range<f32>,
630 theta_steps: usize,
631 phi_range: Range<f32>,
632 phi_steps: usize,
633 transform: Matrix4<f32>,
634 color: Color,
635 ) {
636 assert!(theta_range.start < theta_range.end);
637 assert!(phi_range.start < phi_range.end);
638
639 assert_ne!(phi_steps, 0);
640 assert_ne!(theta_steps, 0);
641
642 let theta_step = (theta_range.end - theta_range.start) / theta_steps as f32;
643 let phi_step = (phi_range.end - phi_range.start) / phi_steps as f32;
644
645 fn spherical_to_cartesian(radius: f32, theta: f32, phi: f32) -> Vector3<f32> {
646 Vector3::new(
647 radius * theta.sin() * phi.cos(),
648 radius * theta.cos(),
649 radius * theta.sin() * phi.sin(),
650 )
651 }
652
653 let mut theta = theta_range.start;
654 while theta < theta_range.end {
655 let mut phi = phi_range.start;
656 while phi < phi_range.end {
657 let p0 = transform
658 .transform_point(&Point3::from(spherical_to_cartesian(radius, theta, phi)))
659 .coords;
660 let p1 = transform
661 .transform_point(&Point3::from(spherical_to_cartesian(
662 radius,
663 theta,
664 phi + phi_step,
665 )))
666 .coords;
667 let p2 = transform
668 .transform_point(&Point3::from(spherical_to_cartesian(
669 radius,
670 theta + theta_step,
671 phi + phi_step,
672 )))
673 .coords;
674 let p3 = transform
675 .transform_point(&Point3::from(spherical_to_cartesian(
676 radius,
677 theta + theta_step,
678 phi,
679 )))
680 .coords;
681
682 self.draw_triangle(p0, p1, p2, color);
683 self.draw_triangle(p0, p2, p3, color);
684
685 phi += phi_step;
686 }
687 theta += theta_step;
688 }
689 }
690
691 pub fn draw_cone(
693 &mut self,
694 sides: usize,
695 r: f32,
696 h: f32,
697 transform: Matrix4<f32>,
698 color: Color,
699 cap: bool,
700 ) {
701 let d_phi = 2.0 * std::f32::consts::PI / sides as f32;
702
703 let half_height = h / 2.0;
704
705 for i in 0..sides {
706 let nx0 = (d_phi * i as f32).cos();
707 let ny0 = (d_phi * i as f32).sin();
708 let nx1 = (d_phi * (i + 1) as f32).cos();
709 let ny1 = (d_phi * (i + 1) as f32).sin();
710
711 let x0 = r * nx0;
712 let z0 = r * ny0;
713 let x1 = r * nx1;
714 let z1 = r * ny1;
715
716 if cap {
718 self.draw_triangle(
719 transform
720 .transform_point(&Point3::new(0.0, -half_height, 0.0))
721 .coords,
722 transform
723 .transform_point(&Point3::new(x0, -half_height, z0))
724 .coords,
725 transform
726 .transform_point(&Point3::new(x1, -half_height, z1))
727 .coords,
728 color,
729 );
730 }
731
732 self.draw_triangle(
734 transform
735 .transform_point(&Point3::new(0.0, half_height, 0.0))
736 .coords,
737 transform
738 .transform_point(&Point3::new(x1, -half_height, z1))
739 .coords,
740 transform
741 .transform_point(&Point3::new(x0, -half_height, z0))
742 .coords,
743 color,
744 );
745 }
746 }
747
748 pub fn draw_cylinder(
750 &mut self,
751 sides: usize,
752 r: f32,
753 h: f32,
754 caps: bool,
755 transform: Matrix4<f32>,
756 color: Color,
757 ) {
758 let d_phi = 2.0 * std::f32::consts::PI / sides as f32;
759
760 let half_height = h / 2.0;
761
762 for i in 0..sides {
763 let nx0 = (d_phi * i as f32).cos();
764 let ny0 = (d_phi * i as f32).sin();
765 let nx1 = (d_phi * (i + 1) as f32).cos();
766 let ny1 = (d_phi * (i + 1) as f32).sin();
767
768 let x0 = r * nx0;
769 let z0 = r * ny0;
770 let x1 = r * nx1;
771 let z1 = r * ny1;
772
773 if caps {
774 self.draw_triangle(
776 transform
777 .transform_point(&Point3::new(x1, half_height, z1))
778 .coords,
779 transform
780 .transform_point(&Point3::new(x0, half_height, z0))
781 .coords,
782 transform
783 .transform_point(&Point3::new(0.0, half_height, 0.0))
784 .coords,
785 color,
786 );
787
788 self.draw_triangle(
790 transform
791 .transform_point(&Point3::new(x0, -half_height, z0))
792 .coords,
793 transform
794 .transform_point(&Point3::new(x1, -half_height, z1))
795 .coords,
796 transform
797 .transform_point(&Point3::new(0.0, -half_height, 0.0))
798 .coords,
799 color,
800 );
801 }
802
803 self.draw_triangle(
805 transform
806 .transform_point(&Point3::new(x0, -half_height, z0))
807 .coords,
808 transform
809 .transform_point(&Point3::new(x0, half_height, z0))
810 .coords,
811 transform
812 .transform_point(&Point3::new(x1, -half_height, z1))
813 .coords,
814 color,
815 );
816
817 self.draw_triangle(
818 transform
819 .transform_point(&Point3::new(x1, -half_height, z1))
820 .coords,
821 transform
822 .transform_point(&Point3::new(x0, half_height, z0))
823 .coords,
824 transform
825 .transform_point(&Point3::new(x1, half_height, z1))
826 .coords,
827 color,
828 );
829 }
830 }
831
832 pub fn draw_flat_capsule(
834 &mut self,
835 radius: f32,
836 height: f32,
837 segments: usize,
838 transform: Matrix4<f32>,
839 color: Color,
840 ) {
841 self.draw_circle_segment(
842 Vector3::new(0.0, height * 0.5, 0.0),
843 radius,
844 segments,
845 0.0,
846 std::f32::consts::PI,
847 transform,
848 color,
849 );
850
851 self.draw_circle_segment(
852 Vector3::new(0.0, -height * 0.5, 0.0),
853 radius,
854 segments,
855 std::f32::consts::PI,
856 std::f32::consts::TAU,
857 transform,
858 color,
859 );
860
861 self.add_line(Line {
862 begin: transform
863 .transform_point(&Point3::new(-radius, height * 0.5, 0.0))
864 .coords,
865 end: transform
866 .transform_point(&Point3::new(-radius, -height * 0.5, 0.0))
867 .coords,
868 color,
869 });
870 self.add_line(Line {
871 begin: transform
872 .transform_point(&Point3::new(radius, height * 0.5, 0.0))
873 .coords,
874 end: transform
875 .transform_point(&Point3::new(radius, -height * 0.5, 0.0))
876 .coords,
877 color,
878 });
879 }
880
881 pub fn draw_capsule(
883 &mut self,
884 radius: f32,
885 height: f32,
886 transform: Matrix4<f32>,
887 color: Color,
888 ) {
889 self.draw_sphere_section(
891 radius,
892 0.0..std::f32::consts::FRAC_PI_2,
893 10,
894 0.0..std::f32::consts::TAU,
895 10,
896 transform * Matrix4::new_translation(&Vector3::new(0.0, height * 0.5 - radius, 0.0)),
897 color,
898 );
899
900 self.draw_sphere_section(
902 radius,
903 std::f32::consts::PI..std::f32::consts::PI * 1.5,
904 10,
905 0.0..std::f32::consts::TAU,
906 10,
907 transform * Matrix4::new_translation(&Vector3::new(0.0, -height * 0.5 + radius, 0.0)),
908 color,
909 );
910
911 let cylinder_height = height - 2.0 * radius;
912
913 if cylinder_height > 0.0 {
914 self.draw_cylinder(10, radius, cylinder_height, false, transform, color);
915 }
916 }
917
918 pub fn draw_segment_flat_capsule(
921 &mut self,
922 begin: Vector2<f32>,
923 end: Vector2<f32>,
924 radius: f32,
925 segments: usize,
926 transform: Matrix4<f32>,
927 color: Color,
928 ) {
929 self.draw_circle(
932 Vector3::new(begin.x, begin.y, 0.0),
933 radius,
934 segments,
935 transform,
936 color,
937 );
938 self.draw_circle(
939 Vector3::new(end.x, end.y, 0.0),
940 radius,
941 segments,
942 transform,
943 color,
944 );
945 let perp = (end - begin)
946 .try_normalize(f32::EPSILON)
947 .map(|v| Vector2::new(v.y, -v.x).scale(radius))
948 .unwrap_or_default();
949
950 self.add_line(Line {
951 begin: transform
952 .transform_point(&Point3::from((begin - perp).to_homogeneous()))
953 .coords,
954 end: transform
955 .transform_point(&Point3::from((end - perp).to_homogeneous()))
956 .coords,
957 color,
958 });
959 self.add_line(Line {
960 begin: transform
961 .transform_point(&Point3::from((begin + perp).to_homogeneous()))
962 .coords,
963 end: transform
964 .transform_point(&Point3::from((end + perp).to_homogeneous()))
965 .coords,
966 color,
967 });
968 }
969
970 pub fn draw_segment_capsule(
972 &mut self,
973 begin: Vector3<f32>,
974 end: Vector3<f32>,
975 radius: f32,
976 v_segments: usize,
977 h_segments: usize,
978 transform: Matrix4<f32>,
979 color: Color,
980 ) {
981 let axis = end - begin;
982 let length = axis.norm();
983
984 let z_axis = axis.try_normalize(f32::EPSILON).unwrap_or_else(Vector3::z);
985
986 let y_axis = z_axis
987 .cross(
988 &(if z_axis.y != 0.0 || z_axis.z != 0.0 {
989 Vector3::x()
990 } else {
991 Vector3::y()
992 }),
993 )
994 .try_normalize(f32::EPSILON)
995 .unwrap_or_else(Vector3::y);
996
997 let x_axis = z_axis
998 .cross(&y_axis)
999 .try_normalize(f32::EPSILON)
1000 .unwrap_or_else(Vector3::x); let shaft_point = |u: f32, v: f32| -> Vector3<f32> {
1003 transform
1004 .transform_point(&Point3::from(
1005 begin
1006 + x_axis.scale((std::f32::consts::TAU * u).cos() * radius)
1007 + y_axis.scale((std::f32::consts::TAU * u).sin() * radius)
1008 + z_axis.scale(v * length),
1009 ))
1010 .coords
1011 };
1012
1013 let start_hemisphere_point = |u: f32, v: f32| -> Vector3<f32> {
1014 let latitude = std::f32::consts::FRAC_PI_2 * (v - 1.0);
1015 transform
1016 .transform_point(&Point3::from(
1017 begin
1018 + x_axis.scale((std::f32::consts::TAU * u).cos() * latitude.cos() * radius)
1019 + y_axis.scale((std::f32::consts::TAU * u).sin() * latitude.cos() * radius)
1020 + z_axis.scale(latitude.sin() * radius),
1021 ))
1022 .coords
1023 };
1024
1025 let end_hemisphere_point = |u: f32, v: f32| -> Vector3<f32> {
1026 let latitude = std::f32::consts::FRAC_PI_2 * v;
1027 transform
1028 .transform_point(&Point3::from(
1029 end + x_axis.scale((std::f32::consts::TAU * u).cos() * latitude.cos() * radius)
1030 + y_axis.scale((std::f32::consts::TAU * u).sin() * latitude.cos() * radius)
1031 + z_axis.scale(latitude.sin() * radius),
1032 ))
1033 .coords
1034 };
1035
1036 let dv = 1.0 / h_segments as f32;
1037 let du = 1.0 / v_segments as f32;
1038
1039 let mut u = 0.0;
1040 while u < 1.0 {
1041 let sa = shaft_point(u, 0.0);
1042 let sb = shaft_point(u, 1.0);
1043 let sc = shaft_point(u + du, 1.0);
1044 let sd = shaft_point(u + du, 0.0);
1045
1046 self.draw_triangle(sa, sb, sc, color);
1047 self.draw_triangle(sa, sc, sd, color);
1048
1049 u += du;
1050 }
1051
1052 u = 0.0;
1053 while u < 1.0 {
1054 let mut v = 0.0;
1055 while v < 1.0 {
1056 let sa = start_hemisphere_point(u, v);
1057 let sb = start_hemisphere_point(u, v + dv);
1058 let sc = start_hemisphere_point(u + du, v + dv);
1059 let sd = start_hemisphere_point(u + du, v);
1060
1061 self.draw_triangle(sa, sb, sc, color);
1062 self.draw_triangle(sa, sc, sd, color);
1063
1064 let ea = end_hemisphere_point(u, v);
1065 let eb = end_hemisphere_point(u, v + dv);
1066 let ec = end_hemisphere_point(u + du, v + dv);
1067 let ed = end_hemisphere_point(u + du, v);
1068
1069 self.draw_triangle(ea, eb, ec, color);
1070 self.draw_triangle(ea, ec, ed, color);
1071
1072 v += dv;
1073 }
1074
1075 u += du;
1076 }
1077 }
1078
1079 pub fn draw_arrow(
1081 &mut self,
1082 sides: usize,
1083 color: Color,
1084 length: f32,
1085 radius: f32,
1086 transform: Matrix4<f32>,
1087 ) {
1088 self.draw_cylinder(sides, radius, length, true, transform, color);
1089
1090 let head_radius = radius * 2.0;
1091 let head_height = radius * 4.0;
1092
1093 self.draw_cone(
1094 sides,
1095 head_radius,
1096 head_height,
1097 transform
1098 * Matrix4::new_translation(&Vector3::new(0.0, (length + head_height) * 0.5, 0.0)),
1099 color,
1100 true,
1101 );
1102 }
1103
1104 pub fn add_line(&mut self, line: Line) {
1106 self.lines.push(line);
1107 }
1108
1109 pub fn clear_lines(&mut self) {
1112 self.lines.clear()
1113 }
1114}