chore: 添加第三方依赖库
This commit is contained in:
290
thirdparty/rapier.js/src/control/character_controller.rs
vendored
Normal file
290
thirdparty/rapier.js/src/control/character_controller.rs
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
use crate::dynamics::RawRigidBodySet;
|
||||
use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase};
|
||||
use crate::math::RawVector;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use na::{Isometry, Unit};
|
||||
use rapier::control::{
|
||||
CharacterAutostep, CharacterCollision, CharacterLength, EffectiveCharacterMovement,
|
||||
KinematicCharacterController,
|
||||
};
|
||||
use rapier::geometry::{ColliderHandle, ShapeCastHit};
|
||||
use rapier::math::{Point, Real, Vector};
|
||||
use rapier::parry::query::ShapeCastStatus;
|
||||
use rapier::pipeline::{QueryFilter, QueryFilterFlags};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawKinematicCharacterController {
|
||||
controller: KinematicCharacterController,
|
||||
result: EffectiveCharacterMovement,
|
||||
events: Vec<CharacterCollision>,
|
||||
}
|
||||
|
||||
fn length_value(length: CharacterLength) -> Real {
|
||||
match length {
|
||||
CharacterLength::Absolute(val) => val,
|
||||
CharacterLength::Relative(val) => val,
|
||||
}
|
||||
}
|
||||
#[wasm_bindgen]
|
||||
impl RawKinematicCharacterController {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(offset: Real) -> Self {
|
||||
let controller = KinematicCharacterController {
|
||||
offset: CharacterLength::Absolute(offset),
|
||||
autostep: None,
|
||||
snap_to_ground: None,
|
||||
..KinematicCharacterController::default()
|
||||
};
|
||||
|
||||
Self {
|
||||
controller,
|
||||
result: EffectiveCharacterMovement {
|
||||
translation: Vector::zeros(),
|
||||
grounded: false,
|
||||
is_sliding_down_slope: false,
|
||||
},
|
||||
events: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn up(&self) -> RawVector {
|
||||
self.controller.up.into_inner().into()
|
||||
}
|
||||
|
||||
pub fn setUp(&mut self, vector: &RawVector) {
|
||||
self.controller.up = Unit::new_normalize(vector.0);
|
||||
}
|
||||
|
||||
pub fn normalNudgeFactor(&self) -> Real {
|
||||
self.controller.normal_nudge_factor
|
||||
}
|
||||
|
||||
pub fn setNormalNudgeFactor(&mut self, value: Real) {
|
||||
self.controller.normal_nudge_factor = value;
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> Real {
|
||||
length_value(self.controller.offset)
|
||||
}
|
||||
|
||||
pub fn setOffset(&mut self, value: Real) {
|
||||
self.controller.offset = CharacterLength::Absolute(value);
|
||||
}
|
||||
|
||||
pub fn slideEnabled(&self) -> bool {
|
||||
self.controller.slide
|
||||
}
|
||||
|
||||
pub fn setSlideEnabled(&mut self, enabled: bool) {
|
||||
self.controller.slide = enabled
|
||||
}
|
||||
|
||||
pub fn autostepMaxHeight(&self) -> Option<Real> {
|
||||
self.controller.autostep.map(|e| length_value(e.max_height))
|
||||
}
|
||||
|
||||
pub fn autostepMinWidth(&self) -> Option<Real> {
|
||||
self.controller.autostep.map(|e| length_value(e.min_width))
|
||||
}
|
||||
|
||||
pub fn autostepIncludesDynamicBodies(&self) -> Option<bool> {
|
||||
self.controller.autostep.map(|e| e.include_dynamic_bodies)
|
||||
}
|
||||
|
||||
pub fn autostepEnabled(&self) -> bool {
|
||||
self.controller.autostep.is_some()
|
||||
}
|
||||
|
||||
pub fn enableAutostep(&mut self, maxHeight: Real, minWidth: Real, includeDynamicBodies: bool) {
|
||||
self.controller.autostep = Some(CharacterAutostep {
|
||||
min_width: CharacterLength::Absolute(minWidth),
|
||||
max_height: CharacterLength::Absolute(maxHeight),
|
||||
include_dynamic_bodies: includeDynamicBodies,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn disableAutostep(&mut self) {
|
||||
self.controller.autostep = None;
|
||||
}
|
||||
|
||||
pub fn maxSlopeClimbAngle(&self) -> Real {
|
||||
self.controller.max_slope_climb_angle
|
||||
}
|
||||
|
||||
pub fn setMaxSlopeClimbAngle(&mut self, angle: Real) {
|
||||
self.controller.max_slope_climb_angle = angle;
|
||||
}
|
||||
|
||||
pub fn minSlopeSlideAngle(&self) -> Real {
|
||||
self.controller.min_slope_slide_angle
|
||||
}
|
||||
|
||||
pub fn setMinSlopeSlideAngle(&mut self, angle: Real) {
|
||||
self.controller.min_slope_slide_angle = angle
|
||||
}
|
||||
|
||||
pub fn snapToGroundDistance(&self) -> Option<Real> {
|
||||
self.controller.snap_to_ground.map(length_value)
|
||||
}
|
||||
|
||||
pub fn enableSnapToGround(&mut self, distance: Real) {
|
||||
self.controller.snap_to_ground = Some(CharacterLength::Absolute(distance));
|
||||
}
|
||||
|
||||
pub fn disableSnapToGround(&mut self) {
|
||||
self.controller.snap_to_ground = None;
|
||||
}
|
||||
|
||||
pub fn snapToGroundEnabled(&self) -> bool {
|
||||
self.controller.snap_to_ground.is_some()
|
||||
}
|
||||
|
||||
pub fn computeColliderMovement(
|
||||
&mut self,
|
||||
dt: Real,
|
||||
broad_phase: &RawBroadPhase,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
colliders: &mut RawColliderSet,
|
||||
collider_handle: FlatHandle,
|
||||
desired_translation_delta: &RawVector,
|
||||
apply_impulses_to_dynamic_bodies: bool,
|
||||
character_mass: Option<Real>,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) {
|
||||
let handle = crate::utils::collider_handle(collider_handle);
|
||||
if let Some(collider) = colliders.0.get(handle) {
|
||||
let collider_pose = *collider.position();
|
||||
let collider_shape = collider.shared_shape().clone();
|
||||
let collider_parent = collider.parent();
|
||||
|
||||
crate::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: Some(handle),
|
||||
exclude_rigid_body: collider_parent,
|
||||
predicate,
|
||||
};
|
||||
|
||||
let character_mass = character_mass
|
||||
.or_else(|| {
|
||||
collider_parent
|
||||
.and_then(|h| bodies.0.get(h))
|
||||
.map(|b| b.mass())
|
||||
})
|
||||
.unwrap_or(0.0);
|
||||
|
||||
let mut query_pipeline = broad_phase.0.as_query_pipeline_mut(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&mut bodies.0,
|
||||
&mut colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
self.events.clear();
|
||||
let events = &mut self.events;
|
||||
self.result = self.controller.move_shape(
|
||||
dt,
|
||||
&query_pipeline.as_ref(),
|
||||
&*collider_shape,
|
||||
&collider_pose,
|
||||
desired_translation_delta.0,
|
||||
|event| events.push(event),
|
||||
);
|
||||
|
||||
if apply_impulses_to_dynamic_bodies {
|
||||
self.controller.solve_character_collision_impulses(
|
||||
dt,
|
||||
&mut query_pipeline,
|
||||
&*collider_shape,
|
||||
character_mass,
|
||||
self.events.iter(),
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.result.translation.fill(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn computedMovement(&self) -> RawVector {
|
||||
self.result.translation.into()
|
||||
}
|
||||
|
||||
pub fn computedGrounded(&self) -> bool {
|
||||
self.result.grounded
|
||||
}
|
||||
|
||||
pub fn numComputedCollisions(&self) -> usize {
|
||||
self.events.len()
|
||||
}
|
||||
|
||||
pub fn computedCollision(&self, i: usize, collision: &mut RawCharacterCollision) -> bool {
|
||||
if let Some(coll) = self.events.get(i) {
|
||||
collision.0 = *coll;
|
||||
}
|
||||
|
||||
i < self.events.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawCharacterCollision(CharacterCollision);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawCharacterCollision {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Self(CharacterCollision {
|
||||
handle: ColliderHandle::invalid(),
|
||||
character_pos: Isometry::identity(),
|
||||
translation_applied: Vector::zeros(),
|
||||
translation_remaining: Vector::zeros(),
|
||||
hit: ShapeCastHit {
|
||||
time_of_impact: 0.0,
|
||||
witness1: Point::origin(),
|
||||
witness2: Point::origin(),
|
||||
normal1: Vector::y_axis(),
|
||||
normal2: Vector::y_axis(),
|
||||
status: ShapeCastStatus::Failed,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn handle(&self) -> FlatHandle {
|
||||
utils::flat_handle(self.0.handle.0)
|
||||
}
|
||||
|
||||
pub fn translationDeltaApplied(&self) -> RawVector {
|
||||
self.0.translation_applied.into()
|
||||
}
|
||||
|
||||
pub fn translationDeltaRemaining(&self) -> RawVector {
|
||||
self.0.translation_remaining.into()
|
||||
}
|
||||
|
||||
pub fn toi(&self) -> Real {
|
||||
self.0.hit.time_of_impact
|
||||
}
|
||||
|
||||
pub fn worldWitness1(&self) -> RawVector {
|
||||
self.0.hit.witness1.coords.into() // Already in world-space.
|
||||
}
|
||||
|
||||
pub fn worldWitness2(&self) -> RawVector {
|
||||
(self.0.character_pos * self.0.hit.witness2).coords.into()
|
||||
}
|
||||
|
||||
pub fn worldNormal1(&self) -> RawVector {
|
||||
self.0.hit.normal1.into_inner().into() // Already in world-space.
|
||||
}
|
||||
|
||||
pub fn worldNormal2(&self) -> RawVector {
|
||||
(self.0.character_pos * self.0.hit.normal2.into_inner()).into()
|
||||
}
|
||||
}
|
||||
11
thirdparty/rapier.js/src/control/mod.rs
vendored
Normal file
11
thirdparty/rapier.js/src/control/mod.rs
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
pub use self::character_controller::RawKinematicCharacterController;
|
||||
pub use self::pid_controller::RawPidController;
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub use self::ray_cast_vehicle_controller::RawDynamicRayCastVehicleController;
|
||||
|
||||
mod character_controller;
|
||||
mod pid_controller;
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
mod ray_cast_vehicle_controller;
|
||||
264
thirdparty/rapier.js/src/control/pid_controller.rs
vendored
Normal file
264
thirdparty/rapier.js/src/control/pid_controller.rs
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
use crate::dynamics::RawRigidBodySet;
|
||||
use crate::math::RawVector;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::control::PidController;
|
||||
use rapier::dynamics::AxesMask;
|
||||
use rapier::math::Vector;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
use crate::math::RawRotation;
|
||||
#[cfg(feature = "dim2")]
|
||||
use rapier::math::Rotation;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawPidController {
|
||||
controller: PidController,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawPidController {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(kp: f32, ki: f32, kd: f32, axes_mask: u8) -> Self {
|
||||
let controller = PidController::new(
|
||||
kp,
|
||||
ki,
|
||||
kd,
|
||||
AxesMask::from_bits(axes_mask).unwrap_or(AxesMask::all()),
|
||||
);
|
||||
Self { controller }
|
||||
}
|
||||
|
||||
pub fn set_kp(&mut self, kp: f32, axes: u8) {
|
||||
let axes = AxesMask::from_bits(axes).unwrap_or(AxesMask::all());
|
||||
if axes.contains(AxesMask::LIN_X) {
|
||||
self.controller.pd.lin_kp.x = kp;
|
||||
}
|
||||
if axes.contains(AxesMask::LIN_Y) {
|
||||
self.controller.pd.lin_kp.y = kp;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::LIN_Z) {
|
||||
self.controller.pd.lin_kp.z = kp;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_X) {
|
||||
self.controller.pd.ang_kp.x = kp;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_Y) {
|
||||
self.controller.pd.ang_kp.y = kp;
|
||||
}
|
||||
if axes.contains(AxesMask::ANG_Z) {
|
||||
#[cfg(feature = "dim2")]
|
||||
{
|
||||
self.controller.pd.ang_kp = kp;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
{
|
||||
self.controller.pd.ang_kp.z = kp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_ki(&mut self, ki: f32, axes: u8) {
|
||||
let axes = AxesMask::from_bits(axes).unwrap_or(AxesMask::all());
|
||||
if axes.contains(AxesMask::LIN_X) {
|
||||
self.controller.lin_ki.x = ki;
|
||||
}
|
||||
if axes.contains(AxesMask::LIN_Y) {
|
||||
self.controller.lin_ki.y = ki;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::LIN_Z) {
|
||||
self.controller.lin_ki.z = ki;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_X) {
|
||||
self.controller.ang_ki.x = ki;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_Y) {
|
||||
self.controller.ang_ki.y = ki;
|
||||
}
|
||||
if axes.contains(AxesMask::ANG_Z) {
|
||||
#[cfg(feature = "dim2")]
|
||||
{
|
||||
self.controller.ang_ki = ki;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
{
|
||||
self.controller.ang_ki.z = ki;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_kd(&mut self, kd: f32, axes: u8) {
|
||||
let axes = AxesMask::from_bits(axes).unwrap_or(AxesMask::all());
|
||||
if axes.contains(AxesMask::LIN_X) {
|
||||
self.controller.pd.lin_kd.x = kd;
|
||||
}
|
||||
if axes.contains(AxesMask::LIN_Y) {
|
||||
self.controller.pd.lin_kd.x = kd;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::LIN_Z) {
|
||||
self.controller.pd.lin_kd.x = kd;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_X) {
|
||||
self.controller.pd.ang_kd.x = kd;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_Y) {
|
||||
self.controller.pd.ang_kd.y = kd;
|
||||
}
|
||||
if axes.contains(AxesMask::ANG_Z) {
|
||||
#[cfg(feature = "dim2")]
|
||||
{
|
||||
self.controller.pd.ang_kd = kd;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
{
|
||||
self.controller.pd.ang_kd.z = kd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_axes_mask(&mut self, axes_mask: u8) {
|
||||
if let Some(mask) = AxesMask::from_bits(axes_mask) {
|
||||
self.controller.pd.axes = mask;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_integrals(&mut self) {
|
||||
self.controller.reset_integrals();
|
||||
}
|
||||
|
||||
pub fn apply_linear_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_translation: &RawVector,
|
||||
target_linvel: &RawVector,
|
||||
) {
|
||||
let rb_handle = utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get_mut(rb_handle) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let correction = self.controller.linear_rigid_body_correction(
|
||||
dt,
|
||||
rb,
|
||||
target_translation.0.into(),
|
||||
target_linvel.0,
|
||||
);
|
||||
rb.set_linvel(*rb.linvel() + correction, true);
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn apply_angular_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_rotation: f32,
|
||||
target_angvel: f32,
|
||||
) {
|
||||
let rb_handle = crate::utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get_mut(rb_handle) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let correction = self.controller.angular_rigid_body_correction(
|
||||
dt,
|
||||
rb,
|
||||
Rotation::new(target_rotation),
|
||||
target_angvel,
|
||||
);
|
||||
rb.set_angvel(rb.angvel() + correction, true);
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn apply_angular_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_rotation: &RawRotation,
|
||||
target_angvel: &RawVector,
|
||||
) {
|
||||
let rb_handle = crate::utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get_mut(rb_handle) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let correction = self.controller.angular_rigid_body_correction(
|
||||
dt,
|
||||
rb,
|
||||
target_rotation.0,
|
||||
target_angvel.0,
|
||||
);
|
||||
rb.set_angvel(rb.angvel() + correction, true);
|
||||
}
|
||||
|
||||
pub fn linear_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_translation: &RawVector,
|
||||
target_linvel: &RawVector,
|
||||
) -> RawVector {
|
||||
let rb_handle = crate::utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get(rb_handle) else {
|
||||
return RawVector(Vector::zeros());
|
||||
};
|
||||
|
||||
self.controller
|
||||
.linear_rigid_body_correction(dt, rb, target_translation.0.into(), target_linvel.0)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn angular_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_rotation: f32,
|
||||
target_angvel: f32,
|
||||
) -> f32 {
|
||||
let rb_handle = crate::utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get(rb_handle) else {
|
||||
return 0.0;
|
||||
};
|
||||
|
||||
self.controller.angular_rigid_body_correction(
|
||||
dt,
|
||||
rb,
|
||||
Rotation::new(target_rotation),
|
||||
target_angvel,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn angular_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_rotation: &RawRotation,
|
||||
target_angvel: &RawVector,
|
||||
) -> RawVector {
|
||||
let rb_handle = crate::utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get(rb_handle) else {
|
||||
return RawVector(Vector::zeros());
|
||||
};
|
||||
|
||||
self.controller
|
||||
.angular_rigid_body_correction(dt, rb, target_rotation.0, target_angvel.0)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
336
thirdparty/rapier.js/src/control/ray_cast_vehicle_controller.rs
vendored
Normal file
336
thirdparty/rapier.js/src/control/ray_cast_vehicle_controller.rs
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
use crate::dynamics::RawRigidBodySet;
|
||||
use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase};
|
||||
use crate::math::RawVector;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::control::{DynamicRayCastVehicleController, WheelTuning};
|
||||
use rapier::math::Real;
|
||||
use rapier::pipeline::{QueryFilter, QueryFilterFlags};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawDynamicRayCastVehicleController {
|
||||
controller: DynamicRayCastVehicleController,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawDynamicRayCastVehicleController {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(chassis: FlatHandle) -> Self {
|
||||
Self {
|
||||
controller: DynamicRayCastVehicleController::new(utils::body_handle(chassis)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_vehicle_speed(&self) -> Real {
|
||||
self.controller.current_vehicle_speed
|
||||
}
|
||||
|
||||
pub fn chassis(&self) -> FlatHandle {
|
||||
utils::flat_handle(self.controller.chassis.0)
|
||||
}
|
||||
|
||||
pub fn index_up_axis(&self) -> usize {
|
||||
self.controller.index_up_axis
|
||||
}
|
||||
pub fn set_index_up_axis(&mut self, axis: usize) {
|
||||
self.controller.index_up_axis = axis;
|
||||
}
|
||||
|
||||
pub fn index_forward_axis(&self) -> usize {
|
||||
self.controller.index_forward_axis
|
||||
}
|
||||
pub fn set_index_forward_axis(&mut self, axis: usize) {
|
||||
self.controller.index_forward_axis = axis;
|
||||
}
|
||||
|
||||
pub fn add_wheel(
|
||||
&mut self,
|
||||
chassis_connection_cs: &RawVector,
|
||||
direction_cs: &RawVector,
|
||||
axle_cs: &RawVector,
|
||||
suspension_rest_length: Real,
|
||||
radius: Real,
|
||||
) {
|
||||
self.controller.add_wheel(
|
||||
chassis_connection_cs.0.into(),
|
||||
direction_cs.0,
|
||||
axle_cs.0,
|
||||
suspension_rest_length,
|
||||
radius,
|
||||
&WheelTuning::default(),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn num_wheels(&self) -> usize {
|
||||
self.controller.wheels().len()
|
||||
}
|
||||
|
||||
pub fn update_vehicle(
|
||||
&mut self,
|
||||
dt: Real,
|
||||
broad_phase: &RawBroadPhase,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
colliders: &mut RawColliderSet,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) {
|
||||
crate::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),
|
||||
predicate,
|
||||
exclude_rigid_body: Some(self.controller.chassis),
|
||||
exclude_collider: None,
|
||||
};
|
||||
|
||||
let query_pipeline = broad_phase.0.as_query_pipeline_mut(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&mut bodies.0,
|
||||
&mut colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
self.controller.update_vehicle(dt, query_pipeline);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Access to wheel properties.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Getters + setters
|
||||
*/
|
||||
pub fn wheel_chassis_connection_point_cs(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.chassis_connection_point_cs.into())
|
||||
}
|
||||
pub fn set_wheel_chassis_connection_point_cs(&mut self, i: usize, value: &RawVector) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.chassis_connection_point_cs = value.0.into();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_rest_length(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.suspension_rest_length)
|
||||
}
|
||||
pub fn set_wheel_suspension_rest_length(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.suspension_rest_length = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_max_suspension_travel(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.max_suspension_travel)
|
||||
}
|
||||
pub fn set_wheel_max_suspension_travel(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.max_suspension_travel = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_radius(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.radius)
|
||||
}
|
||||
pub fn set_wheel_radius(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.radius = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_stiffness(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.suspension_stiffness)
|
||||
}
|
||||
pub fn set_wheel_suspension_stiffness(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.suspension_stiffness = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_compression(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.damping_compression)
|
||||
}
|
||||
pub fn set_wheel_suspension_compression(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.damping_compression = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_relaxation(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.damping_relaxation)
|
||||
}
|
||||
pub fn set_wheel_suspension_relaxation(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.damping_relaxation = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_max_suspension_force(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.max_suspension_force)
|
||||
}
|
||||
pub fn set_wheel_max_suspension_force(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.max_suspension_force = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_brake(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.brake)
|
||||
}
|
||||
pub fn set_wheel_brake(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.brake = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_steering(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.steering)
|
||||
}
|
||||
pub fn set_wheel_steering(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.steering = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_engine_force(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.engine_force)
|
||||
}
|
||||
pub fn set_wheel_engine_force(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.engine_force = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_direction_cs(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.direction_cs.into())
|
||||
}
|
||||
pub fn set_wheel_direction_cs(&mut self, i: usize, value: &RawVector) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.direction_cs = value.0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_axle_cs(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller.wheels().get(i).map(|w| w.axle_cs.into())
|
||||
}
|
||||
pub fn set_wheel_axle_cs(&mut self, i: usize, value: &RawVector) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.axle_cs = value.0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_friction_slip(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.friction_slip)
|
||||
}
|
||||
pub fn set_wheel_friction_slip(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.friction_slip = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_side_friction_stiffness(&self, i: usize) -> Option<f32> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.side_friction_stiffness)
|
||||
}
|
||||
|
||||
pub fn set_wheel_side_friction_stiffness(&mut self, i: usize, stiffness: f32) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.side_friction_stiffness = stiffness;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Getters only.
|
||||
*/
|
||||
pub fn wheel_rotation(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.rotation)
|
||||
}
|
||||
|
||||
pub fn wheel_forward_impulse(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.forward_impulse)
|
||||
}
|
||||
|
||||
pub fn wheel_side_impulse(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.side_impulse)
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_force(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.wheel_suspension_force)
|
||||
}
|
||||
|
||||
pub fn wheel_contact_normal_ws(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.raycast_info().contact_normal_ws.into())
|
||||
}
|
||||
|
||||
pub fn wheel_contact_point_ws(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.raycast_info().contact_point_ws.into())
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_length(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.raycast_info().suspension_length)
|
||||
}
|
||||
|
||||
pub fn wheel_hard_point_ws(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.raycast_info().hard_point_ws.into())
|
||||
}
|
||||
|
||||
pub fn wheel_is_in_contact(&self, i: usize) -> bool {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.raycast_info().is_in_contact)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn wheel_ground_object(&self, i: usize) -> Option<FlatHandle> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.and_then(|w| w.raycast_info().ground_object)
|
||||
.map(|h| utils::flat_handle(h.0))
|
||||
}
|
||||
}
|
||||
13
thirdparty/rapier.js/src/dynamics/ccd_solver.rs
vendored
Normal file
13
thirdparty/rapier.js/src/dynamics/ccd_solver.rs
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
use rapier::dynamics::CCDSolver;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawCCDSolver(pub(crate) CCDSolver);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawCCDSolver {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawCCDSolver(CCDSolver::new())
|
||||
}
|
||||
}
|
||||
215
thirdparty/rapier.js/src/dynamics/impulse_joint.rs
vendored
Normal file
215
thirdparty/rapier.js/src/dynamics/impulse_joint.rs
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
use crate::dynamics::{RawImpulseJointSet, RawJointAxis, RawJointType, RawMotorModel};
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::dynamics::JointAxis;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawImpulseJointSet {
|
||||
/// The type of this joint.
|
||||
pub fn jointType(&self, handle: FlatHandle) -> RawJointType {
|
||||
self.map(handle, |j| j.data.locked_axes.into())
|
||||
}
|
||||
|
||||
/// The unique integer identifier of the first rigid-body this joint it attached to.
|
||||
pub fn jointBodyHandle1(&self, handle: FlatHandle) -> FlatHandle {
|
||||
self.map(handle, |j| utils::flat_handle(j.body1.0))
|
||||
}
|
||||
|
||||
/// The unique integer identifier of the second rigid-body this joint is attached to.
|
||||
pub fn jointBodyHandle2(&self, handle: FlatHandle) -> FlatHandle {
|
||||
self.map(handle, |j| utils::flat_handle(j.body2.0))
|
||||
}
|
||||
|
||||
/// The angular part of the joint’s local frame relative to the first rigid-body it is attached to.
|
||||
pub fn jointFrameX1(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |j| j.data.local_frame1.rotation.into())
|
||||
}
|
||||
|
||||
/// The angular part of the joint’s local frame relative to the second rigid-body it is attached to.
|
||||
pub fn jointFrameX2(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |j| j.data.local_frame2.rotation.into())
|
||||
}
|
||||
|
||||
/// The position of the first anchor of this joint.
|
||||
///
|
||||
/// The first anchor gives the position of the points application point on the
|
||||
/// local frame of the first rigid-body it is attached to.
|
||||
pub fn jointAnchor1(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |j| j.data.local_frame1.translation.vector.into())
|
||||
}
|
||||
|
||||
/// The position of the second anchor of this joint.
|
||||
///
|
||||
/// The second anchor gives the position of the points application point on the
|
||||
/// local frame of the second rigid-body it is attached to.
|
||||
pub fn jointAnchor2(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |j| j.data.local_frame2.translation.vector.into())
|
||||
}
|
||||
|
||||
/// Sets the position of the first local anchor
|
||||
pub fn jointSetAnchor1(&mut self, handle: FlatHandle, newPos: &RawVector) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.set_local_anchor1(newPos.0.into());
|
||||
});
|
||||
}
|
||||
|
||||
/// Sets the position of the second local anchor
|
||||
pub fn jointSetAnchor2(&mut self, handle: FlatHandle, newPos: &RawVector) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.set_local_anchor2(newPos.0.into());
|
||||
})
|
||||
}
|
||||
|
||||
/// Are contacts between the rigid-bodies attached by this joint enabled?
|
||||
pub fn jointContactsEnabled(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |j| j.data.contacts_enabled)
|
||||
}
|
||||
|
||||
/// Sets whether contacts are enabled between the rigid-bodies attached by this joint.
|
||||
pub fn jointSetContactsEnabled(&mut self, handle: FlatHandle, enabled: bool) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.contacts_enabled = enabled;
|
||||
});
|
||||
}
|
||||
|
||||
/// Are the limits for this joint enabled?
|
||||
pub fn jointLimitsEnabled(&self, handle: FlatHandle, axis: RawJointAxis) -> bool {
|
||||
self.map(handle, |j| {
|
||||
j.data.limit_axes.contains(JointAxis::from(axis).into())
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the lower limit along the given joint axis.
|
||||
pub fn jointLimitsMin(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 {
|
||||
self.map(handle, |j| j.data.limits[axis as usize].min)
|
||||
}
|
||||
|
||||
/// If this is a prismatic joint, returns its upper limit.
|
||||
pub fn jointLimitsMax(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 {
|
||||
self.map(handle, |j| j.data.limits[axis as usize].max)
|
||||
}
|
||||
|
||||
/// Enables and sets the joint limits
|
||||
pub fn jointSetLimits(&mut self, handle: FlatHandle, axis: RawJointAxis, min: f32, max: f32) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.set_limits(axis.into(), [min, max]);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn jointConfigureMotorModel(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
axis: RawJointAxis,
|
||||
model: RawMotorModel,
|
||||
) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.motors[axis as usize].model = model.into()
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotorVelocity(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
vx: f32,
|
||||
vy: f32,
|
||||
vz: f32,
|
||||
factor: f32,
|
||||
) {
|
||||
let targetVel = Vector3::new(vx, vy, vz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => j.configure_motor_velocity(targetVel, factor),
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotorPosition(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
qw: f32,
|
||||
qx: f32,
|
||||
qy: f32,
|
||||
qz: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
let quat = Quaternion::new(qw, qx, qy, qz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => {
|
||||
if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) {
|
||||
j.configure_motor_position(unit_quat, stiffness, damping)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotor(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
qw: f32,
|
||||
qx: f32,
|
||||
qy: f32,
|
||||
qz: f32,
|
||||
vx: f32,
|
||||
vy: f32,
|
||||
vz: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
let quat = Quaternion::new(qw, qx, qy, qz);
|
||||
let vel = Vector3::new(vx, vy, vz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => {
|
||||
if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) {
|
||||
j.configure_motor(unit_quat, vel, stiffness, damping)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn jointConfigureMotorVelocity(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
axis: RawJointAxis,
|
||||
targetVel: f32,
|
||||
factor: f32,
|
||||
) {
|
||||
self.jointConfigureMotor(handle, axis, 0.0, targetVel, 0.0, factor)
|
||||
}
|
||||
|
||||
pub fn jointConfigureMotorPosition(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
axis: RawJointAxis,
|
||||
targetPos: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
self.jointConfigureMotor(handle, axis, targetPos, 0.0, stiffness, damping)
|
||||
}
|
||||
|
||||
pub fn jointConfigureMotor(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
axis: RawJointAxis,
|
||||
targetPos: f32,
|
||||
targetVel: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data
|
||||
.set_motor(axis.into(), targetPos, targetVel, stiffness, damping);
|
||||
})
|
||||
}
|
||||
}
|
||||
92
thirdparty/rapier.js/src/dynamics/impulse_joint_set.rs
vendored
Normal file
92
thirdparty/rapier.js/src/dynamics/impulse_joint_set.rs
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
use crate::dynamics::RawGenericJoint;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::dynamics::{ImpulseJoint, ImpulseJointSet};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawImpulseJointSet(pub(crate) ImpulseJointSet);
|
||||
|
||||
impl RawImpulseJointSet {
|
||||
pub(crate) fn map<T>(&self, handle: FlatHandle, f: impl FnOnce(&ImpulseJoint) -> T) -> T {
|
||||
let body = self.0.get(utils::impulse_joint_handle(handle)).expect(
|
||||
"Invalid ImpulseJoint reference. It may have been removed from the physics World.",
|
||||
);
|
||||
f(body)
|
||||
}
|
||||
|
||||
pub(crate) fn map_mut<T>(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
f: impl FnOnce(&mut ImpulseJoint) -> T,
|
||||
) -> T {
|
||||
let body = self
|
||||
.0
|
||||
.get_mut(utils::impulse_joint_handle(handle), true)
|
||||
.expect(
|
||||
"Invalid ImpulseJoint reference. It may have been removed from the physics World.",
|
||||
);
|
||||
f(body)
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawImpulseJointSet {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawImpulseJointSet(ImpulseJointSet::new())
|
||||
}
|
||||
|
||||
pub fn createJoint(
|
||||
&mut self,
|
||||
params: &RawGenericJoint,
|
||||
parent1: FlatHandle,
|
||||
parent2: FlatHandle,
|
||||
wake_up: bool,
|
||||
) -> FlatHandle {
|
||||
utils::flat_handle(
|
||||
self.0
|
||||
.insert(
|
||||
utils::body_handle(parent1),
|
||||
utils::body_handle(parent2),
|
||||
params.0.clone(),
|
||||
wake_up,
|
||||
)
|
||||
.0,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, handle: FlatHandle, wakeUp: bool) {
|
||||
let handle = utils::impulse_joint_handle(handle);
|
||||
self.0.remove(handle, wakeUp);
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
pub fn contains(&self, handle: FlatHandle) -> bool {
|
||||
self.0.get(utils::impulse_joint_handle(handle)).is_some()
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each joint managed by this physics world.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each joint managed by this set. Called as `f(collider)`.
|
||||
pub fn forEachJointHandle(&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)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each joint attached to the given rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each joint attached to the rigid-body. Called as `f(collider)`.
|
||||
pub fn forEachJointAttachedToRigidBody(&self, body: FlatHandle, f: &js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
for (_, _, handle, _) in self.0.attached_joints(utils::body_handle(body)) {
|
||||
let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
101
thirdparty/rapier.js/src/dynamics/integration_parameters.rs
vendored
Normal file
101
thirdparty/rapier.js/src/dynamics/integration_parameters.rs
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
use rapier::dynamics::IntegrationParameters;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawIntegrationParameters(pub(crate) IntegrationParameters);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawIntegrationParameters {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawIntegrationParameters(IntegrationParameters::default())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn dt(&self) -> f32 {
|
||||
self.0.dt
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn contact_erp(&self) -> f32 {
|
||||
self.0.contact_erp()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn normalizedAllowedLinearError(&self) -> f32 {
|
||||
self.0.normalized_allowed_linear_error
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn normalizedPredictionDistance(&self) -> f32 {
|
||||
self.0.normalized_prediction_distance
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn numSolverIterations(&self) -> usize {
|
||||
self.0.num_solver_iterations
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn numInternalPgsIterations(&self) -> usize {
|
||||
self.0.num_internal_pgs_iterations
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn minIslandSize(&self) -> usize {
|
||||
self.0.min_island_size
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn maxCcdSubsteps(&self) -> usize {
|
||||
self.0.max_ccd_substeps
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn lengthUnit(&self) -> f32 {
|
||||
self.0.length_unit
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_dt(&mut self, value: f32) {
|
||||
self.0.dt = value;
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_contact_natural_frequency(&mut self, value: f32) {
|
||||
self.0.contact_natural_frequency = value
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_normalizedAllowedLinearError(&mut self, value: f32) {
|
||||
self.0.normalized_allowed_linear_error = value
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_normalizedPredictionDistance(&mut self, value: f32) {
|
||||
self.0.normalized_prediction_distance = value
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_numSolverIterations(&mut self, value: usize) {
|
||||
self.0.num_solver_iterations = value;
|
||||
}
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_numInternalPgsIterations(&mut self, value: usize) {
|
||||
self.0.num_internal_pgs_iterations = value;
|
||||
}
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_minIslandSize(&mut self, value: usize) {
|
||||
self.0.min_island_size = value
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_maxCcdSubsteps(&mut self, value: usize) {
|
||||
self.0.max_ccd_substeps = value
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_lengthUnit(&mut self, value: f32) {
|
||||
self.0.length_unit = value
|
||||
}
|
||||
}
|
||||
31
thirdparty/rapier.js/src/dynamics/island_manager.rs
vendored
Normal file
31
thirdparty/rapier.js/src/dynamics/island_manager.rs
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
use crate::utils;
|
||||
use rapier::dynamics::IslandManager;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawIslandManager(pub(crate) IslandManager);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawIslandManager {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawIslandManager(IslandManager::new())
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each active rigid-body
|
||||
/// managed by this island manager.
|
||||
///
|
||||
/// After a short time of inactivity, a rigid-body is automatically deactivated ("asleep") by
|
||||
/// the physics engine in order to save computational power. A sleeping rigid-body never moves
|
||||
/// unless it is moved manually by the user.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each active rigid-body managed by this
|
||||
/// set. Called as `f(collider)`.
|
||||
pub fn forEachActiveRigidBodyHandle(&self, f: &js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
for handle in self.0.active_bodies() {
|
||||
let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
314
thirdparty/rapier.js/src/dynamics/joint.rs
vendored
Normal file
314
thirdparty/rapier.js/src/dynamics/joint.rs
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use na::Unit;
|
||||
use rapier::dynamics::{
|
||||
FixedJointBuilder, GenericJoint, JointAxesMask, JointAxis, MotorModel, PrismaticJointBuilder,
|
||||
RevoluteJointBuilder, RopeJointBuilder, SpringJointBuilder,
|
||||
};
|
||||
#[cfg(feature = "dim3")]
|
||||
use rapier::dynamics::{GenericJointBuilder, SphericalJointBuilder};
|
||||
use rapier::math::Isometry;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[cfg(feature = "dim2")]
|
||||
pub enum RawJointType {
|
||||
Revolute,
|
||||
Fixed,
|
||||
Prismatic,
|
||||
Rope,
|
||||
Spring,
|
||||
Generic,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[cfg(feature = "dim3")]
|
||||
pub enum RawJointType {
|
||||
Revolute,
|
||||
Fixed,
|
||||
Prismatic,
|
||||
Rope,
|
||||
Spring,
|
||||
Spherical,
|
||||
Generic,
|
||||
}
|
||||
|
||||
/// The type of this joint.
|
||||
#[cfg(feature = "dim2")]
|
||||
impl From<JointAxesMask> for RawJointType {
|
||||
fn from(ty: JointAxesMask) -> RawJointType {
|
||||
let rev_axes = JointAxesMask::LIN_X | JointAxesMask::LIN_Y;
|
||||
let pri_axes = JointAxesMask::LIN_Y | JointAxesMask::ANG_X;
|
||||
let fix_axes = JointAxesMask::LIN_X | JointAxesMask::LIN_Y | JointAxesMask::ANG_X;
|
||||
|
||||
if ty == rev_axes {
|
||||
RawJointType::Revolute
|
||||
} else if ty == pri_axes {
|
||||
RawJointType::Prismatic
|
||||
} else if ty == fix_axes {
|
||||
RawJointType::Fixed
|
||||
} else {
|
||||
RawJointType::Generic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of this joint.
|
||||
#[cfg(feature = "dim3")]
|
||||
impl From<JointAxesMask> for RawJointType {
|
||||
fn from(ty: JointAxesMask) -> RawJointType {
|
||||
let rev_axes = JointAxesMask::LIN_X
|
||||
| JointAxesMask::LIN_Y
|
||||
| JointAxesMask::LIN_Z
|
||||
| JointAxesMask::ANG_Y
|
||||
| JointAxesMask::ANG_Z;
|
||||
let pri_axes = JointAxesMask::LIN_Y
|
||||
| JointAxesMask::LIN_Z
|
||||
| JointAxesMask::ANG_X
|
||||
| JointAxesMask::ANG_Y
|
||||
| JointAxesMask::ANG_Z;
|
||||
let sph_axes = JointAxesMask::ANG_X | JointAxesMask::ANG_Y | JointAxesMask::ANG_Z;
|
||||
let fix_axes = JointAxesMask::LIN_X
|
||||
| JointAxesMask::LIN_Y
|
||||
| JointAxesMask::LIN_Z
|
||||
| JointAxesMask::ANG_X
|
||||
| JointAxesMask::ANG_Y
|
||||
| JointAxesMask::ANG_Z;
|
||||
|
||||
if ty == rev_axes {
|
||||
RawJointType::Revolute
|
||||
} else if ty == pri_axes {
|
||||
RawJointType::Prismatic
|
||||
} else if ty == sph_axes {
|
||||
RawJointType::Spherical
|
||||
} else if ty == fix_axes {
|
||||
RawJointType::Fixed
|
||||
} else {
|
||||
RawJointType::Generic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub enum RawMotorModel {
|
||||
AccelerationBased,
|
||||
ForceBased,
|
||||
}
|
||||
|
||||
impl From<RawMotorModel> for MotorModel {
|
||||
fn from(model: RawMotorModel) -> MotorModel {
|
||||
match model {
|
||||
RawMotorModel::AccelerationBased => MotorModel::AccelerationBased,
|
||||
RawMotorModel::ForceBased => MotorModel::ForceBased,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
#[wasm_bindgen]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum RawJointAxis {
|
||||
LinX,
|
||||
LinY,
|
||||
AngX,
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
#[wasm_bindgen]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum RawJointAxis {
|
||||
LinX,
|
||||
LinY,
|
||||
LinZ,
|
||||
AngX,
|
||||
AngY,
|
||||
AngZ,
|
||||
}
|
||||
|
||||
impl From<RawJointAxis> for JointAxis {
|
||||
fn from(axis: RawJointAxis) -> JointAxis {
|
||||
match axis {
|
||||
RawJointAxis::LinX => JointAxis::LinX,
|
||||
RawJointAxis::LinY => JointAxis::LinY,
|
||||
#[cfg(feature = "dim3")]
|
||||
RawJointAxis::LinZ => JointAxis::LinZ,
|
||||
RawJointAxis::AngX => JointAxis::AngX,
|
||||
#[cfg(feature = "dim3")]
|
||||
RawJointAxis::AngY => JointAxis::AngY,
|
||||
#[cfg(feature = "dim3")]
|
||||
RawJointAxis::AngZ => JointAxis::AngZ,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawGenericJoint(pub(crate) GenericJoint);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawGenericJoint {
|
||||
/// Creates a new joint descriptor that builds generic joints.
|
||||
///
|
||||
/// Generic joints allow arbitrary axes of freedom to be selected
|
||||
/// for the joint from the available 6 degrees of freedom.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn generic(
|
||||
anchor1: &RawVector,
|
||||
anchor2: &RawVector,
|
||||
axis: &RawVector,
|
||||
lockedAxes: u8,
|
||||
) -> Option<RawGenericJoint> {
|
||||
let axesMask: JointAxesMask = JointAxesMask::from_bits(lockedAxes)?;
|
||||
let axis = Unit::try_new(axis.0, 0.0)?;
|
||||
let joint: GenericJoint = GenericJointBuilder::new(axesMask)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.local_axis1(axis)
|
||||
.local_axis2(axis)
|
||||
.into();
|
||||
Some(Self(joint))
|
||||
}
|
||||
|
||||
pub fn spring(
|
||||
rest_length: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
anchor1: &RawVector,
|
||||
anchor2: &RawVector,
|
||||
) -> Self {
|
||||
Self(
|
||||
SpringJointBuilder::new(rest_length, stiffness, damping)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn rope(length: f32, anchor1: &RawVector, anchor2: &RawVector) -> Self {
|
||||
Self(
|
||||
RopeJointBuilder::new(length)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new joint descriptor that builds spherical joints.
|
||||
///
|
||||
/// A spherical joints allows three relative rotational degrees of freedom
|
||||
/// by preventing any relative translation between the anchors of the
|
||||
/// two attached rigid-bodies.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn spherical(anchor1: &RawVector, anchor2: &RawVector) -> Self {
|
||||
Self(
|
||||
SphericalJointBuilder::new()
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new joint descriptor that builds a Prismatic joint.
|
||||
///
|
||||
/// A prismatic joint removes all the degrees of freedom between the
|
||||
/// affected bodies, except for the translation along one axis.
|
||||
///
|
||||
/// Returns `None` if any of the provided axes cannot be normalized.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn prismatic(
|
||||
anchor1: &RawVector,
|
||||
anchor2: &RawVector,
|
||||
axis: &RawVector,
|
||||
limitsEnabled: bool,
|
||||
limitsMin: f32,
|
||||
limitsMax: f32,
|
||||
) -> Option<RawGenericJoint> {
|
||||
let axis = Unit::try_new(axis.0, 0.0)?;
|
||||
let mut joint = PrismaticJointBuilder::new(axis)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into());
|
||||
|
||||
if limitsEnabled {
|
||||
joint = joint.limits([limitsMin, limitsMax]);
|
||||
}
|
||||
|
||||
Some(Self(joint.into()))
|
||||
}
|
||||
|
||||
/// Creates a new joint descriptor that builds a Prismatic joint.
|
||||
///
|
||||
/// A prismatic joint removes all the degrees of freedom between the
|
||||
/// affected bodies, except for the translation along one axis.
|
||||
///
|
||||
/// Returns `None` if any of the provided axes cannot be normalized.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn prismatic(
|
||||
anchor1: &RawVector,
|
||||
anchor2: &RawVector,
|
||||
axis: &RawVector,
|
||||
limitsEnabled: bool,
|
||||
limitsMin: f32,
|
||||
limitsMax: f32,
|
||||
) -> Option<RawGenericJoint> {
|
||||
let axis = Unit::try_new(axis.0, 0.0)?;
|
||||
let mut joint = PrismaticJointBuilder::new(axis)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into());
|
||||
|
||||
if limitsEnabled {
|
||||
joint = joint.limits([limitsMin, limitsMax]);
|
||||
}
|
||||
|
||||
Some(Self(joint.into()))
|
||||
}
|
||||
|
||||
/// Creates a new joint descriptor that builds a Fixed joint.
|
||||
///
|
||||
/// A fixed joint removes all the degrees of freedom between the affected bodies.
|
||||
pub fn fixed(
|
||||
anchor1: &RawVector,
|
||||
axes1: &RawRotation,
|
||||
anchor2: &RawVector,
|
||||
axes2: &RawRotation,
|
||||
) -> RawGenericJoint {
|
||||
let pos1 = Isometry::from_parts(anchor1.0.into(), axes1.0);
|
||||
let pos2 = Isometry::from_parts(anchor2.0.into(), axes2.0);
|
||||
Self(
|
||||
FixedJointBuilder::new()
|
||||
.local_frame1(pos1)
|
||||
.local_frame2(pos2)
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new joint descriptor that builds Revolute joints.
|
||||
///
|
||||
/// A revolute joint removes all degrees of freedom between the affected
|
||||
/// bodies except for the rotation.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn revolute(anchor1: &RawVector, anchor2: &RawVector) -> Option<RawGenericJoint> {
|
||||
Some(Self(
|
||||
RevoluteJointBuilder::new()
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Create a new joint descriptor that builds Revolute joints.
|
||||
///
|
||||
/// A revolute joint removes all degrees of freedom between the affected
|
||||
/// bodies except for the rotation along one axis.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn revolute(
|
||||
anchor1: &RawVector,
|
||||
anchor2: &RawVector,
|
||||
axis: &RawVector,
|
||||
) -> Option<RawGenericJoint> {
|
||||
let axis = Unit::try_new(axis.0, 0.0)?;
|
||||
Some(Self(
|
||||
RevoluteJointBuilder::new(axis)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
20
thirdparty/rapier.js/src/dynamics/mod.rs
vendored
Normal file
20
thirdparty/rapier.js/src/dynamics/mod.rs
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
//! Structures related to dynamics: bodies, joints, etc.
|
||||
|
||||
pub use self::ccd_solver::*;
|
||||
pub use self::impulse_joint_set::*;
|
||||
pub use self::integration_parameters::*;
|
||||
pub use self::island_manager::*;
|
||||
pub use self::joint::*;
|
||||
pub use self::multibody_joint_set::*;
|
||||
pub use self::rigid_body_set::*;
|
||||
|
||||
mod ccd_solver;
|
||||
mod impulse_joint;
|
||||
mod impulse_joint_set;
|
||||
mod integration_parameters;
|
||||
mod island_manager;
|
||||
mod joint;
|
||||
mod multibody_joint;
|
||||
mod multibody_joint_set;
|
||||
mod rigid_body;
|
||||
mod rigid_body_set;
|
||||
196
thirdparty/rapier.js/src/dynamics/multibody_joint.rs
vendored
Normal file
196
thirdparty/rapier.js/src/dynamics/multibody_joint.rs
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
use crate::dynamics::{RawJointAxis, RawJointType, RawMultibodyJointSet};
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use crate::utils::FlatHandle;
|
||||
use rapier::dynamics::JointAxis;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawMultibodyJointSet {
|
||||
/// The type of this joint.
|
||||
pub fn jointType(&self, handle: FlatHandle) -> RawJointType {
|
||||
self.map(handle, |j| j.data.locked_axes.into())
|
||||
}
|
||||
|
||||
// /// The unique integer identifier of the first rigid-body this joint it attached to.
|
||||
// pub fn jointBodyHandle1(&self, handle: FlatHandle) -> u32 {
|
||||
// self.map(handle, |j| j.body1.into_raw_parts().0)
|
||||
// }
|
||||
//
|
||||
// /// The unique integer identifier of the second rigid-body this joint is attached to.
|
||||
// pub fn jointBodyHandle2(&self, handle: FlatHandle) -> u32 {
|
||||
// self.map(handle, |j| j.body2.into_raw_parts().0)
|
||||
// }
|
||||
|
||||
/// The angular part of the joint’s local frame relative to the first rigid-body it is attached to.
|
||||
pub fn jointFrameX1(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |j| j.data.local_frame1.rotation.into())
|
||||
}
|
||||
|
||||
/// The angular part of the joint’s local frame relative to the second rigid-body it is attached to.
|
||||
pub fn jointFrameX2(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |j| j.data.local_frame2.rotation.into())
|
||||
}
|
||||
|
||||
/// The position of the first anchor of this joint.
|
||||
///
|
||||
/// The first anchor gives the position of the points application point on the
|
||||
/// local frame of the first rigid-body it is attached to.
|
||||
pub fn jointAnchor1(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |j| j.data.local_frame1.translation.vector.into())
|
||||
}
|
||||
|
||||
/// The position of the second anchor of this joint.
|
||||
///
|
||||
/// The second anchor gives the position of the points application point on the
|
||||
/// local frame of the second rigid-body it is attached to.
|
||||
pub fn jointAnchor2(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |j| j.data.local_frame2.translation.vector.into())
|
||||
}
|
||||
|
||||
/// Are contacts between the rigid-bodies attached by this joint enabled?
|
||||
pub fn jointContactsEnabled(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |j| j.data.contacts_enabled)
|
||||
}
|
||||
|
||||
/// Sets whether contacts are enabled between the rigid-bodies attached by this joint.
|
||||
pub fn jointSetContactsEnabled(&mut self, handle: FlatHandle, enabled: bool) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.contacts_enabled = enabled;
|
||||
});
|
||||
}
|
||||
|
||||
/// Are the limits for this joint enabled?
|
||||
pub fn jointLimitsEnabled(&self, handle: FlatHandle, axis: RawJointAxis) -> bool {
|
||||
self.map(handle, |j| {
|
||||
j.data.limit_axes.contains(JointAxis::from(axis).into())
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the lower limit along the given joint axis.
|
||||
pub fn jointLimitsMin(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 {
|
||||
self.map(handle, |j| j.data.limits[axis as usize].min)
|
||||
}
|
||||
|
||||
/// If this is a prismatic joint, returns its upper limit.
|
||||
pub fn jointLimitsMax(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 {
|
||||
self.map(handle, |j| j.data.limits[axis as usize].max)
|
||||
}
|
||||
|
||||
// pub fn jointConfigureMotorModel(
|
||||
// &mut self,
|
||||
// handle: FlatHandle,
|
||||
// axis: RawJointAxis,
|
||||
// model: RawMotorModel,
|
||||
// ) {
|
||||
// self.map_mut(handle, |j| {
|
||||
// j.data.motors[axis as usize].model = model.into()
|
||||
// })
|
||||
// }
|
||||
|
||||
/*
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotorVelocity(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
vx: f32,
|
||||
vy: f32,
|
||||
vz: f32,
|
||||
factor: f32,
|
||||
) {
|
||||
let targetVel = Vector3::new(vx, vy, vz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => j.configure_motor_velocity(targetVel, factor),
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotorPosition(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
qw: f32,
|
||||
qx: f32,
|
||||
qy: f32,
|
||||
qz: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
let quat = Quaternion::new(qw, qx, qy, qz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => {
|
||||
if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) {
|
||||
j.configure_motor_position(unit_quat, stiffness, damping)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotor(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
qw: f32,
|
||||
qx: f32,
|
||||
qy: f32,
|
||||
qz: f32,
|
||||
vx: f32,
|
||||
vy: f32,
|
||||
vz: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
let quat = Quaternion::new(qw, qx, qy, qz);
|
||||
let vel = Vector3::new(vx, vy, vz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => {
|
||||
if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) {
|
||||
j.configure_motor(unit_quat, vel, stiffness, damping)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
// pub fn jointConfigureMotorVelocity(
|
||||
// &mut self,
|
||||
// handle: FlatHandle,
|
||||
// axis: RawJointAxis,
|
||||
// targetVel: f32,
|
||||
// factor: f32,
|
||||
// ) {
|
||||
// self.jointConfigureMotor(handle, axis, 0.0, targetVel, 0.0, factor)
|
||||
// }
|
||||
//
|
||||
// pub fn jointConfigureMotorPosition(
|
||||
// &mut self,
|
||||
// handle: FlatHandle,
|
||||
// axis: RawJointAxis,
|
||||
// targetPos: f32,
|
||||
// stiffness: f32,
|
||||
// damping: f32,
|
||||
// ) {
|
||||
// self.jointConfigureMotor(handle, axis, targetPos, 0.0, stiffness, damping)
|
||||
// }
|
||||
|
||||
// pub fn jointConfigureMotor(
|
||||
// &mut self,
|
||||
// handle: FlatHandle,
|
||||
// axis: RawJointAxis,
|
||||
// targetPos: f32,
|
||||
// targetVel: f32,
|
||||
// stiffness: f32,
|
||||
// damping: f32,
|
||||
// ) {
|
||||
// self.map_mut(handle, |j| {
|
||||
// j.data.motors[axis as usize].target_pos = targetPos;
|
||||
// j.data.motors[axis as usize].target_vel = targetVel;
|
||||
// j.data.motors[axis as usize].stiffness = stiffness;
|
||||
// j.data.motors[axis as usize].damping = damping;
|
||||
// })
|
||||
// }
|
||||
}
|
||||
85
thirdparty/rapier.js/src/dynamics/multibody_joint_set.rs
vendored
Normal file
85
thirdparty/rapier.js/src/dynamics/multibody_joint_set.rs
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
use crate::dynamics::RawGenericJoint;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::dynamics::{MultibodyJoint, MultibodyJointSet};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawMultibodyJointSet(pub(crate) MultibodyJointSet);
|
||||
|
||||
impl RawMultibodyJointSet {
|
||||
pub(crate) fn map<T>(&self, handle: FlatHandle, f: impl FnOnce(&MultibodyJoint) -> T) -> T {
|
||||
let (body, link_id) = self
|
||||
.0
|
||||
.get(utils::multibody_joint_handle(handle))
|
||||
.expect("Invalid Joint reference. It may have been removed from the physics World.");
|
||||
f(body.link(link_id).unwrap().joint())
|
||||
}
|
||||
|
||||
pub(crate) fn map_mut<T>(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
f: impl FnOnce(&mut MultibodyJoint) -> T,
|
||||
) -> T {
|
||||
let (body, link_id) = self
|
||||
.0
|
||||
.get_mut(utils::multibody_joint_handle(handle))
|
||||
.expect("Invalid Joint reference. It may have been removed from the physics World.");
|
||||
f(&mut body.link_mut(link_id).unwrap().joint)
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawMultibodyJointSet {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawMultibodyJointSet(MultibodyJointSet::new())
|
||||
}
|
||||
|
||||
pub fn createJoint(
|
||||
&mut self,
|
||||
params: &RawGenericJoint,
|
||||
parent1: FlatHandle,
|
||||
parent2: FlatHandle,
|
||||
wakeUp: bool,
|
||||
) -> FlatHandle {
|
||||
// TODO: avoid the unwrap?
|
||||
let parent1 = utils::body_handle(parent1);
|
||||
let parent2 = utils::body_handle(parent2);
|
||||
|
||||
self.0
|
||||
.insert(parent1, parent2, params.0.clone(), wakeUp)
|
||||
.map(|h| utils::flat_handle(h.0))
|
||||
.unwrap_or(FlatHandle::MAX)
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, handle: FlatHandle, wakeUp: bool) {
|
||||
let handle = utils::multibody_joint_handle(handle);
|
||||
self.0.remove(handle, wakeUp);
|
||||
}
|
||||
|
||||
pub fn contains(&self, handle: FlatHandle) -> bool {
|
||||
self.0.get(utils::multibody_joint_handle(handle)).is_some()
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each joint managed by this physics world.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each joint managed by this set. Called as `f(collider)`.
|
||||
pub fn forEachJointHandle(&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)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each joint attached to the given rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each joint attached to the rigid-body. Called as `f(collider)`.
|
||||
pub fn forEachJointAttachedToRigidBody(&self, body: FlatHandle, f: &js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
for (_, _, handle) in self.0.attached_joints(utils::body_handle(body)) {
|
||||
let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
753
thirdparty/rapier.js/src/dynamics/rigid_body.rs
vendored
Normal file
753
thirdparty/rapier.js/src/dynamics/rigid_body.rs
vendored
Normal file
@@ -0,0 +1,753 @@
|
||||
use crate::dynamics::{RawRigidBodySet, RawRigidBodyType};
|
||||
use crate::geometry::RawColliderSet;
|
||||
#[cfg(feature = "dim3")]
|
||||
use crate::math::RawSdpMatrix3;
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use na::Point;
|
||||
use rapier::dynamics::MassProperties;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawRigidBodySet {
|
||||
/// The world-space translation of this rigid-body.
|
||||
pub fn rbTranslation(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| RawVector(rb.position().translation.vector))
|
||||
}
|
||||
|
||||
/// The world-space orientation of this rigid-body.
|
||||
pub fn rbRotation(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |rb| RawRotation(rb.position().rotation))
|
||||
}
|
||||
|
||||
/// Put the given rigid-body to sleep.
|
||||
pub fn rbSleep(&mut self, handle: FlatHandle) {
|
||||
self.map_mut(handle, |rb| rb.sleep());
|
||||
}
|
||||
|
||||
/// Is this rigid-body sleeping?
|
||||
pub fn rbIsSleeping(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_sleeping())
|
||||
}
|
||||
|
||||
/// Is the velocity of this rigid-body not zero?
|
||||
pub fn rbIsMoving(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_moving())
|
||||
}
|
||||
|
||||
/// The world-space predicted translation of this rigid-body.
|
||||
///
|
||||
/// If this rigid-body is kinematic this value is set by the `setNextKinematicTranslation`
|
||||
/// method and is used for estimating the kinematic body velocity at the next timestep.
|
||||
/// For non-kinematic bodies, this value is currently unspecified.
|
||||
pub fn rbNextTranslation(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| {
|
||||
RawVector(rb.next_position().translation.vector)
|
||||
})
|
||||
}
|
||||
|
||||
/// The world-space predicted orientation of this rigid-body.
|
||||
///
|
||||
/// If this rigid-body is kinematic this value is set by the `setNextKinematicRotation`
|
||||
/// method and is used for estimating the kinematic body velocity at the next timestep.
|
||||
/// For non-kinematic bodies, this value is currently unspecified.
|
||||
pub fn rbNextRotation(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |rb| RawRotation(rb.next_position().rotation))
|
||||
}
|
||||
|
||||
/// Sets the translation of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the world-space position of the rigid-body along the `x` axis.
|
||||
/// - `y`: the world-space position of the rigid-body along the `y` axis.
|
||||
/// - `z`: the world-space position of the rigid-body along the `z` axis.
|
||||
/// - `wakeUp`: forces the rigid-body to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetTranslation(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_translation(na::Vector3::new(x, y, z), wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the translation of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the world-space position of the rigid-body along the `x` axis.
|
||||
/// - `y`: the world-space position of the rigid-body along the `y` axis.
|
||||
/// - `wakeUp`: forces the rigid-body to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetTranslation(&mut self, handle: FlatHandle, x: f32, y: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_translation(na::Vector2::new(x, y), wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the rotation quaternion of this rigid-body.
|
||||
///
|
||||
/// 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 rigid-body to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetRotation(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
w: f32,
|
||||
wakeUp: bool,
|
||||
) {
|
||||
if let Some(q) = na::Unit::try_new(na::Quaternion::new(w, x, y, z), 0.0) {
|
||||
self.map_mut(handle, |rb| rb.set_rotation(q, wakeUp))
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the rotation angle of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `angle`: the rotation angle, in radians.
|
||||
/// - `wakeUp`: forces the rigid-body to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetRotation(&mut self, handle: FlatHandle, angle: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_rotation(na::UnitComplex::new(angle), wakeUp)
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the linear velocity of this rigid-body.
|
||||
pub fn rbSetLinvel(&mut self, handle: FlatHandle, linvel: &RawVector, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_linvel(linvel.0, wakeUp);
|
||||
});
|
||||
}
|
||||
|
||||
/// Sets the angular velocity of this rigid-body.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetAngvel(&mut self, handle: FlatHandle, angvel: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_angvel(angvel, wakeUp);
|
||||
});
|
||||
}
|
||||
|
||||
/// Sets the angular velocity of this rigid-body.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetAngvel(&mut self, handle: FlatHandle, angvel: &RawVector, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_angvel(angvel.0, wakeUp);
|
||||
});
|
||||
}
|
||||
|
||||
/// If this rigid body is kinematic, sets its future translation after the next timestep integration.
|
||||
///
|
||||
/// This should be used instead of `rigidBody.setTranslation` to make the dynamic object
|
||||
/// interacting with this kinematic body behave as expected. Internally, Rapier will compute
|
||||
/// an artificial velocity for this rigid-body from its current position and its next kinematic
|
||||
/// position. This velocity will be used to compute forces on dynamic bodies interacting with
|
||||
/// this body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the world-space position of the rigid-body along the `x` axis.
|
||||
/// - `y`: the world-space position of the rigid-body along the `y` axis.
|
||||
/// - `z`: the world-space position of the rigid-body along the `z` axis.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetNextKinematicTranslation(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_next_kinematic_translation(na::Vector3::new(x, y, z));
|
||||
})
|
||||
}
|
||||
|
||||
/// If this rigid body is kinematic, sets its future translation after the next timestep integration.
|
||||
///
|
||||
/// This should be used instead of `rigidBody.setTranslation` to make the dynamic object
|
||||
/// interacting with this kinematic body behave as expected. Internally, Rapier will compute
|
||||
/// an artificial velocity for this rigid-body from its current position and its next kinematic
|
||||
/// position. This velocity will be used to compute forces on dynamic bodies interacting with
|
||||
/// this body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the world-space position of the rigid-body along the `x` axis.
|
||||
/// - `y`: the world-space position of the rigid-body along the `y` axis.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetNextKinematicTranslation(&mut self, handle: FlatHandle, x: f32, y: f32) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_next_kinematic_translation(na::Vector2::new(x, y));
|
||||
})
|
||||
}
|
||||
|
||||
/// If this rigid body is kinematic, sets its future rotation after the next timestep integration.
|
||||
///
|
||||
/// This should be used instead of `rigidBody.setRotation` to make the dynamic object
|
||||
/// interacting with this kinematic body behave as expected. Internally, Rapier will compute
|
||||
/// an artificial velocity for this rigid-body from its current position and its next kinematic
|
||||
/// position. This velocity will be used to compute forces on dynamic bodies interacting with
|
||||
/// this body.
|
||||
///
|
||||
/// # 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.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetNextKinematicRotation(
|
||||
&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, |rb| {
|
||||
rb.set_next_kinematic_rotation(q);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// If this rigid body is kinematic, sets its future rotation after the next timestep integration.
|
||||
///
|
||||
/// This should be used instead of `rigidBody.setRotation` to make the dynamic object
|
||||
/// interacting with this kinematic body behave as expected. Internally, Rapier will compute
|
||||
/// an artificial velocity for this rigid-body from its current position and its next kinematic
|
||||
/// position. This velocity will be used to compute forces on dynamic bodies interacting with
|
||||
/// this body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `angle`: the rotation angle, in radians.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetNextKinematicRotation(&mut self, handle: FlatHandle, angle: f32) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_next_kinematic_rotation(na::UnitComplex::new(angle));
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbRecomputeMassPropertiesFromColliders(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
colliders: &RawColliderSet,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.recompute_mass_properties_from_colliders(&colliders.0)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbSetAdditionalMass(&mut self, handle: FlatHandle, mass: f32, wake_up: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_additional_mass(mass, wake_up);
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetAdditionalMassProperties(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
mass: f32,
|
||||
centerOfMass: &RawVector,
|
||||
principalAngularInertia: &RawVector,
|
||||
angularInertiaFrame: &RawRotation,
|
||||
wake_up: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
let mprops = MassProperties::with_principal_inertia_frame(
|
||||
centerOfMass.0.into(),
|
||||
mass,
|
||||
principalAngularInertia.0,
|
||||
angularInertiaFrame.0,
|
||||
);
|
||||
rb.set_additional_mass_properties(mprops, wake_up)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetAdditionalMassProperties(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
mass: f32,
|
||||
centerOfMass: &RawVector,
|
||||
principalAngularInertia: f32,
|
||||
wake_up: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
let props = MassProperties::new(centerOfMass.0.into(), mass, principalAngularInertia);
|
||||
rb.set_additional_mass_properties(props, wake_up)
|
||||
})
|
||||
}
|
||||
|
||||
/// The linear velocity of this rigid-body.
|
||||
pub fn rbLinvel(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| RawVector(*rb.linvel()))
|
||||
}
|
||||
|
||||
/// The angular velocity of this rigid-body.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbAngvel(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.angvel())
|
||||
}
|
||||
|
||||
/// The angular velocity of this rigid-body.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbAngvel(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| RawVector(*rb.angvel()))
|
||||
}
|
||||
|
||||
/// The velocity of the given world-space point on this rigid-body.
|
||||
pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector) -> RawVector {
|
||||
self.map(handle, |rb| {
|
||||
rb.velocity_at_point(&Point::from(point.0)).into()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbLockTranslations(&mut self, handle: FlatHandle, locked: bool, wake_up: bool) {
|
||||
self.map_mut(handle, |rb| rb.lock_translations(locked, wake_up))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetEnabledTranslations(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
allow_x: bool,
|
||||
allow_y: bool,
|
||||
wake_up: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_enabled_translations(allow_x, allow_y, wake_up)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetEnabledTranslations(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
allow_x: bool,
|
||||
allow_y: bool,
|
||||
allow_z: bool,
|
||||
wake_up: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_enabled_translations(allow_x, allow_y, allow_z, wake_up)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbLockRotations(&mut self, handle: FlatHandle, locked: bool, wake_up: bool) {
|
||||
self.map_mut(handle, |rb| rb.lock_rotations(locked, wake_up))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetEnabledRotations(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
allow_x: bool,
|
||||
allow_y: bool,
|
||||
allow_z: bool,
|
||||
wake_up: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_enabled_rotations(allow_x, allow_y, allow_z, wake_up)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbDominanceGroup(&self, handle: FlatHandle) -> i8 {
|
||||
self.map(handle, |rb| rb.dominance_group())
|
||||
}
|
||||
|
||||
pub fn rbSetDominanceGroup(&mut self, handle: FlatHandle, group: i8) {
|
||||
self.map_mut(handle, |rb| rb.set_dominance_group(group))
|
||||
}
|
||||
|
||||
pub fn rbEnableCcd(&mut self, handle: FlatHandle, enabled: bool) {
|
||||
self.map_mut(handle, |rb| rb.enable_ccd(enabled))
|
||||
}
|
||||
|
||||
pub fn rbSetSoftCcdPrediction(&mut self, handle: FlatHandle, prediction: f32) {
|
||||
self.map_mut(handle, |rb| rb.set_soft_ccd_prediction(prediction))
|
||||
}
|
||||
|
||||
/// The mass of this rigid-body.
|
||||
pub fn rbMass(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.mass())
|
||||
}
|
||||
|
||||
/// The inverse of the mass of a rigid-body.
|
||||
///
|
||||
/// If this is zero, the rigid-body is assumed to have infinite mass.
|
||||
pub fn rbInvMass(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.mass_properties().local_mprops.inv_mass)
|
||||
}
|
||||
|
||||
/// The inverse mass taking into account translation locking.
|
||||
pub fn rbEffectiveInvMass(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| rb.mass_properties().effective_inv_mass.into())
|
||||
}
|
||||
|
||||
/// The center of mass of a rigid-body expressed in its local-space.
|
||||
pub fn rbLocalCom(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().local_mprops.local_com.into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The world-space center of mass of the rigid-body.
|
||||
pub fn rbWorldCom(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| rb.mass_properties().world_com.into())
|
||||
}
|
||||
|
||||
/// The inverse of the principal angular inertia of the rigid-body.
|
||||
///
|
||||
/// Components set to zero are assumed to be infinite along the corresponding principal axis.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbInvPrincipalInertia(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties()
|
||||
.local_mprops
|
||||
.inv_principal_inertia
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The inverse of the principal angular inertia of the rigid-body.
|
||||
///
|
||||
/// Components set to zero are assumed to be infinite along the corresponding principal axis.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbInvPrincipalInertia(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties()
|
||||
.local_mprops
|
||||
.inv_principal_inertia
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
/// The principal vectors of the local angular inertia tensor of the rigid-body.
|
||||
pub fn rbPrincipalInertiaLocalFrame(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |rb| {
|
||||
RawRotation::from(
|
||||
rb.mass_properties()
|
||||
.local_mprops
|
||||
.principal_inertia_local_frame,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// The angular inertia along the principal inertia axes of the rigid-body.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbPrincipalInertia(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().local_mprops.principal_inertia().into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The angular inertia along the principal inertia axes of the rigid-body.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbPrincipalInertia(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().local_mprops.principal_inertia().into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The world-space inverse angular inertia tensor of the rigid-body,
|
||||
/// taking into account rotation locking.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbEffectiveWorldInvInertia(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().effective_world_inv_inertia.into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The world-space inverse angular inertia tensor of the rigid-body,
|
||||
/// taking into account rotation locking.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbEffectiveWorldInvInertia(&self, handle: FlatHandle) -> RawSdpMatrix3 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().effective_world_inv_inertia.into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The effective world-space angular inertia (that takes the potential rotation locking into account) of
|
||||
/// this rigid-body.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbEffectiveAngularInertia(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().effective_angular_inertia().into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The effective world-space angular inertia (that takes the potential rotation locking into account) of
|
||||
/// this rigid-body.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbEffectiveAngularInertia(&self, handle: FlatHandle) -> RawSdpMatrix3 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().effective_angular_inertia().into()
|
||||
})
|
||||
}
|
||||
|
||||
/// Wakes this rigid-body up.
|
||||
///
|
||||
/// A dynamic rigid-body that does not move during several consecutive frames will
|
||||
/// be put to sleep by the physics engine, i.e., it will stop being simulated in order
|
||||
/// to avoid useless computations.
|
||||
/// This method forces a sleeping rigid-body to wake-up. This is useful, e.g., before modifying
|
||||
/// the position of a dynamic body so that it is properly simulated afterwards.
|
||||
pub fn rbWakeUp(&mut self, handle: FlatHandle) {
|
||||
self.map_mut(handle, |rb| rb.wake_up(true))
|
||||
}
|
||||
|
||||
/// Is Continuous Collision Detection enabled for this rigid-body?
|
||||
pub fn rbIsCcdEnabled(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_ccd_enabled())
|
||||
}
|
||||
pub fn rbSoftCcdPrediction(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.soft_ccd_prediction())
|
||||
}
|
||||
|
||||
/// The number of colliders attached to this rigid-body.
|
||||
pub fn rbNumColliders(&self, handle: FlatHandle) -> usize {
|
||||
self.map(handle, |rb| rb.colliders().len())
|
||||
}
|
||||
|
||||
/// Retrieves the `i-th` collider attached to this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `at`: The index of the collider to retrieve. Must be a number in `[0, this.numColliders()[`.
|
||||
/// This index is **not** the same as the unique identifier of the collider.
|
||||
pub fn rbCollider(&self, handle: FlatHandle, at: usize) -> FlatHandle {
|
||||
self.map(handle, |rb| utils::flat_handle(rb.colliders()[at].0))
|
||||
}
|
||||
|
||||
/// The status of this rigid-body: fixed, dynamic, or kinematic.
|
||||
pub fn rbBodyType(&self, handle: FlatHandle) -> RawRigidBodyType {
|
||||
self.map(handle, |rb| rb.body_type().into())
|
||||
}
|
||||
|
||||
/// Set a new status for this rigid-body: fixed, dynamic, or kinematic.
|
||||
pub fn rbSetBodyType(&mut self, handle: FlatHandle, status: RawRigidBodyType, wake_up: bool) {
|
||||
self.map_mut(handle, |rb| rb.set_body_type(status.into(), wake_up));
|
||||
}
|
||||
|
||||
/// Is this rigid-body fixed?
|
||||
pub fn rbIsFixed(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_fixed())
|
||||
}
|
||||
|
||||
/// Is this rigid-body kinematic?
|
||||
pub fn rbIsKinematic(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_kinematic())
|
||||
}
|
||||
|
||||
/// Is this rigid-body dynamic?
|
||||
pub fn rbIsDynamic(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_dynamic())
|
||||
}
|
||||
|
||||
/// The linear damping coefficient of this rigid-body.
|
||||
pub fn rbLinearDamping(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.linear_damping())
|
||||
}
|
||||
|
||||
/// The angular damping coefficient of this rigid-body.
|
||||
pub fn rbAngularDamping(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.angular_damping())
|
||||
}
|
||||
|
||||
pub fn rbSetLinearDamping(&mut self, handle: FlatHandle, factor: f32) {
|
||||
self.map_mut(handle, |rb| rb.set_linear_damping(factor));
|
||||
}
|
||||
|
||||
pub fn rbSetAngularDamping(&mut self, handle: FlatHandle, factor: f32) {
|
||||
self.map_mut(handle, |rb| rb.set_angular_damping(factor));
|
||||
}
|
||||
|
||||
pub fn rbSetEnabled(&mut self, handle: FlatHandle, enabled: bool) {
|
||||
self.map_mut(handle, |rb| rb.set_enabled(enabled))
|
||||
}
|
||||
|
||||
pub fn rbIsEnabled(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_enabled())
|
||||
}
|
||||
|
||||
pub fn rbGravityScale(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.gravity_scale())
|
||||
}
|
||||
|
||||
pub fn rbSetGravityScale(&mut self, handle: FlatHandle, factor: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| rb.set_gravity_scale(factor, wakeUp));
|
||||
}
|
||||
|
||||
/// Resets to zero all user-added forces added to this rigid-body.
|
||||
pub fn rbResetForces(&mut self, handle: FlatHandle, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.reset_forces(wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Resets to zero all user-added torques added to this rigid-body.
|
||||
pub fn rbResetTorques(&mut self, handle: FlatHandle, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.reset_torques(wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds a force at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `force`: the world-space force to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
pub fn rbAddForce(&mut self, handle: FlatHandle, force: &RawVector, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.add_force(force.0, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Applies an impulse at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `impulse`: the world-space impulse to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
pub fn rbApplyImpulse(&mut self, handle: FlatHandle, impulse: &RawVector, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.apply_impulse(impulse.0, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds a torque at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `torque`: the torque to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbAddTorque(&mut self, handle: FlatHandle, torque: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.add_torque(torque, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds a torque at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `torque`: the world-space torque to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbAddTorque(&mut self, handle: FlatHandle, torque: &RawVector, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.add_torque(torque.0, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Applies an impulsive torque at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `torque impulse`: the torque impulse to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbApplyTorqueImpulse(&mut self, handle: FlatHandle, torque_impulse: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.apply_torque_impulse(torque_impulse, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Applies an impulsive torque at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `torque impulse`: the world-space torque impulse to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbApplyTorqueImpulse(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
torque_impulse: &RawVector,
|
||||
wakeUp: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.apply_torque_impulse(torque_impulse.0, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds a force at the given world-space point of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `force`: the world-space force to apply on the rigid-body.
|
||||
/// - `point`: the world-space point where the impulse is to be applied on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
pub fn rbAddForceAtPoint(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
force: &RawVector,
|
||||
point: &RawVector,
|
||||
wakeUp: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.add_force_at_point(force.0, point.0.into(), wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Applies an impulse at the given world-space point of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `impulse`: the world-space impulse to apply on the rigid-body.
|
||||
/// - `point`: the world-space point where the impulse is to be applied on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
pub fn rbApplyImpulseAtPoint(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
impulse: &RawVector,
|
||||
point: &RawVector,
|
||||
wakeUp: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.apply_impulse_at_point(impulse.0, point.0.into(), wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbAdditionalSolverIterations(&self, handle: FlatHandle) -> usize {
|
||||
self.map(handle, |rb| rb.additional_solver_iterations())
|
||||
}
|
||||
|
||||
pub fn rbSetAdditionalSolverIterations(&mut self, handle: FlatHandle, iters: usize) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_additional_solver_iterations(iters as usize);
|
||||
})
|
||||
}
|
||||
|
||||
/// An arbitrary user-defined 32-bit integer
|
||||
pub fn rbUserData(&self, handle: FlatHandle) -> u32 {
|
||||
self.map(handle, |rb| rb.user_data as u32)
|
||||
}
|
||||
|
||||
/// Sets the user-defined 32-bit integer of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `data`: an arbitrary user-defined 32-bit integer.
|
||||
pub fn rbSetUserData(&mut self, handle: FlatHandle, data: u32) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.user_data = data as u128;
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieves the constant force(s) the user added to this rigid-body.
|
||||
/// Returns zero if the rigid-body is not dynamic.
|
||||
pub fn rbUserForce(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| rb.user_force().into())
|
||||
}
|
||||
|
||||
/// Retrieves the constant torque(s) the user added to this rigid-body.
|
||||
/// Returns zero if the rigid-body is not dynamic.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbUserTorque(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.user_torque())
|
||||
}
|
||||
|
||||
/// Retrieves the constant torque(s) the user added to this rigid-body.
|
||||
/// Returns zero if the rigid-body is not dynamic.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbUserTorque(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| rb.user_torque().into())
|
||||
}
|
||||
}
|
||||
237
thirdparty/rapier.js/src/dynamics/rigid_body_set.rs
vendored
Normal file
237
thirdparty/rapier.js/src/dynamics/rigid_body_set.rs
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
use crate::dynamics::{RawImpulseJointSet, RawIslandManager, RawMultibodyJointSet};
|
||||
use crate::geometry::RawColliderSet;
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::dynamics::{MassProperties, RigidBody, RigidBodyBuilder, RigidBodySet, RigidBodyType};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub enum RawRigidBodyType {
|
||||
Dynamic,
|
||||
Fixed,
|
||||
KinematicPositionBased,
|
||||
KinematicVelocityBased,
|
||||
}
|
||||
|
||||
impl Into<RigidBodyType> for RawRigidBodyType {
|
||||
fn into(self) -> RigidBodyType {
|
||||
match self {
|
||||
RawRigidBodyType::Dynamic => RigidBodyType::Dynamic,
|
||||
RawRigidBodyType::Fixed => RigidBodyType::Fixed,
|
||||
RawRigidBodyType::KinematicPositionBased => RigidBodyType::KinematicPositionBased,
|
||||
RawRigidBodyType::KinematicVelocityBased => RigidBodyType::KinematicVelocityBased,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<RawRigidBodyType> for RigidBodyType {
|
||||
fn into(self) -> RawRigidBodyType {
|
||||
match self {
|
||||
RigidBodyType::Dynamic => RawRigidBodyType::Dynamic,
|
||||
RigidBodyType::Fixed => RawRigidBodyType::Fixed,
|
||||
RigidBodyType::KinematicPositionBased => RawRigidBodyType::KinematicPositionBased,
|
||||
RigidBodyType::KinematicVelocityBased => RawRigidBodyType::KinematicVelocityBased,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawRigidBodySet(pub(crate) RigidBodySet);
|
||||
|
||||
impl RawRigidBodySet {
|
||||
pub(crate) fn map<T>(&self, handle: FlatHandle, f: impl FnOnce(&RigidBody) -> T) -> T {
|
||||
let body = self.0.get(utils::body_handle(handle)).expect(
|
||||
"Invalid RigidBody reference. It may have been removed from the physics World.",
|
||||
);
|
||||
f(body)
|
||||
}
|
||||
|
||||
pub(crate) fn map_mut<T>(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
f: impl FnOnce(&mut RigidBody) -> T,
|
||||
) -> T {
|
||||
let body = self.0.get_mut(utils::body_handle(handle)).expect(
|
||||
"Invalid RigidBody reference. It may have been removed from the physics World.",
|
||||
);
|
||||
f(body)
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawRigidBodySet {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawRigidBodySet(RigidBodySet::new())
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn createRigidBody(
|
||||
&mut self,
|
||||
enabled: bool,
|
||||
translation: &RawVector,
|
||||
rotation: &RawRotation,
|
||||
gravityScale: f32,
|
||||
mass: f32,
|
||||
massOnly: bool,
|
||||
centerOfMass: &RawVector,
|
||||
linvel: &RawVector,
|
||||
angvel: &RawVector,
|
||||
principalAngularInertia: &RawVector,
|
||||
angularInertiaFrame: &RawRotation,
|
||||
translationEnabledX: bool,
|
||||
translationEnabledY: bool,
|
||||
translationEnabledZ: bool,
|
||||
rotationEnabledX: bool,
|
||||
rotationEnabledY: bool,
|
||||
rotationEnabledZ: bool,
|
||||
linearDamping: f32,
|
||||
angularDamping: f32,
|
||||
rb_type: RawRigidBodyType,
|
||||
canSleep: bool,
|
||||
sleeping: bool,
|
||||
softCcdPrediction: f32,
|
||||
ccdEnabled: bool,
|
||||
dominanceGroup: i8,
|
||||
additional_solver_iterations: usize,
|
||||
) -> FlatHandle {
|
||||
let pos = na::Isometry3::from_parts(translation.0.into(), rotation.0);
|
||||
|
||||
let mut rigid_body = RigidBodyBuilder::new(rb_type.into())
|
||||
.enabled(enabled)
|
||||
.pose(pos)
|
||||
.gravity_scale(gravityScale)
|
||||
.enabled_translations(
|
||||
translationEnabledX,
|
||||
translationEnabledY,
|
||||
translationEnabledZ,
|
||||
)
|
||||
.enabled_rotations(rotationEnabledX, rotationEnabledY, rotationEnabledZ)
|
||||
.linvel(linvel.0)
|
||||
.angvel(angvel.0)
|
||||
.linear_damping(linearDamping)
|
||||
.angular_damping(angularDamping)
|
||||
.can_sleep(canSleep)
|
||||
.sleeping(sleeping)
|
||||
.ccd_enabled(ccdEnabled)
|
||||
.dominance_group(dominanceGroup)
|
||||
.additional_solver_iterations(additional_solver_iterations)
|
||||
.soft_ccd_prediction(softCcdPrediction);
|
||||
|
||||
rigid_body = if massOnly {
|
||||
rigid_body.additional_mass(mass)
|
||||
} else {
|
||||
let props = MassProperties::with_principal_inertia_frame(
|
||||
centerOfMass.0.into(),
|
||||
mass,
|
||||
principalAngularInertia.0,
|
||||
angularInertiaFrame.0,
|
||||
);
|
||||
rigid_body.additional_mass_properties(props)
|
||||
};
|
||||
|
||||
utils::flat_handle(self.0.insert(rigid_body.build()).0)
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn createRigidBody(
|
||||
&mut self,
|
||||
enabled: bool,
|
||||
translation: &RawVector,
|
||||
rotation: &RawRotation,
|
||||
gravityScale: f32,
|
||||
mass: f32,
|
||||
massOnly: bool,
|
||||
centerOfMass: &RawVector,
|
||||
linvel: &RawVector,
|
||||
angvel: f32,
|
||||
principalAngularInertia: f32,
|
||||
translationEnabledX: bool,
|
||||
translationEnabledY: bool,
|
||||
rotationsEnabled: bool,
|
||||
linearDamping: f32,
|
||||
angularDamping: f32,
|
||||
rb_type: RawRigidBodyType,
|
||||
canSleep: bool,
|
||||
sleeping: bool,
|
||||
softCcdPrediciton: f32,
|
||||
ccdEnabled: bool,
|
||||
dominanceGroup: i8,
|
||||
additional_solver_iterations: usize,
|
||||
) -> FlatHandle {
|
||||
let pos = na::Isometry2::from_parts(translation.0.into(), rotation.0);
|
||||
let mut rigid_body = RigidBodyBuilder::new(rb_type.into())
|
||||
.enabled(enabled)
|
||||
.pose(pos)
|
||||
.gravity_scale(gravityScale)
|
||||
.enabled_translations(translationEnabledX, translationEnabledY)
|
||||
.linvel(linvel.0)
|
||||
.angvel(angvel)
|
||||
.linear_damping(linearDamping)
|
||||
.angular_damping(angularDamping)
|
||||
.can_sleep(canSleep)
|
||||
.sleeping(sleeping)
|
||||
.ccd_enabled(ccdEnabled)
|
||||
.dominance_group(dominanceGroup)
|
||||
.additional_solver_iterations(additional_solver_iterations)
|
||||
.soft_ccd_prediction(softCcdPrediciton);
|
||||
|
||||
rigid_body = if massOnly {
|
||||
rigid_body.additional_mass(mass)
|
||||
} else {
|
||||
let props = MassProperties::new(centerOfMass.0.into(), mass, principalAngularInertia);
|
||||
rigid_body.additional_mass_properties(props)
|
||||
};
|
||||
|
||||
if !rotationsEnabled {
|
||||
rigid_body = rigid_body.lock_rotations();
|
||||
}
|
||||
|
||||
utils::flat_handle(self.0.insert(rigid_body.build()).0)
|
||||
}
|
||||
|
||||
pub fn remove(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
islands: &mut RawIslandManager,
|
||||
colliders: &mut RawColliderSet,
|
||||
joints: &mut RawImpulseJointSet,
|
||||
articulations: &mut RawMultibodyJointSet,
|
||||
) {
|
||||
let handle = utils::body_handle(handle);
|
||||
self.0.remove(
|
||||
handle,
|
||||
&mut islands.0,
|
||||
&mut colliders.0,
|
||||
&mut joints.0,
|
||||
&mut articulations.0,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
/// The number of rigid-bodies on this set.
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// Checks if a rigid-body with the given integer handle exists.
|
||||
pub fn contains(&self, handle: FlatHandle) -> bool {
|
||||
self.0.get(utils::body_handle(handle)).is_some()
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each rigid-body managed by this set.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each rigid-body managed by this set. Called as `f(collider)`.
|
||||
pub fn forEachRigidBodyHandle(&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)));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn propagateModifiedBodyPositionsToColliders(&mut self, colliders: &mut RawColliderSet) {
|
||||
self.0
|
||||
.propagate_modified_body_positions_to_colliders(&mut colliders.0);
|
||||
}
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
32
thirdparty/rapier.js/src/lib.rs
vendored
Normal file
32
thirdparty/rapier.js/src/lib.rs
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
//! # Rapier
|
||||
//! Fast and deterministic WASM physics engine.
|
||||
|
||||
#![allow(non_snake_case)] // JS uses camelCase, so we will follow its convention for the generated bindings.
|
||||
// #![deny(missing_docs)]
|
||||
|
||||
extern crate nalgebra as na;
|
||||
#[cfg(feature = "dim2")]
|
||||
extern crate rapier2d as rapier;
|
||||
#[cfg(feature = "dim3")]
|
||||
extern crate rapier3d as rapier;
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||
pub fn version() -> String {
|
||||
env!("CARGO_PKG_VERSION").to_string()
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||
pub fn reserve_memory(extra_bytes_count: u32) {
|
||||
let mut unused: Vec<u8> = vec![];
|
||||
unused.reserve(extra_bytes_count as usize);
|
||||
std::hint::black_box(&unused);
|
||||
}
|
||||
|
||||
pub mod control;
|
||||
pub mod dynamics;
|
||||
pub mod geometry;
|
||||
pub mod math;
|
||||
pub mod pipeline;
|
||||
pub mod utils;
|
||||
266
thirdparty/rapier.js/src/math.rs
vendored
Normal file
266
thirdparty/rapier.js/src/math.rs
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
//! Linear algebra primitives.
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
use js_sys::Float32Array;
|
||||
#[cfg(feature = "dim3")]
|
||||
use na::{Quaternion, Unit};
|
||||
#[cfg(feature = "dim3")]
|
||||
use rapier::math::Real;
|
||||
use rapier::math::{Point, Rotation, Vector};
|
||||
#[cfg(feature = "dim3")]
|
||||
use rapier::parry::utils::SdpMatrix3;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone)]
|
||||
/// A rotation quaternion.
|
||||
pub struct RawRotation(pub(crate) Rotation<f32>);
|
||||
|
||||
impl From<Rotation<f32>> for RawRotation {
|
||||
fn from(v: Rotation<f32>) -> Self {
|
||||
RawRotation(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[cfg(feature = "dim2")]
|
||||
/// A unit complex number describing the orientation of a Rapier entity.
|
||||
impl RawRotation {
|
||||
/// The identity rotation.
|
||||
pub fn identity() -> Self {
|
||||
Self(Rotation::identity())
|
||||
}
|
||||
|
||||
/// The rotation with thegiven angle.
|
||||
pub fn fromAngle(angle: f32) -> Self {
|
||||
Self(Rotation::new(angle))
|
||||
}
|
||||
|
||||
/// The imaginary part of this complex number.
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn im(&self) -> f32 {
|
||||
self.0.im
|
||||
}
|
||||
|
||||
/// The real part of this complex number.
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn re(&self) -> f32 {
|
||||
self.0.re
|
||||
}
|
||||
|
||||
/// The rotation angle in radians.
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn angle(&self) -> f32 {
|
||||
self.0.angle()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[cfg(feature = "dim3")]
|
||||
/// A unit quaternion describing the orientation of a Rapier entity.
|
||||
impl RawRotation {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
|
||||
RawRotation(Unit::new_unchecked(Quaternion::new(w, x, y, z)))
|
||||
}
|
||||
|
||||
/// The identity quaternion.
|
||||
pub fn identity() -> Self {
|
||||
Self(Rotation::identity())
|
||||
}
|
||||
|
||||
/// The `x` component of this quaternion.
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn x(&self) -> f32 {
|
||||
self.0.i
|
||||
}
|
||||
|
||||
/// The `y` component of this quaternion.
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn y(&self) -> f32 {
|
||||
self.0.j
|
||||
}
|
||||
|
||||
/// The `z` component of this quaternion.
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn z(&self) -> f32 {
|
||||
self.0.k
|
||||
}
|
||||
|
||||
/// The `w` component of this quaternion.
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn w(&self) -> f32 {
|
||||
self.0.w
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone)]
|
||||
/// A vector.
|
||||
pub struct RawVector(pub(crate) Vector<f32>);
|
||||
|
||||
impl From<Vector<f32>> for RawVector {
|
||||
fn from(v: Vector<f32>) -> Self {
|
||||
RawVector(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Point<f32>> for RawVector {
|
||||
fn from(pt: Point<f32>) -> Self {
|
||||
pt.coords.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawVector {
|
||||
/// Creates a new vector filled with zeros.
|
||||
pub fn zero() -> Self {
|
||||
Self(Vector::zeros())
|
||||
}
|
||||
|
||||
/// Creates a new 2D vector from its two components.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the `x` component of this 2D vector.
|
||||
/// - `y`: the `y` component of this 2D vector.
|
||||
#[cfg(feature = "dim2")]
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(x: f32, y: f32) -> Self {
|
||||
Self(Vector::new(x, y))
|
||||
}
|
||||
|
||||
/// Creates a new 3D vector from its two components.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the `x` component of this 3D vector.
|
||||
/// - `y`: the `y` component of this 3D vector.
|
||||
/// - `z`: the `z` component of this 3D vector.
|
||||
#[cfg(feature = "dim3")]
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(x: f32, y: f32, z: f32) -> Self {
|
||||
Self(Vector::new(x, y, z))
|
||||
}
|
||||
|
||||
/// The `x` component of this vector.
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn x(&self) -> f32 {
|
||||
self.0.x
|
||||
}
|
||||
|
||||
/// Sets the `x` component of this vector.
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_x(&mut self, x: f32) {
|
||||
self.0.x = x
|
||||
}
|
||||
|
||||
/// The `y` component of this vector.
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn y(&self) -> f32 {
|
||||
self.0.y
|
||||
}
|
||||
|
||||
/// Sets the `y` component of this vector.
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_y(&mut self, y: f32) {
|
||||
self.0.y = y
|
||||
}
|
||||
|
||||
/// The `z` component of this vector.
|
||||
#[cfg(feature = "dim3")]
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn z(&self) -> f32 {
|
||||
self.0.z
|
||||
}
|
||||
|
||||
/// Sets the `z` component of this vector.
|
||||
#[cfg(feature = "dim3")]
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_z(&mut self, z: f32) {
|
||||
self.0.z = z
|
||||
}
|
||||
|
||||
/// Create a new 2D vector from this vector with its components rearranged as `{x, y}`.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn xy(&self) -> Self {
|
||||
Self(self.0.xy())
|
||||
}
|
||||
|
||||
/// Create a new 2D vector from this vector with its components rearranged as `{y, x}`.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn yx(&self) -> Self {
|
||||
Self(self.0.yx())
|
||||
}
|
||||
|
||||
/// Create a new 2D vector from this vector with its components rearranged as `{z, y}`.
|
||||
#[cfg(feature = "dim2")]
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn zy(&self) -> Self {
|
||||
Self(self.0.zy())
|
||||
}
|
||||
|
||||
/// Create a new 3D vector from this vector with its components rearranged as `{x, y, z}`.
|
||||
///
|
||||
/// This will effectively return a copy of `this`. This method exist for completeness with the
|
||||
/// other swizzling functions.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn xyz(&self) -> Self {
|
||||
Self(self.0.xyz())
|
||||
}
|
||||
|
||||
/// Create a new 3D vector from this vector with its components rearranged as `{y, x, z}`.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn yxz(&self) -> Self {
|
||||
Self(self.0.yxz())
|
||||
}
|
||||
|
||||
/// Create a new 3D vector from this vector with its components rearranged as `{z, x, y}`.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn zxy(&self) -> Self {
|
||||
Self(self.0.zxy())
|
||||
}
|
||||
|
||||
/// Create a new 3D vector from this vector with its components rearranged as `{x, z, y}`.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn xzy(&self) -> Self {
|
||||
Self(self.0.xzy())
|
||||
}
|
||||
|
||||
/// Create a new 3D vector from this vector with its components rearranged as `{y, z, x}`.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn yzx(&self) -> Self {
|
||||
Self(self.0.yzx())
|
||||
}
|
||||
|
||||
/// Create a new 3D vector from this vector with its components rearranged as `{z, y, x}`.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn zyx(&self) -> Self {
|
||||
Self(self.0.zyx())
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg(feature = "dim3")]
|
||||
pub struct RawSdpMatrix3(pub(crate) SdpMatrix3<Real>);
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
impl From<SdpMatrix3<Real>> for RawSdpMatrix3 {
|
||||
fn from(v: SdpMatrix3<Real>) -> Self {
|
||||
RawSdpMatrix3(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[cfg(feature = "dim3")]
|
||||
impl RawSdpMatrix3 {
|
||||
/// Row major list of the upper-triangular part of the symmetric matrix.
|
||||
pub fn elements(&self) -> Float32Array {
|
||||
let m = self.0;
|
||||
let output = Float32Array::new_with_length(6);
|
||||
output.copy_from(&[m.m11, m.m12, m.m13, m.m22, m.m23, m.m33]);
|
||||
output
|
||||
}
|
||||
}
|
||||
152
thirdparty/rapier.js/src/pipeline/debug_render_pipeline.rs
vendored
Normal file
152
thirdparty/rapier.js/src/pipeline/debug_render_pipeline.rs
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
use crate::dynamics::{RawImpulseJointSet, RawMultibodyJointSet, RawRigidBodySet};
|
||||
use crate::geometry::{RawColliderSet, RawNarrowPhase};
|
||||
use js_sys::Float32Array;
|
||||
use palette::convert::IntoColorUnclamped;
|
||||
use palette::rgb::Rgba;
|
||||
use palette::Hsla;
|
||||
use rapier::dynamics::{RigidBody, RigidBodySet};
|
||||
use rapier::geometry::ColliderSet;
|
||||
use rapier::math::{Point, Real};
|
||||
use rapier::pipeline::{DebugRenderBackend, DebugRenderObject, DebugRenderPipeline};
|
||||
use rapier::prelude::{QueryFilter, QueryFilterFlags};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawDebugRenderPipeline {
|
||||
pub(crate) raw: DebugRenderPipeline,
|
||||
vertices: Vec<f32>,
|
||||
colors: Vec<f32>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawDebugRenderPipeline {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawDebugRenderPipeline {
|
||||
raw: DebugRenderPipeline::default(),
|
||||
vertices: vec![],
|
||||
colors: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vertices(&self) -> Float32Array {
|
||||
let output = Float32Array::new_with_length(self.vertices.len() as u32);
|
||||
output.copy_from(&self.vertices);
|
||||
output
|
||||
}
|
||||
|
||||
pub fn colors(&self) -> Float32Array {
|
||||
let output = Float32Array::new_with_length(self.colors.len() as u32);
|
||||
output.copy_from(&self.colors);
|
||||
output
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
&mut self,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
impulse_joints: &RawImpulseJointSet,
|
||||
multibody_joints: &RawMultibodyJointSet,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
filter_flags: u32,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) {
|
||||
self.vertices.clear();
|
||||
self.colors.clear();
|
||||
|
||||
crate::utils::with_filter(filter_predicate, |predicate| {
|
||||
let mut backend = CopyToBuffersBackend {
|
||||
filter: QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: None,
|
||||
exclude_collider: None,
|
||||
exclude_rigid_body: None,
|
||||
predicate,
|
||||
},
|
||||
bodies: &bodies.0,
|
||||
colliders: &colliders.0,
|
||||
vertices: &mut self.vertices,
|
||||
colors: &mut self.colors,
|
||||
};
|
||||
|
||||
self.raw.render(
|
||||
&mut backend,
|
||||
&bodies.0,
|
||||
&colliders.0,
|
||||
&impulse_joints.0,
|
||||
&multibody_joints.0,
|
||||
&narrow_phase.0,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct CopyToBuffersBackend<'a> {
|
||||
filter: QueryFilter<'a>,
|
||||
bodies: &'a RigidBodySet,
|
||||
colliders: &'a ColliderSet,
|
||||
vertices: &'a mut Vec<f32>,
|
||||
colors: &'a mut Vec<f32>,
|
||||
}
|
||||
|
||||
impl<'a> DebugRenderBackend for CopyToBuffersBackend<'a> {
|
||||
fn filter_object(&self, object: DebugRenderObject) -> bool {
|
||||
let test_rigid_body = |rb: &RigidBody| {
|
||||
rb.colliders().iter().all(|handle| {
|
||||
let Some(co) = self.colliders.get(*handle) else {
|
||||
return false;
|
||||
};
|
||||
self.filter.test(self.bodies, *handle, co)
|
||||
})
|
||||
};
|
||||
|
||||
match object {
|
||||
DebugRenderObject::Collider(handle, co)
|
||||
| DebugRenderObject::ColliderAabb(handle, co, _) => {
|
||||
self.filter.test(self.bodies, handle, co)
|
||||
}
|
||||
DebugRenderObject::ContactPair(pair, co1, co2) => {
|
||||
self.filter.test(self.bodies, pair.collider1, co1)
|
||||
&& self.filter.test(self.bodies, pair.collider2, co2)
|
||||
}
|
||||
DebugRenderObject::ImpulseJoint(_, joint) => {
|
||||
let Some(rb1) = self.bodies.get(joint.body1) else {
|
||||
return false;
|
||||
};
|
||||
let Some(rb2) = self.bodies.get(joint.body2) else {
|
||||
return false;
|
||||
};
|
||||
test_rigid_body(rb1) && test_rigid_body(rb2)
|
||||
}
|
||||
DebugRenderObject::MultibodyJoint(_, _, link) => {
|
||||
let Some(rb) = self.bodies.get(link.rigid_body_handle()) else {
|
||||
return false;
|
||||
};
|
||||
test_rigid_body(rb)
|
||||
}
|
||||
DebugRenderObject::RigidBody(_, rb) => test_rigid_body(rb),
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws a colored line.
|
||||
///
|
||||
/// Note that this method can be called multiple time for the same `object`.
|
||||
fn draw_line(
|
||||
&mut self,
|
||||
_object: DebugRenderObject,
|
||||
a: Point<Real>,
|
||||
b: Point<Real>,
|
||||
color: [f32; 4],
|
||||
) {
|
||||
self.vertices.extend_from_slice(a.coords.as_slice());
|
||||
self.vertices.extend_from_slice(b.coords.as_slice());
|
||||
|
||||
// Convert to RGB which will be easier to handle in JS.
|
||||
let hsl = Hsla::new(color[0], color[1], color[2], color[3]);
|
||||
let rgb: Rgba = hsl.into_color_unclamped();
|
||||
self.colors.extend_from_slice(&[
|
||||
rgb.red, rgb.green, rgb.blue, rgb.alpha, rgb.red, rgb.green, rgb.blue, rgb.alpha,
|
||||
]);
|
||||
}
|
||||
}
|
||||
140
thirdparty/rapier.js/src/pipeline/event_queue.rs
vendored
Normal file
140
thirdparty/rapier.js/src/pipeline/event_queue.rs
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
use crate::math::RawVector;
|
||||
use crate::utils;
|
||||
use crate::utils::FlatHandle;
|
||||
use rapier::geometry::{CollisionEvent, ContactForceEvent};
|
||||
use rapier::pipeline::ChannelEventCollector;
|
||||
use std::sync::mpsc::Receiver;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
/// A structure responsible for collecting events generated
|
||||
/// by the physics engine.
|
||||
#[wasm_bindgen]
|
||||
pub struct RawEventQueue {
|
||||
pub(crate) collector: ChannelEventCollector,
|
||||
collision_events: Receiver<CollisionEvent>,
|
||||
contact_force_events: Receiver<ContactForceEvent>,
|
||||
pub(crate) auto_drain: bool,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawContactForceEvent(ContactForceEvent);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawContactForceEvent {
|
||||
/// The first collider involved in the contact.
|
||||
pub fn collider1(&self) -> FlatHandle {
|
||||
crate::utils::flat_handle(self.0.collider1.0)
|
||||
}
|
||||
|
||||
/// The second collider involved in the contact.
|
||||
pub fn collider2(&self) -> FlatHandle {
|
||||
crate::utils::flat_handle(self.0.collider2.0)
|
||||
}
|
||||
|
||||
/// The sum of all the forces between the two colliders.
|
||||
pub fn total_force(&self) -> RawVector {
|
||||
RawVector(self.0.total_force)
|
||||
}
|
||||
|
||||
/// The sum of the magnitudes of each force between the two colliders.
|
||||
///
|
||||
/// Note that this is **not** the same as the magnitude of `self.total_force`.
|
||||
/// Here we are summing the magnitude of all the forces, instead of taking
|
||||
/// the magnitude of their sum.
|
||||
pub fn total_force_magnitude(&self) -> f32 {
|
||||
self.0.total_force_magnitude
|
||||
}
|
||||
|
||||
/// The world-space (unit) direction of the force with strongest magnitude.
|
||||
pub fn max_force_direction(&self) -> RawVector {
|
||||
RawVector(self.0.max_force_direction)
|
||||
}
|
||||
|
||||
/// The magnitude of the largest force at a contact point of this contact pair.
|
||||
pub fn max_force_magnitude(&self) -> f32 {
|
||||
self.0.max_force_magnitude
|
||||
}
|
||||
}
|
||||
|
||||
// #[wasm_bindgen]
|
||||
// /// The proximity state of a sensor collider and another collider.
|
||||
// pub enum RawIntersection {
|
||||
// /// The sensor is intersecting the other collider.
|
||||
// Intersecting = 0,
|
||||
// /// The sensor is within tolerance margin of the other collider.
|
||||
// WithinMargin = 1,
|
||||
// /// The sensor is disjoint from the other collider.
|
||||
// Disjoint = 2,
|
||||
// }
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawEventQueue {
|
||||
/// Creates a new event collector.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `autoDrain`: setting this to `true` is strongly recommended. If true, the collector will
|
||||
/// be automatically drained before each `world.step(collector)`. If false, the collector will
|
||||
/// keep all events in memory unless it is manually drained/cleared; this may lead to unbounded use of
|
||||
/// RAM if no drain is performed.
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(autoDrain: bool) -> Self {
|
||||
let collision_channel = std::sync::mpsc::channel();
|
||||
let contact_force_channel = std::sync::mpsc::channel();
|
||||
let collector = ChannelEventCollector::new(collision_channel.0, contact_force_channel.0);
|
||||
|
||||
Self {
|
||||
collector,
|
||||
collision_events: collision_channel.1,
|
||||
contact_force_events: contact_force_channel.1,
|
||||
auto_drain: autoDrain,
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies the given javascript closure on each collision event of this collector, then clear
|
||||
/// the internal collision event buffer.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle1, handle2, started)`: JavaScript closure applied to each collision event. The
|
||||
/// closure should take three arguments: two integers representing the handles of the colliders
|
||||
/// involved in the collision, and a boolean indicating if the collision started (true) or stopped
|
||||
/// (false).
|
||||
pub fn drainCollisionEvents(&mut self, f: &js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
while let Ok(event) = self.collision_events.try_recv() {
|
||||
match event {
|
||||
CollisionEvent::Started(co1, co2, _) => {
|
||||
let h1 = utils::flat_handle(co1.0);
|
||||
let h2 = utils::flat_handle(co2.0);
|
||||
let _ = f.call3(
|
||||
&this,
|
||||
&JsValue::from(h1),
|
||||
&JsValue::from(h2),
|
||||
&JsValue::from_bool(true),
|
||||
);
|
||||
}
|
||||
CollisionEvent::Stopped(co1, co2, _) => {
|
||||
let h1 = utils::flat_handle(co1.0);
|
||||
let h2 = utils::flat_handle(co2.0);
|
||||
let _ = f.call3(
|
||||
&this,
|
||||
&JsValue::from(h1),
|
||||
&JsValue::from(h2),
|
||||
&JsValue::from_bool(false),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drainContactForceEvents(&mut self, f: &js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
while let Ok(event) = self.contact_force_events.try_recv() {
|
||||
let _ = f.call1(&this, &JsValue::from(RawContactForceEvent(event)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes all events contained by this collector.
|
||||
pub fn clear(&self) {
|
||||
while let Ok(_) = self.collision_events.try_recv() {}
|
||||
}
|
||||
}
|
||||
11
thirdparty/rapier.js/src/pipeline/mod.rs
vendored
Normal file
11
thirdparty/rapier.js/src/pipeline/mod.rs
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
pub use self::debug_render_pipeline::*;
|
||||
pub use self::event_queue::*;
|
||||
pub use self::physics_hooks::*;
|
||||
pub use self::physics_pipeline::*;
|
||||
pub use self::serialization_pipeline::*;
|
||||
|
||||
mod debug_render_pipeline;
|
||||
mod event_queue;
|
||||
mod physics_hooks;
|
||||
mod physics_pipeline;
|
||||
mod serialization_pipeline;
|
||||
217
thirdparty/rapier.js/src/pipeline/physics_hooks.rs
vendored
Normal file
217
thirdparty/rapier.js/src/pipeline/physics_hooks.rs
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
use crate::utils;
|
||||
use rapier::geometry::SolverFlags;
|
||||
use rapier::pipeline::{ContactModificationContext, PairFilterContext, PhysicsHooks};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub struct RawPhysicsHooks {
|
||||
pub this: js_sys::Object,
|
||||
pub filter_contact_pair: js_sys::Function,
|
||||
pub filter_intersection_pair: js_sys::Function,
|
||||
// pub modify_solver_contacts: &'a js_sys::Function,
|
||||
}
|
||||
|
||||
// HACK: the RawPhysicsHooks is no longer Send+Sync because the JS objects are
|
||||
// no longer Send+Sync since https://github.com/rustwasm/wasm-bindgen/pull/955
|
||||
// As far as this is confined to the bindings this should be fine since we
|
||||
// never use threading in wasm.
|
||||
unsafe impl Send for RawPhysicsHooks {}
|
||||
unsafe impl Sync for RawPhysicsHooks {}
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
// Use `js_namespace` here to bind `console.log(..)` instead of just
|
||||
// `log(..)`
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(s: &str);
|
||||
}
|
||||
|
||||
impl PhysicsHooks for RawPhysicsHooks {
|
||||
fn filter_contact_pair(&self, ctxt: &PairFilterContext) -> Option<SolverFlags> {
|
||||
let rb1 = ctxt
|
||||
.rigid_body1
|
||||
.map(|rb| JsValue::from(utils::flat_handle(rb.0)))
|
||||
.unwrap_or(JsValue::NULL);
|
||||
let rb2 = ctxt
|
||||
.rigid_body2
|
||||
.map(|rb| JsValue::from(utils::flat_handle(rb.0)))
|
||||
.unwrap_or(JsValue::NULL);
|
||||
|
||||
let result = self
|
||||
.filter_contact_pair
|
||||
.bind2(
|
||||
&self.this,
|
||||
&JsValue::from(utils::flat_handle(ctxt.collider1.0)),
|
||||
&JsValue::from(utils::flat_handle(ctxt.collider2.0)),
|
||||
)
|
||||
.call2(&self.this, &rb1, &rb2)
|
||||
.ok()?;
|
||||
let flags = result.as_f64()?;
|
||||
// TODO: not sure exactly why we have to do `flags as u32` instead
|
||||
// of `flags.to_bits() as u32`.
|
||||
SolverFlags::from_bits(flags as u32)
|
||||
}
|
||||
|
||||
fn filter_intersection_pair(&self, ctxt: &PairFilterContext) -> bool {
|
||||
let rb1 = ctxt
|
||||
.rigid_body1
|
||||
.map(|rb| JsValue::from(utils::flat_handle(rb.0)))
|
||||
.unwrap_or(JsValue::NULL);
|
||||
let rb2 = ctxt
|
||||
.rigid_body2
|
||||
.map(|rb| JsValue::from(utils::flat_handle(rb.0)))
|
||||
.unwrap_or(JsValue::NULL);
|
||||
|
||||
self.filter_intersection_pair
|
||||
.bind2(
|
||||
&self.this,
|
||||
&JsValue::from(utils::flat_handle(ctxt.collider1.0)),
|
||||
&JsValue::from(utils::flat_handle(ctxt.collider2.0)),
|
||||
)
|
||||
.call2(&self.this, &rb1, &rb2)
|
||||
.ok()
|
||||
.and_then(|res| res.as_bool())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn modify_solver_contacts(&self, _ctxt: &mut ContactModificationContext) {}
|
||||
}
|
||||
|
||||
/* NOTE: the following is an attempt to make contact modification work.
|
||||
*
|
||||
#[wasm_bindgen]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct RawContactManifold(*const ContactManifold);
|
||||
pub struct RawSolverContact(*const SolverContact);
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawContactModificationContext {
|
||||
pub collider1: u32,
|
||||
pub collider2: u32,
|
||||
pub rigid_body1: Option<u32>,
|
||||
pub rigid_body2: Option<u32>,
|
||||
pub manifold: *const ContactManifold,
|
||||
pub solver_contacts: *mut Vec<SolverContact>,
|
||||
normal: *mut Vector<Real>,
|
||||
user_data: *mut u32,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawContactModificationContext {
|
||||
pub fn collider1(&self) -> u32 {
|
||||
self.collider1
|
||||
}
|
||||
|
||||
pub fn collider2(&self) -> u32 {
|
||||
self.collider2
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn normal(&self) -> RawVector {
|
||||
unsafe { RawVector(*self.normal) }
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_normal(&mut self, normal: RawVector) {
|
||||
unsafe {
|
||||
*self.normal = normal.0;
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn user_data(&self) -> u32 {
|
||||
unsafe { *self.user_data }
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_user_data(&mut self, user_data: u32) {
|
||||
unsafe {
|
||||
*self.user_data = user_data;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_solver_contacts(&self) -> usize {
|
||||
unsafe { (*self.solver_contacts).len() }
|
||||
}
|
||||
|
||||
pub fn clear_solver_contacts(&mut self) {
|
||||
unsafe { (*self.solver_contacts).clear() }
|
||||
}
|
||||
|
||||
pub fn remove_solver_contact(&mut self, i: usize) {
|
||||
unsafe {
|
||||
if i < self.num_solver_contacts() {
|
||||
(*self.solver_contacts).swap_remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn solver_contact_point(&self, i: usize) -> Option<RawVector> {
|
||||
unsafe {
|
||||
(*self.solver_contacts)
|
||||
.get(i)
|
||||
.map(|c| c.point.coords.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_solver_contact_point(&mut self, i: usize, pt: &RawVector) {
|
||||
unsafe {
|
||||
if let Some(c) = (*self.solver_contacts).get_mut(i) {
|
||||
c.point = pt.0.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn solver_contact_dist(&self, i: usize) -> Real {
|
||||
unsafe {
|
||||
(*self.solver_contacts)
|
||||
.get(i)
|
||||
.map(|c| c.dist)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_solver_contact_dist(&mut self, i: usize, dist: Real) {
|
||||
unsafe {
|
||||
if let Some(c) = (*self.solver_contacts).get_mut(i) {
|
||||
c.dist = dist
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn solver_contact_friction(&self, i: usize) -> Real {
|
||||
unsafe { (*self.solver_contacts)[i].friction }
|
||||
}
|
||||
|
||||
pub fn set_solver_contact_friction(&mut self, i: usize, friction: Real) {
|
||||
unsafe {
|
||||
if let Some(c) = (*self.solver_contacts).get_mut(i) {
|
||||
c.friction = friction
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn solver_contact_restitution(&self, i: usize) -> Real {
|
||||
unsafe { (*self.solver_contacts)[i].restitution }
|
||||
}
|
||||
|
||||
pub fn set_solver_contact_restitution(&mut self, i: usize, restitution: Real) {
|
||||
unsafe {
|
||||
if let Some(c) = (*self.solver_contacts).get_mut(i) {
|
||||
c.restitution = restitution
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn solver_contact_tangent_velocity(&self, i: usize) -> RawVector {
|
||||
unsafe { (*self.solver_contacts)[i].tangent_velocity.into() }
|
||||
}
|
||||
|
||||
pub fn set_solver_contact_tangent_velocity(&mut self, i: usize, vel: &RawVector) {
|
||||
unsafe {
|
||||
if let Some(c) = (*self.solver_contacts).get_mut(i) {
|
||||
c.tangent_velocity = vel.0.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
170
thirdparty/rapier.js/src/pipeline/physics_pipeline.rs
vendored
Normal file
170
thirdparty/rapier.js/src/pipeline/physics_pipeline.rs
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
use crate::dynamics::{
|
||||
RawCCDSolver, RawImpulseJointSet, RawIntegrationParameters, RawIslandManager,
|
||||
RawMultibodyJointSet, RawRigidBodySet,
|
||||
};
|
||||
use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase};
|
||||
use crate::math::RawVector;
|
||||
use crate::pipeline::{RawEventQueue, RawPhysicsHooks};
|
||||
use crate::rapier::pipeline::PhysicsPipeline;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawPhysicsPipeline(pub(crate) PhysicsPipeline);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawPhysicsPipeline {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
let mut pipeline = PhysicsPipeline::new();
|
||||
pipeline.counters.disable(); // Disable perf counters by default.
|
||||
RawPhysicsPipeline(pipeline)
|
||||
}
|
||||
|
||||
pub fn set_profiler_enabled(&mut self, enabled: bool) {
|
||||
if enabled {
|
||||
self.0.counters.enable();
|
||||
} else {
|
||||
self.0.counters.disable();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_profiler_enabled(&self) -> bool {
|
||||
self.0.counters.enabled()
|
||||
}
|
||||
|
||||
pub fn timing_step(&self) -> f64 {
|
||||
self.0.counters.step_time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_collision_detection(&self) -> f64 {
|
||||
self.0.counters.collision_detection_time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_broad_phase(&self) -> f64 {
|
||||
self.0.counters.broad_phase_time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_narrow_phase(&self) -> f64 {
|
||||
self.0.counters.narrow_phase_time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_solver(&self) -> f64 {
|
||||
self.0.counters.solver_time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_velocity_assembly(&self) -> f64 {
|
||||
self.0.counters.solver.velocity_assembly_time.time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_velocity_resolution(&self) -> f64 {
|
||||
self.0.counters.velocity_resolution_time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_velocity_update(&self) -> f64 {
|
||||
self.0.counters.velocity_update_time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_velocity_writeback(&self) -> f64 {
|
||||
self.0.counters.solver.velocity_writeback_time.time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_ccd(&self) -> f64 {
|
||||
self.0.counters.ccd_time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_ccd_toi_computation(&self) -> f64 {
|
||||
self.0.counters.ccd.toi_computation_time.time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_ccd_broad_phase(&self) -> f64 {
|
||||
self.0.counters.ccd.broad_phase_time.time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_ccd_narrow_phase(&self) -> f64 {
|
||||
self.0.counters.ccd.narrow_phase_time.time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_ccd_solver(&self) -> f64 {
|
||||
self.0.counters.ccd.solver_time.time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_island_construction(&self) -> f64 {
|
||||
self.0.counters.island_construction_time_ms()
|
||||
}
|
||||
|
||||
pub fn timing_user_changes(&self) -> f64 {
|
||||
self.0.counters.stages.user_changes.time_ms()
|
||||
}
|
||||
|
||||
pub fn step(
|
||||
&mut self,
|
||||
gravity: &RawVector,
|
||||
integrationParameters: &RawIntegrationParameters,
|
||||
islands: &mut RawIslandManager,
|
||||
broadPhase: &mut RawBroadPhase,
|
||||
narrowPhase: &mut RawNarrowPhase,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
colliders: &mut RawColliderSet,
|
||||
joints: &mut RawImpulseJointSet,
|
||||
articulations: &mut RawMultibodyJointSet,
|
||||
ccd_solver: &mut RawCCDSolver,
|
||||
) {
|
||||
self.0.step(
|
||||
&gravity.0,
|
||||
&integrationParameters.0,
|
||||
&mut islands.0,
|
||||
&mut broadPhase.0,
|
||||
&mut narrowPhase.0,
|
||||
&mut bodies.0,
|
||||
&mut colliders.0,
|
||||
&mut joints.0,
|
||||
&mut articulations.0,
|
||||
&mut ccd_solver.0,
|
||||
&(),
|
||||
&(),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn stepWithEvents(
|
||||
&mut self,
|
||||
gravity: &RawVector,
|
||||
integrationParameters: &RawIntegrationParameters,
|
||||
islands: &mut RawIslandManager,
|
||||
broadPhase: &mut RawBroadPhase,
|
||||
narrowPhase: &mut RawNarrowPhase,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
colliders: &mut RawColliderSet,
|
||||
joints: &mut RawImpulseJointSet,
|
||||
articulations: &mut RawMultibodyJointSet,
|
||||
ccd_solver: &mut RawCCDSolver,
|
||||
eventQueue: &mut RawEventQueue,
|
||||
hookObject: js_sys::Object,
|
||||
hookFilterContactPair: js_sys::Function,
|
||||
hookFilterIntersectionPair: js_sys::Function,
|
||||
) {
|
||||
if eventQueue.auto_drain {
|
||||
eventQueue.clear();
|
||||
}
|
||||
|
||||
let hooks = RawPhysicsHooks {
|
||||
this: hookObject,
|
||||
filter_contact_pair: hookFilterContactPair,
|
||||
filter_intersection_pair: hookFilterIntersectionPair,
|
||||
};
|
||||
|
||||
self.0.step(
|
||||
&gravity.0,
|
||||
&integrationParameters.0,
|
||||
&mut islands.0,
|
||||
&mut broadPhase.0,
|
||||
&mut narrowPhase.0,
|
||||
&mut bodies.0,
|
||||
&mut colliders.0,
|
||||
&mut joints.0,
|
||||
&mut articulations.0,
|
||||
&mut ccd_solver.0,
|
||||
&hooks,
|
||||
&eventQueue.collector,
|
||||
);
|
||||
}
|
||||
}
|
||||
145
thirdparty/rapier.js/src/pipeline/serialization_pipeline.rs
vendored
Normal file
145
thirdparty/rapier.js/src/pipeline/serialization_pipeline.rs
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
use crate::dynamics::{
|
||||
RawImpulseJointSet, RawIntegrationParameters, RawIslandManager, RawMultibodyJointSet,
|
||||
RawRigidBodySet,
|
||||
};
|
||||
use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase};
|
||||
use crate::math::RawVector;
|
||||
use js_sys::Uint8Array;
|
||||
use rapier::dynamics::{
|
||||
ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet, RigidBodySet,
|
||||
};
|
||||
use rapier::geometry::{ColliderSet, DefaultBroadPhase, NarrowPhase};
|
||||
use rapier::math::Vector;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SerializableWorld<'a> {
|
||||
gravity: &'a Vector<f32>,
|
||||
integration_parameters: &'a IntegrationParameters,
|
||||
islands: &'a IslandManager,
|
||||
broad_phase: &'a DefaultBroadPhase,
|
||||
narrow_phase: &'a NarrowPhase,
|
||||
bodies: &'a RigidBodySet,
|
||||
colliders: &'a ColliderSet,
|
||||
impulse_joints: &'a ImpulseJointSet,
|
||||
multibody_joints: &'a MultibodyJointSet,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DeserializableWorld {
|
||||
gravity: Vector<f32>,
|
||||
integration_parameters: IntegrationParameters,
|
||||
islands: IslandManager,
|
||||
broad_phase: DefaultBroadPhase,
|
||||
narrow_phase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
impulse_joints: ImpulseJointSet,
|
||||
multibody_joints: MultibodyJointSet,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawDeserializedWorld {
|
||||
gravity: Option<RawVector>,
|
||||
integrationParameters: Option<RawIntegrationParameters>,
|
||||
islands: Option<RawIslandManager>,
|
||||
broadPhase: Option<RawBroadPhase>,
|
||||
narrowPhase: Option<RawNarrowPhase>,
|
||||
bodies: Option<RawRigidBodySet>,
|
||||
colliders: Option<RawColliderSet>,
|
||||
impulse_joints: Option<RawImpulseJointSet>,
|
||||
multibody_joints: Option<RawMultibodyJointSet>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawDeserializedWorld {
|
||||
pub fn takeGravity(&mut self) -> Option<RawVector> {
|
||||
self.gravity.take()
|
||||
}
|
||||
|
||||
pub fn takeIntegrationParameters(&mut self) -> Option<RawIntegrationParameters> {
|
||||
self.integrationParameters.take()
|
||||
}
|
||||
|
||||
pub fn takeIslandManager(&mut self) -> Option<RawIslandManager> {
|
||||
self.islands.take()
|
||||
}
|
||||
|
||||
pub fn takeBroadPhase(&mut self) -> Option<RawBroadPhase> {
|
||||
self.broadPhase.take()
|
||||
}
|
||||
|
||||
pub fn takeNarrowPhase(&mut self) -> Option<RawNarrowPhase> {
|
||||
self.narrowPhase.take()
|
||||
}
|
||||
|
||||
pub fn takeBodies(&mut self) -> Option<RawRigidBodySet> {
|
||||
self.bodies.take()
|
||||
}
|
||||
|
||||
pub fn takeColliders(&mut self) -> Option<RawColliderSet> {
|
||||
self.colliders.take()
|
||||
}
|
||||
|
||||
pub fn takeImpulseJoints(&mut self) -> Option<RawImpulseJointSet> {
|
||||
self.impulse_joints.take()
|
||||
}
|
||||
|
||||
pub fn takeMultibodyJoints(&mut self) -> Option<RawMultibodyJointSet> {
|
||||
self.multibody_joints.take()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawSerializationPipeline;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawSerializationPipeline {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawSerializationPipeline
|
||||
}
|
||||
|
||||
pub fn serializeAll(
|
||||
&self,
|
||||
gravity: &RawVector,
|
||||
integrationParameters: &RawIntegrationParameters,
|
||||
islands: &RawIslandManager,
|
||||
broadPhase: &RawBroadPhase,
|
||||
narrowPhase: &RawNarrowPhase,
|
||||
bodies: &RawRigidBodySet,
|
||||
colliders: &RawColliderSet,
|
||||
impulse_joints: &RawImpulseJointSet,
|
||||
multibody_joints: &RawMultibodyJointSet,
|
||||
) -> Option<Uint8Array> {
|
||||
let to_serialize = SerializableWorld {
|
||||
gravity: &gravity.0,
|
||||
integration_parameters: &integrationParameters.0,
|
||||
islands: &islands.0,
|
||||
broad_phase: &broadPhase.0,
|
||||
narrow_phase: &narrowPhase.0,
|
||||
bodies: &bodies.0,
|
||||
colliders: &colliders.0,
|
||||
impulse_joints: &impulse_joints.0,
|
||||
multibody_joints: &multibody_joints.0,
|
||||
};
|
||||
let snap = bincode::serialize(&to_serialize).ok()?;
|
||||
Some(Uint8Array::from(&snap[..]))
|
||||
}
|
||||
|
||||
pub fn deserializeAll(&self, data: Uint8Array) -> Option<RawDeserializedWorld> {
|
||||
let data = data.to_vec();
|
||||
let d: DeserializableWorld = bincode::deserialize(&data[..]).ok()?;
|
||||
Some(RawDeserializedWorld {
|
||||
gravity: Some(RawVector(d.gravity)),
|
||||
integrationParameters: Some(RawIntegrationParameters(d.integration_parameters)),
|
||||
islands: Some(RawIslandManager(d.islands)),
|
||||
broadPhase: Some(RawBroadPhase(d.broad_phase)),
|
||||
narrowPhase: Some(RawNarrowPhase(d.narrow_phase)),
|
||||
bodies: Some(RawRigidBodySet(d.bodies)),
|
||||
colliders: Some(RawColliderSet(d.colliders)),
|
||||
impulse_joints: Some(RawImpulseJointSet(d.impulse_joints)),
|
||||
multibody_joints: Some(RawMultibodyJointSet(d.multibody_joints)),
|
||||
})
|
||||
}
|
||||
}
|
||||
79
thirdparty/rapier.js/src/utils.rs
vendored
Normal file
79
thirdparty/rapier.js/src/utils.rs
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
use rapier::data::Index;
|
||||
use rapier::dynamics::{ImpulseJointHandle, MultibodyJointHandle, RigidBodyHandle};
|
||||
use rapier::geometry::{Collider, ColliderHandle};
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
pub type FlatHandle = f64;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn collider_handle(id: FlatHandle) -> ColliderHandle {
|
||||
ColliderHandle::from_raw_parts(id.to_bits() as u32, (id.to_bits() >> 32) as u32)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn body_handle(id: FlatHandle) -> RigidBodyHandle {
|
||||
RigidBodyHandle::from_raw_parts(id.to_bits() as u32, (id.to_bits() >> 32) as u32)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn impulse_joint_handle(id: FlatHandle) -> ImpulseJointHandle {
|
||||
ImpulseJointHandle::from_raw_parts(id.to_bits() as u32, (id.to_bits() >> 32) as u32)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn multibody_joint_handle(id: FlatHandle) -> MultibodyJointHandle {
|
||||
MultibodyJointHandle::from_raw_parts(id.to_bits() as u32, (id.to_bits() >> 32) as u32)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn flat_handle(id: Index) -> FlatHandle {
|
||||
let (i, g) = id.into_raw_parts();
|
||||
FlatHandle::from_bits(i as u64 | ((g as u64) << 32))
|
||||
}
|
||||
|
||||
// pub type FlatHandle = u32;
|
||||
//
|
||||
// #[inline(always)]
|
||||
// pub fn collider_handle(id: FlatHandle) -> ColliderHandle {
|
||||
// ColliderHandle::from_raw_parts(id as u32, (id >> 16) as u32)
|
||||
// }
|
||||
//
|
||||
// #[inline(always)]
|
||||
// pub fn body_handle(id: FlatHandle) -> RigidBodyHandle {
|
||||
// RigidBodyHandle::from_raw_parts(id as u32, (id >> 16) as u32)
|
||||
// }
|
||||
//
|
||||
// #[inline(always)]
|
||||
// pub fn impulse_joint_handle(id: FlatHandle) -> ImpulseJointHandle {
|
||||
// ImpulseJointHandle::from_raw_parts(id as u32, (id >> 16) as u32)
|
||||
// }
|
||||
//
|
||||
// #[inline(always)]
|
||||
// pub fn multibody_joint_handle(id: FlatHandle) -> MultibodyJointHandle {
|
||||
// MultibodyJointHandle::from_raw_parts(id as u32, (id >> 16) as u32)
|
||||
// }
|
||||
//
|
||||
// #[inline(always)]
|
||||
// pub fn flat_handle(id: Index) -> FlatHandle {
|
||||
// let (i, g) = id.into_raw_parts();
|
||||
// i as u32 | ((g as u32) << 16)
|
||||
// }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn with_filter<T>(
|
||||
filter: &js_sys::Function,
|
||||
f: impl FnOnce(Option<&dyn Fn(ColliderHandle, &Collider) -> bool>) -> T,
|
||||
) -> T {
|
||||
if filter.is_function() {
|
||||
let filtercb = move |handle: ColliderHandle, _: &Collider| match filter
|
||||
.call1(&JsValue::null(), &JsValue::from(flat_handle(handle.0)))
|
||||
{
|
||||
Err(_) => true,
|
||||
Ok(val) => val.as_bool().unwrap_or(true),
|
||||
};
|
||||
|
||||
f(Some(&filtercb))
|
||||
} else {
|
||||
f(None)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user