rapier_testbed3d_f64/testbed/
testbed.rs1use kiss3d::color::Color;
4use rapier::dynamics::{
5 ImpulseJointSet, IntegrationParameters, MultibodyJointSet, RigidBodyHandle, RigidBodySet,
6};
7use rapier::geometry::{ColliderHandle, ColliderSet};
8use rapier::pipeline::PhysicsHooks;
9
10#[cfg(feature = "dim3")]
11use {glamx::Vec3, rapier::control::DynamicRayCastVehicleController};
12
13use crate::harness::Harness;
14use crate::physics::PhysicsState;
15use crate::settings::ExampleSettings;
16
17use super::graphics_context::TestbedGraphics;
18use super::state::{TestbedActionFlags, TestbedState};
19
20#[cfg(all(feature = "dim3", feature = "other-backends"))]
21use super::OtherBackends;
22
23#[cfg(all(feature = "dim3", feature = "other-backends"))]
24use super::state::{PHYSX_BACKEND_PATCH_FRICTION, PHYSX_BACKEND_TWO_FRICTION_DIR};
25
26#[cfg(all(feature = "dim3", feature = "other-backends"))]
27use crate::physx_backend::PhysxWorld;
28
29use super::Plugins;
30
31#[derive(Clone)]
33pub struct Example {
34 pub name: &'static str,
36 pub group: &'static str,
38 pub builder: fn(&mut Testbed),
40}
41
42impl Example {
43 pub fn new(group: &'static str, name: &'static str, builder: fn(&mut Testbed)) -> Self {
45 Self {
46 name,
47 group,
48 builder,
49 }
50 }
51
52 pub fn demo(name: &'static str, builder: fn(&mut Testbed)) -> Self {
54 Self::new("Demos", name, builder)
55 }
56}
57
58impl From<(&'static str, &'static str, fn(&mut Testbed))> for Example {
60 fn from((group, name, builder): (&'static str, &'static str, fn(&mut Testbed))) -> Self {
61 Self::new(group, name, builder)
62 }
63}
64
65pub type SimulationBuilders = Vec<Example>;
67
68pub struct Testbed<'a> {
70 pub graphics: Option<TestbedGraphics<'a>>,
71 pub harness: &'a mut Harness,
72 pub state: &'a mut TestbedState,
73 #[cfg(all(feature = "dim3", feature = "other-backends"))]
74 pub other_backends: &'a mut OtherBackends,
75 pub plugins: &'a mut Plugins,
76}
77
78impl Testbed<'_> {
79 pub fn set_number_of_steps_per_frame(&mut self, nsteps: usize) {
80 self.state.nsteps = nsteps;
81 }
82
83 #[cfg(feature = "dim3")]
84 pub fn set_vehicle_controller(&mut self, controller: DynamicRayCastVehicleController) {
85 self.state.vehicle_controller = Some(controller);
86 }
87
88 pub fn allow_grabbing_behind_ground(&mut self, allow: bool) {
89 self.state.can_grab_behind_ground = allow;
90 }
91
92 pub fn integration_parameters_mut(&mut self) -> &mut IntegrationParameters {
93 &mut self.harness.physics.integration_parameters
94 }
95
96 pub fn physics_state_mut(&mut self) -> &mut PhysicsState {
97 &mut self.harness.physics
98 }
99
100 pub fn harness(&self) -> &Harness {
101 self.harness
102 }
103
104 pub fn harness_mut(&mut self) -> &mut Harness {
105 self.harness
106 }
107
108 pub fn example_settings_mut(&mut self) -> &mut ExampleSettings {
109 &mut self.state.example_settings
110 }
111
112 pub fn set_world(
113 &mut self,
114 bodies: RigidBodySet,
115 colliders: ColliderSet,
116 impulse_joints: ImpulseJointSet,
117 multibody_joints: MultibodyJointSet,
118 ) {
119 self.set_world_with_params(
120 bodies,
121 colliders,
122 impulse_joints,
123 multibody_joints,
124 rapier::math::Vector::Y * -9.81,
125 (),
126 )
127 }
128
129 pub fn set_world_with_params(
130 &mut self,
131 bodies: RigidBodySet,
132 colliders: ColliderSet,
133 impulse_joints: ImpulseJointSet,
134 multibody_joints: MultibodyJointSet,
135 gravity: rapier::math::Vector,
136 hooks: impl PhysicsHooks + 'static,
137 ) {
138 self.harness.set_world_with_params(
139 bodies,
140 colliders,
141 impulse_joints,
142 multibody_joints,
143 self.state.broad_phase_type,
144 gravity,
145 hooks,
146 );
147
148 self.state
149 .action_flags
150 .set(TestbedActionFlags::RESET_WORLD_GRAPHICS, true);
151
152 #[cfg(feature = "dim3")]
153 {
154 self.state.vehicle_controller = None;
155 }
156
157 #[cfg(all(feature = "dim3", feature = "other-backends"))]
158 {
159 if self.state.selected_backend == PHYSX_BACKEND_PATCH_FRICTION
160 || self.state.selected_backend == PHYSX_BACKEND_TWO_FRICTION_DIR
161 {
162 self.other_backends.physx = Some(PhysxWorld::from_rapier(
163 self.harness.physics.gravity,
164 &self.harness.physics.integration_parameters,
165 &self.harness.physics.bodies,
166 &self.harness.physics.colliders,
167 &self.harness.physics.impulse_joints,
168 &self.harness.physics.multibody_joints,
169 self.state.selected_backend == PHYSX_BACKEND_TWO_FRICTION_DIR,
170 self.harness.state.num_threads(),
171 ));
172 }
173 }
174 }
175
176 pub fn set_graphics_shift(&mut self, shift: rapier::math::Vector) {
177 if !self.state.camera_locked
178 && let Some(graphics) = &mut self.graphics
179 {
180 graphics.graphics.gfx_shift = shift;
181 }
182 }
183
184 #[cfg(feature = "dim2")]
185 pub fn look_at(&mut self, at: glamx::Vec2, zoom: f32) {
186 if !self.state.camera_locked
187 && let Some(graphics) = &mut self.graphics
188 {
189 graphics.camera.set_at(at);
190 graphics.camera.set_zoom(zoom);
191 }
192 }
193
194 #[cfg(feature = "dim3")]
195 pub fn look_at(&mut self, eye: Vec3, at: Vec3) {
196 if !self.state.camera_locked
197 && let Some(graphics) = &mut self.graphics
198 {
199 graphics.camera.look_at(eye, at);
200 }
201 }
202
203 pub fn set_initial_body_color(&mut self, body: RigidBodyHandle, color: Color) {
204 if let Some(graphics) = &mut self.graphics {
205 graphics.graphics.set_initial_body_color(body, color);
206 }
207 }
208
209 pub fn set_initial_collider_color(&mut self, collider: ColliderHandle, color: Color) {
210 if let Some(graphics) = &mut self.graphics {
211 graphics
212 .graphics
213 .set_initial_collider_color(collider, color);
214 }
215 }
216
217 pub fn set_body_wireframe(&mut self, body: RigidBodyHandle, wireframe_enabled: bool) {
218 if let Some(graphics) = &mut self.graphics {
219 graphics
220 .graphics
221 .set_body_wireframe(body, wireframe_enabled);
222 }
223 }
224
225 pub fn add_callback<
226 F: FnMut(
227 Option<&mut TestbedGraphics>,
228 &mut PhysicsState,
229 &crate::physics::PhysicsEvents,
230 &crate::harness::RunState,
231 ) + 'static,
232 >(
233 &mut self,
234 callback: F,
235 ) {
236 self.harness.add_callback(callback);
237 }
238
239 pub fn add_plugin(&mut self, mut plugin: impl crate::plugin::TestbedPlugin + 'static) {
240 plugin.init_plugin();
241 self.plugins.0.push(Box::new(plugin));
242 }
243}