From 9e912fccf9ed058af8246745271253e5b60bd591 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Thu, 24 Jul 2025 20:02:07 -0500 Subject: [PATCH 01/11] initial --- src.ts/dynamics/rigid_body.ts | 11 +++++--- src.ts/math.ts | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src.ts/dynamics/rigid_body.ts b/src.ts/dynamics/rigid_body.ts index 646223b6..73b2cc36 100644 --- a/src.ts/dynamics/rigid_body.ts +++ b/src.ts/dynamics/rigid_body.ts @@ -50,6 +50,7 @@ export class RigidBody { private rawSet: RawRigidBodySet; // The RigidBody won't need to free this. private colliderSet: ColliderSet; readonly handle: RigidBodyHandle; + private readonly scratchBuffer: Float32Array = new Float32Array(6); /** * An arbitrary user-defined object associated with this rigid-body. @@ -293,10 +294,14 @@ export class RigidBody { /** * The world-space translation of this rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public translation(): Vector { - let res = this.rawSet.rbTranslation(this.handle); - return VectorOps.fromRaw(res); + public translation(target?: Vector): Vector { + this.rawSet.rbTranslation(this.handle, this.scratchBuffer); + return VectorOps.fromBuffer(this.scratchBuffer, target); + return VectorOps.fromRaw(this.scratchBuffer, target); } /** diff --git a/src.ts/math.ts b/src.ts/math.ts index ebca392b..0037f4a1 100644 --- a/src.ts/math.ts +++ b/src.ts/math.ts @@ -31,6 +31,17 @@ export class VectorOps { return VectorOps.new(0.0, 0.0); } + public static fromBuffer(buffer: Float32Array, target?: Vector): Vector { + if (!buffer) return null; + + if (target != null){ + target.x = buffer[0]; + target.y = buffer[1]; + return target; + } + return VectorOps.new(buffer[0], buffer[1]); + } + // FIXME: type ram: RawVector? public static fromRaw(raw: RawVector): Vector { if (!raw) return null; @@ -110,6 +121,18 @@ export class VectorOps { return VectorOps.new(0.0, 0.0, 0.0); } + public static fromBuffer(buffer: Float32Array, target?: Vector): Vector { + if (!buffer) return null; + + if (target != null){ + target.x = buffer[0]; + target.y = buffer[1]; + target.z = buffer[2]; + return target; + } + return VectorOps.new(buffer[0], buffer[1], buffer[2]); + } + // FIXME: type ram: RawVector? public static fromRaw(raw: RawVector): Vector { if (!raw) return null; @@ -155,6 +178,19 @@ export class RotationOps { return new Quaternion(0.0, 0.0, 0.0, 1.0); } + public static fromBuffer(buffer: Float32Array, target?: Rotation): Rotation { + if (!buffer) return null; + + if (target != null){ + target.x = buffer[0]; + target.y = buffer[1]; + target.z = buffer[2]; + target.w = buffer[3]; + return; + } + return VectorOps.new(buffer[0], buffer[1], buffer[2], buffer[3]); + } + public static fromRaw(raw: RawRotation): Rotation { if (!raw) return null; @@ -253,6 +289,18 @@ export class SdpMatrix3 { } export class SdpMatrix3Ops { + + public static fromBuffer(buffer: Float32Array, target?: RawSdpMatrix3): RawSdpMatrix3 { + if (!buffer) return null; + + if (target != null){ + target.x = buffer[0]; + target.y = buffer[1]; + return target; + } + return new SdpMatrix3(buffer); + } + public static fromRaw(raw: RawSdpMatrix3): SdpMatrix3 { const sdpMatrix3 = new SdpMatrix3(raw.elements()); raw.free(); From 941bbf8d5a89248a28f0b45a2ebe7e73d9267f53 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Fri, 25 Jul 2025 17:37:50 -0500 Subject: [PATCH 02/11] rigid_body pass --- src.ts/dynamics/rigid_body.ts | 175 +++++++++++++++------- src.ts/math.ts | 14 +- src/dynamics/rigid_body.rs | 273 ++++++++++++++++++++++++---------- 3 files changed, 329 insertions(+), 133 deletions(-) diff --git a/src.ts/dynamics/rigid_body.ts b/src.ts/dynamics/rigid_body.ts index 73b2cc36..a0a7ed76 100644 --- a/src.ts/dynamics/rigid_body.ts +++ b/src.ts/dynamics/rigid_body.ts @@ -301,16 +301,29 @@ export class RigidBody { public translation(target?: Vector): Vector { this.rawSet.rbTranslation(this.handle, this.scratchBuffer); return VectorOps.fromBuffer(this.scratchBuffer, target); - return VectorOps.fromRaw(this.scratchBuffer, target); } + // #if DIM2 /** * The world-space orientation of this rigid-body. */ - public rotation(): Rotation { - let res = this.rawSet.rbRotation(this.handle); - return RotationOps.fromRaw(res); + public rotation(): number { + return this.rawSet.rbRotation(this.handle); } + // #endif + + // #if DIM3 + /** + * The world-space orientation of this rigid-body. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public rotation(target?: Rotation): Rotation { + this.rawSet.rbRotation(this.handle, this.scratchBuffer); + return RotationOps.fromBuffer(this.scratchBuffer, target); + } + // #endif /** * The world-space next translation of this rigid-body. @@ -318,23 +331,44 @@ export class RigidBody { * 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. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public nextTranslation(target?: Vector): Vector { + this.rawSet.rbNextTranslation(this.handle, this.scratchBuffer); + return VectorOps.fromBuffer(this.scratchBuffer, target); + } + + // #if DIM2 + /** + * The world-space next 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. */ - public nextTranslation(): Vector { - let res = this.rawSet.rbNextTranslation(this.handle); - return VectorOps.fromRaw(res); + public nextRotation(): number { + return this.rawSet.rbNextRotation(this.handle); } + // #endif + // #if DIM3 /** * The world-space next 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. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public nextRotation(): Rotation { - let res = this.rawSet.rbNextRotation(this.handle); - return RotationOps.fromRaw(res); + public nextRotation(target?: Rotation): Rotation { + this.rawSet.rbNextRotation(this.handle, this.scratchBuffer); + return RotationOps.fromBuffer(this.scratchBuffer, target); } + // #endif /** * Sets the translation of this rigid-body. @@ -507,31 +541,39 @@ export class RigidBody { /** * The linear velocity of this rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public linvel(): Vector { - return VectorOps.fromRaw(this.rawSet.rbLinvel(this.handle)); + public linvel(target?: Vector): Vector { + this.rawSet.rbLinvel(this.handle, this.scratchBuffer); + return VectorOps.fromBuffer(this.scratchBuffer, target); } /** * The velocity of the given world-space point on this rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public velocityAtPoint(point: Vector): Vector { + public velocityAtPoint(point: Vector, target?: Vector): Vector { const rawPoint = VectorOps.intoRaw(point); - let result = VectorOps.fromRaw( - this.rawSet.rbVelocityAtPoint(this.handle, rawPoint), - ); + this.rawSet.rbVelocityAtPoint(this.handle, rawPoint, this.scratchBuffer); rawPoint.free(); - return result; + return VectorOps.fromBuffer(this.scratchBuffer, target); } // #if DIM3 /** * The angular velocity of this rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public angvel(): Vector { - return VectorOps.fromRaw(this.rawSet.rbAngvel(this.handle)); + public angvel(target?: Vector): Vector { + this.rawSet.rbAngvel(this.handle, this.scratchBuffer); + return VectorOps.fromBuffer(this.scratchBuffer, target); } - // #endif // #if DIM2 @@ -541,7 +583,6 @@ export class RigidBody { public angvel(): number { return this.rawSet.rbAngvel(this.handle); } - // #endif /** @@ -553,9 +594,13 @@ export class RigidBody { /** * The inverse mass taking into account translation locking. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public effectiveInvMass(): Vector { - return VectorOps.fromRaw(this.rawSet.rbEffectiveInvMass(this.handle)); + public effectiveInvMass(target?: Vector): Vector { + this.rawSet.rbEffectiveInvMass(this.handle, this.scratchBuffer); + return VectorOps.fromBuffer(this.scratchBuffer, target); } /** @@ -569,16 +614,24 @@ export class RigidBody { /** * The center of mass of a rigid-body expressed in its local-space. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public localCom(): Vector { - return VectorOps.fromRaw(this.rawSet.rbLocalCom(this.handle)); + public localCom(target?: Vector): Vector { + this.rawSet.rbLocalCom(this.handle, this.scratchBuffer); + return VectorOps.fromBuffer(this.scratchBuffer, target); } /** * The world-space center of mass of the rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public worldCom(): Vector { - return VectorOps.fromRaw(this.rawSet.rbWorldCom(this.handle)); + public worldCom(target?: Vector): Vector { + this.rawSet.rbWorldCom(this.handle, this.scratchBuffer); + return VectorOps.fromBuffer(this.scratchBuffer, target); } // #if DIM2 @@ -598,13 +651,14 @@ export class RigidBody { * 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. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public invPrincipalInertiaSqrt(): Vector { - return VectorOps.fromRaw( - this.rawSet.rbInvPrincipalInertiaSqrt(this.handle), - ); + public invPrincipalInertiaSqrt(target?: Vector): Vector { + this.rawSet.rbInvPrincipalInertiaSqrt(this.handle, this.scratchBuffer); + return VectorOps.fromBuffer(this.scratchBuffer, target); } - // #endif // #if DIM2 @@ -614,29 +668,32 @@ export class RigidBody { public principalInertia(): number { return this.rawSet.rbPrincipalInertia(this.handle); } - // #endif // #if DIM3 /** * The angular inertia along the principal inertia axes of the rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public principalInertia(): Vector { - return VectorOps.fromRaw(this.rawSet.rbPrincipalInertia(this.handle)); + public principalInertia(target?: Vector): Vector { + this.rawSet.rbPrincipalInertia(this.handle, this.scratchBuffer); + return VectorOps.fromBuffer(this.scratchBuffer, target); } - // #endif // #if DIM3 /** * The principal vectors of the local angular inertia tensor of the rigid-body. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public principalInertiaLocalFrame(): Rotation { - return RotationOps.fromRaw( - this.rawSet.rbPrincipalInertiaLocalFrame(this.handle), - ); + public principalInertiaLocalFrame(target?: Rotation): Rotation { + this.rawSet.rbPrincipalInertiaLocalFrame(this.handle, this.scratchBuffer); + return RotationOps.fromBuffer(this.scratchBuffer, target); } - // #endif // #if DIM2 @@ -654,11 +711,13 @@ export class RigidBody { /** * The square-root of the world-space inverse angular inertia tensor of the rigid-body, * taking into account rotation locking. + * + * @param {SdpMatrix3?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public effectiveWorldInvInertiaSqrt(): SdpMatrix3 { - return SdpMatrix3Ops.fromRaw( - this.rawSet.rbEffectiveWorldInvInertiaSqrt(this.handle), - ); + public effectiveWorldInvInertiaSqrt(target?: SdpMatrix3): SdpMatrix3 { + this.rawSet.rbEffectiveWorldInvInertiaSqrt(this.handle, this.scratchBuffer); + return SdpMatrix3Ops.fromBuffer(this.scratchBuffer, target); } // #endif @@ -678,11 +737,13 @@ export class RigidBody { /** * The effective world-space angular inertia (that takes the potential rotation locking into account) of * this rigid-body. + * + * @param {SdpMatrix3?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public effectiveAngularInertia(): SdpMatrix3 { - return SdpMatrix3Ops.fromRaw( - this.rawSet.rbEffectiveAngularInertia(this.handle), - ); + public effectiveAngularInertia(target?: SdpMatrix3): SdpMatrix3 { + this.rawSet.rbEffectiveAngularInertia(this.handle, this.scratchBuffer); + return SdpMatrix3Ops.fromBuffer(this.scratchBuffer, target); } // #endif @@ -1089,9 +1150,13 @@ export class RigidBody { /** * Retrieves the constant force(s) the user added to this rigid-body * Returns zero if the rigid-body is not dynamic. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public userForce(): Vector { - return VectorOps.fromRaw(this.rawSet.rbUserForce(this.handle)); + public userForce(target?: Vector): Vector { + this.rawSet.rbUserForce(this.handle, this.scratchBuffer); + return VectorOps.fromBuffer(this.scratchBuffer, target); } // #if DIM2 @@ -1108,9 +1173,13 @@ export class RigidBody { /** * Retrieves the constant torque(s) the user added to this rigid-body * Returns zero if the rigid-body is not dynamic. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public userTorque(): Vector { - return VectorOps.fromRaw(this.rawSet.rbUserTorque(this.handle)); + public userTorque(target?: Vector): Vector { + this.rawSet.rbUserTorque(this.handle, this.scratchBuffer); + return VectorOps.fromBuffer(this.scratchBuffer, target); } // #endif } diff --git a/src.ts/math.ts b/src.ts/math.ts index 0037f4a1..f43cf538 100644 --- a/src.ts/math.ts +++ b/src.ts/math.ts @@ -186,9 +186,9 @@ export class RotationOps { target.y = buffer[1]; target.z = buffer[2]; target.w = buffer[3]; - return; + return target; } - return VectorOps.new(buffer[0], buffer[1], buffer[2], buffer[3]); + return new Quaternion(buffer[0], buffer[1], buffer[2], buffer[3]); } public static fromRaw(raw: RawRotation): Rotation { @@ -290,12 +290,16 @@ export class SdpMatrix3 { export class SdpMatrix3Ops { - public static fromBuffer(buffer: Float32Array, target?: RawSdpMatrix3): RawSdpMatrix3 { + public static fromBuffer(buffer: Float32Array, target?: SdpMatrix3): SdpMatrix3 { if (!buffer) return null; if (target != null){ - target.x = buffer[0]; - target.y = buffer[1]; + target.elements[0] = buffer[0]; + target.elements[1] = buffer[1]; + target.elements[2] = buffer[2]; + target.elements[3] = buffer[3]; + target.elements[4] = buffer[4]; + target.elements[5] = buffer[5]; return target; } return new SdpMatrix3(buffer); diff --git a/src/dynamics/rigid_body.rs b/src/dynamics/rigid_body.rs index f6b1648b..ca527db9 100644 --- a/src/dynamics/rigid_body.rs +++ b/src/dynamics/rigid_body.rs @@ -1,7 +1,5 @@ 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; @@ -11,13 +9,37 @@ 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)) + #[cfg(feature = "dim2")] + pub fn rbTranslation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.position().translation.vector); + target.set_index(0, u.x); + target.set_index(1, u.y); + } + + /// The world-space translation of this rigid-body. + #[cfg(feature = "dim3")] + pub fn rbTranslation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.position().translation.vector); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); } /// The world-space orientation of this rigid-body. - pub fn rbRotation(&self, handle: FlatHandle) -> RawRotation { - self.map(handle, |rb| RawRotation(rb.position().rotation)) + #[cfg(feature = "dim2")] + pub fn rbRotation(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.position().rotation.angle()) + } + + /// The world-space orientation of this rigid-body. + #[cfg(feature = "dim3")] + pub fn rbRotation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.position().rotation); + let inner = u.into_inner(); + target.set_index(0, inner.i); + target.set_index(1, inner.j); + target.set_index(2, inner.k); + target.set_index(3, inner.w); } /// Put the given rigid-body to sleep. @@ -40,10 +62,34 @@ impl RawRigidBodySet { /// 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) - }) + #[cfg(feature = "dim2")] + pub fn rbNextTranslation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.next_position().translation.vector); + target.set_index(0, u.x); + target.set_index(1, u.y); + } + + /// 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. + #[cfg(feature = "dim3")] + pub fn rbNextTranslation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.next_position().translation.vector); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); + } + + /// 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. + #[cfg(feature = "dim2")] + pub fn rbNextRotation(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.next_position().rotation.angle()) } /// The world-space predicted orientation of this rigid-body. @@ -51,8 +97,14 @@ impl RawRigidBodySet { /// 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)) + #[cfg(feature = "dim3")] + pub fn rbNextRotation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.next_position().rotation); + let inner = u.into_inner(); + target.set_index(0, inner.i); + target.set_index(1, inner.j); + target.set_index(2, inner.k); + target.set_index(3, inner.w); } /// Sets the translation of this rigid-body. @@ -282,8 +334,20 @@ impl RawRigidBodySet { } /// The linear velocity of this rigid-body. - pub fn rbLinvel(&self, handle: FlatHandle) -> RawVector { - self.map(handle, |rb| RawVector(*rb.linvel())) + #[cfg(feature = "dim2")] + pub fn rbLinvel(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| *rb.linvel()); + target.set_index(0, u.x); + target.set_index(1, u.y); + } + + /// The linear velocity of this rigid-body. + #[cfg(feature = "dim3")] + pub fn rbLinvel(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| *rb.linvel()); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); } /// The angular velocity of this rigid-body. @@ -294,15 +358,28 @@ impl RawRigidBodySet { /// The angular velocity of this rigid-body. #[cfg(feature = "dim3")] - pub fn rbAngvel(&self, handle: FlatHandle) -> RawVector { - self.map(handle, |rb| RawVector(*rb.angvel())) + pub fn rbAngvel(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| *rb.angvel()); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); } /// 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() - }) + #[cfg(feature = "dim2")] + pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.velocity_at_point(&Point::from(point.0))); + target.set_index(0, u.x); + target.set_index(1, u.y); + } + + /// The velocity of the given world-space point on this rigid-body. + #[cfg(feature = "dim3")] + pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.velocity_at_point(&Point::from(point.0))); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); } pub fn rbLockTranslations(&mut self, handle: FlatHandle, locked: bool, wake_up: bool) { @@ -383,20 +460,54 @@ impl RawRigidBodySet { } /// 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()) + #[cfg(feature = "dim2")] + pub fn rbEffectiveInvMass(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.mass_properties().effective_inv_mass); + target.set_index(0, u.x); + target.set_index(1, u.y); + } + + /// The inverse mass taking into account translation locking. + #[cfg(feature = "dim3")] + pub fn rbEffectiveInvMass(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.mass_properties().effective_inv_mass); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); } /// 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() - }) + #[cfg(feature = "dim2")] + pub fn rbLocalCom(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.mass_properties().local_mprops.local_com); + target.set_index(0, u.x); + target.set_index(1, u.y); + } + + /// The center of mass of a rigid-body expressed in its local-space. + #[cfg(feature = "dim3")] + pub fn rbLocalCom(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.mass_properties().local_mprops.local_com); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); } /// 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()) + #[cfg(feature = "dim2")] + pub fn rbWorldCom(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.mass_properties().world_com); + target.set_index(0, u.x); + target.set_index(1, u.y); + } + + /// The world-space center of mass of the rigid-body. + #[cfg(feature = "dim3")] + pub fn rbWorldCom(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.mass_properties().world_com); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); } /// The inverse of the principal angular inertia of the rigid-body. @@ -404,89 +515,85 @@ impl RawRigidBodySet { /// Components set to zero are assumed to be infinite along the corresponding principal axis. #[cfg(feature = "dim2")] pub fn rbInvPrincipalInertiaSqrt(&self, handle: FlatHandle) -> f32 { - self.map(handle, |rb| { - rb.mass_properties() - .local_mprops - .inv_principal_inertia_sqrt - .into() - }) + self.map(handle, |rb| rb.mass_properties().local_mprops.inv_principal_inertia_sqrt) } /// 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 rbInvPrincipalInertiaSqrt(&self, handle: FlatHandle) -> RawVector { - self.map(handle, |rb| { - rb.mass_properties() - .local_mprops - .inv_principal_inertia_sqrt - .into() - }) + pub fn rbInvPrincipalInertiaSqrt(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.mass_properties().local_mprops.inv_principal_inertia_sqrt); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); } - #[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, - ) - }) + #[cfg(feature = "dim3")] + pub fn rbPrincipalInertiaLocalFrame(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.mass_properties().local_mprops.principal_inertia_local_frame); + let inner = u.into_inner(); + target.set_index(0, inner.i); + target.set_index(1, inner.j); + target.set_index(2, inner.k); + target.set_index(3, inner.w); } /// 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() - }) + self.map(handle, |rb| rb.mass_properties().local_mprops.principal_inertia()) } /// 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() - }) + pub fn rbPrincipalInertia(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.mass_properties().local_mprops.principal_inertia()); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); + } /// The square-root of the world-space inverse angular inertia tensor of the rigid-body, /// taking into account rotation locking. #[cfg(feature = "dim2")] pub fn rbEffectiveWorldInvInertiaSqrt(&self, handle: FlatHandle) -> f32 { - self.map(handle, |rb| { - rb.mass_properties().effective_world_inv_inertia_sqrt.into() - }) + self.map(handle, |rb| rb.mass_properties().effective_world_inv_inertia_sqrt) } /// The square-root of the world-space inverse angular inertia tensor of the rigid-body, /// taking into account rotation locking. #[cfg(feature = "dim3")] - pub fn rbEffectiveWorldInvInertiaSqrt(&self, handle: FlatHandle) -> RawSdpMatrix3 { - self.map(handle, |rb| { - rb.mass_properties().effective_world_inv_inertia_sqrt.into() - }) + pub fn rbEffectiveWorldInvInertiaSqrt(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.mass_properties().effective_world_inv_inertia_sqrt); + target.set_index(0, u.m11); + target.set_index(1, u.m12); + target.set_index(2, u.m13); + target.set_index(3, u.m22); + target.set_index(4, u.m23); + target.set_index(5, u.m33); } /// 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() - }) + self.map(handle, |rb| rb.mass_properties().effective_angular_inertia()) } /// 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() - }) + pub fn rbEffectiveAngularInertia(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.mass_properties().effective_angular_inertia()); + target.set_index(0, u.m11); + target.set_index(1, u.m12); + target.set_index(2, u.m13); + target.set_index(3, u.m22); + target.set_index(4, u.m23); + target.set_index(5, u.m33); } /// Wakes this rigid-body up. @@ -733,8 +840,21 @@ impl RawRigidBodySet { /// 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()) + #[cfg(feature = "dim2")] + pub fn rbUserForce(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.user_force()); + target.set_index(0, u.x); + target.set_index(1, u.y); + } + + /// Retrieves the constant force(s) the user added to this rigid-body. + /// Returns zero if the rigid-body is not dynamic. + #[cfg(feature = "dim3")] + pub fn rbUserForce(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.user_force()); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); } /// Retrieves the constant torque(s) the user added to this rigid-body. @@ -747,7 +867,10 @@ impl RawRigidBodySet { /// 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()) + pub fn rbUserTorque(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + let u = self.map(handle, |rb| rb.user_torque()); + target.set_index(0, u.x); + target.set_index(1, u.y); + target.set_index(2, u.z); } } From 3eab1a63eb2552305b07033bb85cb2037a953491 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sat, 26 Jul 2025 13:00:23 -0500 Subject: [PATCH 03/11] added parameter info comments to rigid_body.rs --- src/dynamics/rigid_body.rs | 277 +++++++++++++++++++++++-------------- 1 file changed, 176 insertions(+), 101 deletions(-) diff --git a/src/dynamics/rigid_body.rs b/src/dynamics/rigid_body.rs index ca527db9..47e8bca6 100644 --- a/src/dynamics/rigid_body.rs +++ b/src/dynamics/rigid_body.rs @@ -9,20 +9,26 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen] impl RawRigidBodySet { /// The world-space translation of this rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbTranslation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.position().translation.vector); - target.set_index(0, u.x); - target.set_index(1, u.y); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); } /// The world-space translation of this rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbTranslation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.position().translation.vector); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } /// The world-space orientation of this rigid-body. @@ -32,14 +38,17 @@ impl RawRigidBodySet { } /// The world-space orientation of this rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbRotation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbRotation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.position().rotation); let inner = u.into_inner(); - target.set_index(0, inner.i); - target.set_index(1, inner.j); - target.set_index(2, inner.k); - target.set_index(3, inner.w); + scratchBuffer.set_index(0, inner.i); + scratchBuffer.set_index(1, inner.j); + scratchBuffer.set_index(2, inner.k); + scratchBuffer.set_index(3, inner.w); } /// Put the given rigid-body to sleep. @@ -62,11 +71,14 @@ impl RawRigidBodySet { /// 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. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbNextTranslation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbNextTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.next_position().translation.vector); - target.set_index(0, u.x); - target.set_index(1, u.y); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); } /// The world-space predicted translation of this rigid-body. @@ -74,12 +86,15 @@ impl RawRigidBodySet { /// 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. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbNextTranslation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbNextTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.next_position().translation.vector); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } /// The world-space predicted orientation of this rigid-body. @@ -97,14 +112,17 @@ impl RawRigidBodySet { /// 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. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbNextRotation(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbNextRotation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.next_position().rotation); let inner = u.into_inner(); - target.set_index(0, inner.i); - target.set_index(1, inner.j); - target.set_index(2, inner.k); - target.set_index(3, inner.w); + scratchBuffer.set_index(0, inner.i); + scratchBuffer.set_index(1, inner.j); + scratchBuffer.set_index(2, inner.k); + scratchBuffer.set_index(3, inner.w); } /// Sets the translation of this rigid-body. @@ -334,20 +352,26 @@ impl RawRigidBodySet { } /// The linear velocity of this rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbLinvel(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbLinvel(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| *rb.linvel()); - target.set_index(0, u.x); - target.set_index(1, u.y); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); } /// The linear velocity of this rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbLinvel(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbLinvel(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| *rb.linvel()); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } /// The angular velocity of this rigid-body. @@ -357,29 +381,38 @@ impl RawRigidBodySet { } /// The angular velocity of this rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbAngvel(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbAngvel(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| *rb.angvel()); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } /// The velocity of the given world-space point on this rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, target: &js_sys::Float32Array) { + pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.velocity_at_point(&Point::from(point.0))); - target.set_index(0, u.x); - target.set_index(1, u.y); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); } /// The velocity of the given world-space point on this rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, target: &js_sys::Float32Array) { + pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.velocity_at_point(&Point::from(point.0))); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } pub fn rbLockTranslations(&mut self, handle: FlatHandle, locked: bool, wake_up: bool) { @@ -460,54 +493,72 @@ impl RawRigidBodySet { } /// The inverse mass taking into account translation locking. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbEffectiveInvMass(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbEffectiveInvMass(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.mass_properties().effective_inv_mass); - target.set_index(0, u.x); - target.set_index(1, u.y); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); } /// The inverse mass taking into account translation locking. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbEffectiveInvMass(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbEffectiveInvMass(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.mass_properties().effective_inv_mass); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } /// The center of mass of a rigid-body expressed in its local-space. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbLocalCom(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbLocalCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.mass_properties().local_mprops.local_com); - target.set_index(0, u.x); - target.set_index(1, u.y); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); } /// The center of mass of a rigid-body expressed in its local-space. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbLocalCom(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbLocalCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.mass_properties().local_mprops.local_com); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } /// The world-space center of mass of the rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbWorldCom(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbWorldCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.mass_properties().world_com); - target.set_index(0, u.x); - target.set_index(1, u.y); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); } /// The world-space center of mass of the rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbWorldCom(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbWorldCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.mass_properties().world_com); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } /// The inverse of the principal angular inertia of the rigid-body. @@ -521,23 +572,29 @@ impl RawRigidBodySet { /// 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. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbInvPrincipalInertiaSqrt(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbInvPrincipalInertiaSqrt(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.mass_properties().local_mprops.inv_principal_inertia_sqrt); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } /// The principal vectors of the local angular inertia tensor of the rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbPrincipalInertiaLocalFrame(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbPrincipalInertiaLocalFrame(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.mass_properties().local_mprops.principal_inertia_local_frame); let inner = u.into_inner(); - target.set_index(0, inner.i); - target.set_index(1, inner.j); - target.set_index(2, inner.k); - target.set_index(3, inner.w); + scratchBuffer.set_index(0, inner.i); + scratchBuffer.set_index(1, inner.j); + scratchBuffer.set_index(2, inner.k); + scratchBuffer.set_index(3, inner.w); } /// The angular inertia along the principal inertia axes of the rigid-body. @@ -547,12 +604,15 @@ impl RawRigidBodySet { } /// The angular inertia along the principal inertia axes of the rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbPrincipalInertia(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbPrincipalInertia(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.mass_properties().local_mprops.principal_inertia()); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } @@ -565,15 +625,18 @@ impl RawRigidBodySet { /// The square-root of the world-space inverse angular inertia tensor of the rigid-body, /// taking into account rotation locking. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbEffectiveWorldInvInertiaSqrt(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbEffectiveWorldInvInertiaSqrt(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.mass_properties().effective_world_inv_inertia_sqrt); - target.set_index(0, u.m11); - target.set_index(1, u.m12); - target.set_index(2, u.m13); - target.set_index(3, u.m22); - target.set_index(4, u.m23); - target.set_index(5, u.m33); + scratchBuffer.set_index(0, u.m11); + scratchBuffer.set_index(1, u.m12); + scratchBuffer.set_index(2, u.m13); + scratchBuffer.set_index(3, u.m22); + scratchBuffer.set_index(4, u.m23); + scratchBuffer.set_index(5, u.m33); } /// The effective world-space angular inertia (that takes the potential rotation locking into account) of @@ -585,15 +648,18 @@ impl RawRigidBodySet { /// The effective world-space angular inertia (that takes the potential rotation locking into account) of /// this rigid-body. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbEffectiveAngularInertia(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbEffectiveAngularInertia(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.mass_properties().effective_angular_inertia()); - target.set_index(0, u.m11); - target.set_index(1, u.m12); - target.set_index(2, u.m13); - target.set_index(3, u.m22); - target.set_index(4, u.m23); - target.set_index(5, u.m33); + scratchBuffer.set_index(0, u.m11); + scratchBuffer.set_index(1, u.m12); + scratchBuffer.set_index(2, u.m13); + scratchBuffer.set_index(3, u.m22); + scratchBuffer.set_index(4, u.m23); + scratchBuffer.set_index(5, u.m33); } /// Wakes this rigid-body up. @@ -840,21 +906,27 @@ impl RawRigidBodySet { /// Retrieves the constant force(s) the user added to this rigid-body. /// Returns zero if the rigid-body is not dynamic. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbUserForce(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbUserForce(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.user_force()); - target.set_index(0, u.x); - target.set_index(1, u.y); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); } /// Retrieves the constant force(s) the user added to this rigid-body. /// Returns zero if the rigid-body is not dynamic. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbUserForce(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbUserForce(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.user_force()); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } /// Retrieves the constant torque(s) the user added to this rigid-body. @@ -866,11 +938,14 @@ impl RawRigidBodySet { /// Retrieves the constant torque(s) the user added to this rigid-body. /// Returns zero if the rigid-body is not dynamic. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbUserTorque(&self, handle: FlatHandle, target: &js_sys::Float32Array) { + pub fn rbUserTorque(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { let u = self.map(handle, |rb| rb.user_torque()); - target.set_index(0, u.x); - target.set_index(1, u.y); - target.set_index(2, u.z); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); } } From ab1f5f0f324915e32fce9299538a3919375fa98d Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sun, 27 Jul 2025 22:21:47 -0500 Subject: [PATCH 04/11] collider.rs/.ts pass --- src.ts/dynamics/rigid_body.ts | 93 +++++++----- src.ts/geometry/collider.ts | 90 +++++++++--- src.ts/geometry/shape.ts | 46 +++++- src.ts/math.ts | 2 + src/dynamics/rigid_body.rs | 268 +++++++++++++++++++++------------- src/geometry/collider.rs | 195 ++++++++++++++++++++++--- 6 files changed, 501 insertions(+), 193 deletions(-) diff --git a/src.ts/dynamics/rigid_body.ts b/src.ts/dynamics/rigid_body.ts index a0a7ed76..bce26c3b 100644 --- a/src.ts/dynamics/rigid_body.ts +++ b/src.ts/dynamics/rigid_body.ts @@ -1,5 +1,11 @@ import {RawRigidBodySet, RawRigidBodyType} from "../raw"; -import {Rotation, RotationOps, Vector, VectorOps} from "../math"; +import { + Rotation, + RotationOps, + Vector, + VectorOps, + scratchBuffer +} from "../math"; // #if DIM3 import {SdpMatrix3, SdpMatrix3Ops} from "../math"; // #endif @@ -50,7 +56,6 @@ export class RigidBody { private rawSet: RawRigidBodySet; // The RigidBody won't need to free this. private colliderSet: ColliderSet; readonly handle: RigidBodyHandle; - private readonly scratchBuffer: Float32Array = new Float32Array(6); /** * An arbitrary user-defined object associated with this rigid-body. @@ -292,6 +297,22 @@ export class RigidBody { return this.rawSet.rbSoftCcdPrediction(this.handle); } + /** + * The world-space translation of this rigid-body. + */ + public translationOriginal(): Vector { + let res = this.rawSet.rbTranslationOriginal(this.handle); + return VectorOps.fromRaw(res); + } + + /** + * The world-space orientation of this rigid-body. + */ + public rotationOriginal(): Rotation { + let res = this.rawSet.rbRotationOriginal(this.handle); + return RotationOps.fromRaw(res); + } + /** * The world-space translation of this rigid-body. * @@ -299,8 +320,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public translation(target?: Vector): Vector { - this.rawSet.rbTranslation(this.handle, this.scratchBuffer); - return VectorOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbTranslation(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } // #if DIM2 @@ -320,8 +341,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public rotation(target?: Rotation): Rotation { - this.rawSet.rbRotation(this.handle, this.scratchBuffer); - return RotationOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbRotation(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); } // #endif @@ -336,8 +357,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public nextTranslation(target?: Vector): Vector { - this.rawSet.rbNextTranslation(this.handle, this.scratchBuffer); - return VectorOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbNextTranslation(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } // #if DIM2 @@ -365,8 +386,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public nextRotation(target?: Rotation): Rotation { - this.rawSet.rbNextRotation(this.handle, this.scratchBuffer); - return RotationOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbNextRotation(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); } // #endif @@ -546,8 +567,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public linvel(target?: Vector): Vector { - this.rawSet.rbLinvel(this.handle, this.scratchBuffer); - return VectorOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbLinvel(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } /** @@ -558,9 +579,9 @@ export class RigidBody { */ public velocityAtPoint(point: Vector, target?: Vector): Vector { const rawPoint = VectorOps.intoRaw(point); - this.rawSet.rbVelocityAtPoint(this.handle, rawPoint, this.scratchBuffer); + this.rawSet.rbVelocityAtPoint(this.handle, rawPoint, scratchBuffer); rawPoint.free(); - return VectorOps.fromBuffer(this.scratchBuffer, target); + return VectorOps.fromBuffer(scratchBuffer, target); } // #if DIM3 @@ -571,8 +592,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public angvel(target?: Vector): Vector { - this.rawSet.rbAngvel(this.handle, this.scratchBuffer); - return VectorOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbAngvel(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } // #endif @@ -599,8 +620,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public effectiveInvMass(target?: Vector): Vector { - this.rawSet.rbEffectiveInvMass(this.handle, this.scratchBuffer); - return VectorOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbEffectiveInvMass(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } /** @@ -619,8 +640,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public localCom(target?: Vector): Vector { - this.rawSet.rbLocalCom(this.handle, this.scratchBuffer); - return VectorOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbLocalCom(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } /** @@ -630,8 +651,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public worldCom(target?: Vector): Vector { - this.rawSet.rbWorldCom(this.handle, this.scratchBuffer); - return VectorOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbWorldCom(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } // #if DIM2 @@ -656,8 +677,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public invPrincipalInertiaSqrt(target?: Vector): Vector { - this.rawSet.rbInvPrincipalInertiaSqrt(this.handle, this.scratchBuffer); - return VectorOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbInvPrincipalInertiaSqrt(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } // #endif @@ -678,8 +699,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public principalInertia(target?: Vector): Vector { - this.rawSet.rbPrincipalInertia(this.handle, this.scratchBuffer); - return VectorOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbPrincipalInertia(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } // #endif @@ -691,8 +712,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public principalInertiaLocalFrame(target?: Rotation): Rotation { - this.rawSet.rbPrincipalInertiaLocalFrame(this.handle, this.scratchBuffer); - return RotationOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbPrincipalInertiaLocalFrame(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); } // #endif @@ -716,8 +737,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public effectiveWorldInvInertiaSqrt(target?: SdpMatrix3): SdpMatrix3 { - this.rawSet.rbEffectiveWorldInvInertiaSqrt(this.handle, this.scratchBuffer); - return SdpMatrix3Ops.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbEffectiveWorldInvInertiaSqrt(this.handle, scratchBuffer); + return SdpMatrix3Ops.fromBuffer(scratchBuffer, target); } // #endif @@ -742,8 +763,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public effectiveAngularInertia(target?: SdpMatrix3): SdpMatrix3 { - this.rawSet.rbEffectiveAngularInertia(this.handle, this.scratchBuffer); - return SdpMatrix3Ops.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbEffectiveAngularInertia(this.handle, scratchBuffer); + return SdpMatrix3Ops.fromBuffer(scratchBuffer, target); } // #endif @@ -1155,8 +1176,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public userForce(target?: Vector): Vector { - this.rawSet.rbUserForce(this.handle, this.scratchBuffer); - return VectorOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbUserForce(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } // #if DIM2 @@ -1178,8 +1199,8 @@ export class RigidBody { * the function returns this object instead of creating a new one. */ public userTorque(target?: Vector): Vector { - this.rawSet.rbUserTorque(this.handle, this.scratchBuffer); - return VectorOps.fromBuffer(this.scratchBuffer, target); + this.rawSet.rbUserTorque(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } // #endif } diff --git a/src.ts/geometry/collider.ts b/src.ts/geometry/collider.ts index 25817362..275a828f 100644 --- a/src.ts/geometry/collider.ts +++ b/src.ts/geometry/collider.ts @@ -1,5 +1,11 @@ import {RawColliderSet} from "../raw"; -import {Rotation, RotationOps, Vector, VectorOps} from "../math"; +import { + Rotation, + RotationOps, + Vector, + VectorOps, + scratchBuffer +} from "../math"; import { CoefficientCombineRule, RigidBody, @@ -169,43 +175,76 @@ export class Collider { /** * The world-space translation of this collider. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public translation(): Vector { - return VectorOps.fromRaw( - this.colliderSet.raw.coTranslation(this.handle), - ); + public translation(target?: Vector): Vector { + this.colliderSet.raw.coTranslation(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } /** * The translation of this collider relative to its parent rigid-body. * * Returns `null` if the collider doesn’t have a parent rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public translationWrtParent(): Vector | null { - return VectorOps.fromRaw( - this.colliderSet.raw.coTranslationWrtParent(this.handle), - ); + public translationWrtParent(target?: Vector): Vector | null { + const hasParent = this.colliderSet.raw.coTranslationWrtParent(this.handle, scratchBuffer); + return hasParent ? VectorOps.fromBuffer(scratchBuffer, target) : null; } + // #if DIM2 /** * The world-space orientation of this collider. */ - public rotation(): Rotation { - return RotationOps.fromRaw( - this.colliderSet.raw.coRotation(this.handle), - ); + public rotation(): number { + return this.colliderSet.raw.coRotation(this.handle); + } + // #endif + + // #if DIM3 + /** + * The world-space orientation of this collider. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public rotation(target?: Rotation): Rotation { + this.colliderSet.raw.coRotation(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); } + // #endif + // #if DIM2 /** * The orientation of this collider relative to its parent rigid-body. * * Returns `null` if the collider doesn’t have a parent rigid-body. */ public rotationWrtParent(): Rotation | null { - return RotationOps.fromRaw( - this.colliderSet.raw.coRotationWrtParent(this.handle), - ); + const val = this.colliderSet.raw.coRotationWrtParent(this.handle); + return isNaN(val) ? null : val; + } + // #endif + + // #if DIM3 + /** + * The orientation of this collider relative to its parent rigid-body. + * + * Returns `null` if the collider doesn’t have a parent rigid-body. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public rotationWrtParent(target?: Rotation): Rotation | null { + const hasParent = this.colliderSet.raw.coRotationWrtParent(this.handle, scratchBuffer); + return hasParent ? RotationOps.fromBuffer(scratchBuffer, target) : null; } + // #endif /** * Is this collider a sensor? @@ -622,11 +661,13 @@ export class Collider { /** * The half-extents of this collider if it is a cuboid shape. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public halfExtents(): Vector { - return VectorOps.fromRaw( - this.colliderSet.raw.coHalfExtents(this.handle), - ); + public halfExtents(target?: Vector): Vector | null { + const isCuboid = this.colliderSet.raw.coHalfExtents(this.handle, scratchBuffer); + return isCuboid ? VectorOps.fromBuffer(scratchBuffer, target) : null; } /** @@ -842,10 +883,13 @@ export class Collider { /** * If this collider has a heightfield shape, this returns the scale * applied to it. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public heightfieldScale(): Vector { - let scale = this.colliderSet.raw.coHeightfieldScale(this.handle); - return VectorOps.fromRaw(scale); + public heightfieldScale(target?: Vector): Vector | null { + const isHeightfield = this.colliderSet.raw.coHeightfieldScale(this.handle, scratchBuffer); + return isHeightfield ? VectorOps.fromBuffer(scratchBuffer, target) : null; } // #if DIM3 diff --git a/src.ts/geometry/shape.ts b/src.ts/geometry/shape.ts index f3546982..e4cf8d5e 100644 --- a/src.ts/geometry/shape.ts +++ b/src.ts/geometry/shape.ts @@ -1,4 +1,10 @@ -import {Vector, VectorOps, Rotation, RotationOps} from "../math"; +import { + Vector, + VectorOps, + Rotation, + RotationOps, + scratchBuffer +} from "../math"; import {RawColliderSet, RawShape, RawShapeType} from "../raw"; import {ShapeContact} from "./contact"; import {PointProjection} from "./point"; @@ -35,24 +41,43 @@ export abstract class Shape { case RawShapeType.Ball: return new Ball(rawSet.coRadius(handle)); case RawShapeType.Cuboid: - extents = rawSet.coHalfExtents(handle); + rawSet.coHalfExtents(handle, scratchBuffer); + // #if DIM2 + extents = { + x: scratchBuffer[0], + y: scratchBuffer[1] + }; return new Cuboid(extents.x, extents.y); // #endif // #if DIM3 + extents = { + x: scratchBuffer[0], + y: scratchBuffer[1], + z: scratchBuffer[2] + }; return new Cuboid(extents.x, extents.y, extents.z); - // #endif + // #endif case RawShapeType.RoundCuboid: - extents = rawSet.coHalfExtents(handle); borderRadius = rawSet.coRoundRadius(handle); + rawSet.coHalfExtents(handle, scratchBuffer); // #if DIM2 + extents = { + x: scratchBuffer[0], + y: scratchBuffer[1] + }; return new RoundCuboid(extents.x, extents.y, borderRadius); // #endif // #if DIM3 + extents = { + x: scratchBuffer[0], + y: scratchBuffer[1], + z: scratchBuffer[2] + }; return new RoundCuboid( extents.x, extents.y, @@ -143,19 +168,28 @@ export abstract class Shape { return new TriMesh(vs, indices, tri_flags); case RawShapeType.HeightField: - const scale = rawSet.coHeightfieldScale(handle); const heights = rawSet.coHeightfieldHeights(handle); + rawSet.coHeightfieldScale(handle, scratchBuffer); // #if DIM2 + const scale = { + x: scratchBuffer[0], + y: scratchBuffer[1] + }; return new Heightfield(heights, scale); // #endif // #if DIM3 + const scale = { + x: scratchBuffer[0], + y: scratchBuffer[1], + z: scratchBuffer[2] + }; const nrows = rawSet.coHeightfieldNRows(handle); const ncols = rawSet.coHeightfieldNCols(handle); const hf_flags = rawSet.coHeightFieldFlags(handle); return new Heightfield(nrows, ncols, heights, scale, hf_flags); - // #endif + // #endif // #if DIM2 case RawShapeType.ConvexPolygon: diff --git a/src.ts/math.ts b/src.ts/math.ts index f43cf538..ced34391 100644 --- a/src.ts/math.ts +++ b/src.ts/math.ts @@ -3,6 +3,8 @@ import {RawVector, RawRotation} from "./raw"; import {RawSdpMatrix3} from "./raw"; // #endif +export const scratchBuffer = new Float32Array(6); + // #if DIM2 export interface Vector { x: number; diff --git a/src/dynamics/rigid_body.rs b/src/dynamics/rigid_body.rs index 47e8bca6..8d3d4912 100644 --- a/src/dynamics/rigid_body.rs +++ b/src/dynamics/rigid_body.rs @@ -8,15 +8,27 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen] impl RawRigidBodySet { + /// The world-space translation of this rigid-body. + pub fn rbTranslationOriginal(&self, handle: FlatHandle) -> RawVector { + self.map(handle, |rb| RawVector(rb.position().translation.vector)) + } + + /// The world-space orientation of this rigid-body. + pub fn rbRotationOriginal(&self, handle: FlatHandle) -> RawRotation { + self.map(handle, |rb| RawRotation(rb.position().rotation)) + } + /// The world-space translation of this rigid-body. /// /// # Parameters /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] pub fn rbTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.position().translation.vector); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + self.map(handle, |rb| { + let u = rb.position().translation.vector; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + }); } /// The world-space translation of this rigid-body. @@ -25,10 +37,12 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.position().translation.vector); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.position().translation.vector; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } /// The world-space orientation of this rigid-body. @@ -43,12 +57,14 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbRotation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.position().rotation); - let inner = u.into_inner(); - scratchBuffer.set_index(0, inner.i); - scratchBuffer.set_index(1, inner.j); - scratchBuffer.set_index(2, inner.k); - scratchBuffer.set_index(3, inner.w); + self.map(handle, |rb| { + let u = rb.position().rotation; + let inner = u.into_inner(); + scratchBuffer.set_index(0, inner.i); + scratchBuffer.set_index(1, inner.j); + scratchBuffer.set_index(2, inner.k); + scratchBuffer.set_index(3, inner.w); + }); } /// Put the given rigid-body to sleep. @@ -76,9 +92,11 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] pub fn rbNextTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.next_position().translation.vector); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + self.map(handle, |rb| { + let u = rb.next_position().translation.vector; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + }); } /// The world-space predicted translation of this rigid-body. @@ -91,10 +109,12 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbNextTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.next_position().translation.vector); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.next_position().translation.vector; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } /// The world-space predicted orientation of this rigid-body. @@ -117,12 +137,14 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbNextRotation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.next_position().rotation); - let inner = u.into_inner(); - scratchBuffer.set_index(0, inner.i); - scratchBuffer.set_index(1, inner.j); - scratchBuffer.set_index(2, inner.k); - scratchBuffer.set_index(3, inner.w); + self.map(handle, |rb| { + let u = rb.next_position().rotation; + let inner = u.into_inner(); + scratchBuffer.set_index(0, inner.i); + scratchBuffer.set_index(1, inner.j); + scratchBuffer.set_index(2, inner.k); + scratchBuffer.set_index(3, inner.w); + }); } /// Sets the translation of this rigid-body. @@ -357,9 +379,11 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] pub fn rbLinvel(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| *rb.linvel()); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + self.map(handle, |rb| { + let u = rb.linvel(); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + }); } /// The linear velocity of this rigid-body. @@ -368,10 +392,12 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbLinvel(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| *rb.linvel()); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.linvel(); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } /// The angular velocity of this rigid-body. @@ -386,10 +412,12 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbAngvel(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| *rb.angvel()); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.angvel(); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } /// The velocity of the given world-space point on this rigid-body. @@ -398,9 +426,11 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.velocity_at_point(&Point::from(point.0))); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + self.map(handle, |rb| { + let u = rb.velocity_at_point(&Point::from(point.0)); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + }); } /// The velocity of the given world-space point on this rigid-body. @@ -409,10 +439,12 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.velocity_at_point(&Point::from(point.0))); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.velocity_at_point(&Point::from(point.0)); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } pub fn rbLockTranslations(&mut self, handle: FlatHandle, locked: bool, wake_up: bool) { @@ -498,9 +530,11 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] pub fn rbEffectiveInvMass(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.mass_properties().effective_inv_mass); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + self.map(handle, |rb| { + let u = rb.mass_properties().effective_inv_mass; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + }); } /// The inverse mass taking into account translation locking. @@ -509,10 +543,12 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbEffectiveInvMass(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.mass_properties().effective_inv_mass); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.mass_properties().effective_inv_mass; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } /// The center of mass of a rigid-body expressed in its local-space. @@ -521,9 +557,11 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] pub fn rbLocalCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.mass_properties().local_mprops.local_com); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + self.map(handle, |rb| { + let u = rb.mass_properties().local_mprops.local_com; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + }); } /// The center of mass of a rigid-body expressed in its local-space. @@ -532,10 +570,12 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbLocalCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.mass_properties().local_mprops.local_com); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.mass_properties().local_mprops.local_com; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } /// The world-space center of mass of the rigid-body. @@ -544,9 +584,11 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] pub fn rbWorldCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.mass_properties().world_com); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + self.map(handle, |rb| { + let u = rb.mass_properties().world_com; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + }); } /// The world-space center of mass of the rigid-body. @@ -555,10 +597,12 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbWorldCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.mass_properties().world_com); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.mass_properties().world_com; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } /// The inverse of the principal angular inertia of the rigid-body. @@ -577,10 +621,12 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbInvPrincipalInertiaSqrt(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.mass_properties().local_mprops.inv_principal_inertia_sqrt); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.mass_properties().local_mprops.inv_principal_inertia_sqrt; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } /// The principal vectors of the local angular inertia tensor of the rigid-body. @@ -589,12 +635,14 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbPrincipalInertiaLocalFrame(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.mass_properties().local_mprops.principal_inertia_local_frame); - let inner = u.into_inner(); - scratchBuffer.set_index(0, inner.i); - scratchBuffer.set_index(1, inner.j); - scratchBuffer.set_index(2, inner.k); - scratchBuffer.set_index(3, inner.w); + self.map(handle, |rb| { + let u = rb.mass_properties().local_mprops.principal_inertia_local_frame; + let inner = u.into_inner(); + scratchBuffer.set_index(0, inner.i); + scratchBuffer.set_index(1, inner.j); + scratchBuffer.set_index(2, inner.k); + scratchBuffer.set_index(3, inner.w); + }); } /// The angular inertia along the principal inertia axes of the rigid-body. @@ -609,10 +657,12 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbPrincipalInertia(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.mass_properties().local_mprops.principal_inertia()); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.mass_properties().local_mprops.principal_inertia(); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } @@ -630,13 +680,15 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbEffectiveWorldInvInertiaSqrt(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.mass_properties().effective_world_inv_inertia_sqrt); - scratchBuffer.set_index(0, u.m11); - scratchBuffer.set_index(1, u.m12); - scratchBuffer.set_index(2, u.m13); - scratchBuffer.set_index(3, u.m22); - scratchBuffer.set_index(4, u.m23); - scratchBuffer.set_index(5, u.m33); + self.map(handle, |rb| { + let u = rb.mass_properties().effective_world_inv_inertia_sqrt; + scratchBuffer.set_index(0, u.m11); + scratchBuffer.set_index(1, u.m12); + scratchBuffer.set_index(2, u.m13); + scratchBuffer.set_index(3, u.m22); + scratchBuffer.set_index(4, u.m23); + scratchBuffer.set_index(5, u.m33); + }); } /// The effective world-space angular inertia (that takes the potential rotation locking into account) of @@ -653,13 +705,15 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbEffectiveAngularInertia(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.mass_properties().effective_angular_inertia()); - scratchBuffer.set_index(0, u.m11); - scratchBuffer.set_index(1, u.m12); - scratchBuffer.set_index(2, u.m13); - scratchBuffer.set_index(3, u.m22); - scratchBuffer.set_index(4, u.m23); - scratchBuffer.set_index(5, u.m33); + self.map(handle, |rb| { + let u = rb.mass_properties().effective_angular_inertia(); + scratchBuffer.set_index(0, u.m11); + scratchBuffer.set_index(1, u.m12); + scratchBuffer.set_index(2, u.m13); + scratchBuffer.set_index(3, u.m22); + scratchBuffer.set_index(4, u.m23); + scratchBuffer.set_index(5, u.m33); + }); } /// Wakes this rigid-body up. @@ -911,9 +965,11 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim2")] pub fn rbUserForce(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.user_force()); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + self.map(handle, |rb| { + let u = rb.user_force(); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + }); } /// Retrieves the constant force(s) the user added to this rigid-body. @@ -923,10 +979,12 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbUserForce(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.user_force()); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.user_force(); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } /// Retrieves the constant torque(s) the user added to this rigid-body. @@ -943,9 +1001,11 @@ impl RawRigidBodySet { /// - `scratchBuffer`: The array to be populated. #[cfg(feature = "dim3")] pub fn rbUserTorque(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { - let u = self.map(handle, |rb| rb.user_torque()); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + self.map(handle, |rb| { + let u = rb.user_torque(); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); } } diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index e8019044..6847f4f8 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -16,31 +16,113 @@ 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()) + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn coTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + self.map(handle, |co| { + let u = co.position().translation.vector; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + }); + } + /// The world-space translation of this collider. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + self.map(handle, |co| { + let u = co.position().translation.vector; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + }); + } + + /// The world-space orientation of this collider. + #[cfg(feature = "dim2")] + pub fn coRotation(&self, handle: FlatHandle) -> f32 { + self.map(handle, |co| co.position().rotation.angle()) } /// The world-space orientation of this collider. - pub fn coRotation(&self, handle: FlatHandle) -> RawRotation { - self.map(handle, |co| co.position().rotation.into()) + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coRotation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + self.map(handle, |co| { + let u = co.position().rotation; + let inner = u.into_inner(); + scratchBuffer.set_index(0, inner.i); + scratchBuffer.set_index(1, inner.j); + scratchBuffer.set_index(2, inner.k); + scratchBuffer.set_index(3, inner.w); + }); + } + + /// The translation of this collider relative to its parent rigid-body. + /// + /// Returns `false` if it doesn’t have a parent. + #[cfg(feature = "dim2")] + pub fn coTranslationWrtParent(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { + self.map(handle, |co| co.position_wrt_parent().map_or(false, |pose| { + let u = pose.translation.vector; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + true + })) } /// 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 { + /// Returns `false` if it doesn’t have a parent. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coTranslationWrtParent(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { + self.map(handle, |co| co.position_wrt_parent().map_or(false, |pose| { + let u = pose.translation.vector; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + true + })) + } + + /// The orientation of this collider relative to its parent rigid-body. + /// + /// Returns `NAN` if it doesn’t have a parent. + #[cfg(feature = "dim2")] + pub fn coRotationWrtParent(&self, handle: FlatHandle) -> f32 { self.map(handle, |co| { - co.position_wrt_parent() - .map(|pose| pose.translation.vector.into()) + co.position_wrt_parent().map_or(f32::NAN, |pose| { + pose.rotation.angle() + }) }) } /// 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 { + /// Returns `false` if it doesn’t have a parent. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coRotationWrtParent(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { self.map(handle, |co| { - co.position_wrt_parent().map(|pose| pose.rotation.into()) + co.position_wrt_parent().map_or(false, |pose| { + let u = pose.rotation; + let inner = u.into_inner(); + scratchBuffer.set_index(0, inner.i); + scratchBuffer.set_index(1, inner.j); + scratchBuffer.set_index(2, inner.k); + scratchBuffer.set_index(3, inner.w); + true + }) }) } @@ -177,17 +259,55 @@ impl RawColliderSet { }) } - /// The half-extents of this collider if it is has a cuboid shape. - pub fn coHalfExtents(&self, handle: FlatHandle) -> Option { + /// The half-extents of this collider if it has a cuboid shape. + /// + /// Returns `false` if it doesn’t have a cuboid shape. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn coHalfExtents(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { 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()) + co.shape().as_cuboid().map_or_else(|| { + co.shape().as_round_cuboid().map_or(false,|c| { + let u = c.inner_shape.half_extents; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + true + }) + },|c| { + let u = c.half_extents; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + true + }) + }) + } + + /// The half-extents of this collider if it has a cuboid shape. + /// + /// Returns `false` if it doesn’t have a cuboid shape. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coHalfExtents(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { + self.map(handle, |co| { + co.shape().as_cuboid().map_or_else(|| { + co.shape().as_round_cuboid().map_or(false,|c| { + let u = c.inner_shape.half_extents; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + true }) + },|c| { + let u = c.half_extents; + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + true + }) }) } @@ -580,11 +700,38 @@ impl RawColliderSet { }) } - /// The scaling factor applied of this heightfield if it is one. - pub fn coHeightfieldScale(&self, handle: FlatHandle) -> Option { + /// The scaling factor applied to this heightfield if it is one. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn coHeightfieldScale(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { self.map(handle, |co| match co.shape().shape_type() { - ShapeType::HeightField => co.shape().as_heightfield().map(|h| RawVector(*h.scale())), - _ => None, + ShapeType::HeightField => co.shape().as_heightfield().map_or(false, |h| { + let u = h.scale(); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + true + }), + _ => false, + }) + } + + /// The scaling factor applied to this heightfield if it is one. + /// + /// # Parameters + /// - `scratchBuffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coHeightfieldScale(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::HeightField => co.shape().as_heightfield().map_or(false, |h| { + let u = h.scale(); + scratchBuffer.set_index(0, u.x); + scratchBuffer.set_index(1, u.y); + scratchBuffer.set_index(2, u.z); + true + }), + _ => false, }) } From 1f1a44f50b50cfc62d0aad55c480dde8485efc5d Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sat, 20 Sep 2025 09:24:13 -0500 Subject: [PATCH 05/11] update collider.rs and shape.ts --- src.ts/geometry/shape.ts | 31 ++++++------------------------- src/geometry/collider.rs | 2 +- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src.ts/geometry/shape.ts b/src.ts/geometry/shape.ts index e4cf8d5e..c74bac9a 100644 --- a/src.ts/geometry/shape.ts +++ b/src.ts/geometry/shape.ts @@ -29,7 +29,6 @@ export abstract class Shape { ): Shape { const rawType = rawSet.coShapeType(handle); - let extents: Vector; let borderRadius: number; let vs: Float32Array; let indices: Uint32Array; @@ -44,20 +43,11 @@ export abstract class Shape { rawSet.coHalfExtents(handle, scratchBuffer); // #if DIM2 - extents = { - x: scratchBuffer[0], - y: scratchBuffer[1] - }; - return new Cuboid(extents.x, extents.y); + return new Cuboid(scratchBuffer[0], scratchBuffer[1]); // #endif // #if DIM3 - extents = { - x: scratchBuffer[0], - y: scratchBuffer[1], - z: scratchBuffer[2] - }; - return new Cuboid(extents.x, extents.y, extents.z); + return new Cuboid(scratchBuffer[0], scratchBuffer[1], scratchBuffer[2]); // #endif case RawShapeType.RoundCuboid: @@ -65,23 +55,14 @@ export abstract class Shape { rawSet.coHalfExtents(handle, scratchBuffer); // #if DIM2 - extents = { - x: scratchBuffer[0], - y: scratchBuffer[1] - }; - return new RoundCuboid(extents.x, extents.y, borderRadius); + return new RoundCuboid(scratchBuffer[0], scratchBuffer[1], borderRadius); // #endif // #if DIM3 - extents = { - x: scratchBuffer[0], - y: scratchBuffer[1], - z: scratchBuffer[2] - }; return new RoundCuboid( - extents.x, - extents.y, - extents.z, + scratchBuffer[0], + scratchBuffer[1], + scratchBuffer[2], borderRadius, ); // #endif diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 6847f4f8..023dafdc 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -269,7 +269,7 @@ impl RawColliderSet { pub fn coHalfExtents(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { self.map(handle, |co| { co.shape().as_cuboid().map_or_else(|| { - co.shape().as_round_cuboid().map_or(false,|c| { + co.shape().as_round_cuboid().map_or(false, |c| { let u = c.inner_shape.half_extents; scratchBuffer.set_index(0, u.x); scratchBuffer.set_index(1, u.y); From 1307487ade428d38204dbed482abd3ac27773a43 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sat, 20 Sep 2025 10:42:13 -0500 Subject: [PATCH 06/11] indent comment --- src.ts/geometry/shape.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src.ts/geometry/shape.ts b/src.ts/geometry/shape.ts index c74bac9a..58f547c7 100644 --- a/src.ts/geometry/shape.ts +++ b/src.ts/geometry/shape.ts @@ -65,7 +65,7 @@ export abstract class Shape { scratchBuffer[2], borderRadius, ); - // #endif + // #endif case RawShapeType.Capsule: halfHeight = rawSet.coHalfHeight(handle); From adaa43b43843e3cb5714af82f7a50ca05b92b9a1 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sat, 20 Sep 2025 14:58:32 -0500 Subject: [PATCH 07/11] toi (time of impact) updated to make no JS allocations --- src.ts/geometry/broad_phase.ts | 51 +++++++++------ src.ts/geometry/collider.ts | 74 +++++++++++++-------- src.ts/geometry/shape.ts | 39 ++++++----- src.ts/geometry/toi.ts | 114 ++++++++++++++++++++++++--------- src.ts/math.ts | 3 +- src/geometry/toi.rs | 104 +++++++++++++++++++----------- 6 files changed, 256 insertions(+), 129 deletions(-) diff --git a/src.ts/geometry/broad_phase.ts b/src.ts/geometry/broad_phase.ts index addaee92..de4f4f30 100644 --- a/src.ts/geometry/broad_phase.ts +++ b/src.ts/geometry/broad_phase.ts @@ -4,7 +4,7 @@ import {ColliderSet} from "./collider_set"; import {Ray, RayColliderHit, RayColliderIntersection} from "./ray"; import {InteractionGroups} from "./interaction_groups"; import {ColliderHandle} from "./collider"; -import {Rotation, RotationOps, Vector, VectorOps} from "../math"; +import {Rotation, RotationOps, Vector, VectorOps, scratchBuffer} from "../math"; import {Shape} from "./shape"; import {PointColliderProjection} from "./point"; import {ColliderShapeCastHit} from "./toi"; @@ -387,6 +387,8 @@ export class BroadPhase { * that it’s on a path to exit that penetration state. * @param groups - The bit groups and filter associated to the shape to cast, in order to only * test on colliders with collision groups compatible with this group. + * @param {ColliderShapeCastHit?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ public castShape( narrowPhase: NarrowPhase, @@ -404,33 +406,42 @@ export class BroadPhase { filterExcludeCollider?: ColliderHandle, filterExcludeRigidBody?: RigidBodyHandle, filterPredicate?: (collider: ColliderHandle) => boolean, + target?: ColliderShapeCastHit ): ColliderShapeCastHit | null { let rawPos = VectorOps.intoRaw(shapePos); let rawRot = RotationOps.intoRaw(shapeRot); let rawVel = VectorOps.intoRaw(shapeVel); let rawShape = shape.intoRaw(); - let result = ColliderShapeCastHit.fromRaw( - colliders, - this.raw.castShape( - narrowPhase.raw, - bodies.raw, - colliders.raw, - rawPos, - rawRot, - rawVel, - rawShape, - targetDistance, - maxToi, - stopAtPenetration, - filterFlags, - filterGroups, - filterExcludeCollider, - filterExcludeRigidBody, - filterPredicate, - ), + const rawColliderShapeCastHit = this.raw.castShape( + narrowPhase.raw, + bodies.raw, + colliders.raw, + rawPos, + rawRot, + rawVel, + rawShape, + targetDistance, + maxToi, + stopAtPenetration, + filterFlags, + filterGroups, + filterExcludeCollider, + filterExcludeRigidBody, + filterPredicate, + ); + + const colliderHandle: number = rawColliderShapeCastHit.colliderHandle(); + + rawColliderShapeCastHit.getComponents(scratchBuffer); + + let result = ColliderShapeCastHit.fromBuffer( + colliders.get(colliderHandle), + scratchBuffer, + target ); + rawColliderShapeCastHit.free(); rawPos.free(); rawRot.free(); rawVel.free(); diff --git a/src.ts/geometry/collider.ts b/src.ts/geometry/collider.ts index 275a828f..d28d4532 100644 --- a/src.ts/geometry/collider.ts +++ b/src.ts/geometry/collider.ts @@ -1,4 +1,3 @@ -import {RawColliderSet} from "../raw"; import { Rotation, RotationOps, @@ -9,7 +8,6 @@ import { import { CoefficientCombineRule, RigidBody, - RigidBodyHandle, RigidBodySet, } from "../dynamics"; import {ActiveHooks, ActiveEvents} from "../pipeline"; @@ -1028,7 +1026,7 @@ export class Collider { return result; } - /* + /** * Computes the smallest time between this and the given shape under translational movement are separated by a distance smaller or equal to distance. * * @param collider1Vel - The constant velocity of the current shape to cast (i.e. the cast direction). @@ -1043,6 +1041,8 @@ export class Collider { * @param stopAtPenetration - If set to `false`, the linear shape-cast won’t immediately stop if * the shape is penetrating another shape at its starting point **and** its trajectory is such * that it’s on a path to exit that penetration state. + * @param {ShapeCastHit?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ public castShape( collider1Vel: Vector, @@ -1053,6 +1053,7 @@ export class Collider { targetDistance: number, maxToi: number, stopAtPenetration: boolean, + target?: ShapeCastHit ): ShapeCastHit | null { let rawCollider1Vel = VectorOps.intoRaw(collider1Vel); let rawShape2Pos = VectorOps.intoRaw(shape2Pos); @@ -1060,21 +1061,27 @@ export class Collider { let rawShape2Vel = VectorOps.intoRaw(shape2Vel); let rawShape2 = shape2.intoRaw(); - let result = ShapeCastHit.fromRaw( - this.colliderSet, - this.colliderSet.raw.coCastShape( - this.handle, - rawCollider1Vel, - rawShape2, - rawShape2Pos, - rawShape2Rot, - rawShape2Vel, - targetDistance, - maxToi, - stopAtPenetration, - ), + const rawShapeCastHit = this.colliderSet.raw.coCastShape( + this.handle, + rawCollider1Vel, + rawShape2, + rawShape2Pos, + rawShape2Rot, + rawShape2Vel, + targetDistance, + maxToi, + stopAtPenetration, + ); + + rawShapeCastHit.getComponents(scratchBuffer); + + let result = ShapeCastHit.fromBuffer( + null, + scratchBuffer, + target, ); + rawShapeCastHit.free(); rawCollider1Vel.free(); rawShape2Pos.free(); rawShape2Rot.free(); @@ -1084,7 +1091,7 @@ export class Collider { return result; } - /* + /** * Computes the smallest time between this and the given collider under translational movement are separated by a distance smaller or equal to distance. * * @param collider1Vel - The constant velocity of the current collider to cast (i.e. the cast direction). @@ -1097,6 +1104,8 @@ export class Collider { * @param stopAtPenetration - If set to `false`, the linear shape-cast won’t immediately stop if * the shape is penetrating another shape at its starting point **and** its trajectory is such * that it’s on a path to exit that penetration state. + * @param {ColliderShapeCastHit?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ public castCollider( collider1Vel: Vector, @@ -1105,23 +1114,32 @@ export class Collider { targetDistance: number, maxToi: number, stopAtPenetration: boolean, + target?: ColliderShapeCastHit ): ColliderShapeCastHit | null { let rawCollider1Vel = VectorOps.intoRaw(collider1Vel); let rawCollider2Vel = VectorOps.intoRaw(collider2Vel); - let result = ColliderShapeCastHit.fromRaw( - this.colliderSet, - this.colliderSet.raw.coCastCollider( - this.handle, - rawCollider1Vel, - collider2.handle, - rawCollider2Vel, - targetDistance, - maxToi, - stopAtPenetration, - ), + const rawColliderShapeCastHit = this.colliderSet.raw.coCastCollider( + this.handle, + rawCollider1Vel, + collider2.handle, + rawCollider2Vel, + targetDistance, + maxToi, + stopAtPenetration, + ); + + const colliderHandle: number = rawColliderShapeCastHit.colliderHandle(); + + rawColliderShapeCastHit.getComponents(scratchBuffer); + + let result = ColliderShapeCastHit.fromBuffer( + this.colliderSet.get(colliderHandle), + scratchBuffer, + target ); + rawColliderShapeCastHit.free(); rawCollider1Vel.free(); rawCollider2Vel.free(); diff --git a/src.ts/geometry/shape.ts b/src.ts/geometry/shape.ts index 58f547c7..cc1fe0cd 100644 --- a/src.ts/geometry/shape.ts +++ b/src.ts/geometry/shape.ts @@ -219,7 +219,7 @@ export abstract class Shape { /** * Computes the time of impact between two moving shapes. - * @param shapePos1 - The initial position of this sahpe. + * @param shapePos1 - The initial position of this shape. * @param shapeRot1 - The rotation of this shape. * @param shapeVel1 - The velocity of this shape. * @param shape2 - The second moving shape. @@ -232,9 +232,11 @@ export abstract class Shape { * @param stopAtPenetration - If set to `false`, the linear shape-cast won’t immediately stop if * the shape is penetrating another shape at its starting point **and** its trajectory is such * that it’s on a path to exit that penetration state. + * @param {ShapeCastHit?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. * @returns If the two moving shapes collider at some point along their trajectories, this returns the * time at which the two shape collider as well as the contact information during the impact. Returns - * `null`if the two shapes never collide along their paths. + * `null` if the two shapes never collide along their paths. */ public castShape( shapePos1: Vector, @@ -247,6 +249,7 @@ export abstract class Shape { targetDistance: number, maxToi: number, stopAtPenetration: boolean, + target?: ShapeCastHit ): ShapeCastHit | null { let rawPos1 = VectorOps.intoRaw(shapePos1); let rawRot1 = RotationOps.intoRaw(shapeRot1); @@ -258,22 +261,28 @@ export abstract class Shape { let rawShape1 = this.intoRaw(); let rawShape2 = shape2.intoRaw(); - let result = ShapeCastHit.fromRaw( + const rawShapeCastHit = rawShape1.castShape( + rawPos1, + rawRot1, + rawVel1, + rawShape2, + rawPos2, + rawRot2, + rawVel2, + targetDistance, + maxToi, + stopAtPenetration, + ); + + rawShapeCastHit.getComponents(scratchBuffer); + + let result = ShapeCastHit.fromBuffer( null, - rawShape1.castShape( - rawPos1, - rawRot1, - rawVel1, - rawShape2, - rawPos2, - rawRot2, - rawVel2, - targetDistance, - maxToi, - stopAtPenetration, - ), + scratchBuffer, + target, ); + rawShapeCastHit.free(); rawPos1.free(); rawRot1.free(); rawVel1.free(); diff --git a/src.ts/geometry/toi.ts b/src.ts/geometry/toi.ts index ade13f17..57c30bc6 100644 --- a/src.ts/geometry/toi.ts +++ b/src.ts/geometry/toi.ts @@ -1,7 +1,5 @@ import {Collider} from "./collider"; import {Vector, VectorOps} from "../math"; -import {RawShapeCastHit, RawColliderShapeCastHit} from "../raw"; -import {ColliderSet} from "./collider_set"; /** * The intersection between a ray and a collider. @@ -46,21 +44,50 @@ export class ShapeCastHit { this.normal2 = normal2; } - public static fromRaw( - colliderSet: ColliderSet, - raw: RawShapeCastHit, + public static fromBuffer( + collider: Collider, + buffer: Float32Array, + target?: ShapeCastHit ): ShapeCastHit { - if (!raw) return null; - - const result = new ShapeCastHit( - raw.time_of_impact(), - VectorOps.fromRaw(raw.witness1()), - VectorOps.fromRaw(raw.witness2()), - VectorOps.fromRaw(raw.normal1()), - VectorOps.fromRaw(raw.normal2()), + if (!buffer) return null; + + target ??= new ShapeCastHit( + 0, + VectorOps.zeros(), + VectorOps.zeros(), + VectorOps.zeros(), + VectorOps.zeros() ); - raw.free(); - return result; + + target.time_of_impact = buffer[0]; + + // #if DIM2 + target.witness1.x = buffer[1]; + target.witness1.y = buffer[2]; + target.witness2.x = buffer[3]; + target.witness2.y = buffer[4]; + target.normal1.x = buffer[5]; + target.normal1.y = buffer[6]; + target.normal2.x = buffer[7]; + target.normal2.y = buffer[8]; + // #endif + + // #if DIM3 + target.witness1.x = buffer[1]; + target.witness1.y = buffer[2]; + target.witness1.z = buffer[3]; + target.witness2.x = buffer[4]; + target.witness2.y = buffer[5]; + target.witness2.z = buffer[6]; + target.normal1.x = buffer[7]; + target.normal1.y = buffer[8] + target.normal1.z = buffer[9]; + target.normal2.x = buffer[10]; + target.normal2.y = buffer[11]; + target.normal2.z = buffer[12]; + // #endif + + return target; } } @@ -85,21 +112,50 @@ export class ColliderShapeCastHit extends ShapeCastHit { this.collider = collider; } - public static fromRaw( - colliderSet: ColliderSet, - raw: RawColliderShapeCastHit, + public static fromBuffer( + collider: Collider, + buffer: Float32Array, + target?: ColliderShapeCastHit ): ColliderShapeCastHit { - if (!raw) return null; - - const result = new ColliderShapeCastHit( - colliderSet.get(raw.colliderHandle()), - raw.time_of_impact(), - VectorOps.fromRaw(raw.witness1()), - VectorOps.fromRaw(raw.witness2()), - VectorOps.fromRaw(raw.normal1()), - VectorOps.fromRaw(raw.normal2()), + if (!buffer) return null; + + target ??= new ColliderShapeCastHit( + collider, + 0, + VectorOps.zeros(), + VectorOps.zeros(), + VectorOps.zeros(), + VectorOps.zeros() ); - raw.free(); - return result; + + target.time_of_impact = buffer[0]; + + // #if DIM2 + target.witness1.x = buffer[1]; + target.witness1.y = buffer[2]; + target.witness2.x = buffer[3]; + target.witness2.y = buffer[4]; + target.normal1.x = buffer[5]; + target.normal1.y = buffer[6]; + target.normal2.x = buffer[7]; + target.normal2.y = buffer[8]; + // #endif + + // #if DIM3 + target.witness1.x = buffer[1]; + target.witness1.y = buffer[2]; + target.witness1.z = buffer[3]; + target.witness2.x = buffer[4]; + target.witness2.y = buffer[5]; + target.witness2.z = buffer[6]; + target.normal1.x = buffer[7]; + target.normal1.y = buffer[8] + target.normal1.z = buffer[9]; + target.normal2.x = buffer[10]; + target.normal2.y = buffer[11]; + target.normal2.z = buffer[12]; + // #endif + + return target; } } diff --git a/src.ts/math.ts b/src.ts/math.ts index ced34391..5a3a4b69 100644 --- a/src.ts/math.ts +++ b/src.ts/math.ts @@ -3,7 +3,8 @@ import {RawVector, RawRotation} from "./raw"; import {RawSdpMatrix3} from "./raw"; // #endif -export const scratchBuffer = new Float32Array(6); +// scratchBuffer should be as big as the biggest index Rust tries to set on it. +export const scratchBuffer = new Float32Array(16); // #if DIM2 export interface Vector { diff --git a/src/geometry/toi.rs b/src/geometry/toi.rs index 1e00675d..3d306f62 100644 --- a/src/geometry/toi.rs +++ b/src/geometry/toi.rs @@ -1,4 +1,3 @@ -use crate::math::RawVector; use crate::utils::{self, FlatHandle}; use rapier::geometry::{ColliderHandle, ShapeCastHit}; use wasm_bindgen::prelude::*; @@ -10,24 +9,41 @@ pub struct RawShapeCastHit { #[wasm_bindgen] impl RawShapeCastHit { - pub fn time_of_impact(&self) -> f32 { - self.hit.time_of_impact + #[cfg(feature = "dim2")] + pub fn getComponents(&self, scratchBuffer: &js_sys::Float32Array) { + scratchBuffer.set_index(0, self.hit.time_of_impact); + let mut u = self.hit.witness1.coords; + scratchBuffer.set_index(1, u.x); + scratchBuffer.set_index(2, u.y); + u = self.hit.witness2.coords; + scratchBuffer.set_index(3, u.x); + scratchBuffer.set_index(4, u.y); + u = self.hit.normal1.into_inner(); + scratchBuffer.set_index(5, u.x); + scratchBuffer.set_index(6, u.y); + u = self.hit.normal2.into_inner(); + scratchBuffer.set_index(7, u.x); + scratchBuffer.set_index(8, u.y); } - - 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() + #[cfg(feature = "dim3")] + pub fn getComponents(&self, scratchBuffer: &js_sys::Float32Array) { + scratchBuffer.set_index(0, self.hit.time_of_impact); + let mut u = self.hit.witness1.coords; + scratchBuffer.set_index(1, u.x); + scratchBuffer.set_index(2, u.y); + scratchBuffer.set_index(3, u.z); + u = self.hit.witness2.coords; + scratchBuffer.set_index(4, u.x); + scratchBuffer.set_index(5, u.y); + scratchBuffer.set_index(6, u.z); + u = self.hit.normal1.into_inner(); + scratchBuffer.set_index(7, u.x); + scratchBuffer.set_index(8, u.y); + scratchBuffer.set_index(9, u.z); + u = self.hit.normal2.into_inner(); + scratchBuffer.set_index(10, u.x); + scratchBuffer.set_index(11, u.y); + scratchBuffer.set_index(12, u.z); } } @@ -42,24 +58,40 @@ 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 + #[cfg(feature = "dim2")] + pub fn getComponents(&self, scratchBuffer: &js_sys::Float32Array) { + scratchBuffer.set_index(0, self.hit.time_of_impact); + let mut u = self.hit.witness1.coords; + scratchBuffer.set_index(1, u.x); + scratchBuffer.set_index(2, u.y); + u = self.hit.witness2.coords; + scratchBuffer.set_index(3, u.x); + scratchBuffer.set_index(4, u.y); + u = self.hit.normal1.into_inner(); + scratchBuffer.set_index(5, u.x); + scratchBuffer.set_index(6, u.y); + u = self.hit.normal2.into_inner(); + scratchBuffer.set_index(7, u.x); + scratchBuffer.set_index(8, u.y); } - - 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() + #[cfg(feature = "dim3")] + pub fn getComponents(&self, scratchBuffer: &js_sys::Float32Array) { + scratchBuffer.set_index(0, self.hit.time_of_impact); + let mut u = self.hit.witness1.coords; + scratchBuffer.set_index(1, u.x); + scratchBuffer.set_index(2, u.y); + scratchBuffer.set_index(3, u.z); + u = self.hit.witness2.coords; + scratchBuffer.set_index(4, u.x); + scratchBuffer.set_index(5, u.y); + scratchBuffer.set_index(6, u.z); + u = self.hit.normal1.into_inner(); + scratchBuffer.set_index(7, u.x); + scratchBuffer.set_index(8, u.y); + scratchBuffer.set_index(9, u.z); + u = self.hit.normal2.into_inner(); + scratchBuffer.set_index(10, u.x); + scratchBuffer.set_index(11, u.y); + scratchBuffer.set_index(12, u.z); } } From 42943f73e0eab3a0b0fbadad1f19bfb1366bd635 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sat, 20 Sep 2025 15:08:33 -0500 Subject: [PATCH 08/11] ensure ColliderShapeCastHit.collider is not null if target object is provided --- src.ts/geometry/toi.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src.ts/geometry/toi.ts b/src.ts/geometry/toi.ts index 57c30bc6..a72a1791 100644 --- a/src.ts/geometry/toi.ts +++ b/src.ts/geometry/toi.ts @@ -120,7 +120,7 @@ export class ColliderShapeCastHit extends ShapeCastHit { if (!buffer) return null; target ??= new ColliderShapeCastHit( - collider, + null, 0, VectorOps.zeros(), VectorOps.zeros(), @@ -128,6 +128,8 @@ export class ColliderShapeCastHit extends ShapeCastHit { VectorOps.zeros() ); + target.collider = collider; + target.time_of_impact = buffer[0]; // #if DIM2 From 167592c911bdf33e11538ab6445760206b537359 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sun, 21 Sep 2025 11:06:55 -0500 Subject: [PATCH 09/11] simplified VectorOps.fromRaw() and RotationOps.fromRaw() --- src.ts/math.ts | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src.ts/math.ts b/src.ts/math.ts index 5a3a4b69..dd4e5ce1 100644 --- a/src.ts/math.ts +++ b/src.ts/math.ts @@ -37,12 +37,10 @@ export class VectorOps { public static fromBuffer(buffer: Float32Array, target?: Vector): Vector { if (!buffer) return null; - if (target != null){ - target.x = buffer[0]; - target.y = buffer[1]; - return target; - } - return VectorOps.new(buffer[0], buffer[1]); + target ??= VectorOps.zeros(); + target.x = buffer[0]; + target.y = buffer[1]; + return target; } // FIXME: type ram: RawVector? @@ -127,13 +125,11 @@ export class VectorOps { public static fromBuffer(buffer: Float32Array, target?: Vector): Vector { if (!buffer) return null; - if (target != null){ - target.x = buffer[0]; - target.y = buffer[1]; - target.z = buffer[2]; - return target; - } - return VectorOps.new(buffer[0], buffer[1], buffer[2]); + target ??= VectorOps.zeros(); + target.x = buffer[0]; + target.y = buffer[1]; + target.z = buffer[2]; + return target; } // FIXME: type ram: RawVector? @@ -184,14 +180,12 @@ export class RotationOps { public static fromBuffer(buffer: Float32Array, target?: Rotation): Rotation { if (!buffer) return null; - if (target != null){ - target.x = buffer[0]; - target.y = buffer[1]; - target.z = buffer[2]; - target.w = buffer[3]; - return target; - } - return new Quaternion(buffer[0], buffer[1], buffer[2], buffer[3]); + target ??= RotationOps.identity(); + target.x = buffer[0]; + target.y = buffer[1]; + target.z = buffer[2]; + target.w = buffer[3]; + return target; } public static fromRaw(raw: RawRotation): Rotation { From f34f19cbc66bb4e27c233a9ca6c491954f642cbf Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sun, 21 Sep 2025 11:06:55 -0500 Subject: [PATCH 10/11] simplified VectorOps.fromBuffer() and RotationOps.fromBuffer() --- src.ts/math.ts | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src.ts/math.ts b/src.ts/math.ts index 5a3a4b69..dd4e5ce1 100644 --- a/src.ts/math.ts +++ b/src.ts/math.ts @@ -37,12 +37,10 @@ export class VectorOps { public static fromBuffer(buffer: Float32Array, target?: Vector): Vector { if (!buffer) return null; - if (target != null){ - target.x = buffer[0]; - target.y = buffer[1]; - return target; - } - return VectorOps.new(buffer[0], buffer[1]); + target ??= VectorOps.zeros(); + target.x = buffer[0]; + target.y = buffer[1]; + return target; } // FIXME: type ram: RawVector? @@ -127,13 +125,11 @@ export class VectorOps { public static fromBuffer(buffer: Float32Array, target?: Vector): Vector { if (!buffer) return null; - if (target != null){ - target.x = buffer[0]; - target.y = buffer[1]; - target.z = buffer[2]; - return target; - } - return VectorOps.new(buffer[0], buffer[1], buffer[2]); + target ??= VectorOps.zeros(); + target.x = buffer[0]; + target.y = buffer[1]; + target.z = buffer[2]; + return target; } // FIXME: type ram: RawVector? @@ -184,14 +180,12 @@ export class RotationOps { public static fromBuffer(buffer: Float32Array, target?: Rotation): Rotation { if (!buffer) return null; - if (target != null){ - target.x = buffer[0]; - target.y = buffer[1]; - target.z = buffer[2]; - target.w = buffer[3]; - return target; - } - return new Quaternion(buffer[0], buffer[1], buffer[2], buffer[3]); + target ??= RotationOps.identity(); + target.x = buffer[0]; + target.y = buffer[1]; + target.z = buffer[2]; + target.w = buffer[3]; + return target; } public static fromRaw(raw: RawRotation): Rotation { From d3cab357af72431d28b52d70f086cb691ce09554 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sun, 21 Sep 2025 11:09:06 -0500 Subject: [PATCH 11/11] simplified SdpMatrix3Ops.fromBuffer() --- src.ts/math.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src.ts/math.ts b/src.ts/math.ts index dd4e5ce1..1db152b4 100644 --- a/src.ts/math.ts +++ b/src.ts/math.ts @@ -290,16 +290,14 @@ export class SdpMatrix3Ops { public static fromBuffer(buffer: Float32Array, target?: SdpMatrix3): SdpMatrix3 { if (!buffer) return null; - if (target != null){ - target.elements[0] = buffer[0]; - target.elements[1] = buffer[1]; - target.elements[2] = buffer[2]; - target.elements[3] = buffer[3]; - target.elements[4] = buffer[4]; - target.elements[5] = buffer[5]; - return target; - } - return new SdpMatrix3(buffer); + target ??= new SdpMatrix3(buffer); + target.elements[0] = buffer[0]; + target.elements[1] = buffer[1]; + target.elements[2] = buffer[2]; + target.elements[3] = buffer[3]; + target.elements[4] = buffer[4]; + target.elements[5] = buffer[5]; + return target; } public static fromRaw(raw: RawSdpMatrix3): SdpMatrix3 {