use std::fmt;
#[cfg(all(feature = "dim3", feature = "async-collider"))]
use {crate::geometry::VHACDParameters, bevy::utils::HashMap};
use bevy::prelude::*;
use bevy::utils::HashSet;
use rapier::geometry::Shape;
use rapier::prelude::{ColliderHandle, InteractionGroups, SharedShape};
use crate::dynamics::{CoefficientCombineRule, MassProperties};
use crate::math::Vect;
#[derive(Copy, Clone, Debug, Component)]
pub struct RapierColliderHandle(pub ColliderHandle);
#[cfg(all(feature = "dim3", feature = "async-collider"))]
#[derive(Component, Debug, Clone, Default)]
pub struct AsyncCollider(pub ComputedColliderShape);
#[cfg(all(feature = "dim3", feature = "async-collider"))]
#[derive(Component, Debug, Clone)]
pub struct AsyncSceneCollider {
pub shape: Option<ComputedColliderShape>,
pub named_shapes: HashMap<String, Option<ComputedColliderShape>>,
}
#[cfg(all(feature = "dim3", feature = "async-collider"))]
impl Default for AsyncSceneCollider {
fn default() -> Self {
Self {
shape: Some(ComputedColliderShape::TriMesh),
named_shapes: Default::default(),
}
}
}
#[cfg(all(feature = "dim3", feature = "async-collider"))]
#[derive(Debug, Clone, Default)]
pub enum ComputedColliderShape {
#[default]
TriMesh,
ConvexHull,
ConvexDecomposition(VHACDParameters),
}
#[derive(Component, Clone)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct Collider {
pub raw: SharedShape,
pub(crate) unscaled: SharedShape,
pub(crate) scale: Vect,
}
impl From<SharedShape> for Collider {
fn from(shared_shape: SharedShape) -> Collider {
Collider {
raw: shared_shape.clone(),
unscaled: shared_shape,
scale: Vect::ONE,
}
}
}
impl<'a> From<&'a Collider> for &'a dyn Shape {
fn from(collider: &'a Collider) -> &'a dyn Shape {
&*collider.raw
}
}
impl fmt::Debug for Collider {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_typed_shape().fmt(f)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
pub enum ColliderScale {
Relative(Vect),
Absolute(Vect),
}
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
#[reflect(Component, PartialEq)]
pub struct Sensor;
#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
#[reflect(Component, PartialEq)]
pub enum ColliderMassProperties {
Density(f32),
Mass(f32),
MassProperties(MassProperties),
}
impl Default for ColliderMassProperties {
fn default() -> Self {
Self::Density(1.0)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
#[reflect(Component, PartialEq)]
pub struct Friction {
pub coefficient: f32,
pub combine_rule: CoefficientCombineRule,
}
impl Default for Friction {
fn default() -> Self {
Self {
coefficient: 0.5,
combine_rule: CoefficientCombineRule::Average,
}
}
}
impl Friction {
pub const fn new(coefficient: f32) -> Self {
Self {
coefficient,
combine_rule: CoefficientCombineRule::Average,
}
}
pub const fn coefficient(coefficient: f32) -> Self {
Self {
coefficient,
combine_rule: CoefficientCombineRule::Average,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
#[reflect(Component, PartialEq)]
pub struct Restitution {
pub coefficient: f32,
pub combine_rule: CoefficientCombineRule,
}
impl Restitution {
pub const fn new(coefficient: f32) -> Self {
Self {
coefficient,
combine_rule: CoefficientCombineRule::Average,
}
}
pub const fn coefficient(coefficient: f32) -> Self {
Self {
coefficient,
combine_rule: CoefficientCombineRule::Average,
}
}
}
impl Default for Restitution {
fn default() -> Self {
Self {
coefficient: 0.0,
combine_rule: CoefficientCombineRule::Average,
}
}
}
#[derive(Component, Reflect, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[reflect(Component, Hash, PartialEq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct ActiveCollisionTypes(u16);
bitflags::bitflags! {
impl ActiveCollisionTypes: u16 {
const DYNAMIC_DYNAMIC = 0b0000_0000_0000_0001;
const DYNAMIC_KINEMATIC = 0b0000_0000_0000_1100;
const DYNAMIC_STATIC = 0b0000_0000_0000_0010;
const KINEMATIC_KINEMATIC = 0b1100_1100_0000_0000;
const KINEMATIC_STATIC = 0b0010_0010_0000_0000;
const STATIC_STATIC = 0b0000_0000_0010_0000;
}
}
impl Default for ActiveCollisionTypes {
fn default() -> Self {
Self::DYNAMIC_DYNAMIC | Self::DYNAMIC_KINEMATIC | Self::DYNAMIC_STATIC
}
}
impl From<ActiveCollisionTypes> for rapier::geometry::ActiveCollisionTypes {
fn from(collision_types: ActiveCollisionTypes) -> rapier::geometry::ActiveCollisionTypes {
rapier::geometry::ActiveCollisionTypes::from_bits(collision_types.bits())
.expect("Internal error: invalid active events conversion.")
}
}
#[derive(Component, Reflect, Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[reflect(Component, Hash, PartialEq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct Group(u32);
bitflags::bitflags! {
impl Group: u32 {
const GROUP_1 = 1 << 0;
const GROUP_2 = 1 << 1;
const GROUP_3 = 1 << 2;
const GROUP_4 = 1 << 3;
const GROUP_5 = 1 << 4;
const GROUP_6 = 1 << 5;
const GROUP_7 = 1 << 6;
const GROUP_8 = 1 << 7;
const GROUP_9 = 1 << 8;
const GROUP_10 = 1 << 9;
const GROUP_11 = 1 << 10;
const GROUP_12 = 1 << 11;
const GROUP_13 = 1 << 12;
const GROUP_14 = 1 << 13;
const GROUP_15 = 1 << 14;
const GROUP_16 = 1 << 15;
const GROUP_17 = 1 << 16;
const GROUP_18 = 1 << 17;
const GROUP_19 = 1 << 18;
const GROUP_20 = 1 << 19;
const GROUP_21 = 1 << 20;
const GROUP_22 = 1 << 21;
const GROUP_23 = 1 << 22;
const GROUP_24 = 1 << 23;
const GROUP_25 = 1 << 24;
const GROUP_26 = 1 << 25;
const GROUP_27 = 1 << 26;
const GROUP_28 = 1 << 27;
const GROUP_29 = 1 << 28;
const GROUP_30 = 1 << 29;
const GROUP_31 = 1 << 30;
const GROUP_32 = 1 << 31;
const ALL = u32::MAX;
const NONE = 0;
}
}
impl Default for Group {
fn default() -> Self {
Group::ALL
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, Component, Reflect)]
#[reflect(Component, Hash, PartialEq)]
pub struct CollisionGroups {
pub memberships: Group,
pub filters: Group,
}
impl CollisionGroups {
pub const fn new(memberships: Group, filters: Group) -> Self {
Self {
memberships,
filters,
}
}
}
impl From<CollisionGroups> for InteractionGroups {
fn from(collision_groups: CollisionGroups) -> InteractionGroups {
InteractionGroups {
memberships: rapier::geometry::Group::from_bits(collision_groups.memberships.bits())
.unwrap(),
filter: rapier::geometry::Group::from_bits(collision_groups.filters.bits()).unwrap(),
}
}
}
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Hash, Component, Reflect)]
#[reflect(Component, Hash, PartialEq)]
pub struct SolverGroups {
pub memberships: Group,
pub filters: Group,
}
impl SolverGroups {
pub const fn new(memberships: Group, filters: Group) -> Self {
Self {
memberships,
filters,
}
}
}
impl From<SolverGroups> for InteractionGroups {
fn from(solver_groups: SolverGroups) -> InteractionGroups {
InteractionGroups {
memberships: rapier::geometry::Group::from_bits(solver_groups.memberships.bits())
.unwrap(),
filter: rapier::geometry::Group::from_bits(solver_groups.filters.bits()).unwrap(),
}
}
}
#[derive(Default, Component, Reflect, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[reflect(Component)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct ActiveHooks(u32);
bitflags::bitflags! {
impl ActiveHooks: u32 {
const FILTER_CONTACT_PAIRS = 0b0001;
const FILTER_INTERSECTION_PAIR = 0b0010;
const MODIFY_SOLVER_CONTACTS = 0b0100;
}
}
impl From<ActiveHooks> for rapier::pipeline::ActiveHooks {
fn from(active_hooks: ActiveHooks) -> rapier::pipeline::ActiveHooks {
rapier::pipeline::ActiveHooks::from_bits(active_hooks.bits())
.expect("Internal error: invalid active events conversion.")
}
}
#[derive(Default, Component, Reflect, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[reflect(Component)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct ActiveEvents(u32);
bitflags::bitflags! {
impl ActiveEvents: u32 {
const COLLISION_EVENTS = 0b0001;
const CONTACT_FORCE_EVENTS = 0b0010;
}
}
impl From<ActiveEvents> for rapier::pipeline::ActiveEvents {
fn from(active_events: ActiveEvents) -> rapier::pipeline::ActiveEvents {
rapier::pipeline::ActiveEvents::from_bits(active_events.bits())
.expect("Internal error: invalid active events conversion.")
}
}
#[derive(Copy, Clone, PartialEq, Component, Reflect)]
#[reflect(Component)]
pub struct ContactForceEventThreshold(pub f32);
impl Default for ContactForceEventThreshold {
fn default() -> Self {
Self(f32::MAX)
}
}
#[derive(Copy, Clone, PartialEq, Default, Component, Reflect)]
#[reflect(Component)]
pub struct ContactSkin(pub f32);
#[derive(Component, Default, Reflect)]
#[reflect(Component)]
pub struct CollidingEntities(pub(crate) HashSet<Entity>);
impl CollidingEntities {
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[must_use]
pub fn contains(&self, entity: Entity) -> bool {
self.0.contains(&entity)
}
pub fn iter(&self) -> impl Iterator<Item = Entity> + '_ {
self.0.iter().copied()
}
}
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
#[reflect(Component, PartialEq)]
pub struct ColliderDisabled;
pub fn get_snapped_scale(scale: Vect) -> Vect {
fn snap_value(new: f32) -> f32 {
const PRECISION: f32 = 1.0e4;
(new * PRECISION).round() / PRECISION
}
Vect {
x: snap_value(scale.x),
y: snap_value(scale.y),
#[cfg(feature = "dim3")]
z: snap_value(scale.z),
}
}