444 lines
17 KiB
Rust
444 lines
17 KiB
Rust
use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle, RigidBodyType};
|
||
use crate::geometry::{BroadPhaseProxyIndex, InteractionGroups, Shape, SharedShape};
|
||
use crate::math::{Isometry, Real};
|
||
use crate::parry::partitioning::IndexedData;
|
||
use crate::pipeline::{ActiveEvents, ActiveHooks};
|
||
use std::ops::{Deref, DerefMut};
|
||
|
||
/// 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)]
|
||
pub struct ColliderHandle(pub crate::data::arena::Index);
|
||
|
||
impl ColliderHandle {
|
||
/// Converts this handle into its (index, generation) components.
|
||
pub fn into_raw_parts(self) -> (u32, u32) {
|
||
self.0.into_raw_parts()
|
||
}
|
||
|
||
/// 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))
|
||
}
|
||
|
||
/// An always-invalid collider handle.
|
||
pub fn invalid() -> Self {
|
||
Self(crate::data::arena::Index::from_raw_parts(
|
||
crate::INVALID_U32,
|
||
crate::INVALID_U32,
|
||
))
|
||
}
|
||
}
|
||
|
||
impl IndexedData for ColliderHandle {
|
||
fn default() -> Self {
|
||
Self(IndexedData::default())
|
||
}
|
||
|
||
fn index(&self) -> usize {
|
||
self.0.index()
|
||
}
|
||
}
|
||
|
||
bitflags::bitflags! {
|
||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||
/// Flags describing how the collider has been modified by the user.
|
||
pub struct ColliderChanges: u32 {
|
||
/// Flag indicating that any component of the collider has been modified.
|
||
const MODIFIED = 1 << 0;
|
||
/// Flag indicating that the density or mass-properties of this collider was changed.
|
||
const LOCAL_MASS_PROPERTIES = 1 << 1; // => RigidBody local mass-properties update.
|
||
/// Flag indicating that the `ColliderParent` component of the collider has been modified.
|
||
const PARENT = 1 << 2; // => BF & NF updates.
|
||
/// Flag indicating that the `ColliderPosition` component of the collider has been modified.
|
||
const POSITION = 1 << 3; // => BF & NF updates.
|
||
/// Flag indicating that the collision groups of the collider have been modified.
|
||
const GROUPS = 1 << 4; // => NF update.
|
||
/// Flag indicating that the `ColliderShape` component of the collider has been modified.
|
||
const SHAPE = 1 << 5; // => BF & NF update. NF pair workspace invalidation.
|
||
/// Flag indicating that the `ColliderType` component of the collider has been modified.
|
||
const TYPE = 1 << 6; // => NF update. NF pair invalidation.
|
||
/// Flag indicating that the dominance groups of the parent of this collider have been modified.
|
||
///
|
||
/// This flags is automatically set by the `PhysicsPipeline` when the `RigidBodyChanges::DOMINANCE`
|
||
/// or `RigidBodyChanges::TYPE` of the parent rigid-body of this collider is detected.
|
||
const PARENT_EFFECTIVE_DOMINANCE = 1 << 7; // NF update.
|
||
/// Flag indicating that whether or not the collider is enabled was changed.
|
||
const ENABLED_OR_DISABLED = 1 << 8; // BF & NF updates.
|
||
}
|
||
}
|
||
|
||
impl Default for ColliderChanges {
|
||
fn default() -> Self {
|
||
ColliderChanges::empty()
|
||
}
|
||
}
|
||
|
||
impl ColliderChanges {
|
||
/// Do these changes justify a broad-phase update?
|
||
pub fn needs_broad_phase_update(self) -> bool {
|
||
self.intersects(
|
||
ColliderChanges::PARENT
|
||
| ColliderChanges::POSITION
|
||
| ColliderChanges::SHAPE
|
||
| ColliderChanges::ENABLED_OR_DISABLED,
|
||
)
|
||
}
|
||
|
||
/// Do these changes justify a narrow-phase update?
|
||
pub fn needs_narrow_phase_update(self) -> bool {
|
||
// NOTE: for simplicity of implementation, we return `true` even if
|
||
// we only need a dominance update. If this does become a
|
||
// bottleneck at some point in the future (which is very unlikely)
|
||
// we could do a special-case for dominance-only change (so that
|
||
// we only update the relative_dominance of the pre-existing contact.
|
||
self.bits() > 2
|
||
}
|
||
}
|
||
|
||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||
/// The type of collider.
|
||
pub enum ColliderType {
|
||
/// A collider that can generate contacts and contact events.
|
||
Solid,
|
||
/// A collider that can generate intersection and intersection events.
|
||
Sensor,
|
||
}
|
||
|
||
impl ColliderType {
|
||
/// Is this collider a sensor?
|
||
pub fn is_sensor(self) -> bool {
|
||
self == ColliderType::Sensor
|
||
}
|
||
}
|
||
|
||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||
/// Data associated to a collider that takes part to a broad-phase algorithm.
|
||
pub struct ColliderBroadPhaseData {
|
||
pub(crate) proxy_index: BroadPhaseProxyIndex,
|
||
}
|
||
|
||
impl Default for ColliderBroadPhaseData {
|
||
fn default() -> Self {
|
||
ColliderBroadPhaseData {
|
||
proxy_index: crate::INVALID_U32,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// The shape of a collider.
|
||
pub type ColliderShape = SharedShape;
|
||
|
||
#[derive(Clone, PartialEq)]
|
||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||
/// The mass-properties of a collider.
|
||
pub enum ColliderMassProps {
|
||
/// The collider is given a density.
|
||
///
|
||
/// Its actual `MassProperties` are computed automatically with
|
||
/// the help of [`Shape::mass_properties`].
|
||
Density(Real),
|
||
/// The collider is given a mass.
|
||
///
|
||
/// Its angular inertia will be computed automatically based on this mass.
|
||
Mass(Real),
|
||
/// The collider is given explicit mass-properties.
|
||
MassProperties(Box<MassProperties>),
|
||
}
|
||
|
||
impl Default for ColliderMassProps {
|
||
fn default() -> Self {
|
||
ColliderMassProps::Density(1.0)
|
||
}
|
||
}
|
||
|
||
impl From<MassProperties> 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
|
||
/// on the given shape.
|
||
///
|
||
/// 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) => {
|
||
if *density != 0.0 {
|
||
shape.mass_properties(*density)
|
||
} else {
|
||
MassProperties::default()
|
||
}
|
||
}
|
||
ColliderMassProps::Mass(mass) => {
|
||
if *mass != 0.0 {
|
||
let mut mprops = shape.mass_properties(1.0);
|
||
mprops.set_mass(*mass, true);
|
||
mprops
|
||
} else {
|
||
MassProperties::default()
|
||
}
|
||
}
|
||
ColliderMassProps::MassProperties(mass_properties) => **mass_properties,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||
/// Information about the rigid-body this collider is attached to.
|
||
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<Real>,
|
||
}
|
||
|
||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||
/// The position of a collider.
|
||
pub struct ColliderPosition(pub Isometry<Real>);
|
||
|
||
impl AsRef<Isometry<Real>> for ColliderPosition {
|
||
#[inline]
|
||
fn as_ref(&self) -> &Isometry<Real> {
|
||
&self.0
|
||
}
|
||
}
|
||
|
||
impl AsMut<Isometry<Real>> for ColliderPosition {
|
||
fn as_mut(&mut self) -> &mut Isometry<Real> {
|
||
&mut self.0
|
||
}
|
||
}
|
||
|
||
impl Deref for ColliderPosition {
|
||
type Target = Isometry<Real>;
|
||
#[inline]
|
||
fn deref(&self) -> &Isometry<Real> {
|
||
&self.0
|
||
}
|
||
}
|
||
|
||
impl DerefMut for ColliderPosition {
|
||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||
&mut self.0
|
||
}
|
||
}
|
||
|
||
impl Default for ColliderPosition {
|
||
fn default() -> Self {
|
||
Self::identity()
|
||
}
|
||
}
|
||
|
||
impl ColliderPosition {
|
||
/// The identity position.
|
||
#[must_use]
|
||
pub fn identity() -> Self {
|
||
ColliderPosition(Isometry::identity())
|
||
}
|
||
}
|
||
|
||
impl<T> From<T> for ColliderPosition
|
||
where
|
||
Isometry<Real>: From<T>,
|
||
{
|
||
fn from(position: T) -> Self {
|
||
Self(position.into())
|
||
}
|
||
}
|
||
|
||
#[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 {
|
||
/// The friction coefficient of this collider.
|
||
///
|
||
/// The greater the value, the stronger the friction forces will be.
|
||
/// Should be `>= 0`.
|
||
pub friction: Real,
|
||
/// 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,
|
||
/// The rule applied to combine the restitution coefficients of two colliders.
|
||
pub restitution_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 {
|
||
Self {
|
||
friction,
|
||
restitution,
|
||
..Default::default()
|
||
}
|
||
}
|
||
}
|
||
|
||
impl Default for ColliderMaterial {
|
||
fn default() -> Self {
|
||
Self {
|
||
friction: 1.0,
|
||
restitution: 0.0,
|
||
friction_combine_rule: CoefficientCombineRule::default(),
|
||
restitution_combine_rule: CoefficientCombineRule::default(),
|
||
}
|
||
}
|
||
}
|
||
|
||
bitflags::bitflags! {
|
||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||
/// 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 {
|
||
/// Enable collision-detection between a collider attached to a dynamic body
|
||
/// and another collider attached to a dynamic body.
|
||
const DYNAMIC_DYNAMIC = 0b0000_0000_0000_0001;
|
||
/// Enable collision-detection between a collider attached to a dynamic body
|
||
/// and another collider attached to a kinematic body.
|
||
const DYNAMIC_KINEMATIC = 0b0000_0000_0000_1100;
|
||
/// Enable collision-detection between a collider attached to a dynamic body
|
||
/// and another collider attached to a fixed body (or not attached to any body).
|
||
const DYNAMIC_FIXED = 0b0000_0000_0000_0010;
|
||
/// Enable collision-detection between a collider attached to a kinematic body
|
||
/// and another collider attached to a kinematic body.
|
||
const KINEMATIC_KINEMATIC = 0b1100_1100_0000_0000;
|
||
|
||
/// Enable collision-detection between a collider attached to a kinematic body
|
||
/// and another collider attached to a fixed body (or not attached to any body).
|
||
const KINEMATIC_FIXED = 0b0010_0010_0000_0000;
|
||
|
||
/// Enable collision-detection between a collider attached to a fixed body (or
|
||
/// not attached to any body) and another collider attached to a fixed body (or
|
||
/// not attached to any body).
|
||
const FIXED_FIXED = 0b0000_0000_0010_0000;
|
||
}
|
||
}
|
||
|
||
impl ActiveCollisionTypes {
|
||
/// Test whether contact should be computed between two rigid-bodies with the given types.
|
||
pub fn test(self, rb_type1: RigidBodyType, rb_type2: RigidBodyType) -> bool {
|
||
// NOTE: This test is quite complicated so here is an explanation.
|
||
// First, we associate the following bit masks:
|
||
// - DYNAMIC = 0001
|
||
// - FIXED = 0010
|
||
// - KINEMATIC = 1100
|
||
// These are equal to the bits indexed by `RigidBodyType as u32`.
|
||
// The bit masks defined by ActiveCollisionTypes are defined is such a way
|
||
// that the first part of the variant name (e.g. DYNAMIC_*) indicates which
|
||
// groups of four bits should be considered:
|
||
// - DYNAMIC_* = the first group of four bits.
|
||
// - FIXED_* = the second group of four bits.
|
||
// - KINEMATIC_* = the third and fourth groups of four bits.
|
||
// The second part of the variant name (e.g. *_DYNAMIC) indicates the value
|
||
// of the aforementioned groups of four bits.
|
||
// For example, DYNAMIC_FIXED means that the first group of four bits (because
|
||
// of DYNAMIC_*) must have the value 0010 (because of *_FIXED). That gives
|
||
// us 0b0000_0000_0000_0010 for the DYNAMIC_FIXED_VARIANT.
|
||
//
|
||
// The KINEMATIC_* is special because it occupies two groups of four bits. This is
|
||
// because it combines both KinematicPositionBased and KinematicVelocityBased.
|
||
//
|
||
// Now that we have a way of building these bit masks, let's see how we use them.
|
||
// Given a pair of rigid-body types, the first rigid-body type is used to select
|
||
// the group of four bits we want to test (the selection is done by to the
|
||
// `>> (rb_type1 as u32 * 4) & 0b0000_1111`) and the second rigid-body type is
|
||
// used to form the bit mask we test this group of four bits against.
|
||
// In other word, the selection of the group of four bits tells us "for this type
|
||
// of rigid-body I can have collision with rigid-body types with these bit representation".
|
||
// Then the `(1 << rb_type2)` gives us the bit-representation of the rigid-body type,
|
||
// which needs to be checked.
|
||
//
|
||
// Because that test must be symmetric, we perform two similar tests by swapping
|
||
// rb_type1 and rb_type2.
|
||
((self.bits >> (rb_type1 as u32 * 4)) & 0b0000_1111) & (1 << rb_type2 as u32) != 0
|
||
|| ((self.bits >> (rb_type2 as u32 * 4)) & 0b0000_1111) & (1 << rb_type1 as u32) != 0
|
||
}
|
||
}
|
||
|
||
impl Default for ActiveCollisionTypes {
|
||
fn default() -> Self {
|
||
ActiveCollisionTypes::DYNAMIC_DYNAMIC
|
||
| ActiveCollisionTypes::DYNAMIC_KINEMATIC
|
||
| ActiveCollisionTypes::DYNAMIC_FIXED
|
||
}
|
||
}
|
||
|
||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||
/// Enum indicating whether or not a collider is enabled.
|
||
pub enum ColliderEnabled {
|
||
/// The collider is enabled.
|
||
Enabled,
|
||
/// The collider wasn’t disabled by the user explicitly but it is attached to
|
||
/// a disabled rigid-body.
|
||
DisabledByParent,
|
||
/// The collider is disabled by the user explicitly.
|
||
Disabled,
|
||
}
|
||
|
||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||
/// A set of flags for controlling collision/intersection filtering, modification, and events.
|
||
pub struct ColliderFlags {
|
||
/// Controls whether collision-detection happens between two colliders depending on
|
||
/// the type of the rigid-bodies they are attached to.
|
||
pub active_collision_types: ActiveCollisionTypes,
|
||
/// The groups controlling the pairs of colliders that can interact (generate
|
||
/// interaction events or contacts).
|
||
pub collision_groups: InteractionGroups,
|
||
/// The groups controlling the pairs of collider that have their contact
|
||
/// points taken into account for force computation.
|
||
pub solver_groups: InteractionGroups,
|
||
/// 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,
|
||
/// Whether or not the collider is enabled.
|
||
pub enabled: ColliderEnabled,
|
||
}
|
||
|
||
impl Default for ColliderFlags {
|
||
fn default() -> Self {
|
||
Self {
|
||
active_collision_types: ActiveCollisionTypes::default(),
|
||
collision_groups: InteractionGroups::all(),
|
||
solver_groups: InteractionGroups::all(),
|
||
active_hooks: ActiveHooks::empty(),
|
||
active_events: ActiveEvents::empty(),
|
||
enabled: ColliderEnabled::Enabled,
|
||
}
|
||
}
|
||
}
|
||
|
||
impl From<ActiveHooks> for ColliderFlags {
|
||
fn from(active_hooks: ActiveHooks) -> Self {
|
||
Self {
|
||
active_hooks,
|
||
..Default::default()
|
||
}
|
||
}
|
||
}
|
||
|
||
impl From<ActiveEvents> for ColliderFlags {
|
||
fn from(active_events: ActiveEvents) -> Self {
|
||
Self {
|
||
active_events,
|
||
..Default::default()
|
||
}
|
||
}
|
||
}
|