chore: 添加第三方依赖库
This commit is contained in:
462
thirdparty/rapier.js/src/geometry/broad_phase.rs
vendored
Normal file
462
thirdparty/rapier.js/src/geometry/broad_phase.rs
vendored
Normal file
@@ -0,0 +1,462 @@
|
||||
use crate::dynamics::RawRigidBodySet;
|
||||
use crate::geometry::{
|
||||
RawColliderSet, RawColliderShapeCastHit, RawNarrowPhase, RawPointColliderProjection,
|
||||
RawRayColliderHit, RawRayColliderIntersection, RawShape,
|
||||
};
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::geometry::DefaultBroadPhase;
|
||||
use rapier::geometry::{Aabb, ColliderHandle, Ray};
|
||||
use rapier::math::{Isometry, Point};
|
||||
use rapier::parry::query::ShapeCastOptions;
|
||||
use rapier::pipeline::{QueryFilter, QueryFilterFlags};
|
||||
use rapier::prelude::FeatureId;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawBroadPhase(pub(crate) DefaultBroadPhase);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawBroadPhase {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawBroadPhase(DefaultBroadPhase::new())
|
||||
}
|
||||
|
||||
pub fn castRay(
|
||||
&self,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
rayOrig: &RawVector,
|
||||
rayDir: &RawVector,
|
||||
maxToi: f32,
|
||||
solid: bool,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_exclude_collider: Option<FlatHandle>,
|
||||
filter_exclude_rigid_body: Option<FlatHandle>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) -> Option<RawRayColliderHit> {
|
||||
let (handle, timeOfImpact) = utils::with_filter(filter_predicate, |predicate| {
|
||||
let query_filter = QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: filter_groups.map(crate::geometry::unpack_interaction_groups),
|
||||
exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle),
|
||||
exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle),
|
||||
predicate,
|
||||
};
|
||||
|
||||
let query_pipeline = self.0.as_query_pipeline(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&bodies.0,
|
||||
&colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
let ray = Ray::new(rayOrig.0.into(), rayDir.0);
|
||||
query_pipeline.cast_ray(&ray, maxToi, solid)
|
||||
})?;
|
||||
|
||||
Some(RawRayColliderHit {
|
||||
handle,
|
||||
timeOfImpact,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn castRayAndGetNormal(
|
||||
&self,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
rayOrig: &RawVector,
|
||||
rayDir: &RawVector,
|
||||
maxToi: f32,
|
||||
solid: bool,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_exclude_collider: Option<FlatHandle>,
|
||||
filter_exclude_rigid_body: Option<FlatHandle>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) -> Option<RawRayColliderIntersection> {
|
||||
let (handle, inter) = utils::with_filter(filter_predicate, |predicate| {
|
||||
let query_filter = QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: filter_groups.map(crate::geometry::unpack_interaction_groups),
|
||||
exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle),
|
||||
exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle),
|
||||
predicate,
|
||||
};
|
||||
|
||||
let query_pipeline = self.0.as_query_pipeline(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&bodies.0,
|
||||
&colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
let ray = Ray::new(rayOrig.0.into(), rayDir.0);
|
||||
query_pipeline.cast_ray_and_get_normal(&ray, maxToi, solid)
|
||||
})?;
|
||||
|
||||
Some(RawRayColliderIntersection { handle, inter })
|
||||
}
|
||||
|
||||
// The callback is of type (RawRayColliderIntersection) => bool
|
||||
pub fn intersectionsWithRay(
|
||||
&self,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
rayOrig: &RawVector,
|
||||
rayDir: &RawVector,
|
||||
maxToi: f32,
|
||||
solid: bool,
|
||||
callback: &js_sys::Function,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_exclude_collider: Option<FlatHandle>,
|
||||
filter_exclude_rigid_body: Option<FlatHandle>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) {
|
||||
utils::with_filter(filter_predicate, |predicate| {
|
||||
let query_filter = QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: filter_groups.map(crate::geometry::unpack_interaction_groups),
|
||||
exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle),
|
||||
exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle),
|
||||
predicate,
|
||||
};
|
||||
|
||||
let ray = Ray::new(rayOrig.0.into(), rayDir.0);
|
||||
let rcallback = |handle, inter| {
|
||||
let result = RawRayColliderIntersection { handle, inter };
|
||||
match callback.call1(&JsValue::null(), &JsValue::from(result)) {
|
||||
Err(_) => true,
|
||||
Ok(val) => val.as_bool().unwrap_or(true),
|
||||
}
|
||||
};
|
||||
|
||||
let query_pipeline = self.0.as_query_pipeline(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&bodies.0,
|
||||
&colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
for (handle, _, inter) in query_pipeline.intersect_ray(ray, maxToi, solid) {
|
||||
if !rcallback(handle, inter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn intersectionWithShape(
|
||||
&self,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
shapePos: &RawVector,
|
||||
shapeRot: &RawRotation,
|
||||
shape: &RawShape,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_exclude_collider: Option<FlatHandle>,
|
||||
filter_exclude_rigid_body: Option<FlatHandle>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) -> Option<FlatHandle> {
|
||||
utils::with_filter(filter_predicate, |predicate| {
|
||||
let query_filter = QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: filter_groups.map(crate::geometry::unpack_interaction_groups),
|
||||
exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle),
|
||||
exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle),
|
||||
predicate,
|
||||
};
|
||||
|
||||
let query_pipeline = self.0.as_query_pipeline(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&bodies.0,
|
||||
&colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
let pos = Isometry::from_parts(shapePos.0.into(), shapeRot.0);
|
||||
|
||||
// TODO: take a callback as argument so we can yield all the intersecting shapes?
|
||||
for (handle, _) in query_pipeline.intersect_shape(pos, &*shape.0) {
|
||||
// Return the first intersection we find.
|
||||
return Some(utils::flat_handle(handle.0));
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
pub fn projectPoint(
|
||||
&self,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
point: &RawVector,
|
||||
solid: bool,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_exclude_collider: Option<FlatHandle>,
|
||||
filter_exclude_rigid_body: Option<FlatHandle>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) -> Option<RawPointColliderProjection> {
|
||||
utils::with_filter(filter_predicate, |predicate| {
|
||||
let query_filter = QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: filter_groups.map(crate::geometry::unpack_interaction_groups),
|
||||
exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle),
|
||||
exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle),
|
||||
predicate,
|
||||
};
|
||||
|
||||
let query_pipeline = self.0.as_query_pipeline(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&bodies.0,
|
||||
&colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
query_pipeline
|
||||
.project_point(&point.0.into(), f32::MAX, solid)
|
||||
.map(|(handle, proj)| RawPointColliderProjection {
|
||||
handle,
|
||||
proj,
|
||||
feature: FeatureId::Unknown,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn projectPointAndGetFeature(
|
||||
&self,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
point: &RawVector,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_exclude_collider: Option<FlatHandle>,
|
||||
filter_exclude_rigid_body: Option<FlatHandle>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) -> Option<RawPointColliderProjection> {
|
||||
utils::with_filter(filter_predicate, |predicate| {
|
||||
let query_filter = QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: filter_groups.map(crate::geometry::unpack_interaction_groups),
|
||||
exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle),
|
||||
exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle),
|
||||
predicate,
|
||||
};
|
||||
|
||||
let query_pipeline = self.0.as_query_pipeline(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&bodies.0,
|
||||
&colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
query_pipeline
|
||||
.project_point_and_get_feature(&point.0.into())
|
||||
.map(|(handle, proj, feature)| RawPointColliderProjection {
|
||||
handle,
|
||||
proj,
|
||||
feature,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// The callback is of type (u32) => bool
|
||||
pub fn intersectionsWithPoint(
|
||||
&self,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
point: &RawVector,
|
||||
callback: &js_sys::Function,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_exclude_collider: Option<FlatHandle>,
|
||||
filter_exclude_rigid_body: Option<FlatHandle>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) {
|
||||
utils::with_filter(filter_predicate, |predicate| {
|
||||
let query_filter = QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: filter_groups.map(crate::geometry::unpack_interaction_groups),
|
||||
exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle),
|
||||
exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle),
|
||||
predicate,
|
||||
};
|
||||
|
||||
let query_pipeline = self.0.as_query_pipeline(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&bodies.0,
|
||||
&colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
let rcallback = |handle: ColliderHandle| match callback.call1(
|
||||
&JsValue::null(),
|
||||
&JsValue::from(utils::flat_handle(handle.0)),
|
||||
) {
|
||||
Err(_) => true,
|
||||
Ok(val) => val.as_bool().unwrap_or(true),
|
||||
};
|
||||
|
||||
for (handle, _) in query_pipeline.intersect_point(point.0.into()) {
|
||||
if !rcallback(handle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn castShape(
|
||||
&self,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
shapePos: &RawVector,
|
||||
shapeRot: &RawRotation,
|
||||
shapeVel: &RawVector,
|
||||
shape: &RawShape,
|
||||
target_distance: f32,
|
||||
maxToi: f32,
|
||||
stop_at_penetration: bool,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_exclude_collider: Option<FlatHandle>,
|
||||
filter_exclude_rigid_body: Option<FlatHandle>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) -> Option<RawColliderShapeCastHit> {
|
||||
utils::with_filter(filter_predicate, |predicate| {
|
||||
let query_filter = QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: filter_groups.map(crate::geometry::unpack_interaction_groups),
|
||||
exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle),
|
||||
exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle),
|
||||
predicate,
|
||||
};
|
||||
|
||||
let query_pipeline = self.0.as_query_pipeline(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&bodies.0,
|
||||
&colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
let pos = Isometry::from_parts(shapePos.0.into(), shapeRot.0);
|
||||
query_pipeline
|
||||
.cast_shape(
|
||||
&pos,
|
||||
&shapeVel.0,
|
||||
&*shape.0,
|
||||
ShapeCastOptions {
|
||||
max_time_of_impact: maxToi,
|
||||
stop_at_penetration,
|
||||
compute_impact_geometry_on_penetration: true,
|
||||
target_distance,
|
||||
},
|
||||
)
|
||||
.map(|(handle, hit)| RawColliderShapeCastHit { handle, hit })
|
||||
})
|
||||
}
|
||||
|
||||
// The callback has type (u32) => boolean
|
||||
pub fn intersectionsWithShape(
|
||||
&self,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
shapePos: &RawVector,
|
||||
shapeRot: &RawRotation,
|
||||
shape: &RawShape,
|
||||
callback: &js_sys::Function,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_exclude_collider: Option<FlatHandle>,
|
||||
filter_exclude_rigid_body: Option<FlatHandle>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) {
|
||||
utils::with_filter(filter_predicate, |predicate| {
|
||||
let query_filter = QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: filter_groups.map(crate::geometry::unpack_interaction_groups),
|
||||
exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle),
|
||||
exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle),
|
||||
predicate,
|
||||
};
|
||||
|
||||
let query_pipeline = self.0.as_query_pipeline(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&bodies.0,
|
||||
&colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
let rcallback = |handle: ColliderHandle| match callback.call1(
|
||||
&JsValue::null(),
|
||||
&JsValue::from(utils::flat_handle(handle.0)),
|
||||
) {
|
||||
Err(_) => true,
|
||||
Ok(val) => val.as_bool().unwrap_or(true),
|
||||
};
|
||||
|
||||
let pos = Isometry::from_parts(shapePos.0.into(), shapeRot.0);
|
||||
for (handle, _) in query_pipeline.intersect_shape(pos, &*shape.0) {
|
||||
if !rcallback(handle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn collidersWithAabbIntersectingAabb(
|
||||
&self,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
aabbCenter: &RawVector,
|
||||
aabbHalfExtents: &RawVector,
|
||||
callback: &js_sys::Function,
|
||||
) {
|
||||
let rcallback = |handle: &ColliderHandle| match callback.call1(
|
||||
&JsValue::null(),
|
||||
&JsValue::from(utils::flat_handle(handle.0)),
|
||||
) {
|
||||
Err(_) => true,
|
||||
Ok(val) => val.as_bool().unwrap_or(true),
|
||||
};
|
||||
|
||||
let query_pipeline = self.0.as_query_pipeline(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&bodies.0,
|
||||
&colliders.0,
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let center = Point::from(aabbCenter.0);
|
||||
let aabb = Aabb::new(center - aabbHalfExtents.0, center + aabbHalfExtents.0);
|
||||
|
||||
for (handle, _) in query_pipeline.intersect_aabb_conservative(aabb) {
|
||||
if !rcallback(&handle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
993
thirdparty/rapier.js/src/geometry/collider.rs
vendored
Normal file
993
thirdparty/rapier.js/src/geometry/collider.rs
vendored
Normal file
@@ -0,0 +1,993 @@
|
||||
use crate::geometry::shape::SharedShapeUtility;
|
||||
use crate::geometry::{
|
||||
RawColliderSet, RawColliderShapeCastHit, RawPointProjection, RawRayIntersection, RawShape,
|
||||
RawShapeCastHit, RawShapeContact, RawShapeType,
|
||||
};
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::dynamics::MassProperties;
|
||||
use rapier::geometry::{ActiveCollisionTypes, ShapeType};
|
||||
use rapier::math::{Isometry, Point, Real, Vector};
|
||||
use rapier::parry::query;
|
||||
use rapier::parry::query::ShapeCastOptions;
|
||||
use rapier::pipeline::{ActiveEvents, ActiveHooks};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawColliderSet {
|
||||
/// The world-space translation of this collider.
|
||||
pub fn coTranslation(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |co| co.position().translation.vector.into())
|
||||
}
|
||||
|
||||
/// The world-space orientation of this collider.
|
||||
pub fn coRotation(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |co| co.position().rotation.into())
|
||||
}
|
||||
|
||||
/// The translation of this collider relative to its parent rigid-body.
|
||||
///
|
||||
/// Returns the `None` if it doesn’t have a parent.
|
||||
pub fn coTranslationWrtParent(&self, handle: FlatHandle) -> Option<RawVector> {
|
||||
self.map(handle, |co| {
|
||||
co.position_wrt_parent()
|
||||
.map(|pose| pose.translation.vector.into())
|
||||
})
|
||||
}
|
||||
|
||||
/// The orientation of this collider relative to its parent rigid-body.
|
||||
///
|
||||
/// Returns the `None` if it doesn’t have a parent.
|
||||
pub fn coRotationWrtParent(&self, handle: FlatHandle) -> Option<RawRotation> {
|
||||
self.map(handle, |co| {
|
||||
co.position_wrt_parent().map(|pose| pose.rotation.into())
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the translation of this collider.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the world-space position of the collider along the `x` axis.
|
||||
/// - `y`: the world-space position of the collider along the `y` axis.
|
||||
/// - `z`: the world-space position of the collider along the `z` axis.
|
||||
/// - `wakeUp`: forces the collider to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn coSetTranslation(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32) {
|
||||
self.map_mut(handle, |co| {
|
||||
co.set_translation(na::Vector3::new(x, y, z));
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the translation of this collider.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the world-space position of the collider along the `x` axis.
|
||||
/// - `y`: the world-space position of the collider along the `y` axis.
|
||||
/// - `wakeUp`: forces the collider to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn coSetTranslation(&mut self, handle: FlatHandle, x: f32, y: f32) {
|
||||
self.map_mut(handle, |co| {
|
||||
co.set_translation(na::Vector2::new(x, y));
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn coSetTranslationWrtParent(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32) {
|
||||
self.map_mut(handle, |co| {
|
||||
co.set_translation_wrt_parent(na::Vector3::new(x, y, z));
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn coSetTranslationWrtParent(&mut self, handle: FlatHandle, x: f32, y: f32) {
|
||||
self.map_mut(handle, |co| {
|
||||
co.set_translation_wrt_parent(na::Vector2::new(x, y));
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the rotation quaternion of this collider.
|
||||
///
|
||||
/// This does nothing if a zero quaternion is provided.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the first vector component of the quaternion.
|
||||
/// - `y`: the second vector component of the quaternion.
|
||||
/// - `z`: the third vector component of the quaternion.
|
||||
/// - `w`: the scalar component of the quaternion.
|
||||
/// - `wakeUp`: forces the collider to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn coSetRotation(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32, w: f32) {
|
||||
if let Some(q) = na::Unit::try_new(na::Quaternion::new(w, x, y, z), 0.0) {
|
||||
self.map_mut(handle, |co| co.set_rotation(q))
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the rotation angle of this collider.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `angle`: the rotation angle, in radians.
|
||||
/// - `wakeUp`: forces the collider to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn coSetRotation(&mut self, handle: FlatHandle, angle: f32) {
|
||||
self.map_mut(handle, |co| co.set_rotation(na::UnitComplex::new(angle)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn coSetRotationWrtParent(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32, w: f32) {
|
||||
if let Some(q) = na::Unit::try_new(na::Quaternion::new(w, x, y, z), 0.0) {
|
||||
self.map_mut(handle, |co| co.set_rotation_wrt_parent(q.scaled_axis()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn coSetRotationWrtParent(&mut self, handle: FlatHandle, angle: f32) {
|
||||
self.map_mut(handle, |co| co.set_rotation_wrt_parent(angle))
|
||||
}
|
||||
|
||||
/// Is this collider a sensor?
|
||||
pub fn coIsSensor(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |co| co.is_sensor())
|
||||
}
|
||||
|
||||
/// The type of the shape of this collider.
|
||||
pub fn coShapeType(&self, handle: FlatHandle) -> RawShapeType {
|
||||
self.map(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::Ball => RawShapeType::Ball,
|
||||
ShapeType::Cuboid => RawShapeType::Cuboid,
|
||||
ShapeType::Capsule => RawShapeType::Capsule,
|
||||
ShapeType::Segment => RawShapeType::Segment,
|
||||
ShapeType::Polyline => RawShapeType::Polyline,
|
||||
ShapeType::Triangle => RawShapeType::Triangle,
|
||||
ShapeType::TriMesh => RawShapeType::TriMesh,
|
||||
ShapeType::HeightField => RawShapeType::HeightField,
|
||||
ShapeType::Compound => RawShapeType::Compound,
|
||||
ShapeType::HalfSpace => RawShapeType::HalfSpace,
|
||||
ShapeType::Voxels => RawShapeType::Voxels,
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::ConvexPolyhedron => RawShapeType::ConvexPolyhedron,
|
||||
#[cfg(feature = "dim2")]
|
||||
ShapeType::ConvexPolygon => RawShapeType::ConvexPolygon,
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::Cylinder => RawShapeType::Cylinder,
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::Cone => RawShapeType::Cone,
|
||||
ShapeType::RoundCuboid => RawShapeType::RoundCuboid,
|
||||
ShapeType::RoundTriangle => RawShapeType::RoundTriangle,
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundCylinder => RawShapeType::RoundCylinder,
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundCone => RawShapeType::RoundCone,
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundConvexPolyhedron => RawShapeType::RoundConvexPolyhedron,
|
||||
#[cfg(feature = "dim2")]
|
||||
ShapeType::RoundConvexPolygon => RawShapeType::RoundConvexPolygon,
|
||||
ShapeType::Custom => panic!("Not yet implemented."),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coHalfspaceNormal(&self, handle: FlatHandle) -> Option<RawVector> {
|
||||
self.map(handle, |co| {
|
||||
co.shape()
|
||||
.as_halfspace()
|
||||
.map(|h| h.normal.into_inner().into())
|
||||
})
|
||||
}
|
||||
|
||||
/// The half-extents of this collider if it is has a cuboid shape.
|
||||
pub fn coHalfExtents(&self, handle: FlatHandle) -> Option<RawVector> {
|
||||
self.map(handle, |co| {
|
||||
co.shape()
|
||||
.as_cuboid()
|
||||
.map(|c| c.half_extents.into())
|
||||
.or_else(|| {
|
||||
co.shape()
|
||||
.as_round_cuboid()
|
||||
.map(|c| c.inner_shape.half_extents.into())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Set the half-extents of this collider if it has a cuboid shape.
|
||||
pub fn coSetHalfExtents(&mut self, handle: FlatHandle, newHalfExtents: &RawVector) {
|
||||
self.map_mut(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::Cuboid => co
|
||||
.shape_mut()
|
||||
.as_cuboid_mut()
|
||||
.map(|b| b.half_extents = newHalfExtents.0.into()),
|
||||
ShapeType::RoundCuboid => co
|
||||
.shape_mut()
|
||||
.as_round_cuboid_mut()
|
||||
.map(|b| b.inner_shape.half_extents = newHalfExtents.0.into()),
|
||||
_ => None,
|
||||
});
|
||||
}
|
||||
|
||||
/// The radius of this collider if it is a ball, capsule, cylinder, or cone shape.
|
||||
pub fn coRadius(&self, handle: FlatHandle) -> Option<f32> {
|
||||
self.map(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::Ball => co.shape().as_ball().map(|b| b.radius),
|
||||
ShapeType::Capsule => co.shape().as_capsule().map(|b| b.radius),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::Cylinder => co.shape().as_cylinder().map(|b| b.radius),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundCylinder => {
|
||||
co.shape().as_round_cylinder().map(|b| b.inner_shape.radius)
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::Cone => co.shape().as_cone().map(|b| b.radius),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Set the radius of this collider if it is a ball, capsule, cylinder, or cone shape.
|
||||
pub fn coSetRadius(&mut self, handle: FlatHandle, newRadius: Real) {
|
||||
self.map_mut(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::Ball => co.shape_mut().as_ball_mut().map(|b| b.radius = newRadius),
|
||||
ShapeType::Capsule => co
|
||||
.shape_mut()
|
||||
.as_capsule_mut()
|
||||
.map(|b| b.radius = newRadius),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::Cylinder => co
|
||||
.shape_mut()
|
||||
.as_cylinder_mut()
|
||||
.map(|b| b.radius = newRadius),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundCylinder => co
|
||||
.shape_mut()
|
||||
.as_round_cylinder_mut()
|
||||
.map(|b| b.inner_shape.radius = newRadius),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::Cone => co.shape_mut().as_cone_mut().map(|b| b.radius = newRadius),
|
||||
_ => None,
|
||||
});
|
||||
}
|
||||
|
||||
/// The half height of this collider if it is a capsule, cylinder, or cone shape.
|
||||
pub fn coHalfHeight(&self, handle: FlatHandle) -> Option<f32> {
|
||||
self.map(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::Capsule => co.shape().as_capsule().map(|b| b.half_height()),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::Cylinder => co.shape().as_cylinder().map(|b| b.half_height),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundCylinder => co
|
||||
.shape()
|
||||
.as_round_cylinder()
|
||||
.map(|b| b.inner_shape.half_height),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::Cone => co.shape().as_cone().map(|b| b.half_height),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Set the half height of this collider if it is a capsule, cylinder, or cone shape.
|
||||
pub fn coSetHalfHeight(&mut self, handle: FlatHandle, newHalfheight: Real) {
|
||||
self.map_mut(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::Capsule => {
|
||||
let point = Point::from(Vector::y() * newHalfheight);
|
||||
co.shape_mut().as_capsule_mut().map(|b| {
|
||||
b.segment.a = -point;
|
||||
b.segment.b = point;
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::Cylinder => co
|
||||
.shape_mut()
|
||||
.as_cylinder_mut()
|
||||
.map(|b| b.half_height = newHalfheight),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundCylinder => co
|
||||
.shape_mut()
|
||||
.as_round_cylinder_mut()
|
||||
.map(|b| b.inner_shape.half_height = newHalfheight),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::Cone => co
|
||||
.shape_mut()
|
||||
.as_cone_mut()
|
||||
.map(|b| b.half_height = newHalfheight),
|
||||
_ => None,
|
||||
});
|
||||
}
|
||||
|
||||
/// The radius of the round edges of this collider.
|
||||
pub fn coRoundRadius(&self, handle: FlatHandle) -> Option<f32> {
|
||||
self.map(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::RoundCuboid => co.shape().as_round_cuboid().map(|b| b.border_radius),
|
||||
ShapeType::RoundTriangle => co.shape().as_round_triangle().map(|b| b.border_radius),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundCylinder => co.shape().as_round_cylinder().map(|b| b.border_radius),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundCone => co.shape().as_round_cone().map(|b| b.border_radius),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundConvexPolyhedron => co
|
||||
.shape()
|
||||
.as_round_convex_polyhedron()
|
||||
.map(|b| b.border_radius),
|
||||
#[cfg(feature = "dim2")]
|
||||
ShapeType::RoundConvexPolygon => co
|
||||
.shape()
|
||||
.as_round_convex_polygon()
|
||||
.map(|b| b.border_radius),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Set the radius of the round edges of this collider.
|
||||
pub fn coSetRoundRadius(&mut self, handle: FlatHandle, newBorderRadius: Real) {
|
||||
self.map_mut(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::RoundCuboid => co
|
||||
.shape_mut()
|
||||
.as_round_cuboid_mut()
|
||||
.map(|b| b.border_radius = newBorderRadius),
|
||||
ShapeType::RoundTriangle => co
|
||||
.shape_mut()
|
||||
.as_round_triangle_mut()
|
||||
.map(|b| b.border_radius = newBorderRadius),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundCylinder => co
|
||||
.shape_mut()
|
||||
.as_round_cylinder_mut()
|
||||
.map(|b| b.border_radius = newBorderRadius),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundCone => co
|
||||
.shape_mut()
|
||||
.as_round_cone_mut()
|
||||
.map(|b| b.border_radius = newBorderRadius),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundConvexPolyhedron => co
|
||||
.shape_mut()
|
||||
.as_round_convex_polyhedron_mut()
|
||||
.map(|b| b.border_radius = newBorderRadius),
|
||||
#[cfg(feature = "dim2")]
|
||||
ShapeType::RoundConvexPolygon => co
|
||||
.shape_mut()
|
||||
.as_round_convex_polygon_mut()
|
||||
.map(|b| b.border_radius = newBorderRadius),
|
||||
_ => None,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn coVoxelData(&self, handle: FlatHandle) -> Option<Vec<i32>> {
|
||||
self.map(handle, |co| {
|
||||
let vox = co.shape().as_voxels()?;
|
||||
let coords = vox
|
||||
.voxels()
|
||||
.filter_map(|vox| (!vox.state.is_empty()).then_some(vox.grid_coords))
|
||||
.flat_map(|ids| ids.coords.data.0[0])
|
||||
.collect();
|
||||
Some(coords)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coVoxelSize(&self, handle: FlatHandle) -> Option<RawVector> {
|
||||
self.map(handle, |co| {
|
||||
let vox = co.shape().as_voxels()?;
|
||||
Some(RawVector(vox.voxel_size()))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn coSetVoxel(&mut self, handle: FlatHandle, ix: i32, iy: i32, filled: bool) {
|
||||
self.map_mut(handle, |co| {
|
||||
if let Some(vox) = co.shape_mut().as_voxels_mut() {
|
||||
vox.set_voxel(Point::new(ix, iy), filled);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn coSetVoxel(&mut self, handle: FlatHandle, ix: i32, iy: i32, iz: i32, filled: bool) {
|
||||
self.map_mut(handle, |co| {
|
||||
if let Some(vox) = co.shape_mut().as_voxels_mut() {
|
||||
vox.set_voxel(Point::new(ix, iy, iz), filled);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn coPropagateVoxelChange(
|
||||
&mut self,
|
||||
handle1: FlatHandle,
|
||||
handle2: FlatHandle,
|
||||
ix: i32,
|
||||
iy: i32,
|
||||
shift_x: i32,
|
||||
shift_y: i32,
|
||||
) {
|
||||
self.map_pair_mut(handle1, handle2, |co1, co2| {
|
||||
if let (Some(co1), Some(co2)) = (co1, co2) {
|
||||
if let (Some(vox1), Some(vox2)) = (
|
||||
co1.shape_mut().as_voxels_mut(),
|
||||
co2.shape_mut().as_voxels_mut(),
|
||||
) {
|
||||
vox1.propagate_voxel_change(
|
||||
vox2,
|
||||
Point::new(ix, iy),
|
||||
Vector::new(shift_x, shift_y),
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn coPropagateVoxelChange(
|
||||
&mut self,
|
||||
handle1: FlatHandle,
|
||||
handle2: FlatHandle,
|
||||
ix: i32,
|
||||
iy: i32,
|
||||
iz: i32,
|
||||
shift_x: i32,
|
||||
shift_y: i32,
|
||||
shift_z: i32,
|
||||
) {
|
||||
self.map_pair_mut(handle1, handle2, |co1, co2| {
|
||||
if let (Some(co1), Some(co2)) = (co1, co2) {
|
||||
if let (Some(vox1), Some(vox2)) = (
|
||||
co1.shape_mut().as_voxels_mut(),
|
||||
co2.shape_mut().as_voxels_mut(),
|
||||
) {
|
||||
vox1.propagate_voxel_change(
|
||||
vox2,
|
||||
Point::new(ix, iy, iz),
|
||||
Vector::new(shift_x, shift_y, shift_z),
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn coCombineVoxelStates(
|
||||
&mut self,
|
||||
handle1: FlatHandle,
|
||||
handle2: FlatHandle,
|
||||
shift_x: i32,
|
||||
shift_y: i32,
|
||||
) {
|
||||
self.map_pair_mut(handle1, handle2, |co1, co2| {
|
||||
if let (Some(co1), Some(co2)) = (co1, co2) {
|
||||
if let (Some(vox1), Some(vox2)) = (
|
||||
co1.shape_mut().as_voxels_mut(),
|
||||
co2.shape_mut().as_voxels_mut(),
|
||||
) {
|
||||
vox1.combine_voxel_states(vox2, Vector::new(shift_x, shift_y));
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn coCombineVoxelStates(
|
||||
&mut self,
|
||||
handle1: FlatHandle,
|
||||
handle2: FlatHandle,
|
||||
shift_x: i32,
|
||||
shift_y: i32,
|
||||
shift_z: i32,
|
||||
) {
|
||||
self.map_pair_mut(handle1, handle2, |co1, co2| {
|
||||
if let (Some(co1), Some(co2)) = (co1, co2) {
|
||||
if let (Some(vox1), Some(vox2)) = (
|
||||
co1.shape_mut().as_voxels_mut(),
|
||||
co2.shape_mut().as_voxels_mut(),
|
||||
) {
|
||||
vox1.combine_voxel_states(vox2, Vector::new(shift_x, shift_y, shift_z));
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// The vertices of this triangle mesh, polyline, convex polyhedron, segment, triangle or convex polyhedron, if it is one.
|
||||
pub fn coVertices(&self, handle: FlatHandle) -> Option<Vec<f32>> {
|
||||
let flatten =
|
||||
|vertices: &[Point<f32>]| vertices.iter().flat_map(|p| p.iter()).copied().collect();
|
||||
self.map(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::TriMesh => co.shape().as_trimesh().map(|t| flatten(t.vertices())),
|
||||
#[cfg(feature = "dim2")]
|
||||
ShapeType::Polyline => co.shape().as_polyline().map(|p| flatten(p.vertices())),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::ConvexPolyhedron => co
|
||||
.shape()
|
||||
.as_convex_polyhedron()
|
||||
.map(|p| flatten(p.points())),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundConvexPolyhedron => co
|
||||
.shape()
|
||||
.as_round_convex_polyhedron()
|
||||
.map(|p| flatten(p.inner_shape.points())),
|
||||
#[cfg(feature = "dim2")]
|
||||
ShapeType::ConvexPolygon => co.shape().as_convex_polygon().map(|p| flatten(p.points())),
|
||||
#[cfg(feature = "dim2")]
|
||||
ShapeType::RoundConvexPolygon => co
|
||||
.shape()
|
||||
.as_round_convex_polygon()
|
||||
.map(|p| flatten(p.inner_shape.points())),
|
||||
ShapeType::Segment => co.shape().as_segment().map(|s| flatten(&[s.a, s.b])),
|
||||
ShapeType::RoundTriangle => co
|
||||
.shape()
|
||||
.as_round_triangle()
|
||||
.map(|t| flatten(&[t.inner_shape.a, t.inner_shape.b, t.inner_shape.c])),
|
||||
ShapeType::Triangle => co.shape().as_triangle().map(|t| flatten(&[t.a, t.b, t.c])),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// The indices of this triangle mesh, polyline, or convex polyhedron, if it is one.
|
||||
pub fn coIndices(&self, handle: FlatHandle) -> Option<Vec<u32>> {
|
||||
self.map(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::TriMesh => co
|
||||
.shape()
|
||||
.as_trimesh()
|
||||
.map(|t| t.indices().iter().flat_map(|p| p.iter()).copied().collect()),
|
||||
ShapeType::Polyline => co
|
||||
.shape()
|
||||
.as_polyline()
|
||||
.map(|p| p.indices().iter().flat_map(|p| p.iter()).copied().collect()),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::ConvexPolyhedron => co.shape().as_convex_polyhedron().map(|p| {
|
||||
// TODO: avoid the `.to_trimesh()`.
|
||||
p.to_trimesh()
|
||||
.1
|
||||
.iter()
|
||||
.flat_map(|p| p.iter())
|
||||
.copied()
|
||||
.collect()
|
||||
}),
|
||||
#[cfg(feature = "dim3")]
|
||||
ShapeType::RoundConvexPolyhedron => co.shape().as_round_convex_polyhedron().map(|p| {
|
||||
// TODO: avoid the `.to_trimesh()`.
|
||||
p.inner_shape
|
||||
.to_trimesh()
|
||||
.1
|
||||
.iter()
|
||||
.flat_map(|p| p.iter())
|
||||
.copied()
|
||||
.collect()
|
||||
}),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coTriMeshFlags(&self, handle: FlatHandle) -> Option<u32> {
|
||||
self.map(handle, |co| {
|
||||
co.shape().as_trimesh().map(|tri| tri.flags().bits() as u32)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn coHeightFieldFlags(&self, handle: FlatHandle) -> Option<u32> {
|
||||
self.map(handle, |co| {
|
||||
co.shape()
|
||||
.as_heightfield()
|
||||
.map(|hf| hf.flags().bits() as u32)
|
||||
})
|
||||
}
|
||||
|
||||
/// The height of this heightfield if it is one.
|
||||
pub fn coHeightfieldHeights(&self, handle: FlatHandle) -> Option<Vec<f32>> {
|
||||
self.map(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::HeightField => co
|
||||
.shape()
|
||||
.as_heightfield()
|
||||
.map(|h| h.heights().as_slice().to_vec()),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// The scaling factor applied of this heightfield if it is one.
|
||||
pub fn coHeightfieldScale(&self, handle: FlatHandle) -> Option<RawVector> {
|
||||
self.map(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::HeightField => co.shape().as_heightfield().map(|h| RawVector(*h.scale())),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// The number of rows on this heightfield's height matrix, if it is one.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn coHeightfieldNRows(&self, handle: FlatHandle) -> Option<usize> {
|
||||
self.map(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::HeightField => co.shape().as_heightfield().map(|h| h.nrows()),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// The number of columns on this heightfield's height matrix, if it is one.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn coHeightfieldNCols(&self, handle: FlatHandle) -> Option<usize> {
|
||||
self.map(handle, |co| match co.shape().shape_type() {
|
||||
ShapeType::HeightField => co.shape().as_heightfield().map(|h| h.ncols()),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// The unique integer identifier of the collider this collider is attached to.
|
||||
pub fn coParent(&self, handle: FlatHandle) -> Option<FlatHandle> {
|
||||
self.map(handle, |co| co.parent().map(|p| utils::flat_handle(p.0)))
|
||||
}
|
||||
|
||||
pub fn coSetEnabled(&mut self, handle: FlatHandle, enabled: bool) {
|
||||
self.map_mut(handle, |co| co.set_enabled(enabled))
|
||||
}
|
||||
|
||||
pub fn coIsEnabled(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |co| co.is_enabled())
|
||||
}
|
||||
|
||||
pub fn coSetContactSkin(&mut self, handle: FlatHandle, contact_skin: f32) {
|
||||
self.map_mut(handle, |co| co.set_contact_skin(contact_skin))
|
||||
}
|
||||
|
||||
pub fn coContactSkin(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |co| co.contact_skin())
|
||||
}
|
||||
|
||||
/// The friction coefficient of this collider.
|
||||
pub fn coFriction(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |co| co.material().friction)
|
||||
}
|
||||
/// The restitution coefficient of this collider.
|
||||
pub fn coRestitution(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |co| co.material().restitution)
|
||||
}
|
||||
|
||||
/// The density of this collider.
|
||||
pub fn coDensity(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |co| co.density())
|
||||
}
|
||||
|
||||
/// The mass of this collider.
|
||||
pub fn coMass(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |co| co.mass())
|
||||
}
|
||||
|
||||
/// The volume of this collider.
|
||||
pub fn coVolume(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |co| co.volume())
|
||||
}
|
||||
|
||||
/// The collision groups of this collider.
|
||||
pub fn coCollisionGroups(&self, handle: FlatHandle) -> u32 {
|
||||
self.map(handle, |co| {
|
||||
super::pack_interaction_groups(co.collision_groups())
|
||||
})
|
||||
}
|
||||
|
||||
/// The solver groups of this collider.
|
||||
pub fn coSolverGroups(&self, handle: FlatHandle) -> u32 {
|
||||
self.map(handle, |co| {
|
||||
super::pack_interaction_groups(co.solver_groups())
|
||||
})
|
||||
}
|
||||
|
||||
/// The physics hooks enabled for this collider.
|
||||
pub fn coActiveHooks(&self, handle: FlatHandle) -> u32 {
|
||||
self.map(handle, |co| co.active_hooks().bits())
|
||||
}
|
||||
|
||||
/// The collision types enabled for this collider.
|
||||
pub fn coActiveCollisionTypes(&self, handle: FlatHandle) -> u16 {
|
||||
self.map(handle, |co| co.active_collision_types().bits())
|
||||
}
|
||||
|
||||
/// The events enabled for this collider.
|
||||
pub fn coActiveEvents(&self, handle: FlatHandle) -> u32 {
|
||||
self.map(handle, |co| co.active_events().bits())
|
||||
}
|
||||
|
||||
/// The total force magnitude beyond which a contact force event can be emitted.
|
||||
pub fn coContactForceEventThreshold(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |co| co.contact_force_event_threshold())
|
||||
}
|
||||
|
||||
pub fn coContainsPoint(&self, handle: FlatHandle, point: &RawVector) -> bool {
|
||||
self.map(handle, |co| {
|
||||
co.shared_shape()
|
||||
.containsPoint(co.position(), &point.0.into())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coCastShape(
|
||||
&self,
|
||||
handle: FlatHandle,
|
||||
colliderVel: &RawVector,
|
||||
shape2: &RawShape,
|
||||
shape2Pos: &RawVector,
|
||||
shape2Rot: &RawRotation,
|
||||
shape2Vel: &RawVector,
|
||||
target_distance: f32,
|
||||
maxToi: f32,
|
||||
stop_at_penetration: bool,
|
||||
) -> Option<RawShapeCastHit> {
|
||||
let pos2 = Isometry::from_parts(shape2Pos.0.into(), shape2Rot.0);
|
||||
|
||||
self.map(handle, |co| {
|
||||
let pos1 = co.position();
|
||||
co.shared_shape().castShape(
|
||||
pos1,
|
||||
&colliderVel.0.into(),
|
||||
&*shape2.0,
|
||||
&pos2,
|
||||
&shape2Vel.0.into(),
|
||||
target_distance,
|
||||
maxToi,
|
||||
stop_at_penetration,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coCastCollider(
|
||||
&self,
|
||||
handle: FlatHandle,
|
||||
collider1Vel: &RawVector,
|
||||
collider2handle: FlatHandle,
|
||||
collider2Vel: &RawVector,
|
||||
target_distance: f32,
|
||||
max_toi: f32,
|
||||
stop_at_penetration: bool,
|
||||
) -> Option<RawColliderShapeCastHit> {
|
||||
let handle2 = utils::collider_handle(collider2handle);
|
||||
let co2 = self
|
||||
.0
|
||||
.get(handle2)
|
||||
.expect("Invalid Collider reference. It may have been removed from the physics World.");
|
||||
|
||||
self.map(handle, |co| {
|
||||
query::cast_shapes(
|
||||
co.position(),
|
||||
&collider1Vel.0,
|
||||
co.shape(),
|
||||
co2.position(),
|
||||
&collider2Vel.0,
|
||||
co2.shape(),
|
||||
ShapeCastOptions {
|
||||
max_time_of_impact: max_toi,
|
||||
stop_at_penetration,
|
||||
target_distance,
|
||||
compute_impact_geometry_on_penetration: true,
|
||||
},
|
||||
)
|
||||
.unwrap_or(None)
|
||||
.map_or(None, |hit| {
|
||||
Some(RawColliderShapeCastHit {
|
||||
handle: handle2,
|
||||
hit,
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coIntersectsShape(
|
||||
&self,
|
||||
handle: FlatHandle,
|
||||
shape2: &RawShape,
|
||||
shapePos2: &RawVector,
|
||||
shapeRot2: &RawRotation,
|
||||
) -> bool {
|
||||
let pos2 = Isometry::from_parts(shapePos2.0.into(), shapeRot2.0);
|
||||
|
||||
self.map(handle, |co| {
|
||||
co.shared_shape()
|
||||
.intersectsShape(co.position(), &*shape2.0, &pos2)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coContactShape(
|
||||
&self,
|
||||
handle: FlatHandle,
|
||||
shape2: &RawShape,
|
||||
shapePos2: &RawVector,
|
||||
shapeRot2: &RawRotation,
|
||||
prediction: f32,
|
||||
) -> Option<RawShapeContact> {
|
||||
let pos2 = Isometry::from_parts(shapePos2.0.into(), shapeRot2.0);
|
||||
|
||||
self.map(handle, |co| {
|
||||
co.shared_shape()
|
||||
.contactShape(co.position(), &*shape2.0, &pos2, prediction)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coContactCollider(
|
||||
&self,
|
||||
handle: FlatHandle,
|
||||
collider2handle: FlatHandle,
|
||||
prediction: f32,
|
||||
) -> Option<RawShapeContact> {
|
||||
let co2 = self
|
||||
.0
|
||||
.get(utils::collider_handle(collider2handle))
|
||||
.expect("Invalid Collider reference. It may have been removed from the physics World.");
|
||||
|
||||
self.map(handle, |co| {
|
||||
query::contact(
|
||||
co.position(),
|
||||
co.shape(),
|
||||
&co2.position(),
|
||||
co2.shape(),
|
||||
prediction,
|
||||
)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|contact| RawShapeContact { contact })
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coProjectPoint(
|
||||
&self,
|
||||
handle: FlatHandle,
|
||||
point: &RawVector,
|
||||
solid: bool,
|
||||
) -> RawPointProjection {
|
||||
self.map(handle, |co| {
|
||||
co.shared_shape()
|
||||
.projectPoint(co.position(), &point.0.into(), solid)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coIntersectsRay(
|
||||
&self,
|
||||
handle: FlatHandle,
|
||||
rayOrig: &RawVector,
|
||||
rayDir: &RawVector,
|
||||
maxToi: f32,
|
||||
) -> bool {
|
||||
self.map(handle, |co| {
|
||||
co.shared_shape().intersectsRay(
|
||||
co.position(),
|
||||
rayOrig.0.into(),
|
||||
rayDir.0.into(),
|
||||
maxToi,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coCastRay(
|
||||
&self,
|
||||
handle: FlatHandle,
|
||||
rayOrig: &RawVector,
|
||||
rayDir: &RawVector,
|
||||
maxToi: f32,
|
||||
solid: bool,
|
||||
) -> f32 {
|
||||
self.map(handle, |co| {
|
||||
co.shared_shape().castRay(
|
||||
co.position(),
|
||||
rayOrig.0.into(),
|
||||
rayDir.0.into(),
|
||||
maxToi,
|
||||
solid,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coCastRayAndGetNormal(
|
||||
&self,
|
||||
handle: FlatHandle,
|
||||
rayOrig: &RawVector,
|
||||
rayDir: &RawVector,
|
||||
maxToi: f32,
|
||||
solid: bool,
|
||||
) -> Option<RawRayIntersection> {
|
||||
self.map(handle, |co| {
|
||||
co.shared_shape().castRayAndGetNormal(
|
||||
co.position(),
|
||||
rayOrig.0.into(),
|
||||
rayDir.0.into(),
|
||||
maxToi,
|
||||
solid,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coSetSensor(&mut self, handle: FlatHandle, is_sensor: bool) {
|
||||
self.map_mut(handle, |co| co.set_sensor(is_sensor))
|
||||
}
|
||||
|
||||
pub fn coSetRestitution(&mut self, handle: FlatHandle, restitution: f32) {
|
||||
self.map_mut(handle, |co| co.set_restitution(restitution))
|
||||
}
|
||||
|
||||
pub fn coSetFriction(&mut self, handle: FlatHandle, friction: f32) {
|
||||
self.map_mut(handle, |co| co.set_friction(friction))
|
||||
}
|
||||
|
||||
pub fn coFrictionCombineRule(&self, handle: FlatHandle) -> u32 {
|
||||
self.map(handle, |co| co.friction_combine_rule() as u32)
|
||||
}
|
||||
|
||||
pub fn coSetFrictionCombineRule(&mut self, handle: FlatHandle, rule: u32) {
|
||||
let rule = super::combine_rule_from_u32(rule);
|
||||
self.map_mut(handle, |co| co.set_friction_combine_rule(rule))
|
||||
}
|
||||
|
||||
pub fn coRestitutionCombineRule(&self, handle: FlatHandle) -> u32 {
|
||||
self.map(handle, |co| co.restitution_combine_rule() as u32)
|
||||
}
|
||||
|
||||
pub fn coSetRestitutionCombineRule(&mut self, handle: FlatHandle, rule: u32) {
|
||||
let rule = super::combine_rule_from_u32(rule);
|
||||
self.map_mut(handle, |co| co.set_restitution_combine_rule(rule))
|
||||
}
|
||||
|
||||
pub fn coSetCollisionGroups(&mut self, handle: FlatHandle, groups: u32) {
|
||||
let groups = super::unpack_interaction_groups(groups);
|
||||
self.map_mut(handle, |co| co.set_collision_groups(groups))
|
||||
}
|
||||
|
||||
pub fn coSetSolverGroups(&mut self, handle: FlatHandle, groups: u32) {
|
||||
let groups = super::unpack_interaction_groups(groups);
|
||||
self.map_mut(handle, |co| co.set_solver_groups(groups))
|
||||
}
|
||||
|
||||
pub fn coSetActiveHooks(&mut self, handle: FlatHandle, hooks: u32) {
|
||||
let hooks = ActiveHooks::from_bits(hooks).unwrap_or(ActiveHooks::empty());
|
||||
self.map_mut(handle, |co| co.set_active_hooks(hooks));
|
||||
}
|
||||
|
||||
pub fn coSetActiveEvents(&mut self, handle: FlatHandle, events: u32) {
|
||||
let events = ActiveEvents::from_bits(events).unwrap_or(ActiveEvents::empty());
|
||||
self.map_mut(handle, |co| co.set_active_events(events))
|
||||
}
|
||||
|
||||
pub fn coSetActiveCollisionTypes(&mut self, handle: FlatHandle, types: u16) {
|
||||
let types = ActiveCollisionTypes::from_bits(types).unwrap_or(ActiveCollisionTypes::empty());
|
||||
self.map_mut(handle, |co| co.set_active_collision_types(types));
|
||||
}
|
||||
|
||||
pub fn coSetShape(&mut self, handle: FlatHandle, shape: &RawShape) {
|
||||
self.map_mut(handle, |co| co.set_shape(shape.0.clone()));
|
||||
}
|
||||
|
||||
pub fn coSetContactForceEventThreshold(&mut self, handle: FlatHandle, threshold: f32) {
|
||||
self.map_mut(handle, |co| co.set_contact_force_event_threshold(threshold))
|
||||
}
|
||||
|
||||
pub fn coSetDensity(&mut self, handle: FlatHandle, density: f32) {
|
||||
self.map_mut(handle, |co| co.set_density(density))
|
||||
}
|
||||
|
||||
pub fn coSetMass(&mut self, handle: FlatHandle, mass: f32) {
|
||||
self.map_mut(handle, |co| co.set_mass(mass))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn coSetMassProperties(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
mass: f32,
|
||||
centerOfMass: &RawVector,
|
||||
principalAngularInertia: &RawVector,
|
||||
angularInertiaFrame: &RawRotation,
|
||||
) {
|
||||
self.map_mut(handle, |co| {
|
||||
let mprops = MassProperties::with_principal_inertia_frame(
|
||||
centerOfMass.0.into(),
|
||||
mass,
|
||||
principalAngularInertia.0,
|
||||
angularInertiaFrame.0,
|
||||
);
|
||||
|
||||
co.set_mass_properties(mprops)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn coSetMassProperties(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
mass: f32,
|
||||
centerOfMass: &RawVector,
|
||||
principalAngularInertia: f32,
|
||||
) {
|
||||
self.map_mut(handle, |co| {
|
||||
let props = MassProperties::new(centerOfMass.0.into(), mass, principalAngularInertia);
|
||||
co.set_mass_properties(props)
|
||||
})
|
||||
}
|
||||
}
|
||||
293
thirdparty/rapier.js/src/geometry/collider_set.rs
vendored
Normal file
293
thirdparty/rapier.js/src/geometry/collider_set.rs
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
use crate::dynamics::{RawIslandManager, RawRigidBodySet};
|
||||
use crate::geometry::RawShape;
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::prelude::*;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// NOTE: this MUST match the same enum on the TS side.
|
||||
enum MassPropsMode {
|
||||
Density = 0,
|
||||
Mass,
|
||||
MassProps,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawColliderSet(pub(crate) ColliderSet);
|
||||
|
||||
impl RawColliderSet {
|
||||
pub(crate) fn map<T>(&self, handle: FlatHandle, f: impl FnOnce(&Collider) -> T) -> T {
|
||||
let collider = self
|
||||
.0
|
||||
.get(utils::collider_handle(handle))
|
||||
.expect("Invalid Collider reference. It may have been removed from the physics World.");
|
||||
f(collider)
|
||||
}
|
||||
|
||||
pub(crate) fn map_mut<T>(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
f: impl FnOnce(&mut Collider) -> T,
|
||||
) -> T {
|
||||
let collider = self
|
||||
.0
|
||||
.get_mut(utils::collider_handle(handle))
|
||||
.expect("Invalid Collider reference. It may have been removed from the physics World.");
|
||||
f(collider)
|
||||
}
|
||||
|
||||
pub(crate) fn map_pair_mut<T>(
|
||||
&mut self,
|
||||
handle1: FlatHandle,
|
||||
handle2: FlatHandle,
|
||||
f: impl FnOnce(Option<&mut Collider>, Option<&mut Collider>) -> T,
|
||||
) -> T {
|
||||
let (collider1, collider2) = self.0.get_pair_mut(
|
||||
utils::collider_handle(handle1),
|
||||
utils::collider_handle(handle2),
|
||||
);
|
||||
f(collider1, collider2)
|
||||
}
|
||||
}
|
||||
|
||||
impl RawColliderSet {
|
||||
// This is a workaround because wasm-bindgen doesn't support the `cfg(feature = ...)`
|
||||
// for the method arguments.
|
||||
pub fn do_create_collider(
|
||||
&mut self,
|
||||
enabled: bool,
|
||||
shape: &RawShape,
|
||||
translation: &RawVector,
|
||||
rotation: &RawRotation,
|
||||
massPropsMode: u32,
|
||||
mass: f32,
|
||||
centerOfMass: &RawVector,
|
||||
#[cfg(feature = "dim2")] principalAngularInertia: f32,
|
||||
#[cfg(feature = "dim3")] principalAngularInertia: &RawVector,
|
||||
#[cfg(feature = "dim3")] angularInertiaFrame: &RawRotation,
|
||||
density: f32,
|
||||
friction: f32,
|
||||
restitution: f32,
|
||||
frictionCombineRule: u32,
|
||||
restitutionCombineRule: u32,
|
||||
isSensor: bool,
|
||||
collisionGroups: u32,
|
||||
solverGroups: u32,
|
||||
activeCollisionTypes: u16,
|
||||
activeHooks: u32,
|
||||
activeEvents: u32,
|
||||
contactForceEventThreshold: f32,
|
||||
contactSkin: f32,
|
||||
hasParent: bool,
|
||||
parent: FlatHandle,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
) -> Option<FlatHandle> {
|
||||
let pos = Isometry::from_parts(translation.0.into(), rotation.0);
|
||||
let mut builder = ColliderBuilder::new(shape.0.clone())
|
||||
.enabled(enabled)
|
||||
.position(pos)
|
||||
.friction(friction)
|
||||
.restitution(restitution)
|
||||
.collision_groups(super::unpack_interaction_groups(collisionGroups))
|
||||
.solver_groups(super::unpack_interaction_groups(solverGroups))
|
||||
.active_hooks(ActiveHooks::from_bits(activeHooks).unwrap_or(ActiveHooks::empty()))
|
||||
.active_events(ActiveEvents::from_bits(activeEvents).unwrap_or(ActiveEvents::empty()))
|
||||
.active_collision_types(
|
||||
ActiveCollisionTypes::from_bits(activeCollisionTypes)
|
||||
.unwrap_or(ActiveCollisionTypes::empty()),
|
||||
)
|
||||
.sensor(isSensor)
|
||||
.friction_combine_rule(super::combine_rule_from_u32(frictionCombineRule))
|
||||
.restitution_combine_rule(super::combine_rule_from_u32(restitutionCombineRule))
|
||||
.contact_force_event_threshold(contactForceEventThreshold)
|
||||
.contact_skin(contactSkin);
|
||||
|
||||
if massPropsMode == MassPropsMode::MassProps as u32 {
|
||||
#[cfg(feature = "dim2")]
|
||||
let mprops = MassProperties::new(centerOfMass.0.into(), mass, principalAngularInertia);
|
||||
#[cfg(feature = "dim3")]
|
||||
let mprops = MassProperties::with_principal_inertia_frame(
|
||||
centerOfMass.0.into(),
|
||||
mass,
|
||||
principalAngularInertia.0,
|
||||
angularInertiaFrame.0,
|
||||
);
|
||||
builder = builder.mass_properties(mprops);
|
||||
} else if massPropsMode == MassPropsMode::Density as u32 {
|
||||
builder = builder.density(density);
|
||||
} else {
|
||||
assert_eq!(massPropsMode, MassPropsMode::Mass as u32);
|
||||
builder = builder.mass(mass);
|
||||
};
|
||||
|
||||
let collider = builder.build();
|
||||
|
||||
if hasParent {
|
||||
Some(utils::flat_handle(
|
||||
self.0
|
||||
.insert_with_parent(collider, utils::body_handle(parent), &mut bodies.0)
|
||||
.0,
|
||||
))
|
||||
} else {
|
||||
Some(utils::flat_handle(self.0.insert(collider).0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawColliderSet {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawColliderSet(ColliderSet::new())
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
pub fn contains(&self, handle: FlatHandle) -> bool {
|
||||
self.0.get(utils::collider_handle(handle)).is_some()
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn createCollider(
|
||||
&mut self,
|
||||
enabled: bool,
|
||||
shape: &RawShape,
|
||||
translation: &RawVector,
|
||||
rotation: &RawRotation,
|
||||
massPropsMode: u32,
|
||||
mass: f32,
|
||||
centerOfMass: &RawVector,
|
||||
principalAngularInertia: f32,
|
||||
density: f32,
|
||||
friction: f32,
|
||||
restitution: f32,
|
||||
frictionCombineRule: u32,
|
||||
restitutionCombineRule: u32,
|
||||
isSensor: bool,
|
||||
collisionGroups: u32,
|
||||
solverGroups: u32,
|
||||
activeCollisionTypes: u16,
|
||||
activeHooks: u32,
|
||||
activeEvents: u32,
|
||||
contactForceEventThreshold: f32,
|
||||
contactSkin: f32,
|
||||
hasParent: bool,
|
||||
parent: FlatHandle,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
) -> Option<FlatHandle> {
|
||||
self.do_create_collider(
|
||||
enabled,
|
||||
shape,
|
||||
translation,
|
||||
rotation,
|
||||
massPropsMode,
|
||||
mass,
|
||||
centerOfMass,
|
||||
principalAngularInertia,
|
||||
density,
|
||||
friction,
|
||||
restitution,
|
||||
frictionCombineRule,
|
||||
restitutionCombineRule,
|
||||
isSensor,
|
||||
collisionGroups,
|
||||
solverGroups,
|
||||
activeCollisionTypes,
|
||||
activeHooks,
|
||||
activeEvents,
|
||||
contactForceEventThreshold,
|
||||
contactSkin,
|
||||
hasParent,
|
||||
parent,
|
||||
bodies,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn createCollider(
|
||||
&mut self,
|
||||
enabled: bool,
|
||||
shape: &RawShape,
|
||||
translation: &RawVector,
|
||||
rotation: &RawRotation,
|
||||
massPropsMode: u32,
|
||||
mass: f32,
|
||||
centerOfMass: &RawVector,
|
||||
principalAngularInertia: &RawVector,
|
||||
angularInertiaFrame: &RawRotation,
|
||||
density: f32,
|
||||
friction: f32,
|
||||
restitution: f32,
|
||||
frictionCombineRule: u32,
|
||||
restitutionCombineRule: u32,
|
||||
isSensor: bool,
|
||||
collisionGroups: u32,
|
||||
solverGroups: u32,
|
||||
activeCollisionTypes: u16,
|
||||
activeHooks: u32,
|
||||
activeEvents: u32,
|
||||
contactForceEventThreshold: f32,
|
||||
contactSkin: f32,
|
||||
hasParent: bool,
|
||||
parent: FlatHandle,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
) -> Option<FlatHandle> {
|
||||
self.do_create_collider(
|
||||
enabled,
|
||||
shape,
|
||||
translation,
|
||||
rotation,
|
||||
massPropsMode,
|
||||
mass,
|
||||
centerOfMass,
|
||||
principalAngularInertia,
|
||||
angularInertiaFrame,
|
||||
density,
|
||||
friction,
|
||||
restitution,
|
||||
frictionCombineRule,
|
||||
restitutionCombineRule,
|
||||
isSensor,
|
||||
collisionGroups,
|
||||
solverGroups,
|
||||
activeCollisionTypes,
|
||||
activeHooks,
|
||||
activeEvents,
|
||||
contactForceEventThreshold,
|
||||
contactSkin,
|
||||
hasParent,
|
||||
parent,
|
||||
bodies,
|
||||
)
|
||||
}
|
||||
|
||||
/// Removes a collider from this set and wake-up the rigid-body it is attached to.
|
||||
pub fn remove(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
islands: &mut RawIslandManager,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
wakeUp: bool,
|
||||
) {
|
||||
let handle = utils::collider_handle(handle);
|
||||
self.0.remove(handle, &mut islands.0, &mut bodies.0, wakeUp);
|
||||
}
|
||||
|
||||
/// Checks if a collider with the given integer handle exists.
|
||||
pub fn isHandleValid(&self, handle: FlatHandle) -> bool {
|
||||
self.0.get(utils::collider_handle(handle)).is_some()
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each collider managed by this collider set.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each collider managed by this collider set. Called as `f(handle)`.
|
||||
pub fn forEachColliderHandle(&self, f: &js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
for (handle, _) in self.0.iter() {
|
||||
let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
31
thirdparty/rapier.js/src/geometry/contact.rs
vendored
Normal file
31
thirdparty/rapier.js/src/geometry/contact.rs
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
use crate::math::RawVector;
|
||||
use rapier::parry::query;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawShapeContact {
|
||||
pub(crate) contact: query::Contact,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawShapeContact {
|
||||
pub fn distance(&self) -> f32 {
|
||||
self.contact.dist
|
||||
}
|
||||
|
||||
pub fn point1(&self) -> RawVector {
|
||||
self.contact.point1.coords.into()
|
||||
}
|
||||
|
||||
pub fn point2(&self) -> RawVector {
|
||||
self.contact.point2.coords.into()
|
||||
}
|
||||
|
||||
pub fn normal1(&self) -> RawVector {
|
||||
self.contact.normal1.into_inner().into()
|
||||
}
|
||||
|
||||
pub fn normal2(&self) -> RawVector {
|
||||
self.contact.normal2.into_inner().into()
|
||||
}
|
||||
}
|
||||
47
thirdparty/rapier.js/src/geometry/feature.rs
vendored
Normal file
47
thirdparty/rapier.js/src/geometry/feature.rs
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
use rapier::prelude::FeatureId;
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
#[wasm_bindgen]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum RawFeatureType {
|
||||
Vertex,
|
||||
Face,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
#[wasm_bindgen]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum RawFeatureType {
|
||||
Vertex,
|
||||
Edge,
|
||||
Face,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
pub trait IntoTypeValue {
|
||||
fn into_type(self) -> RawFeatureType;
|
||||
fn into_value(self) -> Option<u32>;
|
||||
}
|
||||
|
||||
impl IntoTypeValue for FeatureId {
|
||||
fn into_type(self) -> RawFeatureType {
|
||||
match self {
|
||||
FeatureId::Vertex(_) => RawFeatureType::Vertex,
|
||||
#[cfg(feature = "dim3")]
|
||||
FeatureId::Edge(_) => RawFeatureType::Edge,
|
||||
FeatureId::Face(_) => RawFeatureType::Face,
|
||||
_ => RawFeatureType::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_value(self) -> Option<u32> {
|
||||
match self {
|
||||
FeatureId::Vertex(id) | FeatureId::Face(id) => Some(id),
|
||||
#[cfg(feature = "dim3")]
|
||||
FeatureId::Edge(id) => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
49
thirdparty/rapier.js/src/geometry/mod.rs
vendored
Normal file
49
thirdparty/rapier.js/src/geometry/mod.rs
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
//! Structures related to geometry: colliders, shapes, etc.
|
||||
|
||||
pub use self::broad_phase::*;
|
||||
pub use self::collider_set::*;
|
||||
pub use self::contact::*;
|
||||
pub use self::feature::*;
|
||||
pub use self::narrow_phase::*;
|
||||
pub use self::point::*;
|
||||
pub use self::ray::*;
|
||||
pub use self::shape::*;
|
||||
pub use self::toi::*;
|
||||
|
||||
mod broad_phase;
|
||||
mod collider;
|
||||
mod collider_set;
|
||||
mod contact;
|
||||
mod feature;
|
||||
mod narrow_phase;
|
||||
mod point;
|
||||
mod ray;
|
||||
mod shape;
|
||||
mod toi;
|
||||
|
||||
use rapier::dynamics::CoefficientCombineRule;
|
||||
use rapier::geometry::InteractionGroups;
|
||||
use rapier::prelude::Group;
|
||||
|
||||
pub const fn unpack_interaction_groups(memberships_filter: u32) -> InteractionGroups {
|
||||
InteractionGroups::new(
|
||||
Group::from_bits_retain((memberships_filter >> 16) as u32),
|
||||
Group::from_bits_retain((memberships_filter & 0x0000_ffff) as u32),
|
||||
)
|
||||
}
|
||||
|
||||
pub const fn pack_interaction_groups(groups: InteractionGroups) -> u32 {
|
||||
(groups.memberships.bits() << 16) | groups.filter.bits()
|
||||
}
|
||||
|
||||
pub const fn combine_rule_from_u32(rule: u32) -> CoefficientCombineRule {
|
||||
if rule == CoefficientCombineRule::Average as u32 {
|
||||
CoefficientCombineRule::Average
|
||||
} else if rule == CoefficientCombineRule::Min as u32 {
|
||||
CoefficientCombineRule::Min
|
||||
} else if rule == CoefficientCombineRule::Multiply as u32 {
|
||||
CoefficientCombineRule::Multiply
|
||||
} else {
|
||||
CoefficientCombineRule::Max
|
||||
}
|
||||
}
|
||||
217
thirdparty/rapier.js/src/geometry/narrow_phase.rs
vendored
Normal file
217
thirdparty/rapier.js/src/geometry/narrow_phase.rs
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
use crate::math::RawVector;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::geometry::{ContactManifold, ContactPair, NarrowPhase};
|
||||
use rapier::math::Real;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawNarrowPhase(pub(crate) NarrowPhase);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawNarrowPhase {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawNarrowPhase(NarrowPhase::new())
|
||||
}
|
||||
|
||||
pub fn contact_pairs_with(&self, handle1: FlatHandle, f: js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
let handle1 = utils::collider_handle(handle1);
|
||||
for pair in self.0.contact_pairs_with(handle1) {
|
||||
let handle2 = if pair.collider1 == handle1 {
|
||||
utils::flat_handle(pair.collider2.0)
|
||||
} else {
|
||||
utils::flat_handle(pair.collider1.0)
|
||||
};
|
||||
|
||||
let _ = f.call1(&this, &JsValue::from(handle2));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contact_pair(&self, handle1: FlatHandle, handle2: FlatHandle) -> Option<RawContactPair> {
|
||||
let handle1 = utils::collider_handle(handle1);
|
||||
let handle2 = utils::collider_handle(handle2);
|
||||
self.0
|
||||
.contact_pair(handle1, handle2)
|
||||
.map(|p| RawContactPair(p as *const ContactPair))
|
||||
}
|
||||
|
||||
pub fn intersection_pairs_with(&self, handle1: FlatHandle, f: js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
let handle1 = utils::collider_handle(handle1);
|
||||
for (h1, h2, inter) in self.0.intersection_pairs_with(handle1) {
|
||||
if inter {
|
||||
let handle2 = if h1 == handle1 {
|
||||
utils::flat_handle(h2.0)
|
||||
} else {
|
||||
utils::flat_handle(h1.0)
|
||||
};
|
||||
|
||||
let _ = f.call1(&this, &JsValue::from(handle2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intersection_pair(&self, handle1: FlatHandle, handle2: FlatHandle) -> bool {
|
||||
let handle1 = utils::collider_handle(handle1);
|
||||
let handle2 = utils::collider_handle(handle2);
|
||||
self.0.intersection_pair(handle1, handle2) == Some(true)
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawContactPair(*const ContactPair);
|
||||
#[wasm_bindgen]
|
||||
pub struct RawContactManifold(*const ContactManifold);
|
||||
|
||||
// SAFETY: the use of a raw pointer is very unsafe.
|
||||
// We need this because wasm-bindgen doesn't support
|
||||
// lifetimes. So for the moment, we have to make sure
|
||||
// that our TypeScript wrapper properly free the pair
|
||||
// before the user has a chance to invalidate this pointer.
|
||||
#[wasm_bindgen]
|
||||
impl RawContactPair {
|
||||
pub fn collider1(&self) -> FlatHandle {
|
||||
unsafe { utils::flat_handle((*self.0).collider1.0) }
|
||||
}
|
||||
|
||||
pub fn collider2(&self) -> FlatHandle {
|
||||
unsafe { utils::flat_handle((*self.0).collider2.0) }
|
||||
}
|
||||
|
||||
pub fn numContactManifolds(&self) -> usize {
|
||||
unsafe { (*self.0).manifolds.len() }
|
||||
}
|
||||
pub fn contactManifold(&self, i: usize) -> Option<RawContactManifold> {
|
||||
unsafe {
|
||||
(&(*self.0).manifolds)
|
||||
.get(i)
|
||||
.map(|m| RawContactManifold(m as *const ContactManifold))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawContactManifold {
|
||||
pub fn normal(&self) -> RawVector {
|
||||
unsafe { RawVector((*self.0).data.normal) }
|
||||
}
|
||||
|
||||
// pub fn user_data(&self) -> u32 {
|
||||
// unsafe { (*self.0).data.user_data }
|
||||
// }
|
||||
|
||||
pub fn local_n1(&self) -> RawVector {
|
||||
unsafe { (*self.0).local_n1.into() }
|
||||
}
|
||||
|
||||
pub fn local_n2(&self) -> RawVector {
|
||||
unsafe { (*self.0).local_n2.into() }
|
||||
}
|
||||
|
||||
pub fn subshape1(&self) -> u32 {
|
||||
unsafe { (*self.0).subshape1 }
|
||||
}
|
||||
|
||||
pub fn subshape2(&self) -> u32 {
|
||||
unsafe { (*self.0).subshape2 }
|
||||
}
|
||||
|
||||
pub fn num_contacts(&self) -> usize {
|
||||
unsafe { (*self.0).points.len() }
|
||||
}
|
||||
|
||||
pub fn contact_local_p1(&self, i: usize) -> Option<RawVector> {
|
||||
unsafe { (&(*self.0).points).get(i).map(|c| c.local_p1.coords.into()) }
|
||||
}
|
||||
|
||||
pub fn contact_local_p2(&self, i: usize) -> Option<RawVector> {
|
||||
unsafe { (&(*self.0).points).get(i).map(|c| c.local_p2.coords.into()) }
|
||||
}
|
||||
|
||||
pub fn contact_dist(&self, i: usize) -> Real {
|
||||
unsafe { (&(*self.0).points).get(i).map(|c| c.dist).unwrap_or(0.0) }
|
||||
}
|
||||
|
||||
pub fn contact_fid1(&self, i: usize) -> u32 {
|
||||
unsafe { (&(*self.0).points).get(i).map(|c| c.fid1.0).unwrap_or(0) }
|
||||
}
|
||||
|
||||
pub fn contact_fid2(&self, i: usize) -> u32 {
|
||||
unsafe { (&(*self.0).points).get(i).map(|c| c.fid2.0).unwrap_or(0) }
|
||||
}
|
||||
|
||||
pub fn contact_impulse(&self, i: usize) -> Real {
|
||||
unsafe {
|
||||
(&(*self.0).points)
|
||||
.get(i)
|
||||
.map(|c| c.data.impulse)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn contact_tangent_impulse(&self, i: usize) -> Real {
|
||||
unsafe {
|
||||
(&(*self.0).points)
|
||||
.get(i)
|
||||
.map(|c| c.data.tangent_impulse.x)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn contact_tangent_impulse_x(&self, i: usize) -> Real {
|
||||
unsafe {
|
||||
(&(*self.0).points)
|
||||
.get(i)
|
||||
.map(|c| c.data.tangent_impulse.x)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn contact_tangent_impulse_y(&self, i: usize) -> Real {
|
||||
unsafe {
|
||||
(&(*self.0).points)
|
||||
.get(i)
|
||||
.map(|c| c.data.tangent_impulse.y)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_solver_contacts(&self) -> usize {
|
||||
unsafe { (*self.0).data.solver_contacts.len() }
|
||||
}
|
||||
|
||||
pub fn solver_contact_point(&self, i: usize) -> Option<RawVector> {
|
||||
unsafe {
|
||||
(&(*self.0).data)
|
||||
.solver_contacts
|
||||
.get(i)
|
||||
.map(|c| c.point.coords.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn solver_contact_dist(&self, i: usize) -> Real {
|
||||
unsafe {
|
||||
(&(*self.0).data)
|
||||
.solver_contacts
|
||||
.get(i)
|
||||
.map(|c| c.dist)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn solver_contact_friction(&self, i: usize) -> Real {
|
||||
unsafe { (&(*self.0).data).solver_contacts[i].friction }
|
||||
}
|
||||
|
||||
pub fn solver_contact_restitution(&self, i: usize) -> Real {
|
||||
unsafe { (&(*self.0).data).solver_contacts[i].restitution }
|
||||
}
|
||||
|
||||
pub fn solver_contact_tangent_velocity(&self, i: usize) -> RawVector {
|
||||
unsafe { (&(*self.0).data).solver_contacts[i].tangent_velocity.into() }
|
||||
}
|
||||
}
|
||||
53
thirdparty/rapier.js/src/geometry/point.rs
vendored
Normal file
53
thirdparty/rapier.js/src/geometry/point.rs
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
use crate::geometry::feature::IntoTypeValue;
|
||||
use crate::geometry::RawFeatureType;
|
||||
use crate::math::RawVector;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::{
|
||||
geometry::{ColliderHandle, PointProjection},
|
||||
prelude::FeatureId,
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawPointProjection(pub(crate) PointProjection);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawPointProjection {
|
||||
pub fn point(&self) -> RawVector {
|
||||
self.0.point.coords.into()
|
||||
}
|
||||
|
||||
pub fn isInside(&self) -> bool {
|
||||
self.0.is_inside
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawPointColliderProjection {
|
||||
pub(crate) handle: ColliderHandle,
|
||||
pub(crate) proj: PointProjection,
|
||||
pub(crate) feature: FeatureId,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawPointColliderProjection {
|
||||
pub fn colliderHandle(&self) -> FlatHandle {
|
||||
utils::flat_handle(self.handle.0)
|
||||
}
|
||||
|
||||
pub fn point(&self) -> RawVector {
|
||||
self.proj.point.coords.into()
|
||||
}
|
||||
|
||||
pub fn isInside(&self) -> bool {
|
||||
self.proj.is_inside
|
||||
}
|
||||
|
||||
pub fn featureType(&self) -> RawFeatureType {
|
||||
self.feature.into_type()
|
||||
}
|
||||
|
||||
pub fn featureId(&self) -> Option<u32> {
|
||||
self.feature.into_value()
|
||||
}
|
||||
}
|
||||
74
thirdparty/rapier.js/src/geometry/ray.rs
vendored
Normal file
74
thirdparty/rapier.js/src/geometry/ray.rs
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
use crate::geometry::feature::IntoTypeValue;
|
||||
use crate::geometry::RawFeatureType;
|
||||
use crate::math::RawVector;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::geometry::{ColliderHandle, RayIntersection};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawRayIntersection(pub(crate) RayIntersection);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawRayIntersection {
|
||||
pub fn normal(&self) -> RawVector {
|
||||
self.0.normal.into()
|
||||
}
|
||||
|
||||
pub fn time_of_impact(&self) -> f32 {
|
||||
self.0.time_of_impact
|
||||
}
|
||||
|
||||
pub fn featureType(&self) -> RawFeatureType {
|
||||
self.0.feature.into_type()
|
||||
}
|
||||
|
||||
pub fn featureId(&self) -> Option<u32> {
|
||||
self.0.feature.into_value()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawRayColliderIntersection {
|
||||
pub(crate) handle: ColliderHandle,
|
||||
pub(crate) inter: RayIntersection,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawRayColliderIntersection {
|
||||
pub fn colliderHandle(&self) -> FlatHandle {
|
||||
utils::flat_handle(self.handle.0)
|
||||
}
|
||||
|
||||
pub fn normal(&self) -> RawVector {
|
||||
self.inter.normal.into()
|
||||
}
|
||||
|
||||
pub fn time_of_impact(&self) -> f32 {
|
||||
self.inter.time_of_impact
|
||||
}
|
||||
|
||||
pub fn featureType(&self) -> RawFeatureType {
|
||||
self.inter.feature.into_type()
|
||||
}
|
||||
|
||||
pub fn featureId(&self) -> Option<u32> {
|
||||
self.inter.feature.into_value()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawRayColliderHit {
|
||||
pub(crate) handle: ColliderHandle,
|
||||
pub(crate) timeOfImpact: f32,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawRayColliderHit {
|
||||
pub fn colliderHandle(&self) -> FlatHandle {
|
||||
utils::flat_handle(self.handle.0)
|
||||
}
|
||||
|
||||
pub fn timeOfImpact(&self) -> f32 {
|
||||
self.timeOfImpact
|
||||
}
|
||||
}
|
||||
527
thirdparty/rapier.js/src/geometry/shape.rs
vendored
Normal file
527
thirdparty/rapier.js/src/geometry/shape.rs
vendored
Normal file
@@ -0,0 +1,527 @@
|
||||
use crate::geometry::{RawPointProjection, RawRayIntersection, RawShapeCastHit, RawShapeContact};
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
#[cfg(feature = "dim3")]
|
||||
use na::DMatrix;
|
||||
#[cfg(feature = "dim2")]
|
||||
use na::DVector;
|
||||
use na::Unit;
|
||||
use rapier::geometry::{Shape, SharedShape, TriMeshFlags};
|
||||
use rapier::math::{Isometry, Point, Real, Vector, DIM};
|
||||
use rapier::parry::query;
|
||||
use rapier::parry::query::{Ray, ShapeCastOptions};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub trait SharedShapeUtility {
|
||||
fn castShape(
|
||||
&self,
|
||||
shapePos1: &Isometry<Real>,
|
||||
shapeVel1: &Vector<Real>,
|
||||
shape2: &dyn Shape,
|
||||
shapePos2: &Isometry<Real>,
|
||||
shapeVel2: &Vector<Real>,
|
||||
target_distance: f32,
|
||||
maxToi: f32,
|
||||
stop_at_penetration: bool,
|
||||
) -> Option<RawShapeCastHit>;
|
||||
|
||||
fn intersectsShape(
|
||||
&self,
|
||||
shapePos1: &Isometry<Real>,
|
||||
shape2: &dyn Shape,
|
||||
shapePos2: &Isometry<Real>,
|
||||
) -> bool;
|
||||
|
||||
fn contactShape(
|
||||
&self,
|
||||
shapePos1: &Isometry<Real>,
|
||||
shape2: &dyn Shape,
|
||||
shapePos2: &Isometry<Real>,
|
||||
prediction: f32,
|
||||
) -> Option<RawShapeContact>;
|
||||
|
||||
fn containsPoint(&self, shapePos: &Isometry<Real>, point: &Point<Real>) -> bool;
|
||||
|
||||
fn projectPoint(
|
||||
&self,
|
||||
shapePos: &Isometry<Real>,
|
||||
point: &Point<Real>,
|
||||
solid: bool,
|
||||
) -> RawPointProjection;
|
||||
|
||||
fn intersectsRay(
|
||||
&self,
|
||||
shapePos: &Isometry<Real>,
|
||||
rayOrig: Point<Real>,
|
||||
rayDir: Vector<Real>,
|
||||
maxToi: f32,
|
||||
) -> bool;
|
||||
|
||||
fn castRay(
|
||||
&self,
|
||||
shapePos: &Isometry<Real>,
|
||||
rayOrig: Point<Real>,
|
||||
rayDir: Vector<Real>,
|
||||
maxToi: f32,
|
||||
solid: bool,
|
||||
) -> f32;
|
||||
|
||||
fn castRayAndGetNormal(
|
||||
&self,
|
||||
shapePos: &Isometry<Real>,
|
||||
rayOrig: Point<Real>,
|
||||
rayDir: Vector<Real>,
|
||||
maxToi: f32,
|
||||
solid: bool,
|
||||
) -> Option<RawRayIntersection>;
|
||||
}
|
||||
|
||||
// for RawShape & Collider
|
||||
impl SharedShapeUtility for SharedShape {
|
||||
fn castShape(
|
||||
&self,
|
||||
shapePos1: &Isometry<Real>,
|
||||
shapeVel1: &Vector<Real>,
|
||||
shape2: &dyn Shape,
|
||||
shapePos2: &Isometry<Real>,
|
||||
shapeVel2: &Vector<Real>,
|
||||
target_distance: f32,
|
||||
maxToi: f32,
|
||||
stop_at_penetration: bool,
|
||||
) -> Option<RawShapeCastHit> {
|
||||
query::cast_shapes(
|
||||
shapePos1,
|
||||
shapeVel1,
|
||||
&*self.0,
|
||||
shapePos2,
|
||||
&shapeVel2,
|
||||
shape2,
|
||||
ShapeCastOptions {
|
||||
max_time_of_impact: maxToi,
|
||||
target_distance,
|
||||
stop_at_penetration,
|
||||
compute_impact_geometry_on_penetration: true,
|
||||
},
|
||||
)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|hit| RawShapeCastHit { hit })
|
||||
}
|
||||
|
||||
fn intersectsShape(
|
||||
&self,
|
||||
shapePos1: &Isometry<Real>,
|
||||
shape2: &dyn Shape,
|
||||
shapePos2: &Isometry<Real>,
|
||||
) -> bool {
|
||||
query::intersection_test(shapePos1, &*self.0, shapePos2, shape2).unwrap_or(false)
|
||||
}
|
||||
|
||||
fn contactShape(
|
||||
&self,
|
||||
shapePos1: &Isometry<Real>,
|
||||
shape2: &dyn Shape,
|
||||
shapePos2: &Isometry<Real>,
|
||||
prediction: f32,
|
||||
) -> Option<RawShapeContact> {
|
||||
query::contact(shapePos1, &*self.0, shapePos2, shape2, prediction)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|contact| RawShapeContact { contact })
|
||||
}
|
||||
|
||||
fn containsPoint(&self, shapePos: &Isometry<Real>, point: &Point<Real>) -> bool {
|
||||
self.as_ref().contains_point(shapePos, point)
|
||||
}
|
||||
|
||||
fn projectPoint(
|
||||
&self,
|
||||
shapePos: &Isometry<Real>,
|
||||
point: &Point<Real>,
|
||||
solid: bool,
|
||||
) -> RawPointProjection {
|
||||
RawPointProjection(self.as_ref().project_point(shapePos, point, solid))
|
||||
}
|
||||
|
||||
fn intersectsRay(
|
||||
&self,
|
||||
shapePos: &Isometry<Real>,
|
||||
rayOrig: Point<Real>,
|
||||
rayDir: Vector<Real>,
|
||||
maxToi: f32,
|
||||
) -> bool {
|
||||
self.as_ref()
|
||||
.intersects_ray(shapePos, &Ray::new(rayOrig, rayDir), maxToi)
|
||||
}
|
||||
|
||||
fn castRay(
|
||||
&self,
|
||||
shapePos: &Isometry<Real>,
|
||||
rayOrig: Point<Real>,
|
||||
rayDir: Vector<Real>,
|
||||
maxToi: f32,
|
||||
solid: bool,
|
||||
) -> f32 {
|
||||
self.as_ref()
|
||||
.cast_ray(shapePos, &Ray::new(rayOrig, rayDir), maxToi, solid)
|
||||
.unwrap_or(-1.0) // Negative value = no hit.
|
||||
}
|
||||
|
||||
fn castRayAndGetNormal(
|
||||
&self,
|
||||
shapePos: &Isometry<Real>,
|
||||
rayOrig: Point<Real>,
|
||||
rayDir: Vector<Real>,
|
||||
maxToi: f32,
|
||||
solid: bool,
|
||||
) -> Option<RawRayIntersection> {
|
||||
self.as_ref()
|
||||
.cast_ray_and_get_normal(shapePos, &Ray::new(rayOrig, rayDir), maxToi, solid)
|
||||
.map(|inter| RawRayIntersection(inter))
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[cfg(feature = "dim2")]
|
||||
pub enum RawShapeType {
|
||||
Ball = 0,
|
||||
Cuboid = 1,
|
||||
Capsule = 2,
|
||||
Segment = 3,
|
||||
Polyline = 4,
|
||||
Triangle = 5,
|
||||
TriMesh = 6,
|
||||
HeightField = 7,
|
||||
Compound = 8,
|
||||
ConvexPolygon = 9,
|
||||
RoundCuboid = 10,
|
||||
RoundTriangle = 11,
|
||||
RoundConvexPolygon = 12,
|
||||
HalfSpace = 13,
|
||||
Voxels = 14,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[cfg(feature = "dim3")]
|
||||
pub enum RawShapeType {
|
||||
Ball = 0,
|
||||
Cuboid = 1,
|
||||
Capsule = 2,
|
||||
Segment = 3,
|
||||
Polyline = 4,
|
||||
Triangle = 5,
|
||||
TriMesh = 6,
|
||||
HeightField = 7,
|
||||
Compound = 8,
|
||||
ConvexPolyhedron = 9,
|
||||
Cylinder = 10,
|
||||
Cone = 11,
|
||||
RoundCuboid = 12,
|
||||
RoundTriangle = 13,
|
||||
RoundCylinder = 14,
|
||||
RoundCone = 15,
|
||||
RoundConvexPolyhedron = 16,
|
||||
HalfSpace = 17,
|
||||
Voxels = 18,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawShape(pub(crate) SharedShape);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawShape {
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn cuboid(hx: f32, hy: f32) -> Self {
|
||||
Self(SharedShape::cuboid(hx, hy))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn cuboid(hx: f32, hy: f32, hz: f32) -> Self {
|
||||
Self(SharedShape::cuboid(hx, hy, hz))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn roundCuboid(hx: f32, hy: f32, borderRadius: f32) -> Self {
|
||||
Self(SharedShape::round_cuboid(hx, hy, borderRadius))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn roundCuboid(hx: f32, hy: f32, hz: f32, borderRadius: f32) -> Self {
|
||||
Self(SharedShape::round_cuboid(hx, hy, hz, borderRadius))
|
||||
}
|
||||
|
||||
pub fn ball(radius: f32) -> Self {
|
||||
Self(SharedShape::ball(radius))
|
||||
}
|
||||
|
||||
pub fn halfspace(normal: &RawVector) -> Self {
|
||||
Self(SharedShape::halfspace(Unit::new_normalize(normal.0)))
|
||||
}
|
||||
|
||||
pub fn capsule(halfHeight: f32, radius: f32) -> Self {
|
||||
let p2 = Point::from(Vector::y() * halfHeight);
|
||||
let p1 = -p2;
|
||||
Self(SharedShape::capsule(p1, p2, radius))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn cylinder(halfHeight: f32, radius: f32) -> Self {
|
||||
Self(SharedShape::cylinder(halfHeight, radius))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn roundCylinder(halfHeight: f32, radius: f32, borderRadius: f32) -> Self {
|
||||
Self(SharedShape::round_cylinder(
|
||||
halfHeight,
|
||||
radius,
|
||||
borderRadius,
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn cone(halfHeight: f32, radius: f32) -> Self {
|
||||
Self(SharedShape::cone(halfHeight, radius))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn roundCone(halfHeight: f32, radius: f32, borderRadius: f32) -> Self {
|
||||
Self(SharedShape::round_cone(halfHeight, radius, borderRadius))
|
||||
}
|
||||
|
||||
pub fn voxels(voxel_size: &RawVector, grid_coords: Vec<i32>) -> Self {
|
||||
let grid_coords: Vec<_> = grid_coords
|
||||
.chunks_exact(DIM)
|
||||
.map(Point::from_slice)
|
||||
.collect();
|
||||
Self(SharedShape::voxels(voxel_size.0, &grid_coords))
|
||||
}
|
||||
|
||||
pub fn voxelsFromPoints(voxel_size: &RawVector, points: Vec<f32>) -> Self {
|
||||
let points: Vec<_> = points.chunks_exact(DIM).map(Point::from_slice).collect();
|
||||
Self(SharedShape::voxels_from_points(voxel_size.0, &points))
|
||||
}
|
||||
|
||||
pub fn polyline(vertices: Vec<f32>, indices: Vec<u32>) -> Self {
|
||||
let vertices = vertices.chunks(DIM).map(|v| Point::from_slice(v)).collect();
|
||||
let indices: Vec<_> = indices.chunks(2).map(|v| [v[0], v[1]]).collect();
|
||||
if indices.is_empty() {
|
||||
Self(SharedShape::polyline(vertices, None))
|
||||
} else {
|
||||
Self(SharedShape::polyline(vertices, Some(indices)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trimesh(vertices: Vec<f32>, indices: Vec<u32>, flags: u32) -> Option<RawShape> {
|
||||
let flags = TriMeshFlags::from_bits(flags as u16).unwrap_or_default();
|
||||
let vertices = vertices.chunks(DIM).map(|v| Point::from_slice(v)).collect();
|
||||
let indices = indices.chunks(3).map(|v| [v[0], v[1], v[2]]).collect();
|
||||
SharedShape::trimesh_with_flags(vertices, indices, flags)
|
||||
.ok()
|
||||
.map(Self)
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn heightfield(heights: Vec<f32>, scale: &RawVector) -> Self {
|
||||
let heights = DVector::from_vec(heights);
|
||||
Self(SharedShape::heightfield(heights, scale.0))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn heightfield(
|
||||
nrows: u32,
|
||||
ncols: u32,
|
||||
heights: Vec<f32>,
|
||||
scale: &RawVector,
|
||||
flags: u32,
|
||||
) -> Self {
|
||||
let flags =
|
||||
rapier::parry::shape::HeightFieldFlags::from_bits(flags as u8).unwrap_or_default();
|
||||
let heights = DMatrix::from_vec(nrows as usize + 1, ncols as usize + 1, heights);
|
||||
Self(SharedShape::heightfield_with_flags(heights, scale.0, flags))
|
||||
}
|
||||
|
||||
pub fn segment(p1: &RawVector, p2: &RawVector) -> Self {
|
||||
Self(SharedShape::segment(p1.0.into(), p2.0.into()))
|
||||
}
|
||||
|
||||
pub fn triangle(p1: &RawVector, p2: &RawVector, p3: &RawVector) -> Self {
|
||||
Self(SharedShape::triangle(p1.0.into(), p2.0.into(), p3.0.into()))
|
||||
}
|
||||
|
||||
pub fn roundTriangle(
|
||||
p1: &RawVector,
|
||||
p2: &RawVector,
|
||||
p3: &RawVector,
|
||||
borderRadius: f32,
|
||||
) -> Self {
|
||||
Self(SharedShape::round_triangle(
|
||||
p1.0.into(),
|
||||
p2.0.into(),
|
||||
p3.0.into(),
|
||||
borderRadius,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn convexHull(points: Vec<f32>) -> Option<RawShape> {
|
||||
let points: Vec<_> = points.chunks(DIM).map(|v| Point::from_slice(v)).collect();
|
||||
SharedShape::convex_hull(&points).map(|s| Self(s))
|
||||
}
|
||||
|
||||
pub fn roundConvexHull(points: Vec<f32>, borderRadius: f32) -> Option<RawShape> {
|
||||
let points: Vec<_> = points.chunks(DIM).map(|v| Point::from_slice(v)).collect();
|
||||
SharedShape::round_convex_hull(&points, borderRadius).map(|s| Self(s))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn convexPolyline(vertices: Vec<f32>) -> Option<RawShape> {
|
||||
let vertices = vertices.chunks(DIM).map(|v| Point::from_slice(v)).collect();
|
||||
SharedShape::convex_polyline(vertices).map(|s| Self(s))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn roundConvexPolyline(vertices: Vec<f32>, borderRadius: f32) -> Option<RawShape> {
|
||||
let vertices = vertices.chunks(DIM).map(|v| Point::from_slice(v)).collect();
|
||||
SharedShape::round_convex_polyline(vertices, borderRadius).map(|s| Self(s))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn convexMesh(vertices: Vec<f32>, indices: Vec<u32>) -> Option<RawShape> {
|
||||
let vertices = vertices.chunks(DIM).map(|v| Point::from_slice(v)).collect();
|
||||
let indices: Vec<_> = indices.chunks(3).map(|v| [v[0], v[1], v[2]]).collect();
|
||||
SharedShape::convex_mesh(vertices, &indices).map(|s| Self(s))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn roundConvexMesh(
|
||||
vertices: Vec<f32>,
|
||||
indices: Vec<u32>,
|
||||
borderRadius: f32,
|
||||
) -> Option<RawShape> {
|
||||
let vertices = vertices.chunks(DIM).map(|v| Point::from_slice(v)).collect();
|
||||
let indices: Vec<_> = indices.chunks(3).map(|v| [v[0], v[1], v[2]]).collect();
|
||||
SharedShape::round_convex_mesh(vertices, &indices, borderRadius).map(|s| Self(s))
|
||||
}
|
||||
|
||||
pub fn castShape(
|
||||
&self,
|
||||
shapePos1: &RawVector,
|
||||
shapeRot1: &RawRotation,
|
||||
shapeVel1: &RawVector,
|
||||
shape2: &RawShape,
|
||||
shapePos2: &RawVector,
|
||||
shapeRot2: &RawRotation,
|
||||
shapeVel2: &RawVector,
|
||||
target_distance: f32,
|
||||
maxToi: f32,
|
||||
stop_at_penetration: bool,
|
||||
) -> Option<RawShapeCastHit> {
|
||||
let pos1 = Isometry::from_parts(shapePos1.0.into(), shapeRot1.0);
|
||||
let pos2 = Isometry::from_parts(shapePos2.0.into(), shapeRot2.0);
|
||||
|
||||
self.0.castShape(
|
||||
&pos1,
|
||||
&shapeVel1.0,
|
||||
&*shape2.0,
|
||||
&pos2,
|
||||
&shapeVel2.0,
|
||||
target_distance,
|
||||
maxToi,
|
||||
stop_at_penetration,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn intersectsShape(
|
||||
&self,
|
||||
shapePos1: &RawVector,
|
||||
shapeRot1: &RawRotation,
|
||||
shape2: &RawShape,
|
||||
shapePos2: &RawVector,
|
||||
shapeRot2: &RawRotation,
|
||||
) -> bool {
|
||||
let pos1 = Isometry::from_parts(shapePos1.0.into(), shapeRot1.0);
|
||||
let pos2 = Isometry::from_parts(shapePos2.0.into(), shapeRot2.0);
|
||||
|
||||
self.0.intersectsShape(&pos1, &*shape2.0, &pos2)
|
||||
}
|
||||
|
||||
pub fn contactShape(
|
||||
&self,
|
||||
shapePos1: &RawVector,
|
||||
shapeRot1: &RawRotation,
|
||||
shape2: &RawShape,
|
||||
shapePos2: &RawVector,
|
||||
shapeRot2: &RawRotation,
|
||||
prediction: f32,
|
||||
) -> Option<RawShapeContact> {
|
||||
let pos1 = Isometry::from_parts(shapePos1.0.into(), shapeRot1.0);
|
||||
let pos2 = Isometry::from_parts(shapePos2.0.into(), shapeRot2.0);
|
||||
|
||||
self.0.contactShape(&pos1, &*shape2.0, &pos2, prediction)
|
||||
}
|
||||
|
||||
pub fn containsPoint(
|
||||
&self,
|
||||
shapePos: &RawVector,
|
||||
shapeRot: &RawRotation,
|
||||
point: &RawVector,
|
||||
) -> bool {
|
||||
let pos = Isometry::from_parts(shapePos.0.into(), shapeRot.0);
|
||||
|
||||
self.0.containsPoint(&pos, &point.0.into())
|
||||
}
|
||||
|
||||
pub fn projectPoint(
|
||||
&self,
|
||||
shapePos: &RawVector,
|
||||
shapeRot: &RawRotation,
|
||||
point: &RawVector,
|
||||
solid: bool,
|
||||
) -> RawPointProjection {
|
||||
let pos = Isometry::from_parts(shapePos.0.into(), shapeRot.0);
|
||||
|
||||
self.0.projectPoint(&pos, &point.0.into(), solid)
|
||||
}
|
||||
|
||||
pub fn intersectsRay(
|
||||
&self,
|
||||
shapePos: &RawVector,
|
||||
shapeRot: &RawRotation,
|
||||
rayOrig: &RawVector,
|
||||
rayDir: &RawVector,
|
||||
maxToi: f32,
|
||||
) -> bool {
|
||||
let pos = Isometry::from_parts(shapePos.0.into(), shapeRot.0);
|
||||
|
||||
self.0
|
||||
.intersectsRay(&pos, rayOrig.0.into(), rayDir.0.into(), maxToi)
|
||||
}
|
||||
|
||||
pub fn castRay(
|
||||
&self,
|
||||
shapePos: &RawVector,
|
||||
shapeRot: &RawRotation,
|
||||
rayOrig: &RawVector,
|
||||
rayDir: &RawVector,
|
||||
maxToi: f32,
|
||||
solid: bool,
|
||||
) -> f32 {
|
||||
let pos = Isometry::from_parts(shapePos.0.into(), shapeRot.0);
|
||||
|
||||
self.0
|
||||
.castRay(&pos, rayOrig.0.into(), rayDir.0.into(), maxToi, solid)
|
||||
}
|
||||
|
||||
pub fn castRayAndGetNormal(
|
||||
&self,
|
||||
shapePos: &RawVector,
|
||||
shapeRot: &RawRotation,
|
||||
rayOrig: &RawVector,
|
||||
rayDir: &RawVector,
|
||||
maxToi: f32,
|
||||
solid: bool,
|
||||
) -> Option<RawRayIntersection> {
|
||||
let pos = Isometry::from_parts(shapePos.0.into(), shapeRot.0);
|
||||
|
||||
self.0
|
||||
.castRayAndGetNormal(&pos, rayOrig.0.into(), rayDir.0.into(), maxToi, solid)
|
||||
}
|
||||
}
|
||||
65
thirdparty/rapier.js/src/geometry/toi.rs
vendored
Normal file
65
thirdparty/rapier.js/src/geometry/toi.rs
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
use crate::math::RawVector;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::geometry::{ColliderHandle, ShapeCastHit};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawShapeCastHit {
|
||||
pub(crate) hit: ShapeCastHit,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawShapeCastHit {
|
||||
pub fn time_of_impact(&self) -> f32 {
|
||||
self.hit.time_of_impact
|
||||
}
|
||||
|
||||
pub fn witness1(&self) -> RawVector {
|
||||
self.hit.witness1.coords.into()
|
||||
}
|
||||
|
||||
pub fn witness2(&self) -> RawVector {
|
||||
self.hit.witness2.coords.into()
|
||||
}
|
||||
|
||||
pub fn normal1(&self) -> RawVector {
|
||||
self.hit.normal1.into_inner().into()
|
||||
}
|
||||
|
||||
pub fn normal2(&self) -> RawVector {
|
||||
self.hit.normal2.into_inner().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawColliderShapeCastHit {
|
||||
pub(crate) handle: ColliderHandle,
|
||||
pub(crate) hit: ShapeCastHit,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawColliderShapeCastHit {
|
||||
pub fn colliderHandle(&self) -> FlatHandle {
|
||||
utils::flat_handle(self.handle.0)
|
||||
}
|
||||
|
||||
pub fn time_of_impact(&self) -> f32 {
|
||||
self.hit.time_of_impact
|
||||
}
|
||||
|
||||
pub fn witness1(&self) -> RawVector {
|
||||
self.hit.witness1.coords.into()
|
||||
}
|
||||
|
||||
pub fn witness2(&self) -> RawVector {
|
||||
self.hit.witness2.coords.into()
|
||||
}
|
||||
|
||||
pub fn normal1(&self) -> RawVector {
|
||||
self.hit.normal1.into_inner().into()
|
||||
}
|
||||
|
||||
pub fn normal2(&self) -> RawVector {
|
||||
self.hit.normal2.into_inner().into()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user