aboutsummaryrefslogtreecommitdiff
path: root/src_testbed/testbed.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src_testbed/testbed.rs')
-rw-r--r--src_testbed/testbed.rs1940
1 files changed, 838 insertions, 1102 deletions
diff --git a/src_testbed/testbed.rs b/src_testbed/testbed.rs
index d885c8a..6e314c8 100644
--- a/src_testbed/testbed.rs
+++ b/src_testbed/testbed.rs
@@ -1,22 +1,14 @@
use std::env;
use std::mem;
-use std::path::Path;
-use std::rc::Rc;
+
+use bevy::pbr::Light;
+use bevy::prelude::*;
use crate::physics::{PhysicsEvents, PhysicsSnapshot, PhysicsState};
use crate::plugin::TestbedPlugin;
-use crate::ui::TestbedUi;
-use crate::{engine::GraphicsManager, harness::RunState};
-
-use kiss3d::camera::Camera;
-use kiss3d::event::Event;
-use kiss3d::event::{Action, Key, WindowEvent};
-use kiss3d::light::Light;
-use kiss3d::loader::obj;
-use kiss3d::planar_camera::PlanarCamera;
-use kiss3d::post_processing::PostProcessingEffect;
-use kiss3d::text::Font;
-use kiss3d::window::{State, Window};
+use crate::ui;
+use crate::{graphics::GraphicsManager, harness::RunState};
+
use na::{self, Point2, Point3, Vector3};
use rapier::dynamics::{
IntegrationParameters, JointSet, RigidBodyActivation, RigidBodyHandle, RigidBodySet,
@@ -34,6 +26,15 @@ use crate::harness::Harness;
use crate::nphysics_backend::NPhysicsWorld;
#[cfg(all(feature = "dim3", feature = "other-backends"))]
use crate::physx_backend::PhysxWorld;
+use bevy::render::camera::Camera;
+use bevy::render::wireframe::WireframePlugin;
+use bevy::wgpu::{WgpuFeature, WgpuFeatures, WgpuOptions};
+use bevy_egui::EguiContext;
+
+#[cfg(feature = "dim2")]
+use crate::camera::{OrbitCamera, OrbitCameraPlugin};
+#[cfg(feature = "dim3")]
+use bevy_orbit_controls::{OrbitCamera, OrbitCameraPlugin};
const RAPIER_BACKEND: usize = 0;
#[cfg(feature = "other-backends")]
@@ -48,7 +49,6 @@ pub enum RunMode {
Running,
Stop,
Step,
- Quit,
}
#[cfg(not(feature = "log"))]
@@ -83,8 +83,6 @@ bitflags! {
const CENTER_OF_MASSES = 1 << 7;
const WIREFRAME = 1 << 8;
const STATISTICS = 1 << 9;
- const PROFILE = 1 << 10;
- const DEBUG = 1 << 11;
}
}
@@ -117,33 +115,54 @@ pub struct TestbedState {
pub selected_backend: usize,
pub physx_use_two_friction_directions: bool,
pub snapshot: Option<PhysicsSnapshot>,
+ nsteps: usize,
+ camera_locked: bool, // Used so that the camera can remain the same before and after we change backend or press the restart button.
+}
+
+struct SceneBuilders(Vec<(&'static str, fn(&mut Testbed))>);
+
+#[cfg(feature = "other-backends")]
+struct OtherBackends {
+ #[cfg(feature = "dim2")]
+ box2d: Option<Box2dWorld>,
+ #[cfg(feature = "dim3")]
+ physx: Option<PhysxWorld>,
+ nphysics: Option<NPhysicsWorld>,
+}
+struct Plugins(Vec<Box<dyn TestbedPlugin>>);
+
+pub struct TestbedGraphics<'a, 'b, 'c, 'd> {
+ manager: &'a mut GraphicsManager,
+ commands: &'a mut Commands<'d>,
+ meshes: &'a mut Assets<Mesh>,
+ materials: &'a mut Assets<StandardMaterial>,
+ components: &'a mut Query<'b, (&'c mut Transform,)>,
+ camera: &'a mut OrbitCamera,
}
-pub struct Testbed {
- builders: Vec<(&'static str, fn(&mut Testbed))>,
+pub struct Testbed<'a, 'b, 'c, 'd> {
+ graphics: Option<TestbedGraphics<'a, 'b, 'c, 'd>>,
+ harness: &'a mut Harness,
+ state: &'a mut TestbedState,
+ #[cfg(feature = "other-backends")]
+ other_backends: &'a mut OtherBackends,
+ plugins: &'a mut Plugins,
+}
+
+pub struct TestbedApp {
+ builders: SceneBuilders,
graphics: GraphicsManager,
- nsteps: usize,
- camera_locked: bool, // Used so that the camera can remain the same before and after we change backend or press the restart button.
- plugins: Vec<Box<dyn TestbedPlugin>>,
- // persistant_contacts: HashMap<ContactId, bool>,
- font: Rc<Font>,
- cursor_pos: Point2<f32>,
- ui: Option<TestbedUi>,
state: TestbedState,
harness: Harness,
- #[cfg(all(feature = "dim2", feature = "other-backends"))]
- box2d: Option<Box2dWorld>,
- #[cfg(all(feature = "dim3", feature = "other-backends"))]
- physx: Option<PhysxWorld>,
#[cfg(feature = "other-backends")]
- nphysics: Option<NPhysicsWorld>,
+ other_backends: OtherBackends,
+ plugins: Plugins,
}
-impl Testbed {
- pub fn new_empty() -> Testbed {
+impl TestbedApp {
+ pub fn new_empty() -> Self {
let graphics = GraphicsManager::new();
let flags = TestbedStateFlags::SLEEP;
- let ui = None;
#[allow(unused_mut)]
let mut backend_names = vec!["rapier"];
@@ -174,39 +193,33 @@ impl Testbed {
selected_example: 0,
selected_backend: RAPIER_BACKEND,
physx_use_two_friction_directions: true,
+ nsteps: 1,
+ camera_locked: false,
};
let harness = Harness::new_empty();
+ #[cfg(feature = "other-backends")]
+ let other_backends = OtherBackends {
+ #[cfg(feature = "dim2")]
+ box2d: None,
+ #[cfg(feature = "dim3")]
+ physx: None,
+ nphysics: None,
+ };
- Testbed {
- builders: Vec::new(),
- plugins: Vec::new(),
+ TestbedApp {
+ builders: SceneBuilders(Vec::new()),
+ plugins: Plugins(Vec::new()),
graphics,
- nsteps: 1,
- camera_locked: false,
- // persistant_contacts: HashMap::new(),
- font: Font::default(),
- cursor_pos: Point2::new(0.0f32, 0.0),
- ui,
state,
harness,
- #[cfg(all(feature = "dim2", feature = "other-backends"))]
- box2d: None,
- #[cfg(all(feature = "dim3", feature = "other-backends"))]
- physx: None,
#[cfg(feature = "other-backends")]
- nphysics: None,
+ other_backends,
}
}
- pub fn new(bodies: RigidBodySet, colliders: ColliderSet, joints: JointSet) -> Self {
- let mut res = Self::new_empty();
- res.harness.set_world(bodies, colliders, joints);
- res
- }
-
- pub fn from_builders(default: usize, builders: Vec<(&'static str, fn(&mut Self))>) -> Self {
- let mut res = Testbed::new_empty();
+ pub fn from_builders(default: usize, builders: Vec<(&'static str, fn(&mut Testbed))>) -> Self {
+ let mut res = TestbedApp::new_empty();
res.state
.action_flags
.set(TestbedActionFlags::EXAMPLE_CHANGED, true);
@@ -215,191 +228,9 @@ impl Testbed {
res
}
- pub fn set_number_of_steps_per_frame(&mut self, nsteps: usize) {
- self.nsteps = nsteps
- }
-
- pub fn allow_grabbing_behind_ground(&mut self, allow: bool) {
- self.state.can_grab_behind_ground = allow;
- }
-
- pub fn integration_parameters_mut(&mut self) -> &mut IntegrationParameters {
- &mut self.harness.physics.integration_parameters
- }
-
- pub fn physics_state_mut(&mut self) -> &mut PhysicsState {
- &mut self.harness.physics
- }
-
- pub fn harness_mut(&mut self) -> &mut Harness {
- &mut self.harness
- }
-
- pub fn set_world(&mut self, bodies: RigidBodySet, colliders: ColliderSet, joints: JointSet) {
- self.set_world_with_params(bodies, colliders, joints, Vector::y() * -9.81, ())
- }
-
- pub fn set_world_with_params(
- &mut self,
- bodies: RigidBodySet,
- colliders: ColliderSet,
- joints: JointSet,
- gravity: Vector<f32>,
- hooks: impl PhysicsHooks<RigidBodySet, ColliderSet> + 'static,
- ) {
- self.harness
- .set_world_with_params(bodies, colliders, joints, gravity, hooks);
-
- self.state
- .action_flags
- .set(TestbedActionFlags::RESET_WORLD_GRAPHICS, true);
-
- self.state.highlighted_body = None;
-
- #[cfg(all(feature = "dim2", feature = "other-backends"))]
- {
- if self.state.selected_backend == BOX2D_BACKEND {
- self.box2d = Some(Box2dWorld::from_rapier(
- self.harness.physics.gravity,
- &self.harness.physics.bodies,
- &self.harness.physics.colliders,
- &self.harness.physics.joints,
- ));
- }
- }
-
- #[cfg(all(feature = "dim3", feature = "other-backends"))]
- {
- if self.state.selected_backend == PHYSX_BACKEND_PATCH_FRICTION
- || self.state.selected_backend == PHYSX_BACKEND_TWO_FRICTION_DIR
- {
- self.physx = Some(PhysxWorld::from_rapier(
- self.harness.physics.gravity,
- &self.harness.physics.integration_parameters,
- &self.harness.physics.bodies,
- &self.harness.physics.colliders,
- &self.harness.physics.joints,
- self.state.selected_backend == PHYSX_BACKEND_TWO_FRICTION_DIR,
- self.harness.state.num_threads,
- ));
- }
- }
-
- #[cfg(feature = "other-backends")]
- {
- if self.state.selected_backend == NPHYSICS_BACKEND {
- self.nphysics = Some(NPhysicsWorld::from_rapier(
- self.harness.physics.gravity,
- &self.harness.physics.bodies,
- &self.harness.physics.colliders,
- &self.harness.physics.joints,
- ));
- }
- }
- }
-
- pub fn set_builders(&mut self, builders: Vec<(&'static str, fn(&mut Self))>) {
+ pub fn set_builders(&mut self, builders: Vec<(&'static str, fn(&mut Testbed))>) {
self.state.example_names = builders.iter().map(|e| e.0).collect();
- self.builders = builders
- }
-
- #[cfg(feature = "dim2")]
- pub fn look_at(&mut self, at: Point2<f32>, zoom: f32) {
- if !self.camera_locked {
- self.graphics.look_at(at, zoom);
- }
- }
-
- #[cfg(feature = "dim3")]
- pub fn look_at(&mut self, eye: Point3<f32>, at: Point3<f32>) {
- if !self.camera_locked {
- self.graphics.look_at(eye, at);
- }
- }
-
- pub fn set_body_color(&mut self, body: RigidBodyHandle, color: Point3<f32>) {
- self.graphics.set_body_color(body, color);
- }
-
- pub fn set_collider_initial_color(&mut self, collider: ColliderHandle, color: Point3<f32>) {
- self.graphics.set_collider_initial_color(collider, color);
- }
-
- pub fn set_body_wireframe(&mut self, body: RigidBodyHandle, wireframe_enabled: bool) {
- self.graphics.set_body_wireframe(body, wireframe_enabled);
- }
-
- // pub fn world(&self) -> &Box<WorldOwner> {
- // &self.world
- // }
-
- pub fn graphics_mut(&mut self) -> &mut GraphicsManager {
- &mut self.graphics
- }
-
- #[cfg(feature = "dim3")]
- pub fn set_up_axis(&mut self, up_axis: Vector3<f32>) {
- self.graphics.set_up_axis(up_axis);
- }
-
- pub fn load_obj(path: &str) -> Vec<(Vec<Point3<f32>>, Vec<usize>)> {
- let path = Path::new(path);
- let empty = Path::new("_some_non_existant_folder"); // dont bother loading mtl files correctly
- let objects = obj::parse_file(&path, &empty, "").expect("Unable to open the obj file.");
-
- let mut res = Vec::new();
-
- for (_, m, _) in objects.into_iter() {
- let vertices = m.coords().read().unwrap().to_owned().unwrap();
- let indices = m.faces().read().unwrap().to_owned().unwrap();
-
- let mut flat_indices = Vec::new();
-
- for i in indices.into_iter() {
- flat_indices.push(i.x as usize);
- flat_indices.push(i.y as usize);
- flat_indices.push(i.z as usize);
- }
-
- let m = (vertices, flat_indices);
-
- res.push(m);
- }
-
- res
- }
-
- fn clear(&mut self, window: &mut Window) {
- // self.persistant_contacts.clear();
- // self.state.grabbed_object = None;
- // self.state.grabbed_object_constraint = None;
- self.state.can_grab_behind_ground = false;
- self.graphics.clear(window);
-
- for plugin in &mut self.plugins {
- plugin.clear_graphics(window);
- }
-
- self.plugins.clear();
- }
-
- pub fn add_callback<
- F: FnMut(
- Option<&mut Window>,
- Option<&mut GraphicsManager>,
- &mut PhysicsState,
- &PhysicsEvents,
- &RunState,
- ) + 'static,
- >(
- &mut self,
- callback: F,
- ) {
- self.harness.add_callback(callback);
- }
-
- pub fn add_plugin(&mut self, plugin: impl TestbedPlugin + 'static) {
- self.plugins.push(Box::new(plugin));
+ self.builders = SceneBuilders(builders)
}
pub fn run(mut self) {
@@ -426,7 +257,7 @@ impl Testbed {
use std::io::{BufWriter, Write};
// Don't enter the main loop. We will just step the simulation here.
let mut results = Vec::new();
- let builders = mem::replace(&mut self.builders, Vec::new());
+ let builders = mem::replace(&mut self.builders.0, Vec::new());
let backend_names = self.state.backend_names.clone();
for builder in builders {
@@ -460,7 +291,15 @@ impl Testbed {
.max_position_iterations = 1;
}
// Init world.
- (builder.1)(&mut self);
+ let mut testbed = Testbed {
+ graphics: None,
+ state: &mut self.state,
+ harness: &mut self.harness,
+ #[cfg(feature = "other-backends")]
+ other_backends: &mut self.other_backends,
+ plugins: &mut self.plugins,
+ };
+ (builder.1)(&mut testbed);
// Run the simulation.
let mut timings = Vec::new();
for k in 0..=NUM_ITERS {
@@ -472,11 +311,11 @@ impl Testbed {
#[cfg(all(feature = "dim2", feature = "other-backends"))]
{
if self.state.selected_backend == BOX2D_BACKEND {
- self.box2d.as_mut().unwrap().step(
+ self.other_backends.box2d.as_mut().unwrap().step(
&mut self.harness.physics.pipeline.counters,
&self.harness.physics.integration_parameters,
);
- self.box2d.as_mut().unwrap().sync(
+ self.other_backends.box2d.as_mut().unwrap().sync(
&mut self.harness.physics.bodies,
&mut self.harness.physics.colliders,
);
@@ -489,11 +328,11 @@ impl Testbed {
|| self.state.selected_backend == PHYSX_BACKEND_TWO_FRICTION_DIR
{
// println!("Step");
- self.physx.as_mut().unwrap().step(
+ self.other_backends.physx.as_mut().unwrap().step(
&mut self.harness.physics.pipeline.counters,
&self.harness.physics.integration_parameters,
);
- self.physx.as_mut().unwrap().sync(
+ self.other_backends.physx.as_mut().unwrap().sync(
&mut self.harness.physics.bodies,
&mut self.harness.physics.colliders,
);
@@ -503,11 +342,11 @@ impl Testbed {
#[cfg(feature = "other-backends")]
{
if self.state.selected_backend == NPHYSICS_BACKEND {
- self.nphysics.as_mut().unwrap().step(
+ self.other_backends.nphysics.as_mut().unwrap().step(
&mut self.harness.physics.pipeline.counters,
&self.harness.physics.integration_parameters,
);
- self.nphysics.as_mut().unwrap().sync(
+ self.other_backends.nphysics.as_mut().unwrap().sync(
&mut self.harness.physics.bodies,
&mut self.harness.physics.colliders,
);
@@ -543,960 +382,857 @@ impl Testbed {
}
}
} else {
- #[cfg(feature = "dim3")]
- let mut window = Window::new("rapier: 3d demo");
- #[cfg(feature = "dim2")]
- let mut window = Window::new("rapier: 2d demo");
- window.set_background_color(0.85, 0.85, 0.85);
- window.set_framerate_limit(Some(60));
- window.set_light(Light::StickToCamera);
- self.ui = Some(TestbedUi::new(&mut window));
- window.render_loop(self);
+ let title = if cfg!(feature = "dim2") {
+ "Rapier: 2D demos".to_string()
+ } else {
+ "Rapier: 3D demos".to_string()
+ };
+
+ let mut app = App::build();
+
+ app.insert_resource(WindowDescriptor {
+ title,
+ vsync: true,
+ ..Default::default()
+ })
+ .insert_resource(ClearColor(Color::rgb(0.85, 0.85, 0.85)))
+ .insert_resource(Msaa { samples: 2 })
+ .insert_resource(WgpuOptions {
+ features: WgpuFeatures {
+ // The Wireframe requires NonFillPolygonMode feature
+ features: vec![WgpuFeature::NonFillPolygonMode],
+ },
+ ..Default::default()
+ })
+ .add_plugins(DefaultPlugins)
+ .add_plugin(OrbitCameraPlugin)
+ .add_plugin(WireframePlugin)
+ .add_plugin(bevy_egui::EguiPlugin);
+
+ #[cfg(target_arch = "wasm32")]
+ app.add_plugin(bevy_webgl2::WebGL2Plugin);
+
+ #[cfg(feature = "other-backends")]
+ app.insert_non_send_resource(self.other_backends);
+
+ app.add_startup_system(setup_graphics_environment.system())
+ .insert_non_send_resource(self.graphics)
+ .insert_resource(self.state)
+ .insert_non_send_resource(self.harness)
+ .insert_resource(self.builders)
+ .insert_non_send_resource(self.plugins)
+ .add_stage_before(CoreStage::Update, "physics", SystemStage::single_threaded())
+ .add_system_to_stage("physics", update_testbed.system())
+ .run();
}
}
+}
- fn handle_common_event<'b>(&mut self, event: Event<'b>) -> Event<'b> {
- match event.value {
- WindowEvent::Key(Key::T, Action::Release, _) => {
- if self.state.running == RunMode::Stop {
- self.state.running = RunMode::Running;
- } else {
- self.state.running = RunMode::Stop;
- }
- }
- WindowEvent::Key(Key::S, Action::Release, _) => self.state.running = RunMode::Step,
- WindowEvent::Key(Key::R, Action::Release, _) => self
- .state
- .action_flags
- .set(TestbedActionFlags::EXAMPLE_CHANGED, true),
- WindowEvent::Key(Key::C, Action::Release, _) => {
- // Delete 1 collider of 10% of the remaining dynamic bodies.
- let mut colliders: Vec<_> = self
- .harness
- .physics
- .bodies
- .iter()
- .filter(|e| e.1.is_dynamic())
- .filter(|e| !e.1.colliders().is_empty())
- .map(|e| e.1.colliders().to_vec())
- .collect();
- colliders.sort_by_key(|co| -(co.len() as isize));
-
- let num_to_delete = (colliders.len() / 10).max(1);
- for to_delete in &colliders[..num_to_delete] {
- self.harness.physics.colliders.remove(
- to_delete[0],
- &mut self.harness.physics.islands,
- &mut self.harness.physics.bodies,
- true,
- );
- }
- }
- WindowEvent::Key(Key::D, Action::Release, _) => {
- // Delete 10% of the remaining dynamic bodies.
- let dynamic_bodies: Vec<_> = self
- .harness
- .physics
- .bodies
- .iter()
- .filter(|e| !e.1.is_static())
- .map(|e| e.0)
- .collect();
- let num_to_delete = (dynamic_bodies.len() / 10).max(1);
- for to_delete in &dynamic_bodies[..num_to_delete] {
- self.harness.physics.bodies.remove(
- *to_delete,
- &mut self.harness.physics.islands,
- &mut self.harness.physics.colliders,
- &mut self.harness.physics.joints,
- );
- }
- }
- WindowEvent::Key(Key::J, Action::Release, _) => {
- // Delete 10% of the remaining joints.
- let joints: Vec<_> = self.harness.physics.joints.iter().map(|e| e.0).collect();
- let num_to_delete = (joints.len() / 10).max(1);
- for to_delete in &joints[..num_to_delete] {
- self.harness.physics.joints.remove(
- *to_delete,
- &mut self.harness.physics.islands,
- &mut self.harness.physics.bodies,
- true,
- );
- }
- }
- WindowEvent::CursorPos(x, y, _) => {
- self.cursor_pos.x = x as f32;
- self.cursor_pos.y = y as f32;
- }
- _ => {}
- }
+impl<'a, 'b, 'c, 'd> TestbedGraphics<'a, 'b, 'c, 'd> {
+ pub fn set_body_color(&mut self, body: RigidBodyHandle, color: Point3<f32>) {
+ self.manager
+ .set_body_color(&mut self.materials, body, color);
+ }
- event
+ pub fn add_body(
+ &mut self,
+ handle: RigidBodyHandle,
+ bodies: &RigidBodySet,
+ colliders: &ColliderSet,
+ ) {
+ self.manager.add(
+ &mut *self.commands,
+ &mut *self.meshes,
+ &mut *self.materials,
+ &mut *self.components,
+ handle,
+ bodies,
+ colliders,
+ )
}
- #[cfg(feature = "dim2")]
- fn handle_special_event(&mut self, window: &mut Window, _event: Event) {
- if window.is_conrod_ui_capturing_mouse() {
- return;
+ pub fn remove_collider(&mut self, handle: ColliderHandle, colliders: &ColliderSet) {
+ if let Some(parent_handle) = colliders.get(handle).map(|c| c.parent()) {
+ self.manager
+ .remove_collider_nodes(&mut *self.commands, parent_handle, handle)
}
+ }
- /*
- match event.value {
- WindowEvent::MouseButton(MouseButton::Button1, Action::Press, modifier) => {
- let all_groups = &CollisionGroups::new();
- for b in self.geometrical_world.interferences_with_point(
- &self.colliders,
- &self.cursor_pos,
- all_groups,
- ) {
- if !b.1.query_type().is_proximity_query()
- && Some(b.1.body()) != self.ground_handle
- {
- if let ColliderAnchor::OnBodyPart { body_part, .. } = b.1.anchor() {
- self.state.grabbed_object = Some(*body_part);
- } else {
- continue;
- }
- }
- }
-
- if modifier.contains(Modifiers::Shift) {
- if let Some(body_part) = self.state.grabbed_object {
- if Some(body_part.0) != self.ground_handle {
- self.graphics.remove_body_nodes(window, body_part.0);
- self.bodies.remove(body_part.0);
- }
- }
-
- self.state.grabbed_object = None;
- } else if modifier.contains(Modifiers::Alt) {
- self.state.drawing_ray = Some(self.cursor_pos);
- } else if !modifier.contains(Modifiers::Control) {
- if let Some(body) = self.state.grabbed_object {
- if let Some(joint) = self.state.grabbed_object_constraint {
- let _ = self.constraints.remove(joint);
- }
+ pub fn remove_body(&mut self, handle: RigidBodyHandle) {
+ self.manager.remove_body_nodes(&mut *self.commands, handle)
+ }
- let body_pos = self
- .bodies
- .get(body.0)
- .unwrap()
- .part(body.1)
- .unwrap()
- .position();
- let attach1 = self.cursor_pos;
- let attach2 = body_pos.inv_mul(&attach1);
-
- if let Some(ground) = self.ground_handle {
- let joint = MouseConstraint::new(
- BodyPartHandle(ground, 0),
- body,
- attach1,
- attach2,
- 1.0,
- );
- self.state.grabbed_object_constraint =
- Some(self.constraints.insert(joint));
- }
+ pub fn add_collider(&mut self, handle: ColliderHandle, colliders: &ColliderSet) {
+ self.manager.add_collider(
+ &mut *self.commands,
+ &mut *self.meshes,
+ &mut *self.materials,
+ handle,
+ colliders,
+ )
+ }
+}
- for node in self.graphics.body_nodes_mut(body.0).unwrap().iter_mut() {
- node.select()
- }
- }
+impl<'a, 'b, 'c, 'd> Testbed<'a, 'b, 'c, 'd> {
+ pub fn set_number_of_steps_per_frame(&mut self, nsteps: usize) {
+ self.state.nsteps = nsteps
+ }
- event.inhibited = true;
- } else {
- self.state.grabbed_object = None;
- }
- }
- WindowEvent::MouseButton(MouseButton::Button1, Action::Release, _) => {
- if let Some(body) = self.state.grabbed_object {
- for n in self.graphics.body_nodes_mut(body.0).unwrap().iter_mut() {
- n.unselect()
- }
- }
+ pub fn allow_grabbing_behind_ground(&mut self, allow: bool) {
+ self.state.can_grab_behind_ground = allow;
+ }
- if let Some(joint) = self.state.grabbed_object_constraint {
- let _ = self.constraints.remove(joint);
- }
+ pub fn integration_parameters_mut(&mut self) -> &mut IntegrationParameters {
+ &mut self.harness.physics.integration_parameters
+ }
- if let Some(start) = self.state.drawing_ray {
- self.graphics
- .add_ray(Ray::new(start, self.cursor_pos - start));
- }
+ pub fn physics_state_mut(&mut self) -> &mut PhysicsState {
+ &mut self.harness.physics
+ }
- self.state.drawing_ray = None;
- self.state.grabbed_object = None;
- self.state.grabbed_object_constraint = None;
- }
- WindowEvent::CursorPos(x, y, modifiers) => {
- self.cursor_pos.x = x as f32;
- self.cursor_pos.y = y as f32;
-
- self.cursor_pos = self
- .graphics
- .camera()
- .unproject(&self.cursor_pos, &na::convert(window.size()));
-
- let attach2 = self.cursor_pos;
- if self.state.grabbed_object.is_some() {
- if let Some(constraint) = self
- .state
- .grabbed_object_constraint
- .and_then(|joint| self.constraints.get_mut(joint))
- .and_then(|joint| {
- joint.downcast_mut::<MouseConstraint<f32, RigidBodyHandle>>()
- })
- {
- constraint.set_anchor_1(attach2);
- }
- }
+ pub fn harness_mut(&mut self) -> &mut Harness {
+ &mut self.harness
+ }
- event.inhibited =
- modifiers.contains(Modifiers::Control) || modifiers.contains(Modifiers::Shift);
- }
- _ => {}
- }
- */
+ pub fn set_world(&mut self, bodies: RigidBodySet, colliders: ColliderSet, joints: JointSet) {
+ self.set_world_with_params(bodies, colliders, joints, Vector::y() * -9.81, ())
}
- #[cfg(feature = "dim3")]
- fn handle_special_event(&mut self, window: &mut Window, event: Event) {
- use rapier::dynamics::RigidBodyBuilder;
- use rapier::geometry::ColliderBuilder;
+ pub fn set_world_with_params(
+ &mut self,
+ bodies: RigidBodySet,
+ colliders: ColliderSet,
+ joints: JointSet,
+ gravity: Vector<f32>,
+ hooks: impl PhysicsHooks<RigidBodySet, ColliderSet> + 'static,
+ ) {
+ self.harness
+ .set_world_with_params(bodies, colliders, joints, gravity, hooks);
- if window.is_conrod_ui_capturing_mouse() {
- return;
- }
+ self.state
+ .action_flags
+ .set(TestbedActionFlags::RESET_WORLD_GRAPHICS, true);
+
+ self.state.highlighted_body = None;
- match event.value {
- WindowEvent::Key(Key::Space, Action::Release, _) => {
- let cam_pos = self.graphics.camera().view_transform().inverse();
- let forward = cam_pos * -Vector::z();
- let vel = forward * 1000.0;
-
- let bodies = &mut self.harness.physics.bodies;
- let colliders = &mut self.harness.physics.colliders;
-
- let collider = ColliderBuilder::cuboid(4.0, 2.0, 0.4).density(20.0).build();
- // let collider = ColliderBuilder::ball(2.0).density(1.0).build();
- let body = RigidBodyBuilder::new_dynamic()
- .position(cam_pos)
- .linvel(vel.x, vel.y, vel.z)
- .ccd_enabled(true)
- .build();
-
- let body_handle = bodies.insert(body);
- colliders.insert(collider, body_handle, bodies);
- self.graphics.add(window, body_handle, bodies, colliders);
+ #[cfg(all(feature = "dim2", feature = "other-backends"))]
+ {
+ if self.state.selected_backend == BOX2D_BACKEND {
+ self.other_backends.box2d = Some(Box2dWorld::from_rapier(
+ self.harness.physics.gravity,
+ &self.harness.physics.bodies,
+ &self.harness.physics.colliders,
+ &self.harness.physics.joints,
+ ));
}
- _ => {}
}
- /*
- match event.value {
- WindowEvent::MouseButton(MouseButton::Button1, Action::Press, modifier) => {
- if modifier.contains(Modifiers::Alt) {
- let size = window.size();
- let (pos, dir) = self
- .graphics
- .camera()
- .unproject(&self.cursor_pos, &na::convert(size));
- let ray = Ray::new(pos, dir);
- self.graphics.add_ray(ray);
-
- event.inhibited = true;
- } else if modifier.contains(Modifiers::Shift) {
- // XXX: huge and ugly code duplication for the ray cast.
- let size = window.size();
- let (pos, dir) = self
- .graphics
- .camera()
- .unproject(&self.cursor_pos, &na::convert(size));
- let ray = Ray::new(pos, dir);
-
- // cast the ray
- let mut mintoi = Bounded::max_value();
- let mut minb = None;
-
- let all_groups = CollisionGroups::new();
- for (_, b, inter) in self.geometrical_world.interferences_with_ray(
- &self.colliders,
- &ray,
- std::f32::MAX,
- &all_groups,
- ) {
- if !b.query_type().is_proximity_query() && inter.toi < mintoi {
- mintoi = inter.toi;
-
- let subshape = b.shape().subshape_containing_feature(inter.feature);
- minb = Some(b.body_part(subshape));
- }
- }
-
- if let Some(body_part) = minb {
- if modifier.contains(Modifiers::Control) {
- if Some(body_part.0) != self.ground_handle {
- self.graphics.remove_body_nodes(window, body_part.0);
- self.bodies.remove(body_part.0);
- }
- } else {
- self.bodies
- .get_mut(body_part.0)
- .unwrap()
- .apply_force_at_point(
- body_part.1,
- &(ray.dir.normalize() * 0.01),
- &ray.point_at(mintoi),
- ForceType::Impulse,
- true,
- );
- }
- }
-
- event.inhibited = true;
- } else if !modifier.contains(Modifiers::Control) {
- match self.state.grabbed_object {
- Some(body) => {
- for n in self.graphics.body_nodes_mut(body.0).unwrap().iter_mut() {
- n.unselect()
- }
- }
- None => {}
- }
-
- // XXX: huge and uggly code duplication for the ray cast.
- let size = window.size();
- let (pos, dir) = self
- .graphics
- .camera()
- .unproject(&self.cursor_pos, &na::convert(size));
- let ray = Ray::new(pos, dir);
-
- // cast the ray
- let mut mintoi = Bounded::max_value();
- let mut minb = None;
-
- let all_groups = CollisionGroups::new();
- for (_, b, inter) in self.geometrical_world.interferences_with_ray(
- &self.colliders,
- &ray,
- std::f32::MAX,
- &all_groups,
- ) {
- if ((Some(b.body()) != self.ground_handle)
- || self.state.can_grab_behind_ground)
- && !b.query_type().is_proximity_query()
- && inter.toi < mintoi
- {
- mintoi = inter.toi;
-
- let subshape = b.shape().subshape_containing_feature(inter.feature);
- minb = Some(b.body_part(subshape));
- }
- }
-
- if let Some(body_part_handle) = minb {
- if self
- .bodies
- .get(body_part_handle.0)
- .unwrap()
- .status_dependent_ndofs()
- != 0
- {
- self.state.grabbed_object = minb;
- for n in self
- .graphics
-