From ecd308338b189ab569816a38a03e3f8b89669dde Mon Sep 17 00:00:00 2001 From: Sébastien Crozet Date: Sun, 17 Mar 2024 21:20:18 +0100 Subject: feat: start experimenting with a glam/bevy version --- src/geometry/broad_phase_multi_sap/broad_phase.rs | 6 +- .../broad_phase_pair_event.rs | 8 +- src/geometry/broad_phase_multi_sap/sap_axis.rs | 2 +- src/geometry/broad_phase_multi_sap/sap_endpoint.rs | 2 +- src/geometry/broad_phase_multi_sap/sap_layer.rs | 36 ++--- src/geometry/broad_phase_multi_sap/sap_utils.rs | 18 +-- src/geometry/broad_phase_qbvh.rs | 2 +- src/geometry/collider.rs | 171 ++++++++++----------- src/geometry/collider_components.rs | 160 ++++++++++++++----- src/geometry/collider_set.rs | 95 ++++++++---- src/geometry/contact_pair.rs | 27 ++-- src/geometry/interaction_groups.rs | 10 ++ src/geometry/mod.rs | 24 ++- src/geometry/narrow_phase.rs | 61 ++++---- 14 files changed, 372 insertions(+), 250 deletions(-) (limited to 'src/geometry') diff --git a/src/geometry/broad_phase_multi_sap/broad_phase.rs b/src/geometry/broad_phase_multi_sap/broad_phase.rs index 9e1bc06..07a5854 100644 --- a/src/geometry/broad_phase_multi_sap/broad_phase.rs +++ b/src/geometry/broad_phase_multi_sap/broad_phase.rs @@ -6,7 +6,7 @@ use crate::geometry::{ ColliderBroadPhaseData, ColliderChanges, ColliderHandle, ColliderPosition, ColliderSet, ColliderShape, }; -use crate::math::Real; +use crate::math::*; use crate::utils::IndexMut2; use parry::bounding_volume::BoundingVolume; use parry::utils::hashmap::HashMap; @@ -361,8 +361,8 @@ impl BroadPhase { .compute_aabb(co_pos) .loosened(prediction_distance / 2.0); - if aabb.mins.coords.iter().any(|e| !e.is_finite()) - || aabb.maxs.coords.iter().any(|e| !e.is_finite()) + if aabb.mins.as_vector().iter().any(|e| !e.is_finite()) + || aabb.maxs.as_vector().iter().any(|e| !e.is_finite()) { // Reject Aabbs with non-finite values. return false; diff --git a/src/geometry/broad_phase_multi_sap/broad_phase_pair_event.rs b/src/geometry/broad_phase_multi_sap/broad_phase_pair_event.rs index 7b489f5..5732fad 100644 --- a/src/geometry/broad_phase_multi_sap/broad_phase_pair_event.rs +++ b/src/geometry/broad_phase_multi_sap/broad_phase_pair_event.rs @@ -25,17 +25,17 @@ impl ColliderPair { } /// Constructs a pair of artificial handles that are not guaranteed to be valid.. - pub fn zero() -> Self { + pub fn invalid() -> Self { Self { - collider1: ColliderHandle::from_raw_parts(0, 0), - collider2: ColliderHandle::from_raw_parts(0, 0), + collider1: ColliderHandle::PLACEHOLDER, + collider2: ColliderHandle::PLACEHOLDER, } } } impl Default for ColliderPair { fn default() -> Self { - ColliderPair::zero() + ColliderPair::invalid() } } diff --git a/src/geometry/broad_phase_multi_sap/sap_axis.rs b/src/geometry/broad_phase_multi_sap/sap_axis.rs index 2452148..28c0822 100644 --- a/src/geometry/broad_phase_multi_sap/sap_axis.rs +++ b/src/geometry/broad_phase_multi_sap/sap_axis.rs @@ -1,7 +1,7 @@ use super::{SAPEndpoint, SAPProxies, NUM_SENTINELS}; use crate::geometry::broad_phase_multi_sap::DELETED_AABB_VALUE; use crate::geometry::SAPProxyIndex; -use crate::math::Real; +use crate::math::*; use bit_vec::BitVec; use parry::bounding_volume::BoundingVolume; use parry::utils::hashmap::HashMap; diff --git a/src/geometry/broad_phase_multi_sap/sap_endpoint.rs b/src/geometry/broad_phase_multi_sap/sap_endpoint.rs index a57b8e9..482c046 100644 --- a/src/geometry/broad_phase_multi_sap/sap_endpoint.rs +++ b/src/geometry/broad_phase_multi_sap/sap_endpoint.rs @@ -1,5 +1,5 @@ use super::SENTINEL_VALUE; -use crate::math::Real; +use crate::math::*; #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] diff --git a/src/geometry/broad_phase_multi_sap/sap_layer.rs b/src/geometry/broad_phase_multi_sap/sap_layer.rs index 2266d56..a315cc7 100644 --- a/src/geometry/broad_phase_multi_sap/sap_layer.rs +++ b/src/geometry/broad_phase_multi_sap/sap_layer.rs @@ -1,7 +1,7 @@ use super::{SAPProxies, SAPProxy, SAPRegion, SAPRegionPool}; use crate::geometry::broad_phase_multi_sap::DELETED_AABB_VALUE; use crate::geometry::{Aabb, SAPProxyIndex}; -use crate::math::{Point, Real}; +use crate::math::*; use parry::bounding_volume::BoundingVolume; use parry::utils::hashmap::{Entry, HashMap}; @@ -13,9 +13,9 @@ pub(crate) struct SAPLayer { pub smaller_layer: Option, pub larger_layer: Option, region_width: Real, - pub regions: HashMap, SAPProxyIndex>, + pub regions: HashMap<[i32; DIM], SAPProxyIndex>, #[cfg_attr(feature = "serde-serialize", serde(skip))] - regions_to_potentially_remove: Vec>, // Workspace + regions_to_potentially_remove: Vec<[i32; DIM]>, // Workspace #[cfg_attr(feature = "serde-serialize", serde(skip))] pub created_regions: Vec, } @@ -188,7 +188,7 @@ impl SAPLayer { /// of the new region if it did not exist and has been created by this method. pub fn ensure_region_exists( &mut self, - region_key: Point, + region_key: [i32; DIM], proxies: &mut SAPProxies, pool: &mut SAPRegionPool, ) -> SAPProxyIndex { @@ -227,15 +227,15 @@ impl SAPLayer { #[cfg(feature = "dim2")] let k_range = 0..1; #[cfg(feature = "dim3")] - let k_range = start.z..=end.z; + let k_range = start[2]..=end[2]; - for i in start.x..=end.x { - for j in start.y..=end.y { + for i in start[0]..=end[0] { + for j in start[1]..=end[1] { for _k in k_range.clone() { #[cfg(feature = "dim2")] - let region_key = Point::new(i, j); + let region_key = [i, j]; #[cfg(feature = "dim3")] - let region_key = Point::new(i, j, _k); + let region_key = [i, j, _k]; let region_id = self.ensure_region_exists(region_key, proxies, pool); let region_proxy = &mut proxies[region_id]; let region = region_proxy.data.as_region_mut(); @@ -273,21 +273,21 @@ impl SAPLayer { let end = super::point_key(proxy_aabb.maxs, self.region_width); // Set the Aabb of the proxy to a very large value. - proxy_aabb.mins.coords.fill(DELETED_AABB_VALUE); - proxy_aabb.maxs.coords.fill(DELETED_AABB_VALUE); + proxy_aabb.mins.as_vector_mut().fill(DELETED_AABB_VALUE); + proxy_aabb.maxs.as_vector_mut().fill(DELETED_AABB_VALUE); #[cfg(feature = "dim2")] let k_range = 0..1; #[cfg(feature = "dim3")] - let k_range = start.z..=end.z; + let k_range = start[2]..=end[2]; - for i in start.x..=end.x { - for j in start.y..=end.y { + for i in start[0]..=end[0] { + for j in start[1]..=end[1] { for _k in k_range.clone() { #[cfg(feature = "dim2")] - let key = Point::new(i, j); + let key = [i, j]; #[cfg(feature = "dim3")] - let key = Point::new(i, j, _k); + let key = [i, j, _k]; if let Some(region_id) = self.regions.get(&key) { let region = proxies[*region_id].data.as_region_mut(); region.predelete_proxy(proxy_index); @@ -362,8 +362,8 @@ impl SAPLayer { // Move the proxy to infinity. let proxy = &mut proxies[region_id]; - proxy.aabb.mins.coords.fill(DELETED_AABB_VALUE); - proxy.aabb.maxs.coords.fill(DELETED_AABB_VALUE); + proxy.aabb.mins.as_vector_mut().fill(DELETED_AABB_VALUE); + proxy.aabb.maxs.as_vector_mut().fill(DELETED_AABB_VALUE); // Mark the proxy as deleted. proxies.remove(region_id); diff --git a/src/geometry/broad_phase_multi_sap/sap_utils.rs b/src/geometry/broad_phase_multi_sap/sap_utils.rs index 56183eb..ec1f442 100644 --- a/src/geometry/broad_phase_multi_sap/sap_utils.rs +++ b/src/geometry/broad_phase_multi_sap/sap_utils.rs @@ -1,4 +1,4 @@ -use crate::math::{Point, Real, Vector}; +use crate::math::*; use parry::bounding_volume::Aabb; pub(crate) const NUM_SENTINELS: usize = 1; @@ -19,19 +19,17 @@ pub(crate) fn sort2(a: u32, b: u32) -> (u32, u32) { } } -pub(crate) fn clamp_point(point: Point) -> Point { +pub(crate) fn clamp_point(point: Point) -> Point { point.map(|e| na::clamp(e, -MAX_AABB_EXTENT, MAX_AABB_EXTENT)) } -pub(crate) fn point_key(point: Point, region_width: Real) -> Point { - (point / region_width) - .coords - .map(|e| e.floor() as i32) - .into() +pub(crate) fn point_key(point: Point, region_width: Real) -> [i32; DIM] { + let array: [Real; DIM] = (point / region_width).into_vector().into(); + array.map(|e| e.floor() as i32) } -pub(crate) fn region_aabb(index: Point, region_width: Real) -> Aabb { - let mins = index.coords.map(|i| i as Real * region_width).into(); +pub(crate) fn region_aabb(index: [i32; DIM], region_width: Real) -> Aabb { + let mins = index.map(|i| i as Real * region_width).into(); let maxs = mins + Vector::repeat(region_width); Aabb::new(mins, maxs) } @@ -43,7 +41,7 @@ pub(crate) fn region_width(depth: i8) -> Real { /// Computes the depth of the layer the given Aabb should be part of. /// /// The idea here is that an Aabb should be part of a layer which has -/// regions large enough so that one Aabb doesn't crosses too many +/// regions large enough so that one Aabb doesn't cross too many /// regions. But the regions must also not be too large, otherwise /// we are loosing the benefits of Multi-SAP. /// diff --git a/src/geometry/broad_phase_qbvh.rs b/src/geometry/broad_phase_qbvh.rs index 22ca562..287a7d8 100644 --- a/src/geometry/broad_phase_qbvh.rs +++ b/src/geometry/broad_phase_qbvh.rs @@ -56,7 +56,7 @@ impl BroadPhase { if full_rebuild { self.qbvh.clear_and_rebuild( - colliders.iter().map(|(handle, collider)| { + colliders.iter_internal().map(|(handle, collider)| { ( handle, collider.compute_aabb().loosened(prediction_distance / 2.0), diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 2a31afa..82febe2 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -1,14 +1,13 @@ use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle}; use crate::geometry::{ ActiveCollisionTypes, ColliderBroadPhaseData, ColliderChanges, ColliderFlags, - ColliderMassProps, ColliderMaterial, ColliderParent, ColliderPosition, ColliderShape, - ColliderType, InteractionGroups, SharedShape, + ColliderMassProperties, ColliderParent, ColliderPosition, ColliderShape, ColliderType, + Friction, InteractionGroups, Restitution, SharedShape, }; -use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector, DIM}; +use crate::math::*; use crate::parry::transformation::vhacd::VHACDParameters; use crate::pipeline::{ActiveEvents, ActiveHooks}; use crate::prelude::ColliderEnabled; -use na::Unit; use parry::bounding_volume::Aabb; use parry::shape::{Shape, TriMeshFlags}; @@ -20,11 +19,12 @@ use parry::shape::{Shape, TriMeshFlags}; pub struct Collider { pub(crate) coll_type: ColliderType, pub(crate) shape: ColliderShape, - pub(crate) mprops: ColliderMassProps, + pub(crate) mprops: ColliderMassProperties, pub(crate) changes: ColliderChanges, pub(crate) parent: Option, pub(crate) pos: ColliderPosition, - pub(crate) material: ColliderMaterial, + pub(crate) friction: Friction, + pub(crate) restitution: Restitution, pub(crate) flags: ColliderFlags, pub(crate) bf_data: ColliderBroadPhaseData, contact_force_event_threshold: Real, @@ -92,50 +92,50 @@ impl Collider { /// The friction coefficient of this collider. pub fn friction(&self) -> Real { - self.material.friction + self.friction.coefficient } /// Sets the friction coefficient of this collider. pub fn set_friction(&mut self, coefficient: Real) { - self.material.friction = coefficient + self.friction.coefficient = coefficient } /// The combine rule used by this collider to combine its friction /// coefficient with the friction coefficient of the other collider it /// is in contact with. pub fn friction_combine_rule(&self) -> CoefficientCombineRule { - self.material.friction_combine_rule + self.friction.combine_rule } /// Sets the combine rule used by this collider to combine its friction /// coefficient with the friction coefficient of the other collider it /// is in contact with. pub fn set_friction_combine_rule(&mut self, rule: CoefficientCombineRule) { - self.material.friction_combine_rule = rule; + self.friction.combine_rule = rule; } /// The restitution coefficient of this collider. pub fn restitution(&self) -> Real { - self.material.restitution + self.restitution.coefficient } /// Sets the restitution coefficient of this collider. pub fn set_restitution(&mut self, coefficient: Real) { - self.material.restitution = coefficient + self.restitution.coefficient = coefficient } /// The combine rule used by this collider to combine its restitution /// coefficient with the restitution coefficient of the other collider it /// is in contact with. pub fn restitution_combine_rule(&self) -> CoefficientCombineRule { - self.material.restitution_combine_rule + self.restitution.combine_rule } /// Sets the combine rule used by this collider to combine its restitution /// coefficient with the restitution coefficient of the other collider it /// is in contact with. pub fn set_restitution_combine_rule(&mut self, rule: CoefficientCombineRule) { - self.material.restitution_combine_rule = rule; + self.restitution.combine_rule = rule; } /// Sets the total force magnitude beyond which a contact force event can be emitted. @@ -179,63 +179,63 @@ impl Collider { } /// Sets the translational part of this collider's position. - pub fn set_translation(&mut self, translation: Vector) { + pub fn set_translation(&mut self, translation: Vector) { self.changes.insert(ColliderChanges::POSITION); - self.pos.0.translation.vector = translation; + *self.pos.0.translation.as_vector_mut() = translation; } /// Sets the rotational part of this collider's position. - pub fn set_rotation(&mut self, rotation: Rotation) { + pub fn set_rotation(&mut self, rotation: Rotation) { self.changes.insert(ColliderChanges::POSITION); self.pos.0.rotation = rotation; } /// Sets the position of this collider. - pub fn set_position(&mut self, position: Isometry) { + pub fn set_position(&mut self, position: Isometry) { self.changes.insert(ColliderChanges::POSITION); self.pos.0 = position; } /// The world-space position of this collider. - pub fn position(&self) -> &Isometry { + pub fn position(&self) -> &Isometry { &self.pos } /// The translational part of this collider's position. - pub fn translation(&self) -> &Vector { - &self.pos.0.translation.vector + pub fn translation(&self) -> Vector { + self.pos.0.translation.into_vector() } /// The rotational part of this collider's position. - pub fn rotation(&self) -> &Rotation { + pub fn rotation(&self) -> &Rotation { &self.pos.0.rotation } /// The position of this collider with respect to the body it is attached to. - pub fn position_wrt_parent(&self) -> Option<&Isometry> { + pub fn position_wrt_parent(&self) -> Option<&Isometry> { self.parent.as_ref().map(|p| &p.pos_wrt_parent) } /// Sets the translational part of this collider's translation relative to its parent rigid-body. - pub fn set_translation_wrt_parent(&mut self, translation: Vector) { + pub fn set_translation_wrt_parent(&mut self, translation: Vector) { if let Some(parent) = self.parent.as_mut() { self.changes.insert(ColliderChanges::PARENT); - parent.pos_wrt_parent.translation.vector = translation; + *parent.pos_wrt_parent.translation.as_vector_mut() = translation; } } /// Sets the rotational part of this collider's rotaiton relative to its parent rigid-body. - pub fn set_rotation_wrt_parent(&mut self, rotation: AngVector) { + pub fn set_rotation_wrt_parent(&mut self, rotation: AngVector) { if let Some(parent) = self.parent.as_mut() { self.changes.insert(ColliderChanges::PARENT); - parent.pos_wrt_parent.rotation = Rotation::new(rotation); + parent.pos_wrt_parent.rotation = Rotation::from_scaled_axis(rotation.into()); } } /// Sets the position of this collider with respect to its parent rigid-body. /// /// Does nothing if the collider is not attached to a rigid-body. - pub fn set_position_wrt_parent(&mut self, pos_wrt_parent: Isometry) { + pub fn set_position_wrt_parent(&mut self, pos_wrt_parent: Isometry) { if let Some(parent) = self.parent.as_mut() { self.changes.insert(ColliderChanges::PARENT); parent.pos_wrt_parent = pos_wrt_parent; @@ -268,11 +268,6 @@ impl Collider { } } - /// The material (friction and restitution properties) of this collider. - pub fn material(&self) -> &ColliderMaterial { - &self.material - } - /// The volume (or surface in 2D) of this collider. pub fn volume(&self) -> Real { self.shape.mass_properties(1.0).mass() @@ -281,12 +276,12 @@ impl Collider { /// The density of this collider. pub fn density(&self) -> Real { match &self.mprops { - ColliderMassProps::Density(density) => *density, - ColliderMassProps::Mass(mass) => { + ColliderMassProperties::Density(density) => *density, + ColliderMassProperties::Mass(mass) => { let inv_volume = self.shape.mass_properties(1.0).inv_mass; mass * inv_volume } - ColliderMassProps::MassProperties(mprops) => { + ColliderMassProperties::MassProperties(mprops) => { let inv_volume = self.shape.mass_properties(1.0).inv_mass; mprops.mass() * inv_volume } @@ -296,9 +291,9 @@ impl Collider { /// The mass of this collider. pub fn mass(&self) -> Real { match &self.mprops { - ColliderMassProps::Density(density) => self.shape.mass_properties(*density).mass(), - ColliderMassProps::Mass(mass) => *mass, - ColliderMassProps::MassProperties(mprops) => mprops.mass(), + ColliderMassProperties::Density(density) => self.shape.mass_properties(*density).mass(), + ColliderMassProperties::Mass(mass) => *mass, + ColliderMassProperties::MassProperties(mprops) => mprops.mass(), } } @@ -312,7 +307,7 @@ impl Collider { /// The mass and angular inertia of this collider will be computed automatically based on its /// shape. pub fn set_density(&mut self, density: Real) { - self.do_set_mass_properties(ColliderMassProps::Density(density)); + self.do_set_mass_properties(ColliderMassProperties::Density(density)); } /// Sets the mass of this collider. @@ -325,7 +320,7 @@ impl Collider { /// The angular inertia of this collider will be computed automatically based on its shape /// and this mass value. pub fn set_mass(&mut self, mass: Real) { - self.do_set_mass_properties(ColliderMassProps::Mass(mass)); + self.do_set_mass_properties(ColliderMassProperties::Mass(mass)); } /// Sets the mass properties of this collider. @@ -335,10 +330,12 @@ impl Collider { /// [`ColliderBuilder::mass`], or [`ColliderBuilder::mass_properties`] /// for this collider. pub fn set_mass_properties(&mut self, mass_properties: MassProperties) { - self.do_set_mass_properties(ColliderMassProps::MassProperties(Box::new(mass_properties))) + self.do_set_mass_properties(ColliderMassProperties::MassProperties(Box::new( + mass_properties, + ))) } - fn do_set_mass_properties(&mut self, mprops: ColliderMassProps) { + fn do_set_mass_properties(&mut self, mprops: ColliderMassProperties) { if mprops != self.mprops { self.changes |= ColliderChanges::LOCAL_MASS_PROPERTIES; self.mprops = mprops; @@ -378,7 +375,7 @@ impl Collider { /// Compute the axis-aligned bounding box of this collider moving from its current position /// to the given `next_position` - pub fn compute_swept_aabb(&self, next_position: &Isometry) -> Aabb { + pub fn compute_swept_aabb(&self, next_position: &Isometry) -> Aabb { self.shape.compute_swept_aabb(&self.pos, next_position) } @@ -401,7 +398,7 @@ pub struct ColliderBuilder { /// The shape of the collider to be built. pub shape: SharedShape, /// Controls the way the collider’s mass-properties are computed. - pub mass_properties: ColliderMassProps, + pub mass_properties: ColliderMassProperties, /// The friction coefficient of the collider to be built. pub friction: Real, /// The rule used to combine two friction coefficients. @@ -411,7 +408,7 @@ pub struct ColliderBuilder { /// The rule used to combine two restitution coefficients. pub restitution_combine_rule: CoefficientCombineRule, /// The position of this collider. - pub position: Isometry, + pub position: Isometry, /// Is this collider a sensor? pub is_sensor: bool, /// Contact pairs enabled for this collider. @@ -437,7 +434,7 @@ impl ColliderBuilder { pub fn new(shape: SharedShape) -> Self { Self { shape, - mass_properties: ColliderMassProps::default(), + mass_properties: ColliderMassProperties::default(), friction: Self::default_friction(), restitution: 0.0, position: Isometry::identity(), @@ -456,7 +453,7 @@ impl ColliderBuilder { } /// Initialize a new collider builder with a compound shape. - pub fn compound(shapes: Vec<(Isometry, SharedShape)>) -> Self { + pub fn compound(shapes: Vec<(Isometry, SharedShape)>) -> Self { Self::new(SharedShape::compound(shapes)) } @@ -467,7 +464,7 @@ impl ColliderBuilder { /// Initialize a new collider build with a half-space shape defined by the outward normal /// of its planar boundary. - pub fn halfspace(outward_normal: Unit>) -> Self { + pub fn halfspace(outward_normal: UnitVector) -> Self { Self::new(SharedShape::halfspace(outward_normal)) } @@ -548,39 +545,34 @@ impl ColliderBuilder { } /// Initializes a collider builder with a segment shape. - pub fn segment(a: Point, b: Point) -> Self { + pub fn segment(a: Point, b: Point) -> Self { Self::new(SharedShape::segment(a, b)) } /// Initializes a collider builder with a triangle shape. - pub fn triangle(a: Point, b: Point, c: Point) -> Self { + pub fn triangle(a: Point, b: Point, c: Point) -> Self { Self::new(SharedShape::triangle(a, b, c)) } /// Initializes a collider builder with a triangle shape with round corners. - pub fn round_triangle( - a: Point, - b: Point, - c: Point, - border_radius: Real, - ) -> Self { + pub fn round_triangle(a: Point, b: Point, c: Point, border_radius: Real) -> Self { Self::new(SharedShape::round_triangle(a, b, c, border_radius)) } /// Initializes a collider builder with a polyline shape defined by its vertex and index buffers. - pub fn polyline(vertices: Vec>, indices: Option>) -> Self { + pub fn polyline(vertices: Vec, indices: Option>) -> Self { Self::new(SharedShape::polyline(vertices, indices)) } /// Initializes a collider builder with a triangle mesh shape defined by its vertex and index buffers. - pub fn trimesh(vertices: Vec>, indices: Vec<[u32; 3]>) -> Self { + pub fn trimesh(vertices: Vec, indices: Vec<[u32; 3]>) -> Self { Self::new(SharedShape::trimesh(vertices, indices)) } /// Initializes a collider builder with a triangle mesh shape defined by its vertex and index buffers and /// flags controlling its pre-processing. pub fn trimesh_with_flags( - vertices: Vec>, + vertices: Vec, indices: Vec<[u32; 3]>, flags: TriMeshFlags, ) -> Self { @@ -589,14 +581,14 @@ impl ColliderBuilder { /// Initializes a collider builder with a compound shape obtained from the decomposition of /// the given trimesh (in 3D) or polyline (in 2D) into convex parts. - pub fn convex_decomposition(vertices: &[Point], indices: &[[u32; DIM]]) -> Self { + pub fn convex_decomposition(vertices: &[Point], indices: &[[u32; DIM]]) -> Self { Self::new(SharedShape::convex_decomposition(vertices, indices)) } /// Initializes a collider builder with a compound shape obtained from the decomposition of /// the given trimesh (in 3D) or polyline (in 2D) into convex parts dilated with round corners. pub fn round_convex_decomposition( - vertices: &[Point], + vertices: &[Point], indices: &[[u32; DIM]], border_radius: Real, ) -> Self { @@ -610,7 +602,7 @@ impl ColliderBuilder { /// Initializes a collider builder with a compound shape obtained from the decomposition of /// the given trimesh (in 3D) or polyline (in 2D) into convex parts. pub fn convex_decomposition_with_params( - vertices: &[Point], + vertices: &[Point], indices: &[[u32; DIM]], params: &VHACDParameters, ) -> Self { @@ -622,7 +614,7 @@ impl ColliderBuilder { /// Initializes a collider builder with a compound shape obtained from the decomposition of /// the given trimesh (in 3D) or polyline (in 2D) into convex parts dilated with round corners. pub fn round_convex_decomposition_with_params( - vertices: &[Point], + vertices: &[Point], indices: &[[u32; DIM]], params: &VHACDParameters, border_radius: Real, @@ -637,14 +629,14 @@ impl ColliderBuilder { /// Initializes a new collider builder with a 2D convex polygon or 3D convex polyhedron /// obtained after computing the convex-hull of the given points. - pub fn convex_hull(points: &[Point]) -> Option { + pub fn convex_hull(points: &[Point]) -> Option { SharedShape::convex_hull(points).map(Self::new) } /// Initializes a new collider builder with a round 2D convex polygon or 3D convex polyhedron /// obtained after computing the convex-hull of the given points. The shape is dilated /// by a sphere of radius `border_radius`. - pub fn round_convex_hull(points: &[Point], border_radius: Real) -> Option { + pub fn round_convex_hull(points: &[Point], border_radius: Real) -> Option { SharedShape::round_convex_hull(points, border_radius).map(Self::new) } @@ -652,7 +644,7 @@ impl ColliderBuilder { /// given polyline assumed to be convex (no convex-hull will be automatically /// computed). #[cfg(feature = "dim2")] - pub fn convex_polyline(points: Vec>) -> Option { + pub fn convex_polyline(points: Vec) -> Option { SharedShape::convex_polyline(points).map(Self::new) } @@ -660,7 +652,7 @@ impl ColliderBuilder { /// given polyline assumed to be convex (no convex-hull will be automatically /// computed). The polygon shape is dilated by a sphere of radius `border_radius`. #[cfg(feature = "dim2")] - pub fn round_convex_polyline(points: Vec>, border_radius: Real) -> Option { + pub fn round_convex_polyline(points: Vec, border_radius: Real) -> Option { SharedShape::round_convex_polyline(points, border_radius).map(Self::new) } @@ -668,7 +660,7 @@ impl ColliderBuilder { /// given triangle-mesh assumed to be convex (no convex-hull will be automatically /// computed). #[cfg(feature = "dim3")] - pub fn convex_mesh(points: Vec>, indices: &[[u32; 3]]) -> Option { + pub fn convex_mesh(points: Vec, indices: &[[u32; 3]]) -> Option { SharedShape::convex_mesh(points, indices).map(Self::new) } @@ -677,7 +669,7 @@ impl ColliderBuilder { /// computed). The triangle mesh shape is dilated by a sphere of radius `border_radius`. #[cfg(feature = "dim3")] pub fn round_convex_mesh( - points: Vec>, + points: Vec, indices: &[[u32; 3]], border_radius: Real, ) -> Option { @@ -687,14 +679,14 @@ impl ColliderBuilder { /// Initializes a collider builder with a heightfield shape defined by its set of height and a scale /// factor along each coordinate axis. #[cfg(feature = "dim2")] - pub fn heightfield(heights: na::DVector, scale: Vector) -> Self { + pub fn heightfield(heights: na::DVector, scale: Vector) -> Self { Self::new(SharedShape::heightfield(heights, scale)) } /// Initializes a collider builder with a heightfield shape defined by its set of height and a scale /// factor along each coordinate axis. #[cfg(feature = "dim3")] - pub fn heightfield(heights: na::DMatrix, scale: Vector) -> Self { + pub fn heightfield(heights: na::DMatrix, scale: Vector) -> Self { Self::new(SharedShape::heightfield(heights, scale)) } @@ -788,7 +780,7 @@ impl ColliderBuilder { /// The mass and angular inertia of this collider will be computed automatically based on its /// shape. pub fn density(mut self, density: Real) -> Self { - self.mass_properties = ColliderMassProps::Density(density); + self.mass_properties = ColliderMassProperties::Density(density); self } @@ -800,7 +792,7 @@ impl ColliderBuilder { /// The angular inertia of this collider will be computed automatically based on its shape /// and this mass value. pub fn mass(mut self, mass: Real) -> Self { - self.mass_properties = ColliderMassProps::Mass(mass); + self.mass_properties = ColliderMassProperties::Mass(mass); self } @@ -809,7 +801,7 @@ impl ColliderBuilder { /// This will be overridden by a call to [`Self::density`] or [`Self::mass`] so it only /// makes sense to call either [`Self::density`] or [`Self::mass`] or [`Self::mass_properties`]. pub fn mass_properties(mut self, mass_properties: MassProperties) -> Self { - self.mass_properties = ColliderMassProps::MassProperties(Box::new(mass_properties)); + self.mass_properties = ColliderMassProperties::MassProperties(Box::new(mass_properties)); self } @@ -823,8 +815,8 @@ impl ColliderBuilder { /// /// If the collider will be attached to a rigid-body, this sets the translation relative to the /// rigid-body it will be attached to. - pub fn translation(mut self, translation: Vector) -> Self { - self.position.translation.vector = translation; + pub fn translation(mut self, translation: Vector) -> Self { + *self.position.translation.as_vector_mut() = translation; self } @@ -832,8 +824,8 @@ impl ColliderBuilder { /// /// If the collider will be attached to a rigid-body, this sets the orientation relative to the /// rigid-body it will be attached to. - pub fn rotation(mut self, angle: AngVector) -> Self { - self.position.rotation = Rotation::new(angle); + pub fn rotation(mut self, angle: AngVector) -> Self { + self.position.rotation = Rotation::from_scaled_axis(angle.into()); self } @@ -841,7 +833,7 @@ impl ColliderBuilder { /// /// If the collider will be attached to a rigid-body, this sets the position relative /// to the rigid-body it will be attached to. - pub fn position(mut self, pos: Isometry) -> Self { + pub fn position(mut self, pos: Isometry) -> Self { self.position = pos; self } @@ -849,14 +841,14 @@ impl ColliderBuilder { /// Sets the initial position (translation and orientation) of the collider to be created, /// relative to the rigid-body it is attached to. #[deprecated(note = "Use `.position` instead.")] - pub fn position_wrt_parent(mut self, pos: Isometry) -> Self { + pub fn position_wrt_parent(mut self, pos: Isometry) -> Self { self.position = pos; self } /// Set the position of this collider in the local-space of the rigid-body it is attached to. #[deprecated(note = "Use `.position` instead.")] - pub fn delta(mut self, delta: Isometry) -> Self { + pub fn delta(mut self, delta: Isometry) -> Self { self.position = delta; self } @@ -870,11 +862,13 @@ impl ColliderBuilder { /// Builds a new collider attached to the given rigid-body. pub fn build(&self) -> Collider { let shape = self.shape.clone(); - let material = ColliderMaterial { - friction: self.friction, - restitution: self.restitution, - friction_combine_rule: self.friction_combine_rule, - restitution_combine_rule: self.restitution_combine_rule, + let friction = Friction { + coefficient: self.friction, + combine_rule: self.friction_combine_rule, + }; + let restitution = Restitution { + coefficient: self.restitution, + combine_rule: self.restitution_combine_rule, }; let flags = ColliderFlags { collision_groups: self.collision_groups, @@ -900,7 +894,8 @@ impl ColliderBuilder { Collider { shape, mprops: self.mass_properties.clone(), - material, + friction, + restitution, parent: None, changes, pos, diff --git a/src/geometry/collider_components.rs b/src/geometry/collider_components.rs index b71a7ed..f0e413f 100644 --- a/src/geometry/collider_components.rs +++ b/src/geometry/collider_components.rs @@ -1,22 +1,40 @@ use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle, RigidBodyType}; use crate::geometry::{InteractionGroups, SAPProxyIndex, Shape, SharedShape}; -use crate::math::{Isometry, Real}; +use crate::math::*; use crate::parry::partitioning::IndexedData; use crate::pipeline::{ActiveEvents, ActiveHooks}; use std::ops::{Deref, DerefMut}; +use crate::data::Index; +#[cfg(feature = "bevy")] +use bevy::prelude::{Component, Reflect, ReflectComponent}; + /// The unique identifier of a collider added to a collider set. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[repr(transparent)] +#[cfg(not(feature = "bevy"))] pub struct ColliderHandle(pub crate::data::arena::Index); +#[cfg(feature = "bevy")] +pub type ColliderHandle = bevy::prelude::Entity; + +#[cfg(not(feature = "bevy"))] impl ColliderHandle { + pub const PLACEHOLDER: Self = Self(Index::from_raw_parts( + crate::INVALID_U32, + crate::INVALID_U32, + )); + /// Converts this handle into its (index, generation) components. pub fn into_raw_parts(self) -> (u32, u32) { self.0.into_raw_parts() } + pub fn index(&self) -> u32 { + self.0.into_raw_parts().0 + } + /// Reconstructs an handle from its (index, generation) components. pub fn from_raw_parts(id: u32, generation: u32) -> Self { Self(crate::data::arena::Index::from_raw_parts(id, generation)) @@ -24,13 +42,25 @@ impl ColliderHandle { /// An always-invalid collider handle. pub fn invalid() -> Self { - Self(crate::data::arena::Index::from_raw_parts( - crate::INVALID_U32, - crate::INVALID_U32, - )) + Self::PLACEHOLDER } } +#[cfg(not(feature = "bevy"))] +impl From for ColliderHandle { + fn from(value: Index) -> Self { + Self(value) + } +} + +#[cfg(not(feature = "bevy"))] +impl From for crate::data::arena::Index { + fn from(value: ColliderHandle) -> Self { + value.0 + } +} + +#[cfg(not(feature = "bevy"))] impl IndexedData for ColliderHandle { fn default() -> Self { Self(IndexedData::default()) @@ -134,8 +164,15 @@ pub type ColliderShape = SharedShape; #[derive(Clone, PartialEq)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "bevy", + derive(Component), + // TODO: Reflect doesn’t like Box? + // derive(Component, Reflect), + // reflect(Component, PartialEq) +)] /// The mass-properties of a collider. -pub enum ColliderMassProps { +pub enum ColliderMassProperties { /// The collider is given a density. /// /// Its actual `MassProperties` are computed automatically with @@ -149,19 +186,19 @@ pub enum ColliderMassProps { MassProperties(Box), } -impl Default for ColliderMassProps { +impl Default for ColliderMassProperties { fn default() -> Self { - ColliderMassProps::Density(1.0) + ColliderMassProperties::Density(1.0) } } -impl From for ColliderMassProps { +impl From for ColliderMassProperties { fn from(mprops: MassProperties) -> Self { - ColliderMassProps::MassProperties(Box::new(mprops)) + ColliderMassProperties::MassProperties(Box::new(mprops)) } } -impl ColliderMassProps { +impl ColliderMassProperties { /// The mass-properties of this collider. /// /// If `self` is the `Density` variant, then this computes the mass-properties based @@ -170,14 +207,14 @@ impl ColliderMassProps { /// If `self` is the `MassProperties` variant, then this returns the stored mass-properties. pub fn mass_properties(&self, shape: &dyn Shape) -> MassProperties { match self { - ColliderMassProps::Density(density) => { + ColliderMassProperties::Density(density) => { if *density != 0.0 { shape.mass_properties(*density) } else { MassProperties::default() } } - ColliderMassProps::Mass(mass) => { + ColliderMassProperties::Mass(mass) => { if *mass != 0.0 { let mut mprops = shape.mass_properties(1.0); mprops.set_mass(*mass, true); @@ -186,7 +223,7 @@ impl ColliderMassProps { MassProperties::default() } } - ColliderMassProps::MassProperties(mass_properties) => **mass_properties, + ColliderMassProperties::MassProperties(mass_properties) => **mass_properties, } } } @@ -198,31 +235,31 @@ pub struct ColliderParent { /// Handle of the rigid-body this collider is attached to. pub handle: RigidBodyHandle, /// Const position of this collider relative to its parent rigid-body. - pub pos_wrt_parent: Isometry, + pub pos_wrt_parent: Isometry, } #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] /// The position of a collider. -pub struct ColliderPosition(pub Isometry); +pub struct ColliderPosition(pub Isometry); -impl AsRef> for ColliderPosition { +impl AsRef for ColliderPosition { #[inline] - fn as_ref(&self) -> &Isometry { + fn as_ref(&self) -> &Isometry { &self.0 } } -impl AsMut> for ColliderPosition { - fn as_mut(&mut self) -> &mut Isometry { +impl AsMut for ColliderPosition { + fn as_mut(&mut self) -> &mut Isometry { &mut self.0 } } impl Deref for ColliderPosition { - type Target = Isometry; + type Target = Isometry; #[inline] - fn deref(&self) -> &Isometry { + fn deref(&self) -> &Isometry { &self.0 } } @@ -249,7 +286,7 @@ impl ColliderPosition { impl From for ColliderPosition where - Isometry: From, + Isometry: From, { fn from(position: T) -> Self { Self(position.into()) @@ -258,49 +295,88 @@ where #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -/// The constraints solver-related properties of this collider (friction, restitution, etc.) -pub struct ColliderMaterial { +#[cfg_attr( + feature = "bevy", + derive(Component, Reflect), + reflect(Component, PartialEq) +)] +/// The collider’s friction properties. +pub struct Friction { /// The friction coefficient of this collider. /// /// The greater the value, the stronger the friction forces will be. /// Should be `>= 0`. - pub friction: Real, + pub coefficient: Real, + /// The rule applied to combine the friction coefficients of two colliders in contact. + pub combine_rule: CoefficientCombineRule, +} + +impl Default for Friction { + fn default() -> Self { + Self { + coefficient: 1.0, + combine_rule: CoefficientCombineRule::default(), + } + } +} + +impl Friction { + /// Inits the Friction component with the specified friction coefficient + /// and the default friction [`CoefficientCombineRule`]. + pub fn coefficient(coefficient: Real) -> Self { + Self { + coefficient, + ..Default::default() + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "bevy", + derive(Component, Reflect), + reflect(Component, PartialEq) +)] +/// The collider’s restitution properties. +pub struct Restitution { /// The restitution coefficient of this collider. /// /// Increase this value to make contacts with this collider more "bouncy". /// Should be `>= 0` and should generally not be greater than `1` (perfectly elastic /// collision). - pub restitution: Real, - /// The rule applied to combine the friction coefficients of two colliders in contact. - pub friction_combine_rule: CoefficientCombineRule, + pub coefficient: Real, /// The rule applied to combine the restitution coefficients of two colliders. - pub restitution_combine_rule: CoefficientCombineRule, + pub combine_rule: CoefficientCombineRule, } -impl ColliderMaterial { - /// Creates a new collider material with the given friction and restitution coefficients. - pub fn new(friction: Real, restitution: Real) -> Self { +impl Default for Restitution { + fn default() -> Self { Self { - friction, - restitution, - ..Default::default() + coefficient: 1.0, + combine_rule: CoefficientCombineRule::default(), } } } -impl Default for ColliderMaterial { - fn default() -> Self { +impl Restitution { + /// Inits the Restitution component with the specified friction coefficient + /// and the default friction [`CoefficientCombineRule`]. + pub fn coefficient(coefficient: Real) -> Self { Self { - friction: 1.0, - restitution: 0.0, - friction_combine_rule: CoefficientCombineRule::default(), - restitution_combine_rule: CoefficientCombineRule::default(), + coefficient, + ..Default::default() } } } bitflags::bitflags! { #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] + #[cfg_attr( + feature = "bevy", + derive(Component, Reflect), + reflect(Component, Hash, PartialEq) + )] /// Flags affecting whether or not collision-detection happens between two colliders /// depending on the type of rigid-bodies they are attached to. pub struct ActiveCollisionTypes: u16 { diff --git a/src/geometry/collider_set.rs b/src/geometry/collider_set.rs index 799ee65..ea8564b 100644 --- a/src/geometry/collider_set.rs +++ b/src/geometry/collider_set.rs @@ -1,26 +1,29 @@ use crate::data::arena::Arena; +use crate::data::Coarena; use crate::dynamics::{IslandManager, RigidBodyHandle, RigidBodySet}; use crate::geometry::{Collider, ColliderChanges, ColliderHandle, ColliderParent}; -use crate::math::Isometry; +use crate::math::*; use std::ops::{Index, IndexMut}; +#[cfg(feature = "bevy")] +use crate::data::EntityArena; + #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone, Default)] /// A set of colliders that can be handled by a physics `World`. pub struct ColliderSet { - pub(crate) colliders: Arena, - pub(crate) modified_colliders: Vec, - pub(crate) removed_colliders: Vec, + #[cfg(not(feature = "bevy"))] + colliders: Arena, + #[cfg(feature = "bevy")] + colliders: EntityArena, + modified_colliders: Vec, + removed_colliders: Vec, } impl ColliderSet { /// Create a new empty set of colliders. pub fn new() -> Self { - ColliderSet { - colliders: Arena::new(), - modified_colliders: Vec::new(), - removed_colliders: Vec::new(), - } + Self::default() } pub(crate) fn take_modified(&mut self) -> Vec { @@ -33,19 +36,35 @@ impl ColliderSet { /// An always-invalid collider handle. pub fn invalid_handle() -> ColliderHandle { - ColliderHandle::from_raw_parts(crate::INVALID_U32, crate::INVALID_U32) + ColliderHandle::PLACEHOLDER } /// Iterate through all the colliders on this set. + #[cfg(not(feature = "dev-remove-slow-accessors"))] pub fn iter(&self) -> impl ExactSizeIterator { - self.colliders.iter().map(|(h, c)| (ColliderHandle(h), c)) + self.iter_internal() } /// Iterate through all the enabled colliders on this set. + #[cfg(not(feature = "dev-remove-slow-accessors"))] pub fn iter_enabled(&self) -> impl Iterator { + self.iter_enabled_internal() + } + + pub(crate) fn iter_internal( + &self, + ) -> impl ExactSizeIterator { self.colliders .iter() - .map(|(h, c)| (ColliderHandle(h), c)) + .map(|(h, c)| (ColliderHandle::from(h), c)) + } + + pub(crate) fn iter_enabled_internal( + &self, + ) -> impl Iterator { + self.colliders + .iter() + .map(|(h, c)| (ColliderHandle::from(h), c)) .filter(|(_, c)| c.is_enabled()) } @@ -55,8 +74,8 @@ impl ColliderSet { self.modified_colliders.clear(); let modified_colliders = &mut self.modified_colliders; self.colliders.iter_mut().map(move |(h, b)| { - modified_colliders.push(ColliderHandle(h)); - (ColliderHandle(h), b) + modified_colliders.push(ColliderHandle::from(h)); + (ColliderHandle::from(h), b) }) } @@ -78,17 +97,24 @@ impl ColliderSet { /// Is this collider handle valid? pub fn contains(&self, handle: ColliderHandle) -> bool { - self.colliders.contains(handle.0) + self.colliders.contains(handle.into()) } /// Inserts a new collider to this set and retrieve its handle. - pub fn insert(&mut self, coll: impl Into) -> ColliderHandle { + pub fn insert( + &mut self, + #[cfg(feature = "bevy")] handle: ColliderHandle, + coll: impl Into, + ) -> ColliderHandle { let mut coll = coll.into(); // Make sure the internal links are reset, they may not be - // if this rigid-body was obtained by cloning another one. + // if this collider was obtained by cloning another one. coll.reset_internal_references(); coll.parent = None; + #[cfg(not(feature = "bevy"))] let handle = ColliderHandle(self.colliders.insert(coll)); + #[cfg(feature = "bevy")] + self.colliders.insert(handle, coll); self.modified_colliders.push(handle); handle } @@ -96,6 +122,7 @@ impl ColliderSet { /// Inserts a new collider to this set, attach it to the given rigid-body, and retrieve its handle. pub fn insert_with_parent( &mut self, + #[cfg(feature = "bevy")] handle: ColliderHandle, coll: impl Into, parent_handle: RigidBodyHandle, bodies: &mut RigidBodySet, @@ -119,10 +146,14 @@ impl ColliderSet { let parent = bodies .get_mut_internal_with_modification_tracking(parent_handle) .expect("Parent rigid body not found."); + #[cfg(not(feature = "bevy"))] let handle = ColliderHandle(self.colliders.insert(coll)); + #[cfg(feature = "bevy")] + self.colliders.insert(handle, coll); + self.modified_colliders.push(handle); - let coll = self.colliders.get_mut(handle.0).unwrap(); + let coll = self.colliders.get_mut(handle.into()).unwrap(); parent.add_collider( handle, coll.parent.as_mut().unwrap(), @@ -141,7 +172,7 @@ impl ColliderSet { new_parent_handle: Option, bodies: &mut RigidBodySet, ) { - if let Some(collider) = self.get_mut(handle) { + if let Some(collider) = self.get_mut_internal_with_modification_tracking(handle) { let curr_parent = collider.parent.map(|p| p.handle); if new_parent_handle == curr_parent { return; // Nothing to do, this is the same parent. @@ -150,7 +181,8 @@ impl ColliderSet { collider.changes |= ColliderChanges::PARENT; if let Some(parent_handle) = curr_parent { - if let Some(rb) = bodies.get_mut(parent_handle) { + if let Some(rb) = bodies.get_mut_internal_with_modification_tracking(parent_handle) + { rb.remove_collider_internal(handle); } } @@ -166,7 +198,9 @@ impl ColliderSet { }) }; - if let Some(rb) = bodies.get_mut(new_parent_handle) { + if let Some(rb) = + bodies.get_mut_internal_with_modification_tracking(new_parent_handle) + { rb.add_collider( handle, collider.parent.as_ref().unwrap(), @@ -192,7 +226,7 @@ impl ColliderSet { bodies: &mut RigidBodySet, wake_up: bool, ) -> Option { - let collider = self.colliders.remove(handle.0)?; + let collider = self.colliders.remove(handle.into())?; /* * Delete the collider from its parent body. @@ -228,6 +262,7 @@ impl ColliderSet { /// /// Using this is discouraged in favor of `self.get(handle)` which does not /// suffer form the ABA problem. + #[cfg(not(feature = "bevy"))] pub fn get_unknown_gen(&self, i: u32) -> Option<(&Collider, ColliderHandle)> { self.colliders .get_unknown_gen(i) @@ -244,6 +279,7 @@ impl ColliderSet { /// Using this is discouraged in favor of `self.get_mut(handle)` which does not /// suffer form the ABA problem. #[cfg(not(feature = "dev-remove-slow-accessors"))] + #[cfg(not(feature = "bevy"))] pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut Collider, ColliderHandle)> { let (collider, handle) = self.colliders.get_unknown_gen_mut(i)?; let handle = ColliderHandle(handle); @@ -253,7 +289,7 @@ impl ColliderSet { /// Get the collider with the given handle. pub fn get(&self, handle: ColliderHandle) -> Option<&Collider> { - self.colliders.get(handle.0) + self.colliders.get(handle.into()) } fn mark_as_modified( @@ -270,17 +306,17 @@ impl ColliderSet { /// Gets a mutable reference to the collider with the given handle. #[cfg(not(feature = "dev-remove-slow-accessors"))] pub fn get_mut(&mut self, handle: ColliderHandle) -> Option<&mut Collider> { - let result = self.colliders.get_mut(handle.0)?; + let result = self.colliders.get_mut(handle.into())?; Self::mark_as_modified(handle, result, &mut self.modified_colliders); Some(result) } pub(crate) fn index_mut_internal(&mut self, handle: ColliderHandle) -> &mut Collider { - &mut self.colliders[handle.0] + &mut self.colliders[handle.into()] } pub(crate) fn get_mut_internal(&mut self, handle: ColliderHandle) -> Option<&mut Collider> { - self.colliders.get_mut(handle.0) + self.colliders.get_mut(handle.into()) } // Just a very long name instead of `.get_mut` to make sure @@ -290,12 +326,13 @@ impl ColliderSet { &mut self, handle: ColliderHandle, ) -> Option<&mut Collider> { - let result = self.colliders.get_mut(handle.0)?; + let result = self.colliders.get_mut(handle.into())?; Self::mark_as_modified(handle, result, &mut self.modified_colliders); Some(result) } } +#[cfg(not(feature = "bevy"))] impl Index for ColliderSet { type Output = Collider; @@ -308,14 +345,14 @@ impl Index for ColliderSet { type Output = Collider; fn index(&self, index: ColliderHandle) -> &Collider { - &self.colliders[index.0] + &self.colliders[index.into()] } } #[cfg(not(feature = "dev-remove-slow-accessors"))] impl IndexMut for ColliderSet { fn index_mut(&mut self, handle: ColliderHandle) -> &mut Collider { - let collider = &mut self.colliders[handle.0]; + let collider = &mut self.colliders[handle.into()]; Self::mark_as_modified(handle, collider, &mut self.modified_colliders); collider } diff --git a/src/geometry/contact_pair.rs b/src/geometry/contact_pair.rs index 44730a0..ce29b29 100644 --- a/src/geometry/contact_pair.rs +++ b/src/geometry/contact_pair.rs @@ -1,6 +1,6 @@ use crate::dynamics::{RigidBodyHandle, RigidBodySet}; use crate::geometry::{ColliderHandle, ColliderSet, Contact, ContactManifold}; -use crate::math::{Point, Real, Vector}; +use crate::math::*; use crate::pipeline::EventHandler; use crate::prelude::CollisionEventFlags; use parry::query::ContactManifoldsWorkspace; @@ -23,7 +23,7 @@ impl Default for SolverFlags { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] /// A single contact between two collider. pub struct ContactData { @@ -38,20 +38,11 @@ pub struct ContactData { /// The friction impulses along the basis orthonormal to the contact normal, applied to the first /// collider's rigid-body. #[cfg(feature = "dim3")] - pub tangent_impulse: na::Vector2, -} - -impl Default for ContactData { - fn default() -> Self { - Self { - impulse: 0.0, - tangent_impulse: na::zero(), - } - } + pub tangent_impulse: Vector2, } #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default)] /// The description of all the contacts between a pair of colliders. pub struct IntersectionPair { /// Are the colliders intersecting? @@ -142,7 +133,7 @@ impl ContactPair { } /// The sum of all the impulses applied by contacts on this contact pair. - pub fn total_impulse(&self) -> Vector { + pub fn total_impulse(&self) -> Vector { self.manifolds .iter() .map(|m| m.total_impulse() * m.data.normal) @@ -157,7 +148,7 @@ impl ContactPair { } /// The magnitude and (unit) direction of the maximum impulse on this contact pair. - pub fn max_impulse(&self) -> (Real, Vector) { + pub fn max_impulse(&self) -> (Real, Vector) { let mut result = (0.0, Vector::zeros()); for m in &self.manifolds { @@ -252,7 +243,7 @@ pub struct ContactManifoldData { /// The world-space contact normal shared by all the contact in this contact manifold. // NOTE: read the comment of `solver_contacts` regarding serialization. It applies // to this field as well. - pub normal: Vector, + pub normal: Vector, /// The contacts that will be seen by the constraints solver for computing forces. // NOTE: unfortunately, we can't ignore this field when serialize // the contact manifold data. The reason is that the solver contacts @@ -284,7 +275,7 @@ pub struct SolverContact { /// The index of the manifold contact used to generate this solver contact. pub(crate) contact_id: u8, /// The contact point in world-space. - pub point: Point, + pub point: Point, /// The distance between the two original contacts points along the contact normal. /// If negative, this is measures the penetration depth. pub dist: Real, @@ -296,7 +287,7 @@ pub struct SolverContact { /// /// This is set to zero by default. Set to a non-zero value to /// simulate, e.g., conveyor belts. - pub tangent_velocity: Vector, + pub tangent_velocity: Vector, /// Whether or not this contact existed during the last timestep. pub is_new: bool, } diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index b07389c..6243ad9 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -1,5 +1,8 @@ #![allow(clippy::bad_bit_mask)] // Clippy will complain about the bitmasks due to Group::NONE being 0. +#[cfg(feature = "bevy")] +use bevy::prelude::{Component, Reflect, ReflectComponent}; + /// Pairwise filtering using bit masks. /// /// This filtering method is based on two 32-bit values: @@ -16,6 +19,7 @@ /// (self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0 /// ``` #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "bevy", derive(Reflect), reflect(PartialEq))] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] #[repr(C)] pub struct InteractionGroups { @@ -80,6 +84,12 @@ use bitflags::bitflags; bitflags! { /// A bit mask identifying groups for interaction. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] + #[cfg_attr( + feature = "bevy", + derive(Component, Reflect), + reflect(Component, Hash, PartialEq) + )] + #[derive(Default)] pub struct Group: u32 { /// The group n°1. const GROUP_1 = 1 << 0; diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index 1525211..02f019a 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -21,7 +21,7 @@ pub use parry::bounding_volume::BoundingVolume; pub use parry::query::{PointQuery, PointQueryWithLocation, RayCast, TrackedContact}; pub use parry::shape::SharedShape; -use crate::math::{Real, Vector}; +use crate::math::*; /// A contact between two colliders. pub type Contact = parry::query::TrackedContact; @@ -70,6 +70,7 @@ bitflags::bitflags! { } #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "bevy", derive(bevy::prelude::Event))] #[derive(Copy, Clone, Hash, Debug)] /// Events occurring when two colliders start or stop colliding pub enum CollisionEvent { @@ -123,7 +124,8 @@ impl CollisionEvent { } } -#[derive(Copy, Clone, PartialEq, Debug, Default)] +#[cfg_attr(feature = "bevy", derive(bevy::prelude::Event))] +#[derive(Copy, Clone, PartialEq, Debug)] /// Event occurring when the sum of the magnitudes of the contact forces /// between two colliders exceed a threshold. pub struct ContactForceEvent { @@ -132,7 +134,7 @@ pub struct ContactForceEvent { /// The second collider involved in the contact. pub collider2: ColliderHandle, /// The sum of all the forces between the two colliders. - pub total_force: Vector, + pub total_force: Vector, /// The sum of the magnitudes of each force between the two colliders. /// /// Note that this is **not** the same as the magnitude of `self.total_force`. @@ -140,11 +142,25 @@ pub struct ContactForceEvent { /// the magnitude of their sum. pub total_force_magnitude: Real, /// The world-space (unit) direction of the force with strongest magnitude. - pub max_force_direction: Vector, + pub max_force_direction: Vector, /// The magnitude of the largest force at a contact point of this contact pair. pub max_force_magnitude: Real, } +impl Default for ContactForceEvent { + #[inline] + fn default() -> Self { + Self { + collider1: ColliderHandle::PLACEHOLDER, + collider2: ColliderHandle::PLACEHOLDER, + total_force: Default::default(), + total_force_magnitude: Default::default(), + max_force_direction: Default::default(), + max_force_magnitude: Default::default(), + } + } +} + impl ContactForceEvent { /// Init a contact force event from a contact pair. pub fn from_contact_pair(dt: Real, pair: &ContactPair, total_force_magnitude: Real) -> Self { diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index c644b4d..aaa4bec 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -4,22 +4,21 @@ use rayon::prelude::*; use crate::data::graph::EdgeIndex; use crate::data::Coarena; use crate::dynamics::{ - CoefficientCombineRule, ImpulseJointSet, IslandManager, RigidBodyDominance, RigidBodySet, - RigidBodyType, + CoefficientCombineRule, Dominance, ImpulseJointSet, IslandManager, RigidBodySet, RigidBodyType, }; use crate::geometry::{ BroadPhasePairEvent, ColliderChanges, ColliderGraphIndex, ColliderHandle, ColliderPair, ColliderSet, CollisionEvent, ContactData, ContactManifold, ContactManifoldData, ContactPair, InteractionGraph, IntersectionPair, SolverContact, SolverFlags, TemporaryInteractionIndex, }; -use crate::math::{Real, Vector}; +use crate::math::*; use crate::pipeline::{ ActiveEvents, ActiveHooks, ContactModificationContext, EventHandler, PairFilterContext, PhysicsHooks, }; use crate::prelude::{CollisionEventFlags, MultibodyJointSet}; +use parry::math::center; use parry::query::{DefaultQueryDispatcher, PersistentQueryDispatcher}; -use parry::utils::IsometryOpt; use std::collections::HashMap; use std::sync::Arc; @@ -131,7 +130,7 @@ impl NarrowPhase { collider: ColliderHandle, ) -> impl Iterator { self.graph_indices - .get(collider.0) + .get(collider.into()) .map(|id| id.contact_graph_index) .into_iter() .flat_map(move |id| self.contact_graph.interactions_with(id)) @@ -168,7 +167,7 @@ impl NarrowPhase { collider: ColliderHandle, ) -> impl Iterator