diff options
Diffstat (limited to 'src_testbed/testbed.rs')
| -rw-r--r-- | src_testbed/testbed.rs | 1940 |
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 - |
