diff --git a/common/src/abstractions/assets.rs b/common/src/abstractions/assets.rs index 4abe4a0c..9ad91d2b 100644 --- a/common/src/abstractions/assets.rs +++ b/common/src/abstractions/assets.rs @@ -8,7 +8,7 @@ use std::{ pub use exporters::*; pub use importers::*; -use crate::{FastHashMap, FileSystemError, Guid, impl_from_error, StreamError, StringName, ToVirtualPath, VirtualPath}; +use crate::{FastHashMap, FileSystemError, Guid, StreamError, StringName, ToVirtualPath, VirtualPath}; /// Represents a reference to an asset that can either be loaded or unloaded. /// diff --git a/common/src/collections.rs b/common/src/collections.rs index d29b6c28..3d227aba 100644 --- a/common/src/collections.rs +++ b/common/src/collections.rs @@ -5,6 +5,8 @@ use std::{ hash::BuildHasherDefault, }; +pub use smallvec::{smallvec, SmallVec}; + pub use anymap::*; pub use arena::*; pub use graphs::*; @@ -13,7 +15,6 @@ pub use multimap::*; pub use priorityqueue::*; pub use quadtree::*; pub use ringbuffer::*; -pub use smallvec::{smallvec, SmallVec}; pub use spatialhash::*; mod anymap; @@ -32,7 +33,7 @@ pub type FastHashSet = HashSet>; /// A faster hash map that is not resilient to DoS attacks. pub type FastHashMap = HashMap>; -/// A faster multi-map that is not resilient to DoS attacks. +/// A faster multimap that is not resilient to DoS attacks. pub type FastMultiMap = MultiMap>>; /// A faster any-map that is not resilient to DoS attacks. diff --git a/common/src/maths/linear.rs b/common/src/maths/linear.rs index ce8f0a8a..cd350b7a 100644 --- a/common/src/maths/linear.rs +++ b/common/src/maths/linear.rs @@ -2,11 +2,11 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; +pub use glam::*; + pub use aabb::*; pub use bsp::*; -pub use fields::*; pub use frustum::*; -pub use glam::*; pub use planes::*; pub use rays::*; pub use scalars::*; @@ -17,7 +17,6 @@ use super::*; mod aabb; mod bsp; -mod fields; mod frustum; mod planes; mod rays; diff --git a/common/src/maths/linear/fields.rs b/common/src/maths/linear/fields.rs deleted file mode 100644 index ed8b9ba3..00000000 --- a/common/src/maths/linear/fields.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::*; - -/// A field in 3-space. -#[derive(Clone, Debug)] -pub struct Field { - pub size: Vec3, - pub data: Vec, -} diff --git a/common/src/maths/linear/frustum.rs b/common/src/maths/linear/frustum.rs index 46a0c3f3..85ef2157 100644 --- a/common/src/maths/linear/frustum.rs +++ b/common/src/maths/linear/frustum.rs @@ -1,6 +1,7 @@ -use super::*; use crate::reinterpret_cast; +use super::*; + /// A frustum in 3-space. #[repr(C)] #[derive(Default, Clone, Debug)] @@ -109,16 +110,22 @@ impl Frustum { } /// Converts this frustum to an array of planes. + /// + /// The order is Near, Far, Left, Right, Top, Bottom. pub fn into_array(self) -> [Plane; 6] { [self.near, self.far, self.left, self.right, self.top, self.bottom] } /// Converts this frustum to an array of planes. + /// + /// The order is Near, Far, Left, Right, Top, Bottom. pub fn to_array(&self) -> [Plane; 6] { [self.near, self.far, self.left, self.right, self.top, self.bottom] } /// Converts this frustum to a slice of planes. + /// + /// The order is Near, Far, Left, Right, Top, Bottom. pub fn as_slice(&self) -> &[Plane; 6] { unsafe { reinterpret_cast(self) } } diff --git a/common/src/maths/linear/sdf.rs b/common/src/maths/linear/sdf.rs index 1996fae1..318db930 100644 --- a/common/src/maths/linear/sdf.rs +++ b/common/src/maths/linear/sdf.rs @@ -15,11 +15,6 @@ pub trait SDF { /// Computes the distance to the shape at the given point. fn distance_to(&self, point: Self::Vector) -> ::Scalar; - - /// Converts this signed distance field into an evaluated field structure. - fn to_field(&self, _size: Self::Vector, _step: Self::Vector) -> Field { - todo!() - } } impl SDF for Circle { diff --git a/modules/physics/src/lib.rs b/modules/physics/src/lib.rs index 832e96e8..1d533c80 100644 --- a/modules/physics/src/lib.rs +++ b/modules/physics/src/lib.rs @@ -9,6 +9,7 @@ mod simplex; common::impl_arena_index!(ColliderId, "Identifies a collider."); common::impl_arena_index!(BodyId, "Identifies a physics body."); common::impl_arena_index!(EffectorId, "Identifies an effector."); +common::impl_arena_index!(JointId, "Identifies a joint."); common::impl_server!(PhysicsEngine, PhysicsBackend); @@ -111,6 +112,15 @@ pub trait PhysicsWorld2D: PhysicsWorld { fn effector_set_strength(&self, effector: EffectorId, strength: f32); fn effector_get_strength(&self, effector: EffectorId) -> f32; fn effector_delete(&self, effector: EffectorId); + + // joints + fn joint_create(&self) -> JointId; + fn joint_attach(&self, joint: JointId, body_a: BodyId, body_b: BodyId); + fn joint_detach(&self, joint: JointId); + fn joint_get_bodies(&self, joint: JointId) -> (BodyId, BodyId); + fn joint_set_anchor(&self, joint: JointId, anchor: Vec2); + fn joint_get_anchor(&self, joint: JointId) -> Vec2; + fn joint_delete(&self, joint: JointId); } /// A world of 3D physics. diff --git a/modules/physics/src/simplex/world2d.rs b/modules/physics/src/simplex/world2d.rs index 12f6dc27..6dde1dc6 100644 --- a/modules/physics/src/simplex/world2d.rs +++ b/modules/physics/src/simplex/world2d.rs @@ -11,6 +11,7 @@ pub struct SimplexWorld2D { bodies: RwLock>, colliders: RwLock>, effectors: RwLock>, + joints: RwLock>, } /// Internal settings for a physics world. @@ -82,6 +83,13 @@ enum EffectorShape { Cylinder { radius: f32, height: f32 }, } +/// A joint in the 2d physics world. +struct Joint { + body_a: Option, + body_b: Option, + anchor: Vec2, +} + impl Default for Settings { fn default() -> Self { Self { @@ -615,6 +623,69 @@ impl PhysicsWorld2D for SimplexWorld2D { effectors.remove(effector); } + + #[profiling] + fn joint_create(&self) -> JointId { + let mut joints = self.joints.write().unwrap(); + + joints.insert(Joint { + body_a: None, + body_b: None, + anchor: Vec2::ZERO, + }) + } + + #[profiling] + fn joint_attach(&self, joint: JointId, body_a: BodyId, body_b: BodyId) { + let mut joints = self.joints.write().unwrap(); + + if let Some(joint) = joints.get_mut(joint) { + joint.body_a = Some(body_a); + joint.body_b = Some(body_b); + } + } + + #[profiling] + fn joint_detach(&self, joint: JointId) { + let mut joints = self.joints.write().unwrap(); + + if let Some(joint) = joints.get_mut(joint) { + joint.body_a = None; + joint.body_b = None; + } + } + + #[profiling] + fn joint_get_bodies(&self, joint: JointId) -> (BodyId, BodyId) { + let joints = self.joints.read().unwrap(); + + joints.get(joint).map_or((BodyId::default(), BodyId::default()), |it| { + (it.body_a.unwrap_or_default(), it.body_b.unwrap_or_default()) + }) + } + + #[profiling] + fn joint_set_anchor(&self, joint: JointId, anchor: Vec2) { + let mut joints = self.joints.write().unwrap(); + + if let Some(joint) = joints.get_mut(joint) { + joint.anchor = anchor; + } + } + + #[profiling] + fn joint_get_anchor(&self, joint: JointId) -> Vec2 { + let joints = self.joints.read().unwrap(); + + joints.get(joint).map_or(Vec2::ZERO, |it| it.anchor) + } + + #[profiling] + fn joint_delete(&self, joint: JointId) { + let mut joints = self.joints.write().unwrap(); + + joints.remove(joint); + } } #[cfg(test)] @@ -648,4 +719,17 @@ mod tests { assert_eq!(world.body_get_velocity(body_id), Vec2::ZERO); } + + #[test] + fn it_should_create_a_simple_joint() { + let world = SimplexWorld2D::default(); + let body1 = world.body_create(BodyKind::Kinematic, Vec2::ZERO); + let body2 = world.body_create(BodyKind::Kinematic, Vec2::ZERO); + + let joint = world.joint_create(); + + world.joint_attach(joint, body1, body2); + + assert_eq!(world.joint_get_bodies(joint), (body1, body2)); + } }