From 9e912fccf9ed058af8246745271253e5b60bd591 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Thu, 24 Jul 2025 20:02:07 -0500 Subject: [PATCH 01/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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 { From 9bcc580e0960cdd0230b0fe2a84b500b2af92653 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sat, 7 Mar 2026 18:43:50 -0600 Subject: [PATCH 12/14] Update collider.rs and collider.ts to use scratchBuffer. Ensured all references to scratchBuffer use "snake case" in Rust: scratch_buffer. --- src.ts/geometry/narrow_phase.ts | 87 +++++++++-- src/dynamics/rigid_body.rs | 252 ++++++++++++++++---------------- src/geometry/collider.rs | 104 ++++++------- src/geometry/narrow_phase.rs | 155 +++++++++++++++++--- src/geometry/toi.rs | 96 ++++++------ 5 files changed, 434 insertions(+), 260 deletions(-) diff --git a/src.ts/geometry/narrow_phase.ts b/src.ts/geometry/narrow_phase.ts index af04a227..a04e3bf1 100644 --- a/src.ts/geometry/narrow_phase.ts +++ b/src.ts/geometry/narrow_phase.ts @@ -1,6 +1,10 @@ import {RawNarrowPhase, RawContactManifold} from "../raw"; import {ColliderHandle} from "./collider"; -import {Vector, VectorOps} from "../math"; +import { + Vector, + VectorOps, + scratchBuffer +} from "../math"; /** * The narrow-phase used for precise collision-detection. @@ -113,16 +117,37 @@ export class TempContactManifold { this.raw = raw; } - public normal(): Vector { - return VectorOps.fromRaw(this.raw.normal()); + /** + * (no description) + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public normal(target?: Vector): Vector { + this.raw.normal(scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } - public localNormal1(): Vector { - return VectorOps.fromRaw(this.raw.local_n1()); + /** + * (no description) + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public localNormal1(target?: Vector): Vector { + this.raw.local_n1(scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } - public localNormal2(): Vector { - return VectorOps.fromRaw(this.raw.local_n2()); + /** + * (no description) + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public localNormal2(target?: Vector): Vector { + this.raw.local_n2(scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } public subshape1(): number { @@ -137,12 +162,28 @@ export class TempContactManifold { return this.raw.num_contacts(); } - public localContactPoint1(i: number): Vector | null { - return VectorOps.fromRaw(this.raw.contact_local_p1(i)); + /** + * (no description) + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public localContactPoint1(i: number, target?: Vector): Vector | null { + const exists = this.raw.contact_local_p1(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; } - public localContactPoint2(i: number): Vector | null { - return VectorOps.fromRaw(this.raw.contact_local_p2(i)); + /** + * (no description) + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public localContactPoint2(i: number, target?: Vector): Vector | null { + const exists = this.raw.contact_local_p2(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; } public contactDist(i: number): number { @@ -181,8 +222,16 @@ export class TempContactManifold { return this.raw.num_solver_contacts(); } - public solverContactPoint(i: number): Vector { - return VectorOps.fromRaw(this.raw.solver_contact_point(i)); + /** + * (no description) + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public solverContactPoint(i: number, target?: Vector): Vector | null { + const exists = this.raw.solver_contact_point(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; } public solverContactDist(i: number): number { @@ -197,7 +246,15 @@ export class TempContactManifold { return this.raw.solver_contact_restitution(i); } - public solverContactTangentVelocity(i: number): Vector { - return VectorOps.fromRaw(this.raw.solver_contact_tangent_velocity(i)); + /** + * (no description) + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public solverContactTangentVelocity(i: number, target?: Vector): Vector { + this.raw.solver_contact_tangent_velocity(i, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); } } diff --git a/src/dynamics/rigid_body.rs b/src/dynamics/rigid_body.rs index b4be7076..ddd3c48a 100644 --- a/src/dynamics/rigid_body.rs +++ b/src/dynamics/rigid_body.rs @@ -21,27 +21,27 @@ impl RawRigidBodySet { /// The world-space translation of this rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbTranslation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { self.map(handle, |rb| { let u = rb.position().translation.vector; - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); }); } /// The world-space translation of this rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbTranslation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); }); } @@ -54,16 +54,16 @@ impl RawRigidBodySet { /// The world-space orientation of this rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbRotation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbRotation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, inner.i); + scratch_buffer.set_index(1, inner.j); + scratch_buffer.set_index(2, inner.k); + scratch_buffer.set_index(3, inner.w); }); } @@ -89,13 +89,13 @@ impl RawRigidBodySet { /// For non-kinematic bodies, this value is currently unspecified. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbNextTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbNextTranslation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { self.map(handle, |rb| { let u = rb.next_position().translation.vector; - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); }); } @@ -106,14 +106,14 @@ impl RawRigidBodySet { /// For non-kinematic bodies, this value is currently unspecified. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbNextTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbNextTranslation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); }); } @@ -134,16 +134,16 @@ impl RawRigidBodySet { /// For non-kinematic bodies, this value is currently unspecified. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbNextRotation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbNextRotation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, inner.i); + scratch_buffer.set_index(1, inner.j); + scratch_buffer.set_index(2, inner.k); + scratch_buffer.set_index(3, inner.w); }); } @@ -376,27 +376,27 @@ impl RawRigidBodySet { /// The linear velocity of this rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbLinvel(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbLinvel(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { self.map(handle, |rb| { let u = rb.linvel(); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); }); } /// The linear velocity of this rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbLinvel(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbLinvel(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); }); } @@ -409,41 +409,41 @@ impl RawRigidBodySet { /// The angular velocity of this rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbAngvel(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbAngvel(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); }); } /// The velocity of the given world-space point on this rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, scratchBuffer: &js_sys::Float32Array) { + pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); }); } /// The velocity of the given world-space point on this rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, scratchBuffer: &js_sys::Float32Array) { + pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); }); } @@ -527,81 +527,81 @@ impl RawRigidBodySet { /// The inverse mass taking into account translation locking. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbEffectiveInvMass(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbEffectiveInvMass(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { self.map(handle, |rb| { let u = rb.mass_properties().effective_inv_mass; - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); }); } /// The inverse mass taking into account translation locking. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbEffectiveInvMass(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbEffectiveInvMass(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.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. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbLocalCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbLocalCom(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.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. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbLocalCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbLocalCom(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); }); } /// The world-space center of mass of the rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbWorldCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbWorldCom(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { self.map(handle, |rb| { let u = rb.mass_properties().world_com; - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); }); } /// The world-space center of mass of the rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbWorldCom(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbWorldCom(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); }); } @@ -618,30 +618,30 @@ impl RawRigidBodySet { /// Components set to zero are assumed to be infinite along the corresponding principal axis. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbInvPrincipalInertia(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbInvPrincipalInertia(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { self.map(handle, |rb| { let u = rb.mass_properties().local_mprops.inv_principal_inertia; - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); - scratchBuffer.set_index(2, u.z); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.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. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbPrincipalInertiaLocalFrame(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbPrincipalInertiaLocalFrame(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, inner.i); + scratch_buffer.set_index(1, inner.j); + scratch_buffer.set_index(2, inner.k); + scratch_buffer.set_index(3, inner.w); }); } @@ -654,14 +654,14 @@ impl RawRigidBodySet { /// The angular inertia along the principal inertia axes of the rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbPrincipalInertia(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbPrincipalInertia(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); }); } @@ -677,17 +677,17 @@ impl RawRigidBodySet { /// taking into account rotation locking. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbEffectiveWorldInvInertia(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbEffectiveWorldInvInertia(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { self.map(handle, |rb| { let u = rb.mass_properties().effective_world_inv_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); + scratch_buffer.set_index(0, u.m11); + scratch_buffer.set_index(1, u.m12); + scratch_buffer.set_index(2, u.m13); + scratch_buffer.set_index(3, u.m22); + scratch_buffer.set_index(4, u.m23); + scratch_buffer.set_index(5, u.m33); }); } @@ -702,17 +702,17 @@ impl RawRigidBodySet { /// this rigid-body. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbEffectiveAngularInertia(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbEffectiveAngularInertia(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.m11); + scratch_buffer.set_index(1, u.m12); + scratch_buffer.set_index(2, u.m13); + scratch_buffer.set_index(3, u.m22); + scratch_buffer.set_index(4, u.m23); + scratch_buffer.set_index(5, u.m33); }); } @@ -962,13 +962,13 @@ impl RawRigidBodySet { /// Returns zero if the rigid-body is not dynamic. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn rbUserForce(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbUserForce(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { self.map(handle, |rb| { let u = rb.user_force(); - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); }); } @@ -976,14 +976,14 @@ impl RawRigidBodySet { /// Returns zero if the rigid-body is not dynamic. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbUserForce(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbUserForce(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); }); } @@ -998,14 +998,14 @@ impl RawRigidBodySet { /// Returns zero if the rigid-body is not dynamic. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn rbUserTorque(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn rbUserTorque(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { 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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); }); } } diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 023dafdc..5f1925d0 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -18,26 +18,26 @@ impl RawColliderSet { /// The world-space translation of this collider. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn coTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn coTranslation(&self, handle: FlatHandle, scratch_buffer: &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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); }); } /// The world-space translation of this collider. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn coTranslation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn coTranslation(&self, handle: FlatHandle, scratch_buffer: &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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); }); } @@ -50,16 +50,16 @@ impl RawColliderSet { /// The world-space orientation of this collider. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn coRotation(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) { + pub fn coRotation(&self, handle: FlatHandle, scratch_buffer: &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); + scratch_buffer.set_index(0, inner.i); + scratch_buffer.set_index(1, inner.j); + scratch_buffer.set_index(2, inner.k); + scratch_buffer.set_index(3, inner.w); }); } @@ -67,11 +67,11 @@ impl RawColliderSet { /// /// Returns `false` if it doesn’t have a parent. #[cfg(feature = "dim2")] - pub fn coTranslationWrtParent(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { + pub fn coTranslationWrtParent(&self, handle: FlatHandle, scratch_buffer: &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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); true })) } @@ -81,14 +81,14 @@ impl RawColliderSet { /// Returns `false` if it doesn’t have a parent. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn coTranslationWrtParent(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { + pub fn coTranslationWrtParent(&self, handle: FlatHandle, scratch_buffer: &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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); true })) } @@ -110,17 +110,17 @@ impl RawColliderSet { /// Returns `false` if it doesn’t have a parent. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn coRotationWrtParent(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { + pub fn coRotationWrtParent(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) -> bool { self.map(handle, |co| { 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); + scratch_buffer.set_index(0, inner.i); + scratch_buffer.set_index(1, inner.j); + scratch_buffer.set_index(2, inner.k); + scratch_buffer.set_index(3, inner.w); true }) }) @@ -264,21 +264,21 @@ impl RawColliderSet { /// Returns `false` if it doesn’t have a cuboid shape. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn coHalfExtents(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { + pub fn coHalfExtents(&self, handle: FlatHandle, scratch_buffer: &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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); true }) },|c| { let u = c.half_extents; - scratchBuffer.set_index(0, u.x); - scratchBuffer.set_index(1, u.y); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); true }) }) @@ -289,23 +289,23 @@ impl RawColliderSet { /// Returns `false` if it doesn’t have a cuboid shape. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn coHalfExtents(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { + pub fn coHalfExtents(&self, handle: FlatHandle, scratch_buffer: &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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); true }) }) @@ -703,14 +703,14 @@ impl RawColliderSet { /// The scaling factor applied to this heightfield if it is one. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim2")] - pub fn coHeightfieldScale(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { + pub fn coHeightfieldScale(&self, handle: FlatHandle, scratch_buffer: &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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); true }), _ => false, @@ -720,15 +720,15 @@ impl RawColliderSet { /// The scaling factor applied to this heightfield if it is one. /// /// # Parameters - /// - `scratchBuffer`: The array to be populated. + /// - `scratch_buffer`: The array to be populated. #[cfg(feature = "dim3")] - pub fn coHeightfieldScale(&self, handle: FlatHandle, scratchBuffer: &js_sys::Float32Array) -> bool { + pub fn coHeightfieldScale(&self, handle: FlatHandle, scratch_buffer: &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); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); true }), _ => false, diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index be3fee25..398d6ae9 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -1,4 +1,3 @@ -use crate::math::RawVector; use crate::utils::{self, FlatHandle}; use rapier::geometry::{ContactManifold, ContactPair, NarrowPhase}; use rapier::math::Real; @@ -93,20 +92,65 @@ impl RawContactPair { #[wasm_bindgen] impl RawContactManifold { - pub fn normal(&self) -> RawVector { - unsafe { RawVector((*self.0).data.normal) } + #[cfg(feature = "dim2")] + pub fn normal(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).data.normal; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + } + + #[cfg(feature = "dim3")] + pub fn normal(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).data.normal; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } } // pub fn user_data(&self) -> u32 { // unsafe { (*self.0).data.user_data } // } - pub fn local_n1(&self) -> RawVector { - unsafe { (*self.0).local_n1.into() } + #[cfg(feature = "dim2")] + pub fn local_n1(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).local_n1; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } } - pub fn local_n2(&self) -> RawVector { - unsafe { (*self.0).local_n2.into() } + #[cfg(feature = "dim3")] + pub fn local_n1(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).local_n1; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + } + + #[cfg(feature = "dim2")] + pub fn local_n2(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).local_n2; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + } + + #[cfg(feature = "dim3")] + pub fn local_n2(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).local_n2; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } } pub fn subshape1(&self) -> u32 { @@ -121,12 +165,54 @@ impl RawContactManifold { unsafe { (*self.0).points.len() } } - pub fn contact_local_p1(&self, i: usize) -> Option { - unsafe { (&(*self.0).points).get(i).map(|c| c.local_p1.coords.into()) } + #[cfg(feature = "dim2")] + pub fn contact_local_p1(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + unsafe { + (&(*self.0).points).get(i).map_or(false, |c| { + let u = c.local_p1.coords; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + } + + #[cfg(feature = "dim3")] + pub fn contact_local_p1(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + unsafe { + (&(*self.0).points).get(i).map_or(false, |c| { + let u = c.local_p1.coords; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } } - pub fn contact_local_p2(&self, i: usize) -> Option { - unsafe { (&(*self.0).points).get(i).map(|c| c.local_p2.coords.into()) } + #[cfg(feature = "dim2")] + pub fn contact_local_p2(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + unsafe { + (&(*self.0).points).get(i).map_or(false, |c| { + let u = c.local_p2.coords; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + } + + #[cfg(feature = "dim3")] + pub fn contact_local_p2(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + unsafe { + (&(*self.0).points).get(i).map_or(false, |c| { + let u = c.local_p2.coords; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } } pub fn contact_dist(&self, i: usize) -> Real { @@ -184,12 +270,28 @@ impl RawContactManifold { unsafe { (*self.0).data.solver_contacts.len() } } - pub fn solver_contact_point(&self, i: usize) -> Option { + #[cfg(feature = "dim2")] + pub fn solver_contact_point(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { unsafe { - (&(*self.0).data) - .solver_contacts - .get(i) - .map(|c| c.point.coords.into()) + (&(*self.0).data).solver_contacts.get(i).map_or(false, |c| { + let u = c.point.coords; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + } + + #[cfg(feature = "dim3")] + pub fn solver_contact_point(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + unsafe { + (&(*self.0).data).solver_contacts.get(i).map_or(false, |c| { + let u = c.point.coords; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) } } @@ -211,7 +313,22 @@ impl RawContactManifold { unsafe { (&(*self.0).data).solver_contacts[i].restitution } } - pub fn solver_contact_tangent_velocity(&self, i: usize) -> RawVector { - unsafe { (&(*self.0).data).solver_contacts[i].tangent_velocity.into() } + #[cfg(feature = "dim2")] + pub fn solver_contact_tangent_velocity(&self, i: usize, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (&(*self.0).data).solver_contacts[i].tangent_velocity; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + } + + #[cfg(feature = "dim3")] + pub fn solver_contact_tangent_velocity(&self, i: usize, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (&(*self.0).data).solver_contacts[i].tangent_velocity; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } } -} +} \ No newline at end of file diff --git a/src/geometry/toi.rs b/src/geometry/toi.rs index 3d306f62..909b0138 100644 --- a/src/geometry/toi.rs +++ b/src/geometry/toi.rs @@ -10,40 +10,40 @@ pub struct RawShapeCastHit { #[wasm_bindgen] impl RawShapeCastHit { #[cfg(feature = "dim2")] - pub fn getComponents(&self, scratchBuffer: &js_sys::Float32Array) { - scratchBuffer.set_index(0, self.hit.time_of_impact); + pub fn getComponents(&self, scratch_buffer: &js_sys::Float32Array) { + scratch_buffer.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); + scratch_buffer.set_index(1, u.x); + scratch_buffer.set_index(2, u.y); u = self.hit.witness2.coords; - scratchBuffer.set_index(3, u.x); - scratchBuffer.set_index(4, u.y); + scratch_buffer.set_index(3, u.x); + scratch_buffer.set_index(4, u.y); u = self.hit.normal1.into_inner(); - scratchBuffer.set_index(5, u.x); - scratchBuffer.set_index(6, u.y); + scratch_buffer.set_index(5, u.x); + scratch_buffer.set_index(6, u.y); u = self.hit.normal2.into_inner(); - scratchBuffer.set_index(7, u.x); - scratchBuffer.set_index(8, u.y); + scratch_buffer.set_index(7, u.x); + scratch_buffer.set_index(8, u.y); } #[cfg(feature = "dim3")] - pub fn getComponents(&self, scratchBuffer: &js_sys::Float32Array) { - scratchBuffer.set_index(0, self.hit.time_of_impact); + pub fn getComponents(&self, scratch_buffer: &js_sys::Float32Array) { + scratch_buffer.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); + scratch_buffer.set_index(1, u.x); + scratch_buffer.set_index(2, u.y); + scratch_buffer.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); + scratch_buffer.set_index(4, u.x); + scratch_buffer.set_index(5, u.y); + scratch_buffer.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); + scratch_buffer.set_index(7, u.x); + scratch_buffer.set_index(8, u.y); + scratch_buffer.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); + scratch_buffer.set_index(10, u.x); + scratch_buffer.set_index(11, u.y); + scratch_buffer.set_index(12, u.z); } } @@ -59,39 +59,39 @@ impl RawColliderShapeCastHit { utils::flat_handle(self.handle.0) } #[cfg(feature = "dim2")] - pub fn getComponents(&self, scratchBuffer: &js_sys::Float32Array) { - scratchBuffer.set_index(0, self.hit.time_of_impact); + pub fn getComponents(&self, scratch_buffer: &js_sys::Float32Array) { + scratch_buffer.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); + scratch_buffer.set_index(1, u.x); + scratch_buffer.set_index(2, u.y); u = self.hit.witness2.coords; - scratchBuffer.set_index(3, u.x); - scratchBuffer.set_index(4, u.y); + scratch_buffer.set_index(3, u.x); + scratch_buffer.set_index(4, u.y); u = self.hit.normal1.into_inner(); - scratchBuffer.set_index(5, u.x); - scratchBuffer.set_index(6, u.y); + scratch_buffer.set_index(5, u.x); + scratch_buffer.set_index(6, u.y); u = self.hit.normal2.into_inner(); - scratchBuffer.set_index(7, u.x); - scratchBuffer.set_index(8, u.y); + scratch_buffer.set_index(7, u.x); + scratch_buffer.set_index(8, u.y); } #[cfg(feature = "dim3")] - pub fn getComponents(&self, scratchBuffer: &js_sys::Float32Array) { - scratchBuffer.set_index(0, self.hit.time_of_impact); + pub fn getComponents(&self, scratch_buffer: &js_sys::Float32Array) { + scratch_buffer.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); + scratch_buffer.set_index(1, u.x); + scratch_buffer.set_index(2, u.y); + scratch_buffer.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); + scratch_buffer.set_index(4, u.x); + scratch_buffer.set_index(5, u.y); + scratch_buffer.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); + scratch_buffer.set_index(7, u.x); + scratch_buffer.set_index(8, u.y); + scratch_buffer.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); + scratch_buffer.set_index(10, u.x); + scratch_buffer.set_index(11, u.y); + scratch_buffer.set_index(12, u.z); } } From c32bbadb4eadde564d6000956a90a1bb29e4df21 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sun, 8 Mar 2026 13:46:29 -0500 Subject: [PATCH 13/14] Updated ray_cast_vehicle_controller. --- src.ts/control/ray_cast_vehicle_controller.ts | 57 +++++-- src/control/ray_cast_vehicle_controller.rs | 148 ++++++++++++++---- 2 files changed, 163 insertions(+), 42 deletions(-) diff --git a/src.ts/control/ray_cast_vehicle_controller.ts b/src.ts/control/ray_cast_vehicle_controller.ts index fa65b3e3..4ba43c08 100644 --- a/src.ts/control/ray_cast_vehicle_controller.ts +++ b/src.ts/control/ray_cast_vehicle_controller.ts @@ -1,5 +1,5 @@ import {RawDynamicRayCastVehicleController} from "../raw"; -import {Vector, VectorOps} from "../math"; +import {scratchBuffer, Vector, VectorOps} from "../math"; import { BroadPhase, Collider, @@ -163,11 +163,17 @@ export class DynamicRayCastVehicleController { /* * Getters + setters */ + /** * The position of the i-th wheel, relative to the chassis. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public wheelChassisConnectionPointCs(i: number): Vector | null { - return VectorOps.fromRaw(this.raw.wheel_chassis_connection_point_cs(i)); + public wheelChassisConnectionPointCs(i: number, target?: Vector): Vector | null { + const exists = this.raw.wheel_chassis_connection_point_cs(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; } /** @@ -331,9 +337,14 @@ export class DynamicRayCastVehicleController { * The direction of the i-th wheel’s suspension, relative to the chassis. * * The ray-casting will happen following this direction to detect the ground. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public wheelDirectionCs(i: number): Vector | null { - return VectorOps.fromRaw(this.raw.wheel_direction_cs(i)); + public wheelDirectionCs(i: number, target?: Vector): Vector | null { + const exists = this.raw.wheel_direction_cs(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; } /** @@ -351,9 +362,14 @@ export class DynamicRayCastVehicleController { * The i-th wheel’s axle axis, relative to the chassis. * * The axis index defined as 0 = X, 1 = Y, 2 = Z. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public wheelAxleCs(i: number): Vector | null { - return VectorOps.fromRaw(this.raw.wheel_axle_cs(i)); + public wheelAxleCs(i: number, target?: Vector): Vector | null { + const exists = this.raw.wheel_axle_cs(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; } /** @@ -439,16 +455,26 @@ export class DynamicRayCastVehicleController { /** * The (world-space) contact normal between the i-th wheel and the floor. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public wheelContactNormal(i: number): Vector | null { - return VectorOps.fromRaw(this.raw.wheel_contact_normal_ws(i)); + public wheelContactNormal(i: number, target?: Vector): Vector | null { + const exists = this.raw.wheel_contact_normal_ws(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; } /** * The (world-space) point hit by the wheel’s ray-cast for the i-th wheel. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public wheelContactPoint(i: number): Vector | null { - return VectorOps.fromRaw(this.raw.wheel_contact_point_ws(i)); + public wheelContactPoint(i: number, target?: Vector): Vector | null { + const exists = this.raw.wheel_contact_point_ws(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; } /** @@ -460,9 +486,14 @@ export class DynamicRayCastVehicleController { /** * The (world-space) starting point of the ray-cast for the i-th wheel. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public wheelHardPoint(i: number): Vector | null { - return VectorOps.fromRaw(this.raw.wheel_hard_point_ws(i)); + public wheelHardPoint(i: number, target?: Vector): Vector | null { + const exists = this.raw.wheel_hard_point_ws(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; } /** diff --git a/src/control/ray_cast_vehicle_controller.rs b/src/control/ray_cast_vehicle_controller.rs index 36bd7f61..01846f8f 100644 --- a/src/control/ray_cast_vehicle_controller.rs +++ b/src/control/ray_cast_vehicle_controller.rs @@ -105,12 +105,27 @@ impl RawDynamicRayCastVehicleController { /* * Getters + setters */ - pub fn wheel_chassis_connection_point_cs(&self, i: usize) -> Option { - self.controller - .wheels() - .get(i) - .map(|w| w.chassis_connection_point_cs.into()) + #[cfg(feature = "dim2")] + pub fn wheel_chassis_connection_point_cs(&self,i: usize,scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.chassis_connection_point_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_chassis_connection_point_cs(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.chassis_connection_point_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) } + pub fn set_wheel_chassis_connection_point_cs(&mut self, i: usize, value: &RawVector) { if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { wheel.chassis_connection_point_cs = value.0.into(); @@ -225,21 +240,54 @@ impl RawDynamicRayCastVehicleController { } } - pub fn wheel_direction_cs(&self, i: usize) -> Option { - self.controller - .wheels() - .get(i) - .map(|w| w.direction_cs.into()) + #[cfg(feature = "dim2")] + pub fn wheel_direction_cs(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.direction_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_direction_cs(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.direction_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) } + pub fn set_wheel_direction_cs(&mut self, i: usize, value: &RawVector) { if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { wheel.direction_cs = value.0; } } - pub fn wheel_axle_cs(&self, i: usize) -> Option { - self.controller.wheels().get(i).map(|w| w.axle_cs.into()) + #[cfg(feature = "dim2")] + pub fn wheel_axle_cs(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.axle_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_axle_cs(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.axle_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) } + pub fn set_wheel_axle_cs(&mut self, i: usize, value: &RawVector) { if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { wheel.axle_cs = value.0; @@ -290,18 +338,46 @@ impl RawDynamicRayCastVehicleController { .map(|w| w.wheel_suspension_force) } - pub fn wheel_contact_normal_ws(&self, i: usize) -> Option { - self.controller - .wheels() - .get(i) - .map(|w| w.raycast_info().contact_normal_ws.into()) - } - - pub fn wheel_contact_point_ws(&self, i: usize) -> Option { - self.controller - .wheels() - .get(i) - .map(|w| w.raycast_info().contact_point_ws.into()) + #[cfg(feature = "dim2")] + pub fn wheel_contact_normal_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().contact_normal_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_contact_normal_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().contact_normal_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } + + #[cfg(feature = "dim2")] + pub fn wheel_contact_point_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().contact_point_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_contact_point_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().contact_point_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) } pub fn wheel_suspension_length(&self, i: usize) -> Option { @@ -311,11 +387,25 @@ impl RawDynamicRayCastVehicleController { .map(|w| w.raycast_info().suspension_length) } - pub fn wheel_hard_point_ws(&self, i: usize) -> Option { - self.controller - .wheels() - .get(i) - .map(|w| w.raycast_info().hard_point_ws.into()) + #[cfg(feature = "dim2")] + pub fn wheel_hard_point_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().hard_point_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_hard_point_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().hard_point_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) } pub fn wheel_is_in_contact(&self, i: usize) -> bool { From 857403662c723fe57d3324bfecfb0b7ac7b91a54 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Sun, 8 Mar 2026 16:53:33 -0500 Subject: [PATCH 14/14] Updated impulse_joint. --- src.ts/dynamics/impulse_joint.ts | 34 +++++++++++----- src/dynamics/impulse_joint.rs | 68 ++++++++++++++++++++++++++++---- 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/src.ts/dynamics/impulse_joint.ts b/src.ts/dynamics/impulse_joint.ts index 0c637ddf..d5b05daa 100644 --- a/src.ts/dynamics/impulse_joint.ts +++ b/src.ts/dynamics/impulse_joint.ts @@ -1,4 +1,4 @@ -import {Rotation, Vector, VectorOps, RotationOps} from "../math"; +import {Rotation, Vector, VectorOps, RotationOps, scratchBuffer} from "../math"; import { RawGenericJoint, RawImpulseJointSet, @@ -149,9 +149,13 @@ export class ImpulseJoint { // #if DIM3 /** * The rotation quaternion that aligns this joint's first local axis to the `x` axis. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public frameX1(): Rotation { - return RotationOps.fromRaw(this.rawSet.jointFrameX1(this.handle)); + public frameX1(target?: Rotation): Rotation { + this.rawSet.jointFrameX1(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); } // #endif @@ -159,9 +163,13 @@ export class ImpulseJoint { // #if DIM3 /** * The rotation matrix that aligns this joint's second local axis to the `x` axis. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public frameX2(): Rotation { - return RotationOps.fromRaw(this.rawSet.jointFrameX2(this.handle)); + public frameX2(target?: Rotation): Rotation { + this.rawSet.jointFrameX2(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); } // #endif @@ -171,9 +179,13 @@ export class ImpulseJoint { * * The first anchor gives the position of the application point on the * local frame of the first rigid-body it is attached to. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public anchor1(): Vector { - return VectorOps.fromRaw(this.rawSet.jointAnchor1(this.handle)); + public anchor1(target?: Vector): Vector { + this.rawSet.jointAnchor1(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); } /** @@ -181,9 +193,13 @@ export class ImpulseJoint { * * The second anchor gives the position of the application point on the * local frame of the second rigid-body it is attached to. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. */ - public anchor2(): Vector { - return VectorOps.fromRaw(this.rawSet.jointAnchor2(this.handle)); + public anchor2(target?: Vector): Vector { + this.rawSet.jointAnchor2(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); } /** diff --git a/src/dynamics/impulse_joint.rs b/src/dynamics/impulse_joint.rs index bfbdf128..f53df66c 100644 --- a/src/dynamics/impulse_joint.rs +++ b/src/dynamics/impulse_joint.rs @@ -22,29 +22,81 @@ impl RawImpulseJointSet { } /// The angular part of the joint’s local frame relative to the first rigid-body it is attached to. - pub fn jointFrameX1(&self, handle: FlatHandle) -> RawRotation { - self.map(handle, |j| j.data.local_frame1.rotation.into()) + #[cfg(feature = "dim3")] + pub fn jointFrameX1(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame1.rotation.into_inner(); + scratch_buffer.set_index(0, u.i); + scratch_buffer.set_index(1, u.j); + scratch_buffer.set_index(2, u.k); + scratch_buffer.set_index(3, u.w); + }); } /// The angular part of the joint’s local frame relative to the second rigid-body it is attached to. - pub fn jointFrameX2(&self, handle: FlatHandle) -> RawRotation { - self.map(handle, |j| j.data.local_frame2.rotation.into()) + #[cfg(feature = "dim3")] + pub fn jointFrameX2(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame2.rotation.into_inner(); + scratch_buffer.set_index(0, u.i); + scratch_buffer.set_index(1, u.j); + scratch_buffer.set_index(2, u.k); + scratch_buffer.set_index(3, u.w); + }); } /// The position of the first anchor of this joint. /// /// The first anchor gives the position of the points application point on the /// local frame of the first rigid-body it is attached to. - pub fn jointAnchor1(&self, handle: FlatHandle) -> RawVector { - self.map(handle, |j| j.data.local_frame1.translation.vector.into()) + #[cfg(feature = "dim2")] + pub fn jointAnchor1(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame1.translation.vector; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + + /// The position of the second anchor of this joint. + /// + /// The second anchor gives the position of the points application point on the + /// local frame of the second rigid-body it is attached to. + #[cfg(feature = "dim3")] + pub fn jointAnchor1(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame1.translation.vector; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The position of the second anchor of this joint. + /// + /// The second anchor gives the position of the points application point on the + /// local frame of the second rigid-body it is attached to. + #[cfg(feature = "dim2")] + pub fn jointAnchor2(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame2.translation.vector; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); } /// The position of the second anchor of this joint. /// /// The second anchor gives the position of the points application point on the /// local frame of the second rigid-body it is attached to. - pub fn jointAnchor2(&self, handle: FlatHandle) -> RawVector { - self.map(handle, |j| j.data.local_frame2.translation.vector.into()) + #[cfg(feature = "dim3")] + pub fn jointAnchor2(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame2.translation.vector; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); } /// Sets the position of the first local anchor