1pub struct Inspector {
3 selected_rigid_body: Option<rapier3d::dynamics::RigidBodyHandle>,
4 selected_collider: Option<rapier3d::geometry::ColliderHandle>,
5}
6
7trait UiValue {
8 fn value(&mut self, v: f32);
9 fn value_vec3(&mut self, v3: &nalgebra::Vector3<f32>) {
10 for &v in v3.as_slice() {
11 self.value(v);
12 }
13 }
14}
15impl UiValue for egui::Ui {
16 fn value(&mut self, v: f32) {
17 self.colored_label(egui::Color32::WHITE, format!("{v:.1}"));
18 }
19}
20
21impl Inspector {
22 pub fn new() -> Self {
24 Inspector {
25 selected_rigid_body: None,
26 selected_collider: None,
27 }
28 }
29
30 pub fn reset_selection(&mut self) {
32 self.selected_rigid_body = None;
33 self.selected_collider = None;
34 }
35
36 pub fn populate_debug_render(
38 &mut self,
39 ui: &mut egui::Ui,
40 debug_render_mode: &mut rapier3d::pipeline::DebugRenderMode,
41 ) {
42 let all_bits = rapier3d::pipeline::DebugRenderMode::all().bits();
43 for bit_pos in 0..=all_bits.ilog2() {
44 let flag = match rapier3d::pipeline::DebugRenderMode::from_bits(1 << bit_pos) {
45 Some(flag) => flag,
46 None => continue,
47 };
48 let mut enabled = debug_render_mode.contains(flag);
49 ui.checkbox(&mut enabled, format!("{flag:?}"));
50 debug_render_mode.set(flag, enabled);
51 }
52 }
53
54 pub fn populate_objects(
56 &mut self,
57 ui: &mut egui::Ui,
58 rigid_bodies: &mut rapier3d::dynamics::RigidBodySet,
59 colliders: &mut rapier3d::geometry::ColliderSet,
60 ) {
61 for (handle, _object) in rigid_bodies.iter() {
62 ui.selectable_value(&mut self.selected_rigid_body, Some(handle), "rigid body");
63 }
64
65 if let Some(rb_handle) = self.selected_rigid_body {
66 let rigid_body = &rigid_bodies[rb_handle];
67 if ui.button("Unselect").clicked() {
68 self.reset_selection();
69 }
70 egui::CollapsingHeader::new("Stats")
71 .default_open(false)
72 .show(ui, |ui| {
73 ui.horizontal(|ui| {
74 ui.label(format!("Position:"));
75 ui.value_vec3(&rigid_body.translation());
76 });
77 ui.horizontal(|ui| {
78 ui.label(format!("Linear velocity:"));
79 ui.value_vec3(&rigid_body.linvel());
80 ui.label(format!("Damping:"));
81 ui.value(rigid_body.linear_damping());
82 });
83 ui.horizontal(|ui| {
84 ui.label(format!("Angular velocity:"));
85 ui.value_vec3(&rigid_body.angvel());
86 ui.label(format!("Damping:"));
87 ui.value(rigid_body.angular_damping());
88 });
89 ui.horizontal(|ui| {
90 ui.label(format!("Kinematic energy:"));
91 ui.value(rigid_body.kinetic_energy());
92 });
93 });
94 ui.heading("Colliders");
95 for &collider in rigid_body.colliders() {
96 let name = "collider";
97 ui.selectable_value(&mut self.selected_collider, Some(collider), name);
98 }
99 }
100
101 if let Some(collider_handle) = self.selected_collider {
102 ui.heading("Properties");
103 let collider = colliders.get_mut(collider_handle).unwrap();
104 let mut mass = collider.mass();
105 if ui
106 .add(
107 egui::DragValue::new(&mut mass)
108 .prefix("Mass: ")
109 .clamp_range(0.0..=1e6),
110 )
111 .changed()
112 {
113 collider.set_mass(mass);
114 }
115 let mut friction = collider.friction();
116 if ui
117 .add(
118 egui::DragValue::new(&mut friction)
119 .prefix("Friction: ")
120 .clamp_range(0.0..=2.0),
121 )
122 .changed()
123 {
124 collider.set_friction(friction);
125 }
126 let mut restitution = collider.restitution();
127 if ui
128 .add(
129 egui::DragValue::new(&mut restitution)
130 .prefix("Restituion: ")
131 .clamp_range(0.0..=1.0),
132 )
133 .changed()
134 {
135 collider.set_restitution(restitution);
136 }
137 }
138 }
139}