From 1bef66fea941307a7305ddaebdb0abe3d0cb281f Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 25 May 2021 11:00:13 +0200 Subject: Add prelude + use vectors for setting linvel/translation in builders --- src/geometry/collider.rs | 179 ++++++++++++++++++++++-------------- src/geometry/collider_components.rs | 10 +- src/geometry/collider_set.rs | 44 ++++++--- src/geometry/contact_pair.rs | 16 ++-- src/geometry/interaction_groups.rs | 54 ++++++----- src/geometry/narrow_phase.rs | 108 +++++++++++++++++----- 6 files changed, 271 insertions(+), 140 deletions(-) (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 08295c1..e73c518 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -2,10 +2,11 @@ use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle}; use crate::geometry::{ ColliderBroadPhaseData, ColliderChanges, ColliderGroups, ColliderMassProperties, ColliderMaterial, ColliderParent, ColliderPosition, ColliderShape, ColliderType, - InteractionGroups, SharedShape, SolverFlags, + InteractionGroups, SharedShape, }; use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector, DIM}; use crate::parry::transformation::vhacd::VHACDParameters; +use crate::pipeline::PhysicsHooksFlags; use na::Unit; use parry::bounding_volume::AABB; use parry::shape::Shape; @@ -20,7 +21,7 @@ pub struct Collider { pub(crate) co_shape: ColliderShape, pub(crate) co_mprops: ColliderMassProperties, pub(crate) co_changes: ColliderChanges, - pub(crate) co_parent: ColliderParent, + pub(crate) co_parent: Option, pub(crate) co_pos: ColliderPosition, pub(crate) co_material: ColliderMaterial, pub(crate) co_groups: ColliderGroups, @@ -31,14 +32,14 @@ pub struct Collider { impl Collider { pub(crate) fn reset_internal_references(&mut self) { - self.co_parent.handle = RigidBodyHandle::invalid(); + self.co_parent = None; self.co_bf_data.proxy_index = crate::INVALID_U32; self.co_changes = ColliderChanges::all(); } /// The rigid body this collider is attached to. - pub fn parent(&self) -> RigidBodyHandle { - self.co_parent.handle + pub fn parent(&self) -> Option { + self.co_parent.map(|parent| parent.handle) } /// Is this collider a sensor? @@ -46,6 +47,26 @@ impl Collider { self.co_type.is_sensor() } + /// The physics hooks enabled for this collider. + pub fn active_hooks(&self) -> PhysicsHooksFlags { + self.co_material.active_hooks + } + + /// Sets the physics hooks enabled for this collider. + pub fn set_active_hooks(&mut self, active_hooks: PhysicsHooksFlags) { + self.co_material.active_hooks = active_hooks; + } + + /// The friction coefficient of this collider. + pub fn friction(&self) -> Real { + self.co_material.friction + } + + /// Sets the friction coefficient of this collider. + pub fn set_friction(&mut self, coefficient: Real) { + self.co_material.friction = 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. @@ -60,6 +81,16 @@ impl Collider { self.co_material.friction_combine_rule = rule; } + /// The restitution coefficient of this collider. + pub fn restitution(&self) -> Real { + self.co_material.restitution + } + + /// Sets the restitution coefficient of this collider. + pub fn set_restitution(&mut self, coefficient: Real) { + self.co_material.restitution = 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. @@ -86,15 +117,22 @@ impl Collider { } } - #[doc(hidden)] - pub fn set_position_debug(&mut self, position: Isometry) { - self.co_pos.0 = position; + /// Sets the translational part of this collider's position. + pub fn set_translation(&mut self, translation: Vector) { + self.co_changes.insert(ColliderChanges::POSITION); + self.co_pos.0.translation.vector = translation; } - /// The position of this collider expressed in the local-space of the rigid-body it is attached to. - #[deprecated(note = "use `.position_wrt_parent()` instead.")] - pub fn delta(&self) -> &Isometry { - &self.co_parent.pos_wrt_parent + /// Sets the rotational part of this collider's position. + pub fn set_rotation(&mut self, rotation: AngVector) { + self.co_changes.insert(ColliderChanges::POSITION); + self.co_pos.0.rotation = Rotation::new(rotation); + } + + /// Sets the position of this collider. + pub fn set_position(&mut self, position: Isometry) { + self.co_changes.insert(ColliderChanges::POSITION); + self.co_pos.0 = position; } /// The world-space position of this collider. @@ -102,15 +140,31 @@ impl Collider { &self.co_pos } + /// The translational part of this rigid-body's position. + pub fn translation(&self) -> &Vector { + &self.co_pos.0.translation.vector + } + + /// The rotational part of this rigid-body's position. + pub fn rotation(&self) -> &Rotation { + &self.co_pos.0.rotation + } + /// The position of this collider wrt the body it is attached to. - pub fn position_wrt_parent(&self) -> &Isometry { - &self.co_parent.pos_wrt_parent + pub fn position_wrt_parent(&self) -> Option<&Isometry> { + self.co_parent.as_ref().map(|p| &p.pos_wrt_parent) } /// Sets the position of this collider wrt. its parent rigid-body. - pub fn set_position_wrt_parent(&mut self, position: Isometry) { + /// + /// Panics if the collider is not attached to a rigid-body. + pub fn set_position_wrt_parent(&mut self, pos_wrt_parent: Isometry) { self.co_changes.insert(ColliderChanges::PARENT); - self.co_parent.pos_wrt_parent = position; + let co_parent = self + .co_parent + .as_mut() + .expect("This collider has no parent."); + co_parent.pos_wrt_parent = pos_wrt_parent; } /// The collision groups used by this collider. @@ -213,13 +267,12 @@ pub struct ColliderBuilder { pub restitution: Real, /// The rule used to combine two restitution coefficients. pub restitution_combine_rule: CoefficientCombineRule, - /// The position of this collider relative to the local frame of the rigid-body it is attached to. - pub pos_wrt_parent: Isometry, + /// The position of this collider. + pub position: Isometry, /// Is this collider a sensor? pub is_sensor: bool, - /// Do we have to always call the contact modifier - /// on this collider? - pub modify_solver_contacts: bool, + /// Physics hooks enabled for this collider. + pub active_hooks: PhysicsHooksFlags, /// The user-data of the collider being built. pub user_data: u128, /// The collision groups for the collider being built. @@ -237,14 +290,14 @@ impl ColliderBuilder { mass_properties: None, friction: Self::default_friction(), restitution: 0.0, - pos_wrt_parent: Isometry::identity(), + position: Isometry::identity(), is_sensor: false, user_data: 0, collision_groups: InteractionGroups::all(), solver_groups: InteractionGroups::all(), friction_combine_rule: CoefficientCombineRule::Average, restitution_combine_rule: CoefficientCombineRule::Average, - modify_solver_contacts: false, + active_hooks: PhysicsHooksFlags::empty(), } } @@ -489,6 +542,11 @@ impl ColliderBuilder { 0.5 } + /// The default density used by the collider builder. + pub fn default_density() -> Real { + 1.0 + } + /// Sets an arbitrary user-defined 128-bit integer associated to the colliders built by this builder. pub fn user_data(mut self, data: u128) -> Self { self.user_data = data; @@ -522,10 +580,9 @@ impl ColliderBuilder { self } - /// If set to `true` then the physics hooks will always run to modify - /// contacts involving this collider. - pub fn modify_solver_contacts(mut self, modify_solver_contacts: bool) -> Self { - self.modify_solver_contacts = modify_solver_contacts; + /// The set of physics hooks enabled for this collider. + pub fn active_hooks(mut self, active_hooks: PhysicsHooksFlags) -> Self { + self.active_hooks = active_hooks; self } @@ -571,51 +628,45 @@ impl ColliderBuilder { self } - /// Sets the initial translation of the collider to be created, - /// relative to the rigid-body it is attached to. - #[cfg(feature = "dim2")] - pub fn translation(mut self, x: Real, y: Real) -> Self { - self.pos_wrt_parent.translation.x = x; - self.pos_wrt_parent.translation.y = y; - self - } - - /// Sets the initial translation of the collider to be created, - /// relative to the rigid-body it is attached to. - #[cfg(feature = "dim3")] - pub fn translation(mut self, x: Real, y: Real, z: Real) -> Self { - self.pos_wrt_parent.translation.x = x; - self.pos_wrt_parent.translation.y = y; - self.pos_wrt_parent.translation.z = z; + /// Sets the initial translation of the collider to be created. + /// + /// 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; self } - /// Sets the initial orientation of the collider to be created, - /// relative to the rigid-body it is attached to. + /// Sets the initial orientation of the collider to be created. + /// + /// 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.pos_wrt_parent.rotation = Rotation::new(angle); + self.position.rotation = Rotation::new(angle); self } - /// Sets the initial position (translation and orientation) of the collider to be created, - /// relative to the rigid-body it is attached to. - pub fn position_wrt_parent(mut self, pos: Isometry) -> Self { - self.pos_wrt_parent = pos; + /// Sets the initial position (translation and orientation) of the collider to be created. + /// + /// 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 { + self.position = pos; self } /// 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_wrt_parent` instead.")] - pub fn position(mut self, pos: Isometry) -> Self { - self.pos_wrt_parent = pos; + #[deprecated(note = "Use `.position` instead.")] + 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_wrt_parent` instead.")] + #[deprecated(note = "Use `.position` instead.")] pub fn delta(mut self, delta: Isometry) -> Self { - self.pos_wrt_parent = delta; + self.position = delta; self } @@ -623,15 +674,11 @@ impl ColliderBuilder { pub fn build(&self) -> Collider { let (co_changes, co_pos, co_bf_data, co_shape, co_type, co_groups, co_material, co_mprops) = self.components(); - let co_parent = ColliderParent { - pos_wrt_parent: co_pos.0, - handle: RigidBodyHandle::invalid(), - }; Collider { co_shape, co_mprops, co_material, - co_parent, + co_parent: None, co_changes, co_pos, co_bf_data, @@ -657,17 +704,11 @@ impl ColliderBuilder { let mass_info = if let Some(mp) = self.mass_properties { ColliderMassProperties::MassProperties(Box::new(mp)) } else { - let default_density = if self.is_sensor { 0.0 } else { 1.0 }; + let default_density = Self::default_density(); let density = self.density.unwrap_or(default_density); ColliderMassProperties::Density(density) }; - let mut solver_flags = SolverFlags::default(); - solver_flags.set( - SolverFlags::MODIFY_SOLVER_CONTACTS, - self.modify_solver_contacts, - ); - let co_shape = self.shape.clone(); let co_mprops = mass_info; let co_material = ColliderMaterial { @@ -675,10 +716,10 @@ impl ColliderBuilder { restitution: self.restitution, friction_combine_rule: self.friction_combine_rule, restitution_combine_rule: self.restitution_combine_rule, - solver_flags, + active_hooks: self.active_hooks, }; let co_changes = ColliderChanges::all(); - let co_pos = ColliderPosition(self.pos_wrt_parent); + let co_pos = ColliderPosition(self.position); let co_bf_data = ColliderBroadPhaseData::default(); let co_groups = ColliderGroups { collision_groups: self.collision_groups, diff --git a/src/geometry/collider_components.rs b/src/geometry/collider_components.rs index a02c706..b63b290 100644 --- a/src/geometry/collider_components.rs +++ b/src/geometry/collider_components.rs @@ -1,7 +1,8 @@ use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle}; -use crate::geometry::{InteractionGroups, SAPProxyIndex, Shape, SharedShape, SolverFlags}; +use crate::geometry::{InteractionGroups, SAPProxyIndex, Shape, SharedShape}; use crate::math::{Isometry, Real}; use crate::parry::partitioning::IndexedData; +use crate::pipeline::PhysicsHooksFlags; use std::ops::Deref; /// The unique identifier of a collider added to a collider set. @@ -241,9 +242,8 @@ pub struct ColliderMaterial { pub friction_combine_rule: CoefficientCombineRule, /// The rule applied to combine the restitution coefficients of two colliders. pub restitution_combine_rule: CoefficientCombineRule, - /// The solver flags attached to this collider in order to customize the way the - /// constraints solver will work with contacts involving this collider. - pub solver_flags: SolverFlags, + /// The physics hooks enabled for contact pairs and intersection pairs involving this collider. + pub active_hooks: PhysicsHooksFlags, } impl ColliderMaterial { @@ -264,7 +264,7 @@ impl Default for ColliderMaterial { restitution: 0.0, friction_combine_rule: CoefficientCombineRule::default(), restitution_combine_rule: CoefficientCombineRule::default(), - solver_flags: SolverFlags::default(), + active_hooks: PhysicsHooksFlags::empty(), } } } diff --git a/src/geometry/collider_set.rs b/src/geometry/collider_set.rs index 14eb54c..268dbdd 100644 --- a/src/geometry/collider_set.rs +++ b/src/geometry/collider_set.rs @@ -61,12 +61,19 @@ impl_field_component_set!(ColliderType, co_type); impl_field_component_set!(ColliderShape, co_shape); impl_field_component_set!(ColliderMassProperties, co_mprops); impl_field_component_set!(ColliderChanges, co_changes); -impl_field_component_set!(ColliderParent, co_parent); impl_field_component_set!(ColliderPosition, co_pos); impl_field_component_set!(ColliderMaterial, co_material); impl_field_component_set!(ColliderGroups, co_groups); impl_field_component_set!(ColliderBroadPhaseData, co_bf_data); +impl ComponentSetOption for ColliderSet { + #[inline(always)] + fn get(&self, handle: crate::data::Index) -> Option<&ColliderParent> { + self.get(ColliderHandle(handle)) + .and_then(|b| b.co_parent.as_ref()) + } +} + impl ColliderSet { /// Create a new empty set of colliders. pub fn new() -> Self { @@ -122,7 +129,17 @@ impl ColliderSet { } /// Inserts a new collider to this set and retrieve its handle. - pub fn insert( + pub fn insert(&mut self, mut coll: Collider) -> ColliderHandle { + // Make sure the internal links are reset, they may not be + // if this rigid-body was obtained by cloning another one. + coll.reset_internal_references(); + let handle = ColliderHandle(self.colliders.insert(coll)); + self.modified_colliders.push(handle); + handle + } + + /// 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, mut coll: Collider, parent_handle: RigidBodyHandle, @@ -131,7 +148,10 @@ impl ColliderSet { // Make sure the internal links are reset, they may not be // if this rigid-body was obtained by cloning another one. coll.reset_internal_references(); - coll.co_parent.handle = parent_handle; + coll.co_parent = Some(ColliderParent { + handle: parent_handle, + pos_wrt_parent: coll.co_pos.0, + }); // NOTE: we use `get_mut` instead of `get_mut_internal` so that the // modification flag is updated properly. @@ -144,7 +164,7 @@ impl ColliderSet { let coll = self.colliders.get_mut(handle.0).unwrap(); parent.add_collider( handle, - &mut coll.co_parent, + coll.co_parent.as_mut().unwrap(), &mut coll.co_pos, &coll.co_shape, &coll.co_mprops, @@ -170,13 +190,15 @@ impl ColliderSet { */ // NOTE: we use `get_mut_internal_with_modification_tracking` instead of `get_mut_internal` so that the // modification flag is updated properly. - if let Some(parent) = - bodies.get_mut_internal_with_modification_tracking(collider.co_parent.handle) - { - parent.remove_collider_internal(handle, &collider); - - if wake_up { - islands.wake_up(bodies, collider.co_parent.handle, true); + if let Some(co_parent) = &collider.co_parent { + if let Some(parent) = + bodies.get_mut_internal_with_modification_tracking(co_parent.handle) + { + parent.remove_collider_internal(handle, &collider); + + if wake_up { + islands.wake_up(bodies, co_parent.handle, true); + } } } diff --git a/src/geometry/contact_pair.rs b/src/geometry/contact_pair.rs index 5a568fa..f4e7834 100644 --- a/src/geometry/contact_pair.rs +++ b/src/geometry/contact_pair.rs @@ -1,5 +1,5 @@ use crate::dynamics::RigidBodyHandle; -use crate::geometry::{ColliderPair, Contact, ContactManifold}; +use crate::geometry::{ColliderHandle, Contact, ContactManifold}; use crate::math::{Point, Real, Vector}; use parry::query::ContactManifoldsWorkspace; @@ -10,9 +10,6 @@ bitflags::bitflags! { /// The constraint solver will take this contact manifold into /// account for force computation. const COMPUTE_IMPULSES = 0b001; - /// The user-defined physics hooks will be used to - /// modify the solver contacts of this contact manifold. - const MODIFY_SOLVER_CONTACTS = 0b010; } } @@ -56,8 +53,10 @@ impl Default for ContactData { #[derive(Clone)] /// The description of all the contacts between a pair of colliders. pub struct ContactPair { - /// The pair of colliders involved. - pub pair: ColliderPair, + /// The first collider involved in the contact pair. + pub collider1: ColliderHandle, + /// The second collider involved in the contact pair. + pub collider2: ColliderHandle, /// The set of contact manifolds between the two colliders. /// /// All contact manifold contain themselves contact points between the colliders. @@ -68,9 +67,10 @@ pub struct ContactPair { } impl ContactPair { - pub(crate) fn new(pair: ColliderPair) -> Self { + pub(crate) fn new(collider1: ColliderHandle, collider2: ColliderHandle) -> Self { Self { - pair, + collider1, + collider2, has_any_active_contact: false, manifolds: Vec::new(), workspace: None, diff --git a/src/geometry/interaction_groups.rs b/src/geometry/interaction_groups.rs index 37b7586..b2961d9 100644 --- a/src/geometry/interaction_groups.rs +++ b/src/geometry/interaction_groups.rs @@ -1,56 +1,66 @@ -#[repr(transparent)] -#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] /// Pairwise filtering using bit masks. /// -/// This filtering method is based on two 16-bit values: -/// - The interaction groups (the 16 left-most bits of `self.0`). -/// - The interaction mask (the 16 right-most bits of `self.0`). +/// This filtering method is based on two 32-bit values: +/// - The interaction groups memberships. +/// - The interaction groups filter. /// /// An interaction is allowed between two filters `a` and `b` when two conditions /// are met simultaneously: -/// - The interaction groups of `a` has at least one bit set to `1` in common with the interaction mask of `b`. -/// - The interaction groups of `b` has at least one bit set to `1` in common with the interaction mask of `a`. +/// - The groups membership of `a` has at least one bit set to `1` in common with the groups filter of `b`. +/// - The groups membership of `b` has at least one bit set to `1` in common with the groups filter of `a`. /// /// In other words, interactions are allowed between two filter iff. the following condition is met: /// ```ignore -/// ((self.0 >> 16) & rhs.0) != 0 && ((rhs.0 >> 16) & self.0) != 0 +/// (self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0 /// ``` -pub struct InteractionGroups(pub u32); +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[repr(C)] +pub struct InteractionGroups { + /// Groups memberships. + pub memberships: u32, + /// Groups filter. + pub filter: u32, +} impl InteractionGroups { /// Initializes with the given interaction groups and interaction mask. - pub const fn new(groups: u16, masks: u16) -> Self { - Self::none().with_groups(groups).with_mask(masks) + pub const fn new(memberships: u32, filter: u32) -> Self { + Self { + memberships, + filter, + } } /// Allow interaction with everything. pub const fn all() -> Self { - Self(u32::MAX) + Self::new(u32::MAX, u32::MAX) } /// Prevent all interactions. pub const fn none() -> Self { - Self(0) + Self::new(0, 0) } /// Sets the group this filter is part of. - pub const fn with_groups(self, groups: u16) -> Self { - Self((self.0 & 0x0000ffff) | ((groups as u32) << 16)) + pub const fn with_memberships(mut self, memberships: u32) -> Self { + self.memberships = memberships; + self } /// Sets the interaction mask of this filter. - pub const fn with_mask(self, mask: u16) -> Self { - Self((self.0 & 0xffff0000) | (mask as u32)) + pub const fn with_filter(mut self, filter: u32) -> Self { + self.filter = filter; + self } - /// Check if interactions should be allowed based on the interaction groups and mask. + /// Check if interactions should be allowed based on the interaction memberships and filter. /// - /// An interaction is allowed iff. the groups of `self` contain at least one bit set to 1 in common - /// with the mask of `rhs`, and vice-versa. + /// An interaction is allowed iff. the memberships of `self` contain at least one bit set to 1 in common + /// with the filter of `rhs`, and vice-versa. #[inline] pub const fn test(self, rhs: Self) -> bool { - ((self.0 >> 16) & rhs.0) != 0 && ((rhs.0 >> 16) & self.0) != 0 + (self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0 } } diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index 57504f5..e196798 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -97,6 +97,18 @@ impl NarrowPhase { &self.intersection_graph } + /// All the contacts involving the given collider. + /// + /// It is strongly recommended to use the [`NarrowPhase::contacts_with`] method instead. This + /// method can be used if the generation number of the collider handle isn't known. + pub fn contacts_with_unknown_gen( + &self, + collider: u32, + ) -> Option> { + let id = self.graph_indices.get_unknown_gen(collider)?; + Some(self.contact_graph.interactions_with(id.contact_graph_index)) + } + /// All the contacts involving the given collider. pub fn contacts_with( &self, @@ -106,6 +118,22 @@ impl NarrowPhase { Some(self.contact_graph.interactions_with(id.contact_graph_index)) } + /// All the intersections involving the given collider. + /// + /// It is strongly recommended to use the [`NarrowPhase::intersections_with`] method instead. + /// This method can be used if the generation number of the collider handle isn't known. + pub fn intersections_with_unknown_gen( + &self, + collider: u32, + ) -> Option + '_> { + let id = self.graph_indices.get_unknown_gen(collider)?; + Some( + self.intersection_graph + .interactions_with(id.intersection_graph_index) + .map(|e| (e.0, e.1, *e.2)), + ) + } + /// All the intersections involving the given collider. pub fn intersections_with( &self, @@ -119,6 +147,22 @@ impl NarrowPhase { ) } + /// The contact pair involving two specific colliders. + /// + /// It is strongly recommended to use the [`NarrowPhase::contact_pair`] method instead. This + /// method can be used if the generation number of the collider handle isn't known. + /// + /// If this returns `None`, there is no contact between the two colliders. + /// If this returns `Some`, then there may be a contact between the two colliders. Check the + /// result [`ContactPair::has_any_active_collider`] method to see if there is an actual contact. + pub fn contact_pair_unknown_gen(&self, collider1: u32, collider2: u32) -> Option<&ContactPair> { + let id1 = self.graph_indices.get_unknown_gen(collider1)?; + let id2 = self.graph_indices.get_unknown_gen(collider2)?; + self.contact_graph + .interaction_pair(id1.contact_graph_index, id2.contact_graph_index) + .map(|c| c.2) + } + /// The contact pair involving two specific colliders. /// /// If this returns `None`, there is no contact between the two colliders. @@ -136,6 +180,21 @@ impl NarrowPhase { .map(|c| c.2) } + /// The intersection pair involving two specific colliders. + /// + /// It is strongly recommended to use the [`NarrowPhase::intersection_pair`] method instead. This + /// method can be used if the generation number of the collider handle isn't known. + /// + /// If this returns `None` or `Some(false)`, then there is no intersection between the two colliders. + /// If this returns `Some(true)`, then there may be an intersection between the two colliders. + pub fn intersection_pair_unknown_gen(&self, collider1: u32, collider2: u32) -> Option { + let id1 = self.graph_indices.get_unknown_gen(collider1)?; + let id2 = self.graph_indices.get_unknown_gen(collider2)?; + self.intersection_graph + .interaction_pair(id1.intersection_graph_index, id2.intersection_graph_index) + .map(|c| *c.2) + } + /// The intersection pair involving two specific colliders. /// /// If this returns `None` or `Some(false)`, then there is no intersection between the two colliders. @@ -527,7 +586,7 @@ impl NarrowPhase { .find_edge(gid1.contact_graph_index, gid2.contact_graph_index) .is_none() { - let interaction = ContactPair::new(*pair); + let interaction = ContactPair::new(pair.collider1, pair.collider2); let _ = self.contact_graph.add_edge( gid1.contact_graph_index, gid2.contact_graph_index, @@ -585,7 +644,8 @@ impl NarrowPhase { + ComponentSetOption + ComponentSet + ComponentSet - + ComponentSet, + + ComponentSet + + ComponentSet, { if modified_colliders.is_empty() { return; @@ -593,7 +653,6 @@ impl NarrowPhase { let nodes = &self.intersection_graph.graph.nodes; let query_dispatcher = &*self.query_dispatcher; - let active_hooks = hooks.active_hooks(); // TODO: don't iterate on all the edges. par_iter_mut!(&mut self.intersection_graph.graph.edges).for_each(|edge| { @@ -601,19 +660,21 @@ impl NarrowPhase { let handle2 = nodes[edge.target().index()].weight; let co_parent1: Option<&ColliderParent> = colliders.get(handle1.0); - let (co_changes1, co_groups1, co_shape1, co_pos1): ( + let (co_changes1, co_groups1, co_shape1, co_pos1, co_material1): ( &ColliderChanges, &ColliderGroups, &ColliderShape, &ColliderPosition, + &ColliderMaterial, ) = colliders.index_bundle(handle1.0); let co_parent2: Option<&ColliderParent> = colliders.get(handle2.0); - let (co_changes2, co_groups2, co_shape2, co_pos2): ( + let (co_changes2, co_groups2, co_shape2, co_pos2, co_material2): ( &ColliderChanges, &ColliderGroups, &ColliderShape, &ColliderPosition, + &ColliderMaterial, ) = colliders.index_bundle(handle2.0); if !co_changes1.needs_narrow_phase_update() && !co_changes2.needs_narrow_phase_update() @@ -656,6 +717,8 @@ impl NarrowPhase { return; } + let active_hooks = co_material1.active_hooks | co_material2.active_hooks; + if !active_hooks.contains(PhysicsHooksFlags::FILTER_INTERSECTION_PAIR) && !status1.is_dynamic() && !status2.is_dynamic() @@ -721,29 +784,28 @@ impl NarrowPhase { } let query_dispatcher = &*self.query_dispatcher; - let active_hooks = hooks.active_hooks(); // TODO: don't iterate on all the edges. par_iter_mut!(&mut self.contact_graph.graph.edges).for_each(|edge| { let pair = &mut edge.weight; - let co_parent1: Option<&ColliderParent> = colliders.get(pair.pair.collider1.0); + let co_parent1: Option<&ColliderParent> = colliders.get(pair.collider1.0); let (co_changes1, co_groups1, co_shape1, co_pos1, co_material1): ( &ColliderChanges, &ColliderGroups, &ColliderShape, &ColliderPosition, &ColliderMaterial, - ) = colliders.index_bundle(pair.pair.collider1.0); + ) = colliders.index_bundle(pair.collider1.0); - let co_parent2: Option<&ColliderParent> = colliders.get(pair.pair.collider2.0); + let co_parent2: Option<&ColliderParent> = colliders.get(pair.collider2.0); let (co_changes2, co_groups2, co_shape2, co_pos2, co_material2): ( &ColliderChanges, &ColliderGroups, &ColliderShape, &ColliderPosition, &ColliderMaterial, - ) = colliders.index_bundle(pair.pair.collider2.0); + ) = colliders.index_bundle(pair.collider2.0); if !co_changes1.needs_narrow_phase_update() && !co_changes2.needs_narrow_phase_update() { @@ -785,6 +847,7 @@ impl NarrowPhase { return; } + let active_hooks = co_material1.active_hooks | co_material2.active_hooks; if !active_hooks.contains(PhysicsHooksFlags::FILTER_CONTACT_PAIR) && !status1.is_dynamic() && !status2.is_dynamic() @@ -800,8 +863,8 @@ impl NarrowPhase { colliders, rigid_body1: co_parent1.map(|p| p.handle), rigid_body2: co_parent2.map(|p| p.handle), - collider1: pair.pair.collider1, - collider2: pair.pair.collider2, + collider1: pair.collider1, + collider2: pair.collider2, }; if let Some(solver_flags) = hooks.filter_contact_pair(&context) { @@ -811,7 +874,7 @@ impl NarrowPhase { return; } } else { - co_material1.solver_flags | co_material2.solver_flags + SolverFlags::default() }; if !co_groups1.solver_groups.test(co_groups2.solver_groups) { @@ -896,12 +959,7 @@ impl NarrowPhase { } // Apply the user-defined contact modification. - if active_hooks.contains(PhysicsHooksFlags::MODIFY_SOLVER_CONTACTS) - && manifold - .data - .solver_flags - .contains(SolverFlags::MODIFY_SOLVER_CONTACTS) - { + if active_hooks.contains(PhysicsHooksFlags::MODIFY_SOLVER_CONTACTS) { let mut modifiable_solver_contacts = std::mem::replace(&mut manifold.data.solver_contacts, Vec::new()); let mut modifiable_user_data = manifold.data.user_data; @@ -912,8 +970,8 @@ impl NarrowPhase { colliders, rigid_body1: co_parent1.map(|p| p.handle), rigid_body2: co_parent2.map(|p| p.handle), - collider1: pair.pair.collider1, - collider2: pair.pair.collider2, + collider1: pair.collider1, + collider2: pair.collider2, manifold, solver_contacts: &mut modifiable_solver_contacts, normal: &mut modifiable_normal, @@ -931,13 +989,13 @@ impl NarrowPhase { if has_any_active_contact != pair.has_any_active_contact { if has_any_active_contact { events.handle_contact_event(ContactEvent::Started( - pair.pair.collider1, - pair.pair.collider2, + pair.collider1, + pair.collider2, )); } else { events.handle_contact_event(ContactEvent::Stopped( - pair.pair.collider1, - pair.pair.collider2, + pair.collider1, + pair.collider2, )); } -- cgit From 826ce5f014281fd04b7a18238f102f2591d0b255 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 1 Jun 2021 12:36:01 +0200 Subject: Rework the event system --- src/geometry/collider.rs | 73 +++++++++++---- src/geometry/collider_components.rs | 56 ++++++++++-- src/geometry/collider_set.rs | 7 +- src/geometry/narrow_phase.rs | 177 ++++++++++++++++++++++-------------- 4 files changed, 216 insertions(+), 97 deletions(-) (limited to 'src/geometry') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index e73c518..612df3c 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -1,12 +1,12 @@ use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle}; use crate::geometry::{ - ColliderBroadPhaseData, ColliderChanges, ColliderGroups, ColliderMassProperties, + ColliderBroadPhaseData, ColliderChanges, ColliderFlags, ColliderGroups, ColliderMassProps, ColliderMaterial, ColliderParent, ColliderPosition, ColliderShape, ColliderType, InteractionGroups, SharedShape, }; use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector, DIM}; use crate::parry::transformation::vhacd::VHACDParameters; -use crate::pipeline::PhysicsHooksFlags; +use crate::pipeline::{ActiveEvents, ActiveHooks}; use na::Unit; use parry::bounding_volume::AABB; use parry::shape::Shape; @@ -19,11 +19,12 @@ use parry::shape::Shape; pub struct Collider { pub(crate) co_type: ColliderType, pub(crate) co_shape: ColliderShape, - pub(crate) co_mprops: ColliderMassProperties, + pub(crate) co_mprops: ColliderMassProps, pub(crate) co_changes: ColliderChanges, pub(crate) co_parent: Option, pub(crate) co_pos: ColliderPosition, pub(crate) co_material: ColliderMaterial, + pub(crate) co_flags: ColliderFlags, pub(crate) co_groups: ColliderGroups, pub(crate) co_bf_data: ColliderBroadPhaseData, /// User-defined data associated to this rigid-body. @@ -48,13 +49,23 @@ impl Collider { } /// The physics hooks enabled for this collider. - pub fn active_hooks(&self) -> PhysicsHooksFlags { - self.co_material.active_hooks + pub fn active_hooks(&self) -> ActiveHooks { + self.co_flags.active_hooks } /// Sets the physics hooks enabled for this collider. - pub fn set_active_hooks(&mut self, active_hooks: PhysicsHooksFlags) { - self.co_material.active_hooks = active_hooks; + pub fn set_active_hooks(&mut self, active_hooks: ActiveHooks) { + self.co_flags.active_hooks = active_hooks; + } + + /// The physics hooks enabled for this collider. + pub fn active_events(&self) -> ActiveEvents { + self.co_flags.active_events + } + + /// Sets the physics hooks enabled for this collider. + pub fn set_active_events(&mut self, active_events: ActiveEvents) { + self.co_flags.active_events = active_events; } /// The friction coefficient of this collider. @@ -201,8 +212,8 @@ impl Collider { /// The density of this collider, if set. pub fn density(&self) -> Option { match &self.co_mprops { - ColliderMassProperties::Density(density) => Some(*density), - ColliderMassProperties::MassProperties(_) => None, + ColliderMassProps::Density(density) => Some(*density), + ColliderMassProps::MassProperties(_) => None, } } @@ -242,8 +253,8 @@ impl Collider { /// Compute the local-space mass properties of this collider. pub fn mass_properties(&self) -> MassProperties { match &self.co_mprops { - ColliderMassProperties::Density(density) => self.co_shape.mass_properties(*density), - ColliderMassProperties::MassProperties(mass_properties) => **mass_properties, + ColliderMassProps::Density(density) => self.co_shape.mass_properties(*density), + ColliderMassProps::MassProperties(mass_properties) => **mass_properties, } } } @@ -272,7 +283,9 @@ pub struct ColliderBuilder { /// Is this collider a sensor? pub is_sensor: bool, /// Physics hooks enabled for this collider. - pub active_hooks: PhysicsHooksFlags, + pub active_hooks: ActiveHooks, + /// Events enabled for this collider. + pub active_events: ActiveEvents, /// The user-data of the collider being built. pub user_data: u128, /// The collision groups for the collider being built. @@ -297,7 +310,8 @@ impl ColliderBuilder { solver_groups: InteractionGroups::all(), friction_combine_rule: CoefficientCombineRule::Average, restitution_combine_rule: CoefficientCombineRule::Average, - active_hooks: PhysicsHooksFlags::empty(), + active_hooks: ActiveHooks::empty(), + active_events: ActiveEvents::empty(), } } @@ -581,11 +595,17 @@ impl ColliderBuilder { } /// The set of physics hooks enabled for this collider. - pub fn active_hooks(mut self, active_hooks: PhysicsHooksFlags) -> Self { + pub fn active_hooks(mut self, active_hooks: ActiveHooks) -> Self { self.active_hooks = active_hooks; self } + /// The set of events enabled for this collider. + pub fn active_events(mut self, active_events: ActiveEvents) -> Self { + self.active_events = active_events; + self + } + /// Sets the friction coefficient of the collider this builder will build. pub fn friction(mut self, friction: Real) -> Self { self.friction = friction; @@ -672,12 +692,22 @@ impl ColliderBuilder { /// Builds a new collider attached to the given rigid-body. pub fn build(&self) -> Collider { - let (co_changes, co_pos, co_bf_data, co_shape, co_type, co_groups, co_material, co_mprops) = - self.components(); + let ( + co_changes, + co_pos, + co_bf_data, + co_shape, + co_type, + co_groups, + co_material, + co_flags, + co_mprops, + ) = self.components(); Collider { co_shape, co_mprops, co_material, + co_flags, co_parent: None, co_changes, co_pos, @@ -699,14 +729,15 @@ impl ColliderBuilder { ColliderType, ColliderGroups, ColliderMaterial, - ColliderMassProperties, + ColliderFlags, + ColliderMassProps, ) { let mass_info = if let Some(mp) = self.mass_properties { - ColliderMassProperties::MassProperties(Box::new(mp)) + ColliderMassProps::MassProperties(Box::new(mp)) } else { let default_density = Self::default_density(); let density = self.density.unwrap_or(default_density); - ColliderMassProperties::Density(density) + ColliderMassProps::Density(density) }; let co_shape = self.shape.clone(); @@ -716,7 +747,10 @@ impl ColliderBuilder { restitution: self.restitution, friction_combine_rule: self.friction_combine_rule, restitution_combine_rule: self.restitution_combine_rule, + }; + let co_flags = ColliderFlags { active_hooks: self.active_hooks, + active_events: self.active_events, }; let co_changes = ColliderChanges::all(); let co_pos = ColliderPosition(self.position); @@ -739,6 +773,7 @@ impl ColliderBuilder { co_type, co_groups, co_material, + co_flags, co_mprops, ) } diff --git a/src/geometry/collider_components.rs b/src/geometry/collider_components.rs index b63b290..5923a42 100644 --- a/src/geometry/collider_components.rs +++ b/src/geometry/collider_components.rs @@ -2,7 +2,7 @@ use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle}; use crate::geometry::{InteractionGroups, SAPProxyIndex, Shape, SharedShape}; use crate::math::{Isometry, Real}; use crate::parry::partitioning::IndexedData; -use crate::pipeline::PhysicsHooksFlags; +use crate::pipeline::{ActiveEvents, ActiveHooks}; use std::ops::Deref; /// The unique identifier of a collider added to a collider set. @@ -118,7 +118,7 @@ pub type ColliderShape = SharedShape; #[derive(Clone)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] /// The mass-properties of a collider. -pub enum ColliderMassProperties { +pub enum ColliderMassProps { /// The collider is given a density. /// /// Its actual `MassProperties` are computed automatically with @@ -128,13 +128,19 @@ pub enum ColliderMassProperties { MassProperties(Box), } -impl Default for ColliderMassProperties { +impl Default for ColliderMassProps { fn default() -> Self { - ColliderMassProperties::Density(1.0) + ColliderMassProps::Density(1.0) } } -impl ColliderMassProperties { +impl From for ColliderMassProps { + fn from(mprops: MassProperties) -> Self { + ColliderMassProps::MassProperties(Box::new(mprops)) + } +} + +impl ColliderMassProps { /// The mass-properties of this collider. /// /// If `self` is the `Density` variant, then this computes the mass-properties based @@ -242,8 +248,6 @@ pub struct ColliderMaterial { pub friction_combine_rule: CoefficientCombineRule, /// The rule applied to combine the restitution coefficients of two colliders. pub restitution_combine_rule: CoefficientCombineRule, - /// The physics hooks enabled for contact pairs and intersection pairs involving this collider. - pub active_hooks: PhysicsHooksFlags, } impl ColliderMaterial { @@ -264,7 +268,43 @@ impl Default for ColliderMaterial { restitution: 0.0, friction_combine_rule: CoefficientCombineRule::default(), restitution_combine_rule: CoefficientCombineRule::default(), - active_hooks: PhysicsHooksFlags::empty(), + } + } +} + +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +/// A set of flags controlling the active hooks and events for this colliders. +pub struct ColliderFlags { + /// The physics hooks enabled for contact pairs and intersection pairs involving this collider. + pub active_hooks: ActiveHooks, + /// The events enabled for this collider. + pub active_events: ActiveEvents, +} + +impl Default for ColliderFlags { + fn default() -> Self { + Self { + active_hooks: ActiveHooks::empty(), + active_events: ActiveEvents::empty(), + } + } +} + +impl From for ColliderFlags { + fn from(active_hooks: ActiveHooks) -> Self { + Self { + active_hooks, + ..Default::default() + } + } +} + +impl From for ColliderFlags { + fn from(active_events: ActiveEvents) -> Self { + Self { + active_events, + ..Default::default() } } } diff --git a/src/geometry/collider_set.rs b/src/geometry/collider_set.rs index 268dbdd..d8603cd 100644 --- a/src/geometry/collider_set.rs +++ b/src/geometry/collider_set.rs @@ -2,8 +2,8 @@ use crate::data::arena::Arena; use crate::data::{ComponentSet, ComponentSetMut, ComponentSetOption}; use crate::dynamics::{IslandManager, RigidBodyHandle, RigidBodySet}; use crate::geometry::{ - Collider, ColliderBroadPhaseData, ColliderGroups, ColliderMassProperties, ColliderMaterial, - ColliderParent, ColliderPosition, ColliderShape, ColliderType, + Collider, ColliderBroadPhaseData, ColliderFlags, ColliderGroups, ColliderMassProps, + ColliderMaterial, ColliderParent, ColliderPosition, ColliderShape, ColliderType, }; use crate::geometry::{ColliderChanges, ColliderHandle}; use std::ops::{Index, IndexMut}; @@ -59,10 +59,11 @@ macro_rules! impl_field_component_set( impl_field_component_set!(ColliderType, co_type); impl_field_component_set!(ColliderShape, co_shape); -impl_field_component_set!(ColliderMassProperties, co_mprops); +impl_field_component_set!(ColliderMassProps, co_mprops); impl_field_component_set!(ColliderChanges, co_changes); impl_field_component_set!(ColliderPosition, co_pos); impl_field_component_set!(ColliderMaterial, co_material); +impl_field_component_set!(ColliderFlags, co_flags); impl_field_component_set!(ColliderGroups, co_groups); impl_field_component_set!(ColliderBroadPhaseData, co_bf_data); diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index e196798..61bb4c0 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -14,8 +14,10 @@ use crate::geometry::{ }; use crate::math::{Real, Vector}; use crate::pipeline::{ - ContactModificationContext, EventHandler, PairFilterContext, PhysicsHooks, PhysicsHooksFlags, + ActiveEvents, ActiveHooks, ContactModificationContext, EventHandler, PairFilterContext, + PhysicsHooks, }; +use crate::prelude::ColliderFlags; use parry::query::{DefaultQueryDispatcher, PersistentQueryDispatcher}; use parry::utils::IsometryOpt; use std::collections::HashMap; @@ -101,21 +103,26 @@ impl NarrowPhase { /// /// It is strongly recommended to use the [`NarrowPhase::contacts_with`] method instead. This /// method can be used if the generation number of the collider handle isn't known. - pub fn contacts_with_unknown_gen( - &self, - collider: u32, - ) -> Option> { - let id = self.graph_indices.get_unknown_gen(collider)?; - Some(self.contact_graph.interactions_with(id.contact_graph_index)) + pub fn contacts_with_unknown_gen(&self, collider: u32) -> impl Iterator { + self.graph_indices + .get_unknown_gen(collider) + .map(|id| id.contact_graph_index) + .into_iter() + .flat_map(move |id| self.contact_graph.interactions_with(id)) + .map(|pair| pair.2) } /// All the contacts involving the given collider. - pub fn contacts_with( + pub fn contacts_with<'a>( &self, collider: ColliderHandle, - ) -> Option> { - let id = self.graph_indices.get(collider.0)?; - Some(self.contact_graph.interactions_with(id.contact_graph_index)) + ) -> impl Iterator { + self.graph_indices + .get(collider.0) + .map(|id| id.contact_graph_index) + .into_iter() + .flat_map(move |id| self.contact_graph.interactions_with(id)) + .map(|pair| pair.2) } /// All the intersections involving the given collider. @@ -125,26 +132,32 @@ impl NarrowPhase { pub fn intersections_with_unknown_gen( &self, collider: u32, - ) -> Option + '_> { - let id = self.graph_indices.get_unknown_gen(collider)?; - Some( - self.intersection_graph - .interactions_with(id.intersection_graph_index) - .map(|e| (e.0, e.1, *e.2)), - ) + ) -> impl Iterator + '_ { + self.graph_indices + .get_unknown_gen(collider) + .map(|id| id.intersection_graph_index) + .into_iter() + .flat_map(move |id| { + self.intersection_graph + .interactions_with(id) + .map(|e| (e.0, e.1, *e.2)) + }) } /// All the intersections involving the given collider. pub fn intersections_with( &self, collider: ColliderHandle, - ) -> Option + '_> { - let id = self.graph_indices.get(collider.0)?; - Some( - self.intersection_graph - .interactions_with(id.intersection_graph_index) - .map(|e| (e.0, e.1, *e.2)), - ) + ) -> impl Iterator + '_ { + self.graph_indices + .get(collider.0) + .map(|id| id.intersection_graph_index) + .into_iter() + .flat_map(move |id| { + self.intersection_graph + .interactions_with(id) + .map(|e| (e.0, e.1, *e.2)) + }) } /// The contact pair involving two specific colliders. @@ -244,8 +257,9 @@ impl NarrowPhase { + ComponentSet + ComponentSetMut, Colliders: ComponentSet - + ComponentSetOption - + ComponentSet, + + ComponentSet + + ComponentSet + + ComponentSetOption, { // TODO: avoid these hash-maps. // They are necessary to handle the swap-remove done internally @@ -340,8 +354,9 @@ impl NarrowPhase { + ComponentSet + ComponentSetMut, Colliders: ComponentSet - + ComponentSetOption - + ComponentSet, + + ComponentSet + + ComponentSet + + ComponentSetOption, { let mut pairs_to_remove = vec![]; @@ -456,7 +471,9 @@ impl NarrowPhase { Bodies: ComponentSetMut + ComponentSet + ComponentSetMut, - Colliders: ComponentSet + ComponentSetOption, + Colliders: ComponentSet + + ComponentSet + + ComponentSetOption, { let co_type1: Option<&ColliderType> = colliders.get(pair.collider1.0); let co_type2: Option<&ColliderType> = colliders.get(pair.collider2.0); @@ -478,9 +495,16 @@ impl NarrowPhase { // Emit an intersection lost event if we had an intersection before removing the edge. if Some(true) == was_intersecting { - let prox_event = - IntersectionEvent::new(pair.collider1, pair.collider2, false); - events.handle_intersection_event(prox_event) + let co_flag1: &ColliderFlags = colliders.index(pair.collider1.0); + let co_flag2: &ColliderFlags = colliders.index(pair.collider2.0); + + if (co_flag1.active_events | co_flag2.active_events) + .contains(ActiveEvents::INTERSECTION_EVENTS) + { + let prox_event = + IntersectionEvent::new(pair.collider1, pair.collider2, false); + events.handle_intersection_event(prox_event) + } } } else { let contact_pair = self @@ -506,10 +530,17 @@ impl NarrowPhase { } } - events.handle_contact_event(ContactEvent::Stopped( - pair.collider1, - pair.collider2, - )) + let co_flag1: &ColliderFlags = colliders.index(pair.collider1.0); + let co_flag2: &ColliderFlags = colliders.index(pair.collider2.0); + + if (co_flag1.active_events | co_flag2.active_events) + .contains(ActiveEvents::CONTACT_EVENTS) + { + events.handle_contact_event( + ContactEvent::Stopped(pair.collider1, pair.collider2), + &ctct, + ) + } } } } @@ -606,9 +637,11 @@ impl NarrowPhase { events: &dyn EventHandler, ) where Bodies: ComponentSetMut - + ComponentSet - + ComponentSetMut, - Colliders: ComponentSet + ComponentSetOption, + + ComponentSetMut + + ComponentSet, + Colliders: ComponentSet + + ComponentSet + + ComponentSetOption, { for event in broad_phase_events { match event { @@ -645,7 +678,8 @@ impl NarrowPhase { + ComponentSet + ComponentSet + ComponentSet - + ComponentSet, + + ComponentSet + + ComponentSet, { if modified_colliders.is_empty() { return; @@ -660,21 +694,21 @@ impl NarrowPhase { let handle2 = nodes[edge.target().index()].weight; let co_parent1: Option<&ColliderParent> = colliders.get(handle1.0); - let (co_changes1, co_groups1, co_shape1, co_pos1, co_material1): ( + let (co_changes1, co_groups1, co_shape1, co_pos1, co_flags1): ( &ColliderChanges, &ColliderGroups, &ColliderShape, &ColliderPosition, - &ColliderMaterial, + &ColliderFlags, ) = colliders.index_bundle(handle1.0); let co_parent2: Option<&ColliderParent> = colliders.get(handle2.0); - let (co_changes2, co_groups2, co_shape2, co_pos2, co_material2): ( + let (co_changes2, co_groups2, co_shape2, co_pos2, co_flags2): ( &ColliderChanges, &ColliderGroups, &ColliderShape, &ColliderPosition, - &ColliderMaterial, + &ColliderFlags, ) = colliders.index_bundle(handle2.0); if !co_changes1.needs_narrow_phase_update() && !co_changes2.needs_narrow_phase_update() @@ -717,9 +751,10 @@ impl NarrowPhase { return; } - let active_hooks = co_material1.active_hooks | co_material2.active_hooks; + let active_hooks = co_flags1.active_hooks | co_flags2.active_hooks; + let active_events = co_flags1.active_events | co_flags2.active_events; - if !active_hooks.contains(PhysicsHooksFlags::FILTER_INTERSECTION_PAIR) + if !active_hooks.contains(ActiveHooks::FILTER_INTERSECTION_PAIR) && !status1.is_dynamic() && !status2.is_dynamic() { @@ -727,7 +762,7 @@ impl NarrowPhase { return; } - if active_hooks.contains(PhysicsHooksFlags::FILTER_INTERSECTION_PAIR) { + if active_hooks.contains(ActiveHooks::FILTER_INTERSECTION_PAIR) { let context = PairFilterContext { bodies, colliders, @@ -748,7 +783,9 @@ impl NarrowPhase { if let Ok(intersection) = query_dispatcher.intersection_test(&pos12, &**co_shape1, &**co_shape2) { - if intersection != edge.weight { + if active_events.contains(ActiveEvents::INTERSECTION_EVENTS) + && intersection != edge.weight + { edge.weight = intersection; events.handle_intersection_event(IntersectionEvent::new( handle1, @@ -777,7 +814,8 @@ impl NarrowPhase { + ComponentSet + ComponentSet + ComponentSet - + ComponentSet, + + ComponentSet + + ComponentSet, { if modified_colliders.is_empty() { return; @@ -790,21 +828,23 @@ impl NarrowPhase { let pair = &mut edge.weight; let co_parent1: Option<&ColliderParent> = colliders.get(pair.collider1.0); - let (co_changes1, co_groups1, co_shape1, co_pos1, co_material1): ( + let (co_changes1, co_groups1, co_shape1, co_pos1, co_material1, co_flags1): ( &ColliderChanges, &ColliderGroups, &ColliderShape, &ColliderPosition, &ColliderMaterial, + &ColliderFlags, ) = colliders.index_bundle(pair.collider1.0); let co_parent2: Option<&ColliderParent> = colliders.get(pair.collider2.0); - let (co_changes2, co_groups2, co_shape2, co_pos2, co_material2): ( + let (co_changes2, co_groups2, co_shape2, co_pos2, co_material2, co_flags2): ( &ColliderChanges, &ColliderGroups, &ColliderShape, &ColliderPosition, &ColliderMaterial, + &ColliderFlags, ) = colliders.index_bundle(pair.collider2.0); if !co_changes1.needs_narrow_phase_update() && !co_changes2.needs_narrow_phase_update() @@ -847,8 +887,10 @@ impl NarrowPhase { return; } - let active_hooks = co_material1.active_hooks | co_material2.active_hooks; - if !active_hooks.contains(PhysicsHooksFlags::FILTER_CONTACT_PAIR) + let active_hooks = co_flags1.active_hooks | co_flags2.active_hooks; + let active_events = co_flags1.active_events | co_flags2.active_events; + + if !active_hooks.contains(ActiveHooks::FILTER_CONTACT_PAIRS) && !status1.is_dynamic() && !status2.is_dynamic() { @@ -856,8 +898,7 @@ impl NarrowPhase { return; } - let mut solver_flags = if active_hooks.contains(PhysicsHooksFlags::FILTER_CONTACT_PAIR) - { + let mut solver_flags = if active_hooks.contains(ActiveHooks::FILTER_CONTACT_PAIRS) { let context = PairFilterContext { bodies, colliders, @@ -959,7 +1000,7 @@ impl NarrowPhase { } // Apply the user-defined contact modification. - if active_hooks.contains(PhysicsHooksFlags::MODIFY_SOLVER_CONTACTS) { + if active_hooks.contains(ActiveHooks::MODIFY_SOLVER_CONTACTS) { let mut modifiable_solver_contacts = std::mem::replace(&mut manifold.data.solver_contacts, Vec::new()); let mut modifiable_user_data = manifold.data.user_data; @@ -987,16 +1028,18 @@ impl NarrowPhase { } if has_any_active_contact != pair.has_any_active_contact { - if has_any_active_contact { - events.handle_contact_event(ContactEvent::Started( - pair.collider1, - pair.collider2, - )); - } else { - events.handle_contact_event(ContactEvent::Stopped( - pair.collider1, - pair.collider2, - )); + if active_events.contains(ActiveEvents::CONTACT_EVENTS) { + if has_any_active_contact { + events.handle_contact_event( + ContactEvent::Started(pair.collider1, pair.collider2), + pair, + ); + } else { + events.handle_contact_event( + ContactEvent::Stopped(pair.collider1, pair.collider2), + pair, + ); + } } pair