polytope_playground/
guides.rs1use glam::{Vec2, Vec3};
2use loam::math::{EuclideanR4, Rotor};
3use loam::runtime::{DomainHandle, PointRecord, SegmentRecord, Session};
4
5use crate::consts::FLOOR_Y;
6use crate::mode::Mode;
7use crate::toy::{ARENA_HALF, BODY_SIZE};
8use crate::Playground;
9
10const HANDLE_COLOR: [f32; 4] = [1.0, 0.85, 0.25, 1.0];
11
12#[derive(Default)]
13pub(crate) struct Guides {
14 pub(crate) lines: Vec<SegmentRecord>,
15 pub(crate) points: Vec<PointRecord>,
16}
17
18impl Guides {
19 pub(crate) fn update(
20 &mut self,
21 session: &Session<Playground>,
22 domain: DomainHandle<EuclideanR4>,
23 alpha: f32,
24 ) {
25 self.lines.clear();
26 self.points.clear();
27 if *session.app.mode.get() != Mode::Toybox
28 || session.app.strip.get().on
29 || !*session.app.guides.get()
30 {
31 return;
32 }
33 self.rectangle(
34 Vec2::splat(-ARENA_HALF),
35 Vec2::splat(ARENA_HALF),
36 [0.55, 0.60, 0.68, 1.0],
37 );
38 let Some(drag) = session.dragging() else {
39 return;
40 };
41 let Some(polytope) = session
42 .app
43 .slots
44 .get(drag.entity)
45 .and_then(|slot| slot.entry.shape.polytope4())
46 else {
47 return;
48 };
49 let Ok(r4) = session.domains().read(domain) else {
50 return;
51 };
52 if *session.app.toybox_debug.get() {
53 let placement = session
54 .views()
55 .to_root(drag.image)
56 .and_then(|to| to.rigid());
57 let anchor = r4
58 .physics()
59 .and_then(|physics| physics.held_anchor(drag.entity));
60 if let (Some(anchor), Some(tick), Some(drawn), Some(placement), Some(view), Some(eye)) = (
61 anchor,
62 r4.poses().get(drag.entity),
63 r4.drawn_pose(drag.entity, alpha),
64 placement,
65 r4.view(drag.view),
66 r4.view_eye(drag.view)
67 .and_then(|eye| r4.drawn_pose(eye, alpha)),
68 ) {
69 let anchor = drawn.point
70 + drawn
71 .frame
72 .apply(tick.frame.inverse().apply(anchor - tick.point));
73 if let Some(point) = view.mapping().image_point(&eye, anchor) {
74 self.points.push(PointRecord {
75 position: placement.apply(point),
76 radius_px: 6.0,
77 color: HANDLE_COLOR,
78 });
79 }
80 }
81 }
82 let Some(pose) = r4.drawn_pose(drag.entity, alpha) else {
83 return;
84 };
85 let mut min = Vec2::splat(f32::INFINITY);
86 let mut max = Vec2::splat(f32::NEG_INFINITY);
87 for vertex in polytope.topology().vertices {
88 let point = pose.point + pose.frame.apply(*vertex * BODY_SIZE);
89 let xz = Vec2::new(point.x, point.z);
90 min = min.min(xz);
91 max = max.max(xz);
92 }
93 self.rectangle(min, max, HANDLE_COLOR);
94 }
95
96 fn rectangle(&mut self, min: Vec2, max: Vec2, color: [f32; 4]) {
97 let y = FLOOR_Y + 0.002;
98 let corners = [
99 Vec3::new(min.x, y, min.y),
100 Vec3::new(max.x, y, min.y),
101 Vec3::new(max.x, y, max.y),
102 Vec3::new(min.x, y, max.y),
103 ];
104 for index in 0..4 {
105 self.lines.push(SegmentRecord {
106 start: corners[index].to_array(),
107 end: corners[(index + 1) % 4].to_array(),
108 start_color: color,
109 end_color: color,
110 width_px: 1.5,
111 ..SegmentRecord::default()
112 });
113 }
114 }
115}