diff options
| author | Sébastien Crozet <developer@crozet.re> | 2020-08-25 22:10:25 +0200 |
|---|---|---|
| committer | Sébastien Crozet <developer@crozet.re> | 2020-08-25 22:10:25 +0200 |
| commit | 754a48b7ff6d8c58b1ee08651e60112900b60455 (patch) | |
| tree | 7d777a6c003f1f5d8f8d24f533f35a95a88957fe /src/geometry/proximity_detector/proximity_detector.rs | |
| download | rapier-0.1.0.tar.gz rapier-0.1.0.tar.bz2 rapier-0.1.0.zip | |
First public release of Rapier.v0.1.0
Diffstat (limited to 'src/geometry/proximity_detector/proximity_detector.rs')
| -rw-r--r-- | src/geometry/proximity_detector/proximity_detector.rs | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/src/geometry/proximity_detector/proximity_detector.rs b/src/geometry/proximity_detector/proximity_detector.rs new file mode 100644 index 0000000..76e8cd7 --- /dev/null +++ b/src/geometry/proximity_detector/proximity_detector.rs @@ -0,0 +1,212 @@ +use crate::geometry::{ + Collider, ColliderSet, Proximity, ProximityDispatcher, ProximityEvent, ProximityPair, Shape, +}; +use crate::math::Isometry; +#[cfg(feature = "simd-is-enabled")] +use crate::math::{SimdFloat, SIMD_WIDTH}; +use crate::pipeline::EventHandler; +use std::any::Any; + +#[derive(Copy, Clone)] +pub enum ProximityPhase { + NearPhase(ProximityDetector), + ExactPhase(PrimitiveProximityDetector), +} + +impl ProximityPhase { + #[inline] + pub fn detect_proximity( + self, + mut context: ProximityDetectionContext, + events: &dyn EventHandler, + ) { + let proximity = match self { + Self::NearPhase(gen) => (gen.detect_proximity)(&mut context), + Self::ExactPhase(gen) => { + // Build the primitive context from the non-primitive context and dispatch. + let collider1 = &context.colliders[context.pair.pair.collider1]; + let collider2 = &context.colliders[context.pair.pair.collider2]; + + let mut context2 = PrimitiveProximityDetectionContext { + prediction_distance: context.prediction_distance, + collider1, + collider2, + shape1: collider1.shape(), + shape2: collider2.shape(), + position1: collider1.position(), + position2: collider2.position(), + workspace: context.pair.detector_workspace.as_mut().map(|w| &mut **w), + }; + + (gen.detect_proximity)(&mut context2) + } + }; + + if context.pair.proximity != proximity { + events.handle_proximity_event(ProximityEvent::new( + context.pair.pair.collider1, + context.pair.pair.collider2, + context.pair.proximity, + proximity, + )) + } + + context.pair.proximity = proximity; + } + + #[cfg(feature = "simd-is-enabled")] + #[inline] + pub fn detect_proximity_simd( + self, + mut context: ProximityDetectionContextSimd, + events: &dyn EventHandler, + ) { + let proximities = match self { + Self::NearPhase(gen) => (gen.detect_proximity_simd)(&mut context), + Self::ExactPhase(gen) => { + // Build the primitive context from the non-primitive context and dispatch. + use arrayvec::ArrayVec; + let mut colliders_arr: ArrayVec<[(&Collider, &Collider); SIMD_WIDTH]> = + ArrayVec::new(); + let mut workspace_arr: ArrayVec< + [Option<&mut (dyn Any + Send + Sync)>; SIMD_WIDTH], + > = ArrayVec::new(); + + for pair in context.pairs.iter_mut() { + let collider1 = &context.colliders[pair.pair.collider1]; + let collider2 = &context.colliders[pair.pair.collider2]; + colliders_arr.push((collider1, collider2)); + workspace_arr.push(pair.detector_workspace.as_mut().map(|w| &mut **w)); + } + + let max_index = colliders_arr.len() - 1; + let colliders1 = array![|ii| colliders_arr[ii.min(max_index)].0; SIMD_WIDTH]; + let colliders2 = array![|ii| colliders_arr[ii.min(max_index)].1; SIMD_WIDTH]; + + let mut context2 = PrimitiveProximityDetectionContextSimd { + prediction_distance: context.prediction_distance, + colliders1, + colliders2, + shapes1: array![|ii| colliders1[ii].shape(); SIMD_WIDTH], + shapes2: array![|ii| colliders2[ii].shape(); SIMD_WIDTH], + positions1: &Isometry::from( + array![|ii| *colliders1[ii].position(); SIMD_WIDTH], + ), + positions2: &Isometry::from( + array![|ii| *colliders2[ii].position(); SIMD_WIDTH], + ), + workspaces: workspace_arr.as_mut_slice(), + }; + + (gen.detect_proximity_simd)(&mut context2) + } + }; + + for (i, pair) in context.pairs.iter_mut().enumerate() { + if pair.proximity != proximities[i] { + events.handle_proximity_event(ProximityEvent::new( + pair.pair.collider1, + pair.pair.collider2, + pair.proximity, + proximities[i], + )) + } + pair.proximity = proximities[i]; + } + } +} + +pub struct PrimitiveProximityDetectionContext<'a> { + pub prediction_distance: f32, + pub collider1: &'a Collider, + pub collider2: &'a Collider, + pub shape1: &'a Shape, + pub shape2: &'a Shape, + pub position1: &'a Isometry<f32>, + pub position2: &'a Isometry<f32>, + pub workspace: Option<&'a mut (dyn Any + Send + Sync)>, +} + +#[cfg(feature = "simd-is-enabled")] +pub struct PrimitiveProximityDetectionContextSimd<'a, 'b> { + pub prediction_distance: f32, + pub colliders1: [&'a Collider; SIMD_WIDTH], + pub colliders2: [&'a Collider; SIMD_WIDTH], + pub shapes1: [&'a Shape; SIMD_WIDTH], + pub shapes2: [&'a Shape; SIMD_WIDTH], + pub positions1: &'a Isometry<SimdFloat>, + pub positions2: &'a Isometry<SimdFloat>, + pub workspaces: &'a mut [Option<&'b mut (dyn Any + Send + Sync)>], +} + +#[derive(Copy, Clone)] +pub struct PrimitiveProximityDetector { + pub detect_proximity: fn(&mut PrimitiveProximityDetectionContext) -> Proximity, + #[cfg(feature = "simd-is-enabled")] + pub detect_proximity_simd: + fn(&mut PrimitiveProximityDetectionContextSimd) -> [Proximity; SIMD_WIDTH], +} + +impl PrimitiveProximityDetector { + fn unimplemented_fn(_ctxt: &mut PrimitiveProximityDetectionContext) -> Proximity { + Proximity::Disjoint + } + #[cfg(feature = "simd-is-enabled")] + fn unimplemented_simd_fn( + _ctxt: &mut PrimitiveProximityDetectionContextSimd, + ) -> [Proximity; SIMD_WIDTH] { + [Proximity::Disjoint; SIMD_WIDTH] + } +} + +impl Default for PrimitiveProximityDetector { + fn default() -> Self { + Self { + detect_proximity: Self::unimplemented_fn, + #[cfg(feature = "simd-is-enabled")] + detect_proximity_simd: Self::unimplemented_simd_fn, + } + } +} + +pub struct ProximityDetectionContext<'a> { + pub dispatcher: &'a dyn ProximityDispatcher, + pub prediction_distance: f32, + pub colliders: &'a ColliderSet, + pub pair: &'a mut ProximityPair, +} + +#[cfg(feature = "simd-is-enabled")] +pub struct ProximityDetectionContextSimd<'a, 'b> { + pub dispatcher: &'a dyn ProximityDispatcher, + pub prediction_distance: f32, + pub colliders: &'a ColliderSet, + pub pairs: &'a mut [&'b mut ProximityPair], +} + +#[derive(Copy, Clone)] +pub struct ProximityDetector { + pub detect_proximity: fn(&mut ProximityDetectionContext) -> Proximity, + #[cfg(feature = "simd-is-enabled")] + pub detect_proximity_simd: fn(&mut ProximityDetectionContextSimd) -> [Proximity; SIMD_WIDTH], +} + +impl ProximityDetector { + fn unimplemented_fn(_ctxt: &mut ProximityDetectionContext) -> Proximity { + Proximity::Disjoint + } + #[cfg(feature = "simd-is-enabled")] + fn unimplemented_simd_fn(_ctxt: &mut ProximityDetectionContextSimd) -> [Proximity; SIMD_WIDTH] { + [Proximity::Disjoint; SIMD_WIDTH] + } +} + +impl Default for ProximityDetector { + fn default() -> Self { + Self { + detect_proximity: Self::unimplemented_fn, + #[cfg(feature = "simd-is-enabled")] + detect_proximity_simd: Self::unimplemented_simd_fn, + } + } +} |
