diff --git a/src/collision/collider/backend.rs b/src/collision/collider/backend.rs index a573b83a..bcab08df 100644 --- a/src/collision/collider/backend.rs +++ b/src/collision/collider/backend.rs @@ -5,7 +5,7 @@ use std::marker::PhantomData; use crate::{broad_phase::BroadPhaseSet, prelude::*, prepare::PrepareSet}; -#[cfg(feature = "bevy_scene")] +#[cfg(all(feature = "bevy_scene", feature = "default-collider"))] use bevy::scene::SceneInstance; use bevy::{ ecs::{intern::Interned, schedule::ScheduleLabel, system::SystemId}, @@ -233,6 +233,7 @@ impl Plugin for ColliderBackendPlugin { .ambiguous_with_all(), ); + #[cfg(feature = "default-collider")] app.add_systems( Update, ( @@ -315,6 +316,7 @@ fn update_root_collider_parents( /// # Panics /// /// Panics if the [`ColliderConstructor`] requires a mesh but no mesh handle is found. +#[cfg(feature = "default-collider")] fn init_collider_constructors( mut commands: Commands, #[cfg(feature = "collider-from-mesh")] meshes: Res>, @@ -371,6 +373,7 @@ fn init_collider_constructors( /// Generates [`Collider`]s for descendants of entities with the [`ColliderConstructorHierarchy`] component. /// /// If an entity has a `SceneInstance`, its collider hierarchy is only generated once the scene is ready. +#[cfg(feature = "default-collider")] fn init_collider_constructor_hierarchies( mut commands: Commands, #[cfg(feature = "collider-from-mesh")] meshes: Res>, @@ -481,6 +484,7 @@ fn init_collider_constructor_hierarchies( } } +#[cfg(feature = "default-collider")] fn pretty_name(name: Option<&Name>, entity: Entity) -> String { name.map(|n| n.to_string()) .unwrap_or_else(|| format!("", entity.index())) @@ -728,9 +732,11 @@ pub(crate) fn update_collider_mass_properties( #[cfg(test)] mod tests { + #[cfg(feature = "default-collider")] use super::*; #[test] + #[cfg(feature = "default-collider")] fn sensor_mass_properties() { let mut app = App::new(); diff --git a/src/collision/collider/hierarchy.rs b/src/collision/collider/hierarchy.rs index 4d26ecb3..ee6e331d 100644 --- a/src/collision/collider/hierarchy.rs +++ b/src/collision/collider/hierarchy.rs @@ -125,10 +125,6 @@ impl Plugin for ColliderHierarchyPlugin { } } -#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq)] -#[reflect(Component)] -pub(crate) struct PreviousColliderTransform(pub ColliderTransform); - /// Updates [`ColliderParent`] for descendant colliders of [`RigidBody`] entities. /// /// The [`ColliderBackendPlugin`] handles collider parents for colliders that are diff --git a/src/collision/collider/mod.rs b/src/collision/collider/mod.rs index 9659182e..e62e78b3 100644 --- a/src/collision/collider/mod.rs +++ b/src/collision/collider/mod.rs @@ -13,7 +13,6 @@ mod hierarchy; pub use backend::{ColliderBackendPlugin, ColliderMarker}; pub use hierarchy::ColliderHierarchyPlugin; -pub(crate) use hierarchy::PreviousColliderTransform; /// The default [`Collider`] that uses Parry. #[cfg(all( @@ -30,7 +29,9 @@ pub use parry::*; mod world_query; pub use world_query::*; +#[cfg(feature = "default-collider")] mod constructor; +#[cfg(feature = "default-collider")] pub use constructor::{ ColliderConstructor, ColliderConstructorHierarchy, ColliderConstructorHierarchyConfig, }; @@ -466,3 +467,7 @@ impl MapEntities for CollidingEntities { .collect() } } + +#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq)] +#[reflect(Component)] +pub(crate) struct PreviousColliderTransform(pub ColliderTransform); diff --git a/src/collision/contact_query.rs b/src/collision/contact_query.rs index be948824..0d7246e2 100644 --- a/src/collision/contact_query.rs +++ b/src/collision/contact_query.rs @@ -245,7 +245,7 @@ pub fn contact_manifolds( normal2, -contact.dist, ) - .with_feature_ids(contact.fid1, contact.fid2) + .with_feature_ids(contact.fid1.into(), contact.fid2.into()) }) .collect(), index: manifold_index, diff --git a/src/collision/feature_id.rs b/src/collision/feature_id.rs new file mode 100644 index 00000000..a6cfeb56 --- /dev/null +++ b/src/collision/feature_id.rs @@ -0,0 +1,76 @@ +use bevy::prelude::*; + +/// A feature ID indicating the type of a geometric feature: a vertex, an edge, or (in 3D) a face. +/// +/// This type packs the feature type into the same value as the feature index, +/// which indicates the specific vertex/edge/face that this ID belongs to. +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Reflect)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))] +#[reflect(Debug, Hash, PartialEq)] +pub struct PackedFeatureId(pub u32); + +impl PackedFeatureId { + /// Packed feature id identifying an unknown feature. + pub const UNKNOWN: Self = Self(0); + + const CODE_MASK: u32 = 0x3fff_ffff; + const HEADER_MASK: u32 = !Self::CODE_MASK; + const HEADER_VERTEX: u32 = 0b01 << 30; + #[cfg(feature = "3d")] + const HEADER_EDGE: u32 = 0b10 << 30; + const HEADER_FACE: u32 = 0b11 << 30; + + /// Converts a vertex feature id into a packed feature id. + pub fn vertex(code: u32) -> Self { + assert_eq!(code & Self::HEADER_MASK, 0); + Self(Self::HEADER_VERTEX | code) + } + + /// Converts a edge feature id into a packed feature id. + #[cfg(feature = "3d")] + pub fn edge(code: u32) -> Self { + assert_eq!(code & Self::HEADER_MASK, 0); + Self(Self::HEADER_EDGE | code) + } + + /// Converts a face feature id into a packed feature id. + pub fn face(code: u32) -> Self { + assert_eq!(code & Self::HEADER_MASK, 0); + Self(Self::HEADER_FACE | code) + } + + /// Is the identified feature a face? + pub fn is_face(self) -> bool { + self.0 & Self::HEADER_MASK == Self::HEADER_FACE + } + + /// Is the identified feature a vertex? + pub fn is_vertex(self) -> bool { + self.0 & Self::HEADER_MASK == Self::HEADER_VERTEX + } + + /// Is the identified feature an edge? + #[cfg(feature = "3d")] + pub fn is_edge(self) -> bool { + self.0 & Self::HEADER_MASK == Self::HEADER_EDGE + } + + /// Is the identified feature unknown? + pub fn is_unknown(self) -> bool { + self == Self::UNKNOWN + } +} + +impl From for PackedFeatureId { + fn from(code: u32) -> Self { + Self(code) + } +} + +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] +impl From for PackedFeatureId { + fn from(id: crate::parry::shape::PackedFeatureId) -> Self { + Self(id.0) + } +} diff --git a/src/collision/mod.rs b/src/collision/mod.rs index bc67eb41..0726f7d4 100644 --- a/src/collision/mod.rs +++ b/src/collision/mod.rs @@ -30,16 +30,13 @@ pub use collider::*; mod layers; pub use layers::*; +mod feature_id; +pub use feature_id::PackedFeatureId; + use crate::prelude::*; use bevy::prelude::*; use indexmap::IndexMap; -/// A feature ID indicating the type of a geometric feature: a vertex, an edge, or (in 3D) a face. -/// -/// This type packs the feature type into the same value as the feature index, -/// which indicates the specific vertex/edge/face that this ID belongs to. -pub type PackedFeatureId = parry::shape::PackedFeatureId; - // TODO: Refactor this into a contact graph. // Collisions are stored in an `IndexMap` that uses fxhash. // It should have faster iteration than a `HashMap` while mostly retaining other performance characteristics. diff --git a/src/dynamics/ccd/mod.rs b/src/dynamics/ccd/mod.rs index e739f261..c64c681a 100644 --- a/src/dynamics/ccd/mod.rs +++ b/src/dynamics/ccd/mod.rs @@ -120,6 +120,8 @@ //! //! ## Swept CCD //! +//! *Note: Swept CCD currently only supports the built-in `Collider`.* +//! //! **Swept CCD** is a form of Continuous Collision Detection that sweeps potentially colliding objects //! from their previous positions to their current positions, and if a collision is found, moves the bodies //! back to the time of impact. This way, the normal collision algorithms will be able to detect and handle @@ -225,11 +227,14 @@ //! However, this comes at the cost of worse performance for the entire simulation. use crate::{collision::broad_phase::AabbIntersections, prelude::*, prepare::PrepareSet}; +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] +use bevy::ecs::query::QueryData; use bevy::{ - ecs::{intern::Interned, query::QueryData, schedule::ScheduleLabel}, + ecs::{intern::Interned, schedule::ScheduleLabel}, prelude::*, }; use derive_more::From; +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] use parry::query::{ cast_shapes, cast_shapes_nonlinear, NonlinearRigidMotion, ShapeCastHit, ShapeCastOptions, }; @@ -272,6 +277,7 @@ impl Plugin for CcdPlugin { physics.configure_sets(SweptCcdSet.in_set(SolverSet::PostSubstep)); + #[cfg(any(feature = "parry-f32", feature = "parry-f64"))] physics.add_systems(solve_swept_ccd.in_set(SweptCcdSet)); } } @@ -510,6 +516,7 @@ fn init_ccd_aabb_intersections(mut commands: Commands, query: Query>, bodies: Query, @@ -698,6 +706,7 @@ fn solve_swept_ccd( /// Computes the time of impact for the motion of two objects for Continuous Collision Detection. /// If the TOI is larger than `min_toi` or the shapes never touch, `None` is returned. +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] fn compute_ccd_toi( mode: SweepMode, motion1: &NonlinearRigidMotion, diff --git a/src/lib.rs b/src/lib.rs index a2853fbd..35930e63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -472,6 +472,8 @@ pub use type_registration::PhysicsTypeRegistrationPlugin; pub mod prelude { #[cfg(feature = "debug-plugin")] pub use crate::debug_render::*; + #[cfg(feature = "default-collider")] + pub(crate) use crate::position::RotationValue; pub use crate::{ collision::{ self, @@ -494,9 +496,7 @@ pub mod prelude { }; pub(crate) use crate::{ math::*, - position::{ - PreSolveAccumulatedTranslation, PreSolveRotation, PreviousRotation, RotationValue, - }, + position::{PreSolveAccumulatedTranslation, PreSolveRotation, PreviousRotation}, }; pub use avian_derive::*; } diff --git a/src/spatial_query/mod.rs b/src/spatial_query/mod.rs index 95ca3927..25e55760 100644 --- a/src/spatial_query/mod.rs +++ b/src/spatial_query/mod.rs @@ -152,40 +152,22 @@ //! //! To specify which colliders should be considered in the query, use a [spatial query filter](`SpatialQueryFilter`). -#[cfg(all( - feature = "default-collider", - any(feature = "parry-f32", feature = "parry-f64") -))] +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] mod pipeline; mod query_filter; mod ray_caster; -#[cfg(all( - feature = "default-collider", - any(feature = "parry-f32", feature = "parry-f64") -))] +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] mod shape_caster; -#[cfg(all( - feature = "default-collider", - any(feature = "parry-f32", feature = "parry-f64") -))] +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] mod system_param; -#[cfg(all( - feature = "default-collider", - any(feature = "parry-f32", feature = "parry-f64") -))] +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] pub use pipeline::*; pub use query_filter::*; pub use ray_caster::*; -#[cfg(all( - feature = "default-collider", - any(feature = "parry-f32", feature = "parry-f64") -))] +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] pub use shape_caster::*; -#[cfg(all( - feature = "default-collider", - any(feature = "parry-f32", feature = "parry-f64") -))] +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] pub use system_param::*; use crate::{prelude::*, prepare::PrepareSet}; @@ -273,10 +255,7 @@ fn init_ray_hits(mut commands: Commands, rays: Query<(Entity, &RayCaster), Added } } -#[cfg(all( - feature = "default-collider", - any(feature = "parry-f32", feature = "parry-f64") -))] +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] fn init_shape_hits( mut commands: Commands, shape_casters: Query<(Entity, &ShapeCaster), Added>, @@ -356,10 +335,7 @@ fn update_ray_caster_positions( } } -#[cfg(all( - feature = "default-collider", - any(feature = "parry-f32", feature = "parry-f64") -))] +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] type ShapeCasterPositionQueryComponents = ( &'static mut ShapeCaster, Option<&'static Position>, @@ -368,10 +344,7 @@ type ShapeCasterPositionQueryComponents = ( Option<&'static GlobalTransform>, ); -#[cfg(all( - feature = "default-collider", - any(feature = "parry-f32", feature = "parry-f64") -))] +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] #[allow(clippy::type_complexity)] fn update_shape_caster_positions( mut shape_casters: Query, @@ -459,10 +432,7 @@ fn update_shape_caster_positions( } } -#[cfg(all( - feature = "default-collider", - any(feature = "parry-f32", feature = "parry-f64") -))] +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] fn raycast(mut rays: Query<(Entity, &RayCaster, &mut RayHits)>, spatial_query: SpatialQuery) { for (entity, ray, mut hits) in &mut rays { if ray.enabled { @@ -473,10 +443,7 @@ fn raycast(mut rays: Query<(Entity, &RayCaster, &mut RayHits)>, spatial_query: S } } -#[cfg(all( - feature = "default-collider", - any(feature = "parry-f32", feature = "parry-f64") -))] +#[cfg(any(feature = "parry-f32", feature = "parry-f64"))] fn shapecast( mut shape_casters: Query<(Entity, &ShapeCaster, &mut ShapeHits)>, spatial_query: SpatialQuery, diff --git a/src/type_registration.rs b/src/type_registration.rs index 9d5840fc..5e932a88 100644 --- a/src/type_registration.rs +++ b/src/type_registration.rs @@ -65,18 +65,20 @@ impl Plugin for PhysicsTypeRegistrationPlugin { .register_type::() .register_type::() .register_type::() - .register_type::() - .register_type::() - .register_type::() .register_type::>() .register_type::>() .register_type::() - .register_type::() .register_type::() .register_type::() .register_type::() .register_type::(); + #[cfg(feature = "default-collider")] + app.register_type::() + .register_type::() + .register_type::() + .register_type::(); + #[cfg(feature = "3d")] app.register_type::(); }