From 65b977c3576a99f48b167a0016b4417475eed35c Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sun, 18 Apr 2021 17:11:36 +0200 Subject: [PATCH 1/2] Implement rotation + translation locking Translation locking is limited to locking all axises at the moment. It is presumably possible to do it individually, but I'm not sure of the benefits. --- Cargo.lock | 34 ++++++++-------- rapier3d/Cargo.toml | 2 +- rapier3d/src/body.rs | 40 ++++++++++++++++++- rapier3d/src/server/body.rs | 78 ++++++++++++++++++++++++++++++------- 4 files changed, 121 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 717a714..ecbd2a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,9 +100,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clang-sys" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54d78e30b388d4815220c8dd03fea5656b6c6d32adb59e89061552a102f8da1" +checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c" dependencies = [ "glob", "libc", @@ -111,9 +111,9 @@ dependencies = [ [[package]] name = "const_fn" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076a6803b0dacd6a88cfe64deba628b01533ff5ef265687e6938280c1afd0a28" +checksum = "402da840495de3f976eaefc3485b7f5eb5b0bf9761f9a47be27fe975b3b8c2ec" [[package]] name = "crossbeam" @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -204,9 +204,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "euclid" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e5bac4ec41ece6346fd867815a57a221abdf48f4eb931b033789b5b4b6fc70" +checksum = "536d206ede9fae5a338a1576623b04fd2459f6086e551d374ebf10e9b78bb4df" dependencies = [ "num-traits", ] @@ -411,9 +411,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" [[package]] name = "libloading" @@ -451,9 +451,9 @@ dependencies = [ [[package]] name = "matrixmultiply" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1300bdbea33ec2836b01ff1f5a6eed8bad66d0c31f94d9b7993407a8b054c3a1" +checksum = "5a8a15b776d9dfaecd44b03c5828c2199cddff5247215858aac14624f8d6b741" dependencies = [ "rawpointer", ] @@ -671,7 +671,7 @@ dependencies = [ [[package]] name = "rapier3d" version = "0.7.2" -source = "git+https://github.com/Demindiro/rapier?branch=interaction-groups-or#64fc83c752cd0f5f324c32e26c8d90d4ed6a0f22" +source = "git+https://github.com/Demindiro/rapier?branch=godot#34b5289dd82fb8f76da790ad9843d82f7d9c1374" dependencies = [ "approx", "arrayvec", @@ -697,9 +697,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "redox_syscall" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" dependencies = [ "bitflags", ] @@ -898,9 +898,9 @@ checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" [[package]] name = "syn" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" +checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" dependencies = [ "proc-macro2", "quote", diff --git a/rapier3d/Cargo.toml b/rapier3d/Cargo.toml index 2beeb7f..77b3999 100644 --- a/rapier3d/Cargo.toml +++ b/rapier3d/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" name = "godot_rapier3d" [dependencies] -rapier3d = { git = "https://github.com/Demindiro/rapier", branch = "interaction-groups-or", version = "*", features = ["simd-nightly"] } +rapier3d = { git = "https://github.com/Demindiro/rapier", branch = "godot", version = "*", features = ["simd-nightly"] } gdnative = "*" lazy_static = "*" diff --git a/rapier3d/src/body.rs b/rapier3d/src/body.rs index 64fea4d..36c9ba6 100644 --- a/rapier3d/src/body.rs +++ b/rapier3d/src/body.rs @@ -6,12 +6,12 @@ use crate::space::Space; use crate::util::*; use core::convert::{TryFrom, TryInto}; use gdnative::core_types::*; -use rapier3d::dynamics::{BodyStatus, MassProperties, RigidBody, RigidBodyHandle, RigidBodySet}; +use rapier3d::dynamics::{BodyStatus, MassProperties, RigidBody, RigidBodyHandle, RigidBodySet, Axis}; use rapier3d::geometry::{ Collider, ColliderBuilder, ColliderHandle, InteractionGroups, SharedShape, }; use rapier3d::math::Isometry; -use rapier3d::na::Point3; +use rapier3d::na::{self, Point3}; pub struct BodyShape { index: ShapeIndex, @@ -51,6 +51,8 @@ pub struct Body { restitution: f32, friction: f32, + mass_properties: MassProperties, + inertia_stale: bool, area_gravity: Option, @@ -88,6 +90,8 @@ impl Body { restitution: 0.0, friction: 1.0, + mass_properties: MassProperties::new(Point3::origin(), 1.0, na::Vector3::zeros()), + inertia_stale: false, area_gravity: None, @@ -703,6 +707,7 @@ impl Body { /// Sets the mass of this body pub fn set_mass(&mut self, mass: f32) { + self.mass_properties.set_mass(mass, true); self.map_rigidbody_mut(|body| { let mut p = *body.mass_properties(); p.inv_mass = 1.0 / mass; @@ -809,6 +814,37 @@ impl Body { pub fn enable_ccd(&mut self, enable: bool) { self.map_rigidbody_mut(|body| body.enable_ccd(enable)); } + + /// Locks this body in place at it's current position, which prevents it from being pushed + /// by external forces. It may still rotate around it's origin. + pub fn set_translation_lock(&mut self, lock: bool) { + self.map_rigidbody_mut(|body| { + body.set_translation_locked(lock) + }); + } + + /// Prevents this body from rotating due to external forces. It can + /// still be translated however. The axis is defined in global space. + pub fn set_rotation_lock(&mut self, axis: Axis, lock: bool) { + self.map_rigidbody_mut(|body| { + body.set_rotation_locked(axis, lock) + }); + } + + /// Returns whether this body is locked in place + pub fn is_translation_locked(&self) -> bool { + self.map_rigidbody(|body| body.is_translation_locked()) + } + + /// Returns whether the given local axis of this body is locked + pub fn is_rotation_locked(&self, axis: Axis) -> bool { + let axis = match axis { + Axis::X => 0, + Axis::Y => 1, + Axis::Z => 2, + }; + self.map_rigidbody(|body| body.is_rotation_locked()[axis]) + } } impl ContactEvent { diff --git a/rapier3d/src/server/body.rs b/rapier3d/src/server/body.rs index e716a0d..8c15d4e 100644 --- a/rapier3d/src/server/body.rs +++ b/rapier3d/src/server/body.rs @@ -4,7 +4,7 @@ use crate::body::Body; use crate::util::*; use gdnative::core_types::*; use gdnative::godot_error; -use rapier3d::dynamics::{ActivationStatus, BodyStatus, RigidBody, RigidBodyBuilder}; +use rapier3d::dynamics::{ActivationStatus, BodyStatus, RigidBody, RigidBodyBuilder, Axis}; #[derive(Debug)] enum Type { @@ -40,6 +40,11 @@ enum Mode { Character, } +enum BodyAxis { + Linear(Axis), + Angular(Axis), +} + #[derive(Debug)] enum StateError { InvalidType, @@ -49,6 +54,9 @@ enum StateError { #[derive(Debug)] struct InvalidMode; +#[derive(Debug)] +struct InvalidAxis; + impl Type { fn new(n: i32) -> Result { Ok(match n { @@ -68,8 +76,8 @@ impl Type { Type::Character => RigidBodyBuilder::new_dynamic(), } .sleeping(sleep) - .additional_mass(1.0) - .build() + .additional_mass(1.0) + .build() } } @@ -112,6 +120,21 @@ impl Mode { } } +impl BodyAxis { + fn new(n: i32) -> Result { + // TODO is it possible that multiplpe axises can be specified at once? + Ok(match n { + 1 => Self::Linear(Axis::X), + 2 => Self::Linear(Axis::Y), + 4 => Self::Linear(Axis::Z), + 8 => Self::Angular(Axis::X), + 16 => Self::Angular(Axis::Y), + 32 => Self::Angular(Axis::Z), + _ => return Err(InvalidAxis), + }) + } +} + pub fn init(ffi: &mut ffi::FFI) { ffi!(ffi, body_add_force, add_force); ffi!(ffi, body_add_shape, add_shape); @@ -121,36 +144,38 @@ pub fn init(ffi: &mut ffi::FFI) { ffi, body_attach_object_instance_id, attach_object_instance_id - ); + ); ffi!(ffi, body_create, create); ffi!( ffi, body_is_continuous_collision_detection_enabled, is_continuous_collision_detection_enabled - ); + ); ffi!(ffi, body_get_contact, get_contact); ffi!(ffi, body_get_direct_state, get_direct_state); ffi!(ffi, body_get_kinematic_safe_margin, |_| 0.0); + ffi!(ffi, body_is_axis_locked, is_axis_locked); ffi!(ffi, body_remove_shape, remove_shape); + ffi!(ffi, body_set_axis_lock, set_axis_lock); ffi!(ffi, body_set_collision_layer, set_collision_layer); ffi!(ffi, body_set_collision_mask, set_collision_mask); ffi!( ffi, body_set_enable_continuous_collision_detection, set_enable_continuous_collision_detection - ); + ); ffi!(ffi, body_set_kinematic_safe_margin, |_, _| ()); ffi!( ffi, body_set_max_contacts_reported, set_max_contacts_reported - ); + ); ffi!(ffi, body_set_mode, set_mode); ffi!( ffi, body_set_omit_force_integration, set_omit_force_integration - ); + ); ffi!(ffi, body_set_param, set_param); ffi!(ffi, body_set_shape_transform, set_shape_transform); ffi!(ffi, body_set_shape_disabled, set_shape_disabled); @@ -225,7 +250,7 @@ fn apply_impulse(body: Index, position: &Vector3, impulse: &Vector3) { fn attach_object_instance_id(body: Index, id: u32) { map_or_err!(body, map_body_mut, |b, _| b - .set_object_id(ObjectID::new(id))); + .set_object_id(ObjectID::new(id))); } fn get_direct_state(body: Index, state: &mut ffi::PhysicsBodyState) { @@ -271,7 +296,7 @@ fn get_contact(body: Index, id: u32, contact: &mut ffi::PhysicsBodyContact) { fn remove_shape(body: Index, shape: i32) { map_or_err!(body, map_body_mut, |body, _| body - .remove_shape(shape as u32)); + .remove_shape(shape as u32)); } fn set_param(body: Index, param: i32, value: f32) { @@ -319,18 +344,18 @@ fn set_mode(body: Index, mode: i32) { fn set_omit_force_integration(body: Index, enable: bool) { map_or_err!(body, map_body_mut, |body, _| body - .set_omit_force_integration(enable)); + .set_omit_force_integration(enable)); } fn set_shape_transform(body: Index, shape: i32, transform: &Transform) { let shape = shape as u32; map_or_err!(body, map_body_mut, |body, _| body - .set_shape_transform(shape, transform)); + .set_shape_transform(shape, transform)); } fn set_shape_disabled(body: Index, shape: i32, disable: bool) { map_or_err!(body, map_body_mut, |body, _| body - .set_shape_enable(shape as u32, !disable)); + .set_shape_enable(shape as u32, !disable)); } fn set_space(body: Index, space: Option) { @@ -379,6 +404,33 @@ fn set_enable_continuous_collision_detection(body: Index, enable: bool) { map_or_err!(body, map_body_mut, |body, _| body.enable_ccd(enable)); } +fn set_axis_lock(body: Index, axis: i32, lock: bool) { + if let Ok(axis) = BodyAxis::new(axis) { + map_or_err!(body, map_body_mut, |body, _| { + match axis { + BodyAxis::Linear(_) => body.set_translation_lock(lock), + BodyAxis::Angular(axis) => body.set_rotation_lock(axis, lock), + } + }); + } else { + godot_error!("Invalid axis"); + } +} + +fn is_axis_locked(body: Index, axis: i32) -> bool { + if let Ok(axis) = BodyAxis::new(axis) { + map_or_err!(body, map_body, |body, _| { + match axis { + BodyAxis::Linear(_) => body.is_translation_locked(), + BodyAxis::Angular(axis) => body.is_rotation_locked(axis), + } + }).unwrap_or(false) + } else { + godot_error!("Invalid axis"); + false + } +} + /// Godot's "It's local position but global rotation" is such a mindfuck that this function exists /// to help out fn transform_force_arguments( From bf1d6e69bb9e9604d63e4f6a3644432313dc381f Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sun, 18 Apr 2021 18:17:28 +0200 Subject: [PATCH 2/2] Fix space debug contacts FFI being broken Turns out that there is no well-defined ABI for returning C structs. Damnit. --- module/generate.py | 5 +++-- module/server.cpp | 2 +- rapier3d/src/server/space.rs | 12 +++++------- rapier3d/src/space.rs | 3 +-- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/module/generate.py b/module/generate.py index ba8d759..8191720 100755 --- a/module/generate.py +++ b/module/generate.py @@ -101,9 +101,10 @@ 'free': ('void', [ ('index_t', 'id') ]), - 'space_get_contact': ('godot_vector3', [ + 'space_get_contact': ('void', [ ('index_t', 'space'), - ('size_t', 'id'), + ('int', 'id'), + ('godot_vector3 *', 'out'), ]), 'space_intersect_ray': ('bool', [ ('index_t', 'space'), diff --git a/module/server.cpp b/module/server.cpp index 454e310..4f77911 100644 --- a/module/server.cpp +++ b/module/server.cpp @@ -216,7 +216,7 @@ Vector PluggablePhysicsServer::space_get_contacts(RID space) const { contacts.resize(count); Vector3 *contacts_ptr = contacts.ptrw(); for (size_t i = 0; i < count; i++) { - contacts_ptr[i] = (*this->fn_table.space_get_contact)(id, i); + (*this->fn_table.space_get_contact)(id, i, &contacts_ptr[i]); } return contacts; } diff --git a/rapier3d/src/server/space.rs b/rapier3d/src/server/space.rs index 0661463..e8bfdb0 100644 --- a/rapier3d/src/server/space.rs +++ b/rapier3d/src/server/space.rs @@ -1,7 +1,6 @@ use super::*; use crate::space::{BodyOrAreaIndex, Space}; -use gdnative::core_types::{Vector3, Vector3Godot}; -use gdnative::sys; +use gdnative::core_types::Vector3; pub fn init(ffi: &mut ffi::FFI) { ffi!(ffi, space_create, create); @@ -114,15 +113,14 @@ fn get_contact_count(space: Index) -> i32 { .unwrap_or(0) as i32 } -fn get_contact(space: Index, contact: usize) -> sys::godot_vector3 { - map_or_err!(space, map_space_mut, |space, _| { - if let Some(contact) = space.debug_contacts().get(contact) { +fn get_contact(space: Index, contact: i32, out: &mut Vector3) { + *out = map_or_err!(space, map_space_mut, |space, _| { + if let Some(contact) = space.debug_contacts().get(contact as usize) { *contact } else { godot_error!("Invalid contact index"); Vector3::zero() } }) - .unwrap_or(Vector3::zero()) - .to_sys() + .unwrap_or(Vector3::zero()); } diff --git a/rapier3d/src/space.rs b/rapier3d/src/space.rs index c6afc9f..a3708ca 100644 --- a/rapier3d/src/space.rs +++ b/rapier3d/src/space.rs @@ -478,7 +478,6 @@ impl Space { /// Sets the amount of debug contacts to keep track of pub fn set_debug_contact_count(&mut self, count: usize) { - dbg!(count); self.debug_contact_count = count; } @@ -495,7 +494,7 @@ impl Space { .flat_map(|(cm, pos)| { cm.points .iter() - .map(move |p| pos * p.local_p1) + .map(move |p| pos.transform_point(&p.local_p1)) }) .map(|p| vec_na_to_gd(p.coords)) .collect();