rapier_egui/
lib.rs

1/// Structure to hold the Rapier-Egui inspector state.
2pub 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    /// Create a new rapier inspector.
23    pub fn new() -> Self {
24        Inspector {
25            selected_rigid_body: None,
26            selected_collider: None,
27        }
28    }
29
30    /// Reset all selections.
31    pub fn reset_selection(&mut self) {
32        self.selected_rigid_body = None;
33        self.selected_collider = None;
34    }
35
36    /// Produce a sequence of checkboxes for various render debug modes.
37    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    /// Produce a list of rigid bodies and their colliders.
55    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}