chore: 添加第三方依赖库
This commit is contained in:
12
thirdparty/rapier.js/.github/FUNDING.yml
vendored
Normal file
12
thirdparty/rapier.js/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: ["dimforge"] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
154
thirdparty/rapier.js/.github/workflows/main.yml
vendored
Normal file
154
thirdparty/rapier.js/.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
name: main
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
check-fmt:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22.x"
|
||||
- run: npm ci
|
||||
- name: Check formatting
|
||||
run: npm run fmt -- --check
|
||||
- name: Check Rust formatting
|
||||
run: cargo fmt -- --check
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
RUSTFLAGS: -D warnings
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- run: npm ci;
|
||||
- name: Prepare no-compat builds
|
||||
run: |
|
||||
./builds/prepare_builds/prepare_all_projects.sh
|
||||
- name: Build all no-compat projects
|
||||
run: |
|
||||
./builds/prepare_builds/build_all_projects.sh
|
||||
# Install dependencies to check simd for builds
|
||||
- name: Install wabt
|
||||
run: |
|
||||
sudo apt install wabt;
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Install wabt
|
||||
run: |
|
||||
brew install wabt;
|
||||
if: matrix.os == 'macos-latest'
|
||||
# Check simd for rust builds
|
||||
- name: Check 2d simd rust build
|
||||
run: |
|
||||
if ! wasm-objdump -d builds/rapier2d-simd/pkg/rapier_wasm2d_bg.wasm | grep :\\sfd ; then
|
||||
>&2 echo "ERROR: 2d simd compat build does not include simd opcode prefix." && exit 1
|
||||
fi
|
||||
- name: Check 3d simd compat build
|
||||
run: |
|
||||
if ! wasm-objdump -d builds/rapier3d-simd/pkg/rapier_wasm3d_bg.wasm | grep :\\sfd ; then
|
||||
>&2 echo "ERROR: 3d simd compat build does not include simd opcode prefix." && exit 1
|
||||
fi
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pkg no-compat ${{ matrix.os }}
|
||||
path: |
|
||||
builds/*/pkg
|
||||
overwrite: true
|
||||
build-compat:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
RUSTFLAGS: -D warnings
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- run: npm ci;
|
||||
- name: Prepare compat builds
|
||||
run: |
|
||||
./builds/prepare_builds/prepare_all_projects.sh
|
||||
- name: Build rapier-compat
|
||||
run: |
|
||||
cd rapier-compat;
|
||||
npm ci;
|
||||
npm run build;
|
||||
npm run test;
|
||||
# Install dependencies to check simd for builds
|
||||
- name: Install wabt
|
||||
run: |
|
||||
sudo apt install wabt;
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Install wabt
|
||||
run: |
|
||||
brew install wabt;
|
||||
if: matrix.os == 'macos-latest'
|
||||
# Check simd for compat builds
|
||||
- name: Check 2d simd compat build
|
||||
run: |
|
||||
if ! wasm-objdump -d rapier-compat/builds/2d-simd/pkg/rapier_wasm2d_bg.wasm | grep :\\sfd ; then
|
||||
>&2 echo "ERROR: 2d simd compat build does not include simd opcode prefix." && exit 1;
|
||||
fi
|
||||
- name: Check 3d simd compat build
|
||||
run: |
|
||||
if ! wasm-objdump -d rapier-compat/builds/3d-simd/pkg/rapier_wasm3d_bg.wasm | grep :\\sfd ; then
|
||||
>&2 echo "ERROR: 3d simd compat build does not include simd opcode prefix." && exit 1;
|
||||
fi
|
||||
# Upload
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pkg compat ${{ matrix.os }}
|
||||
path: |
|
||||
rapier-compat/builds/*/pkg
|
||||
overwrite: true
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build, build-compat]
|
||||
if: github.ref == 'refs/heads/master'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: pkg no-compat ubuntu-latest
|
||||
path: builds
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: pkg compat ubuntu-latest
|
||||
path: rapier-compat/builds
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22.x"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
- name: Publish projects
|
||||
run: |
|
||||
./publish_all_canary.sh
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
21
thirdparty/rapier.js/.gitignore
vendored
Normal file
21
thirdparty/rapier.js/.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
rapier2d/compat
|
||||
rapier3d/compat
|
||||
**/*.rs.bk
|
||||
node_modules
|
||||
target
|
||||
.idea
|
||||
.DS_Store
|
||||
dist
|
||||
pkg
|
||||
gen2d/
|
||||
gen3d/
|
||||
docs
|
||||
*.swp
|
||||
*.d.ts
|
||||
|
||||
# Made by the prepare_builds crate
|
||||
builds/*
|
||||
!builds/prepare_builds
|
||||
|
||||
# compat generated builds
|
||||
rapier-compat/builds/
|
||||
7
thirdparty/rapier.js/.prettierignore
vendored
Normal file
7
thirdparty/rapier.js/.prettierignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
pkg
|
||||
gen2d
|
||||
gen3d
|
||||
docs
|
||||
target
|
||||
**/CHANGELOG.md
|
||||
**/README.md
|
||||
5
thirdparty/rapier.js/.prettierrc
vendored
Normal file
5
thirdparty/rapier.js/.prettierrc
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"tabWidth": 4,
|
||||
"bracketSpacing": false,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
937
thirdparty/rapier.js/CHANGELOG.md
vendored
Normal file
937
thirdparty/rapier.js/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,937 @@
|
||||
## 0.19.3 (05 Nov. 2025)
|
||||
|
||||
- Significantly improve performances of `combineVoxelStates`.
|
||||
|
||||
### 0.19.2 (17 Oct. 2025)
|
||||
|
||||
- Fix bug where kinematic bodies would not wake up when setting its velocity.
|
||||
- Fix bug where slow-moving kinematic bodies would fall asleep.
|
||||
- Fix point-projection on voxels shapes.
|
||||
|
||||
### 0.19.1 (03 Oct. 2025)
|
||||
|
||||
### Modified
|
||||
|
||||
- Update to Rapier 0.30.0. The only change is a [switch to a sparse storage](https://github.com/dimforge/parry/pull/380)
|
||||
for the Voxels shapes. This allows support for orders of magnitudes larger maps without reaching the 4GB WASM memory
|
||||
limit.
|
||||
|
||||
### 0.19.0 (05 Sept. 2025)
|
||||
|
||||
### Modified
|
||||
|
||||
- Update to Rapier 0.29.0 which includes performance improvements for scenes involving a lot of contact constraints.
|
||||
See https://github.com/dimforge/rapier/pull/876 for details.
|
||||
- Renamed the `RigidBody.invPrincipalInertiaSqrt` and `.effectiveWorldInvInertiaSqrt` methods to
|
||||
`RigidBody.invPrincipalInertia` and `.effectiveWorldInvInertia` (removed the `Sqrt` suffix). These methods will now
|
||||
return the actual inverse angular inertia matrix rather than its square root.
|
||||
- Removed methods related to the legacy PGS solver: `World.numAdditionalFrictionIterations`,
|
||||
`switchToStandardPgsSolver`, `switchToSmallStepsPgsSolver`, `switchToSmallStepsPgsSolverWithoutWarmstart`.
|
||||
|
||||
### 0.18.2 (13 August 2025)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix rollup configuration adding `types: "./rapier.d.ts"` to the export config.
|
||||
|
||||
### 0.18.1 (8 August 2025)
|
||||
|
||||
### Modified
|
||||
|
||||
- Update to Rapier 0.28.0 which includes performance improvements when CCD is active and when
|
||||
the user applies modification to a collider or rigid-body.
|
||||
|
||||
### Fix
|
||||
|
||||
- Another attempt to fix bundlerless module import with rapier-compat.
|
||||
|
||||
### 0.18.0 (24 July 2025)
|
||||
|
||||
### Added
|
||||
|
||||
- Add `World.timing*` functions to access the internal performances measurements if the internal
|
||||
profiler is enabled with `World.profilerEnabled = true`.
|
||||
- Add `World.maxCcdSubsteps` to get/set the max number of CCD substeps run by the engine.
|
||||
|
||||
### Fix
|
||||
|
||||
- Fixed crash that would happen when removing colliders in a particular order (e.g. in the same order
|
||||
as their insertion).
|
||||
|
||||
### 0.18.0-beta.0 (12 July 2025)
|
||||
|
||||
#### Modified
|
||||
|
||||
- Update to Rapier 0.27.0-beta.1 which includes a fully reworked broad-phase tha supports scene queries.
|
||||
This implies a performance gain on large scenes by avoiding the need to re-build the underlying acceleration
|
||||
structure at each frame.
|
||||
- Un-deprecate methods for reading shape properties (for example `collider.radius()`). It turned out that these
|
||||
methods are more convenient as they are guaranteed to always be in sync with rapier’s state on wasm.
|
||||
- Add `collider.translationWrtParent()` and `collider.rotationWrtParent()` to get the collider’s translation/rotation
|
||||
relative to its parent rigid-body.
|
||||
|
||||
#### Fix
|
||||
|
||||
- rapier-compat top level javascript files extensions have been changed from `.cjs.js` and `.es.js` to `.cjs` and `mjs`
|
||||
respectively. This results in better compatibility with NPM.
|
||||
|
||||
### 0.17.3 (30 May 2025)
|
||||
|
||||
#### Fix
|
||||
|
||||
- The published package for 0.17.2 had a broken package.json. It is fixed on this release.
|
||||
|
||||
### 0.17.2 (30 May 2025)
|
||||
|
||||
#### Added
|
||||
|
||||
- Added the function `RAPIER.reserveMemory` to instruct the internal allocator to pre-allocate more memory in preparation
|
||||
for future operations. This typically called only once after initializing the WASM module.
|
||||
|
||||
### 0.17.1 (23 May 2025)
|
||||
|
||||
#### Added
|
||||
|
||||
- Added optional arguments to `World.debugRender(filterFlags, filterPredicate)` to prevent some colliders from being
|
||||
rendered.
|
||||
- Added `Collider.combineVoxelStates` to ensure two adjacent voxels colliders don’t suffer from the internal edges
|
||||
problem, and `Collider.propagateVoxelChange` to maintain that coupling after modifications with `.setVoxel`.
|
||||
|
||||
### 0.17.0 (16 May 2025)
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fix sensor events not triggering when hitting a voxels collider.
|
||||
|
||||
#### Added
|
||||
|
||||
- Added support for voxels colliders attached to dynamic rigid-bodies.
|
||||
- Added force calculation between colliding voxels/voxels and voxels/compound shapes.
|
||||
|
||||
### 0.16.2 (5 May 2025)
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fixed infinite loop in `collider.setVoxel`.
|
||||
|
||||
### 0.16.1 (2 May 2025)
|
||||
|
||||
#### Added
|
||||
|
||||
- Added `Collider.clearShapeCache` to release the reference to the JS shape stored in the collider, oor too force its
|
||||
recomputation the next time the collider shape is accessed.
|
||||
- Added support for shape-casting involving Voxels colliders.
|
||||
- Added support for CCD involving Voxels colliders.
|
||||
|
||||
### 0.16.0 (24 April 2025)
|
||||
|
||||
#### Added
|
||||
|
||||
- Added `ColliderDesc.voxels` to create a collider with a shape optimized for voxels.
|
||||
- Added `Collider.setVoxel` for adding or removing a voxel from a collider with a voxel shape.
|
||||
- Added the `Voxels` shape class.
|
||||
|
||||
The support or voxels is still experimental. In particular the following features will currently **not** work on
|
||||
colliders with voxel shapes:
|
||||
|
||||
- Voxels colliders attached to dynamic rigid-bodies will not run the automatic mass/angular inertia calculation.
|
||||
- Shape-casting on voxel shapes/colliders.
|
||||
- Collision-detection between two-voxels colliders, or a voxels collider and a mesh, polyline, or heightfield.
|
||||
|
||||
See [parry#336](https://github.com/dimforge/parry/pull/336) for additional information.
|
||||
|
||||
### 0.15.1 (10 April 2025)
|
||||
|
||||
#### Added
|
||||
|
||||
- Added `RigidBody.velocityAtPoint` function to retrieve the velocity of a given world-space point on a rigid-body.
|
||||
|
||||
#### Modified
|
||||
|
||||
- Update to Rapier 0.25. The main notable change is that the `TriMeshFlags.FIX_INTERNAL_EDGES` flag will no longer
|
||||
imply that the `TriMeshFlags.ORIENTED` flag is set, avoiding edge-cases where enabling `FIX_INTERNAL_EDGES`
|
||||
results in unexpected collisions between open meshes and balls.
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fixed `*-simd-compat` builds not actually emitting SIMD instructions.
|
||||
|
||||
### 0.15.0 (06 March 2025)
|
||||
|
||||
#### Added
|
||||
|
||||
- Added `PidController`, `World.createPidController`, `World.removePidController` to create a Position-Integral-Derivative
|
||||
controller; a building block for building velocity-based dynamic character controllers.
|
||||
|
||||
#### Modified
|
||||
|
||||
- Update to Rapier 0.24.
|
||||
- Package tree shaking has been disabled to avoid a crash on certain build configuration (#289).
|
||||
- Multiple packages with different feature sets are now released, and their build process has been automated (#309)
|
||||
- Released packages are:
|
||||
- rapier2d
|
||||
- rapier2d-compat
|
||||
- rapier2d-simd
|
||||
- rapier2d-simd-compat
|
||||
- rapier2d-deterministic
|
||||
- rapier2d-deterministic-compat
|
||||
- rapier3d
|
||||
- rapier3d-compat
|
||||
- rapier2d
|
||||
- rapier2d-compat
|
||||
- rapier3d-simd
|
||||
- rapier3d-simd-compat
|
||||
- rapier3d-deterministic
|
||||
- rapier3d-deterministic-compat
|
||||
- :warning: To this occasion, existing packages `rapier2d` and `rapier3d` are now built without `enhanced-determinism` feature enabled,
|
||||
so if you rely on that feature, you should migrate to the new `-deterministic` flavor.
|
||||
|
||||
|
||||
### 0.14.0 (20 July 2024)
|
||||
|
||||
#### Modified
|
||||
|
||||
- Update from the rust library of rapier 0.19 to 0.22, see [rapier's changelog](https://github.com/dimforge/rapier/blob/master/CHANGELOG.md#v0210-23-june-2024) for more context.
|
||||
|
||||
#### Added
|
||||
|
||||
- Added `RigidBody.userForce` function to retrieve the constant force(s) the user added to a rigid-body
|
||||
- Added `RigidBody.userTorque` function to retrieve the constant torque(s) the user added to a rigid-body
|
||||
|
||||
### 0.13.1 (2024-05-08)
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fix regression that could cause missed contact between a ball and another shape type.
|
||||
|
||||
### 0.13.0 (2024-05-05)
|
||||
|
||||
Several stability improvements are added as part of this release.
|
||||
See [rapier#625](https://github.com/dimforge/rapier/pull/625) for overviews of the most important improvements.
|
||||
|
||||
#### Modified
|
||||
|
||||
- The `castShape` and `castCollider` functions have been modified to add a `targetDistance` parameter. This parameter
|
||||
indicates the distance below which a hit is detected.
|
||||
- Rename `RayIntersection.toi` to `.timeOfImpact` for better clarity.
|
||||
- Rename `RayColliderIntersection.toi` to `.timeOfImpact` for better clarity.
|
||||
- Rename `RayColliderToi` to `RayColliderHit`.
|
||||
- Rename `RayColliderHit.toi` to `.timeOfImpact` for better clarity.
|
||||
- Rename `ShapeTOI` to `ShapeCastHit`.
|
||||
- Rename `ShapeColliderTOI` to `ColliderShapeCastHit`.
|
||||
- Rename `ShapeCastHit.toi` to `.timeOfImpact`.
|
||||
|
||||
#### Added
|
||||
|
||||
- Fix the kinematic character controller getting stuck against vertical walls.
|
||||
- Add `KinematicCharacterController.normalNudgeFactor` and `.setNormalNudgeFactor` so set a coefficient used for
|
||||
avoiding having the character controller get stuck on penetrations.
|
||||
- Add `RigidBody.softCcdPrediction`, `.setSoftCcdPrediction`, and `RigidBodyDesc.setSoftCcdPrediction` for configuring
|
||||
soft-ccd on the rigid-body. See [rapier#625](https://github.com/dimforge/rapier/pull/625) for additional details on
|
||||
soft-ccd.
|
||||
- 3D version only: add `TriMeshFlags::FIX_INTERNAL_EDGES` and `HeightFieldFlags::FIX_INTERNAL_EDGES` for enabling
|
||||
internal edges correction (which is no longer enabled by default). The flags have been added as an optional parameter
|
||||
when building the shapes.
|
||||
- Add `Collider.contactSkin`, `.setContactSkin`, and `ColliderDesc.setContactSkin` for configuring the collider’s
|
||||
contact skin. See [rapier#625](https://github.com/dimforge/rapier/pull/625) for additional details on contact skins.
|
||||
- Add `World.lengthUnit` which can be used to indicate the typical size of dynamic objects (e.g. 100 pixels instead of
|
||||
1 meter). This helps the physics engine adjust internal thresholds for better results.
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fix an issue where the reported contact force are lower than their actual value.
|
||||
|
||||
### 0.12.0 (2024-01-28)
|
||||
|
||||
The main highlight of this release is the implementation of a new non-linear constraints solver for better stability
|
||||
and increased convergence rates. See [#579](https://github.com/dimforge/rapier/pull/579) for additional information.
|
||||
|
||||
In order to adjust the number of iterations of the new solver, simply adjust `World.numSolverIterations`.
|
||||
If recovering the old solver behavior is useful to you, call `World.switchToStandardPgsSolver()`.
|
||||
|
||||
It is now possible to specify some additional solver iteration for specific rigid-bodies (and everything interacting
|
||||
with it directly or indirectly through contacts and joints): `RigidBodyDesc.additionalSolverIterations` and
|
||||
`RigidBody::setAdditionalSolverIterations`. This allows for higher-accuracy on subsets of the physics scene
|
||||
without affecting performance of the other parts of the simulation.
|
||||
|
||||
#### Modified
|
||||
|
||||
- Renamed `CharacterController.translationApplied`, `.translationRemaining` and the `desiredTranslation`
|
||||
method argument to `CharacterController.translationDeltaApplied`, `.translationDeltaRemaining` and the
|
||||
`desiredTranslationDelta` to avoid confusion with the usage of the `translation` world in `RigidBody.translation()`.
|
||||
|
||||
#### Added
|
||||
|
||||
- Added `DynamicRayCastVehicleController` to simulate vehicles based on ray-casting.
|
||||
- Added `JointData.generic` (3D only) to create a generic 6-dof joint and manually specify the locked axes.
|
||||
|
||||
### 0.11.2
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fix bug that made dynamic rigid-bodies behave like kinematic bodies after being disabled and then re-enabled.
|
||||
- Fix issue with convex polyhedron jitter due to missing contacts.
|
||||
- Fix character controller getting stuck against vertical walls.
|
||||
- Fix character controller’s snapping to ground not triggering sometimes.
|
||||
- Fix character controller’s horizontal offset being mostly ignored and some instances of vertical offset being ignored.
|
||||
|
||||
#### Added
|
||||
|
||||
- Add `JointData.spring` and `JointData.rope` joints.
|
||||
- Add access to the mass-properties of a rigid-body: `RigidBody.effectiveInvMass`, `.invMass()`, `.localCom()`,
|
||||
`.worldCom()`, `.invPrincipalInertiaSqrt()`, `.principalInertia()`, `.principalInertiaLocalFrame()`,
|
||||
`.effectiveWorldInvInertiaSqrt()`, `.effectiveAngularInertia()`.
|
||||
- Add `DynamicRayCastVehicleController.siteFrictionStiffness` to customize the side friction applied to the vehicle
|
||||
controller’s wheel.
|
||||
|
||||
#### Modified
|
||||
|
||||
- Rename `World.contactsWith` to `World.contactPairsWith`.
|
||||
- Rename `World.intersectionsWith` to `World.intersectionPairsWith`.
|
||||
|
||||
### 0.11.1 (2023-01-16)
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fix bug that disabled all colliders at construction time.
|
||||
|
||||
### 0.11.0 (2023-01-15)
|
||||
|
||||
#### Added
|
||||
|
||||
- Add `World.propagateModifiedBodyPositionsToColliders` to propagate rigid-bodies position changes to their attached
|
||||
colliders.
|
||||
- Add `World.updateSceneQueries` to update the scene queries data structures without stepping the whole simulation.
|
||||
- Add `RigidBody.isEnabled, RigidBody.setEnabled, RigidBodyDesc.setEnabled` to disable a rigid-body (and all its
|
||||
attached colliders) without removing it from the physics world.
|
||||
- Add `Collider.isEnabled, Collider.setEnabled, ColliderDesc.setEnabled` to disable a collider without removing it
|
||||
from the physics world.
|
||||
- Add shape-specific methods to modify a collider’s
|
||||
size: `Collider.setRadius, setHalfExtents, setRoundRadius, setHalfHeight`.
|
||||
|
||||
#### Modified
|
||||
|
||||
- Add a boolean argument to `RigidBody.setBodyType` to indicate if the rigid-body should awaken after changing
|
||||
its type.
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fix rigid-bodies automatically waking up at creation even if they were explicitly created sleeping.
|
||||
|
||||
### 0.10.0 (2022-11-06)
|
||||
|
||||
#### Added
|
||||
|
||||
- Add `World.createCharacterController`, `World.removeCharacterController` to create/remove a kinematic character
|
||||
controller.
|
||||
- Add a character-controller implementation with the `KinematicCharacterController` class and its method
|
||||
`KinematicCharacterController.computeColliderMovement`. The character controller features currently supported are:
|
||||
- Slide on uneven terrains
|
||||
- Interaction with dynamic bodies.
|
||||
- Climb stairs automatically.
|
||||
- Automatically snap the body to the floor when going downstairs.
|
||||
- Prevent sliding up slopes that are too steep
|
||||
- Prevent sliding down slopes that are not steep enough
|
||||
- Interactions with moving platforms.
|
||||
- Report information on the obstacles it hit on its path.
|
||||
- Add the `HalfSpace` (infinite plane) shape. Colliders with this shape can be built using `ColliderDesc.halfspace`.
|
||||
|
||||
#### Modified
|
||||
|
||||
- Change the signature of `Collider.castShape` and World.castShape by adding a boolean argument `stop_at_penetration`
|
||||
before the filter-related arguments. Set this argument to `true` to get the same result as before. If this is set to
|
||||
`false` and the shape being cast starts it path already intersecting another shape, then a hit won’t be returned
|
||||
with that intersecting shape unless the casting movement would result in more penetrations.
|
||||
- Reduce rounding errors in 3D when setting the rotation of a rigid-body or collider.
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fix incorrect application of torque if the torque is applies right after setting the rigid-body’s
|
||||
position, but before calling `World.step`.
|
||||
|
||||
### 0.9.0 (2022-10-07)
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fix unpredictable broad-phase panic when using small colliders in the simulation.
|
||||
- Fix collision events being incorrectly generated for any shape that produces multiple
|
||||
contact manifolds (like triangle meshes).
|
||||
|
||||
#### Modified
|
||||
|
||||
- The `RigidBodyDesc.setAdditionalMass` method will now result in the additional angular inertia
|
||||
being automatically computed based on the shapes of the colliders attached to the rigid-body.
|
||||
- Removed the method `RigidBodyDesc.setAdditionalPrincipalAngularInertia`. Use
|
||||
`RigidBodyDesc.setAdditionalMassProperties` instead.
|
||||
- The methods of `RigidBodyDesc` and `ColliderDesc` will now always copy the object provided by
|
||||
the user instead of storing the object itself.
|
||||
- The following method will now copy the user’s objects instead of storing it: `ColliderDesc.setRotation`,
|
||||
`ColliderDesc.setMassProperties`, `RigidBodyDesc.setRotation`, `RigidBodyDesc.setAdditionalMassProperties`,
|
||||
`RigidBodyDesc.setAngvel`.
|
||||
- Rename `RigidBody.restrictRotations` and `RigidBody.restrictTranslations` to
|
||||
`RigidBody.setEnabledRotations` and `RigidBody.setEnabledTranslations`.
|
||||
- Rename `RigidBodyDesc.restrictRotations` and `RigidBodyDesc.restrictTranslations` to
|
||||
`RigidBodyDesc.enabledRotations` and `RigidBodyDesc.enabledTranslations`.
|
||||
|
||||
#### Added
|
||||
|
||||
- Add `ImpulseJoint.setContactsEnabled`, and `MultibodyJoint.setContactsEnabled` to set whether
|
||||
contacts are enabled between colliders attached to rigid-bodies linked by this joint.
|
||||
- Add `UnitImpulseJoint.setLimits` to set the limits of a unit joint.
|
||||
- Add `RigidBody.recomputeMassPropertiesFromColliders` to force the immediate computation
|
||||
of a rigid-body’s mass properties (instead of waiting for them to be recomputed during the next
|
||||
timestep). This is useful to be able to read immediately the result of a change of a rigid-body
|
||||
additional mass-properties or a change of one of its collider’s mass-properties.
|
||||
- Add `RigidBody::setAdditionalMass` to set the additional mass for the rigid-body. The additional
|
||||
angular inertia is automatically computed based on the attached colliders shapes. If this automatic
|
||||
angular inertia computation isn’t desired, use `RigidBody::setAdditionalMassProperties` instead.
|
||||
- Add `Collider.setDensity`, `.setMass`, `.setMassProperties`, to alter a collider’s mass
|
||||
properties. Note that `.setMass` will result in the collider’s angular inertia being automatically
|
||||
computed based on this mass and on its shape.
|
||||
- Add `ColliderDesc.setMass` to set the mass of the collider instead of its density. Its angular
|
||||
inertia tensor will be automatically computed based on this mass and its shape.
|
||||
- Add more filtering options for scene-queries. All the scene query methods now take additional optional
|
||||
arguments to indicate if one particular collider, rigid-body, or type of colliders/rigid-bodies have to
|
||||
be ignored by the query.
|
||||
- Add force reporting based on contact force events. The `EventHandler` trait has been modified to include
|
||||
the method `EventQueue.drainContactForceEvents`. Contact force events are generated whenever the sum of the
|
||||
magnitudes of all the forces between two colliders is greater than any of their
|
||||
`Collider.contactForceEventThreshold` values (only the colliders with the `ActiveEvents.CONTACT_FORCE_EVENT`
|
||||
flag set are taken into account for this threshold).
|
||||
|
||||
### 0.8.1 (2022-04-06)
|
||||
|
||||
Starting with this release, all the examples in `testbed2d` and `testbed3d` have been updated to `webpack 5`,
|
||||
and are written in Typescript. In addition, canary `0.0.0` releases will be generated automatically after each merge
|
||||
to the `master` branch.
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fix bug causing `World.intersectionPair` to always return `false`.
|
||||
|
||||
### 0.8.0 (2022-03-31)
|
||||
|
||||
#### Breaking changes
|
||||
|
||||
- Most APIs that relied on rigid-body handles or collider handles have been modified to rely on `RigidBody`
|
||||
or `Collider` objects instead. Handles are now only needed for events and hooks.
|
||||
- Rename STATIC to FIXED in the `ActiveCollisionTypes` flags.
|
||||
- The `RigidBody.applyForce` and `.applyTorque` methods have been replaced by `.addForce` and `.addTorque`. These
|
||||
force/torques are no longer automatically zeroed after a timestep. To zero them manually, call `.resetForce` or
|
||||
`.resetTorque`.
|
||||
- The `EventQueue.drainContactEvents` and `EventQueue.drainIntersectionEvents` have been merged into a single
|
||||
method: `EventQueue:drainCollisionEvents`.
|
||||
|
||||
#### Added
|
||||
|
||||
- Add a lines-based debug-renderer. See [#119](https://github.com/dimforge/rapier.js/pull/119) for examples of
|
||||
integration of the debug-renderer with `THREE.js` and `PIXI.js`.
|
||||
- Each rigid-body, collider, impulse joint, and multibody joint now have a unique object instance. This instance
|
||||
in only valid as long as the corresponding objects is inserted to the `World`.
|
||||
- Add a `wakeUp: bool` argument to the `World.createImpulseJoint` and `MultibodyJointSet::createMultibodyJoint` to
|
||||
automatically wake-up the rigid-bodies attached to the inserted joint.
|
||||
- Add a `filter` callback to all the scene queries. Use this for filtering more fine-grained than collision groups.
|
||||
- Add `collider.shape` that represents the shape of a collider. This is a more convenient way of reading the collider’s
|
||||
shape properties. Modifying this shape will have no effect unless `collider.setShape` is called with the modified
|
||||
shape.
|
||||
- Add `Collider.containsPoint`, `.projectPoint`, `.intersectsRay`, `.castShape`, `.castCollider`, `.intersectsShape`,
|
||||
`.contactShape`, `.contactCollider`, `.castRay`, `.castRayAndGetNormal`.
|
||||
- Add `Shape.containsPoint`, `.projectPoint`, `.intersectsRay`, `.castShape`, `.intersectsShape`,
|
||||
`.contactShape`, `.castRay`, `.castRayAndGetNormal`.
|
||||
- Add `World.projectPointAndGetFeature` which includes the feature Id the projected point lies on.
|
||||
- Add `RigidBodyDesc.sleeping` to initialize the rigid-body in a sleeping state.
|
||||
|
||||
### 0.8.0-alpha.2 (2022-03-20)
|
||||
|
||||
The changelog hasn’t been updated yet.
|
||||
For an overview of the changes, refer to the changelog for the unreleased Rust version:
|
||||
https://github.com/dimforge/rapier/blob/master/CHANGELOG.md#unreleased
|
||||
|
||||
### 0.8.0-alpha.1 (2022-01-28)
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fix a crash when calling `collider.setShape`.
|
||||
- Fix a crash when calling `world.collidersWithAabbIntersectingAabb`.
|
||||
- Fix damping not being applied properly to some rigid-bodies.
|
||||
|
||||
### 0.8.0-alpha.0 (2022-01-16)
|
||||
|
||||
This release updates to Rapier 0.12.0-alpha.0 which contains:
|
||||
|
||||
- A **complete rewrite** of the joint and contact constraint solver.
|
||||
- The support for locking individual translation axes.
|
||||
- The support for multibody joint.
|
||||
|
||||
This is an **alpha** release because the new solver still needs some tuning,
|
||||
and the spherical joint motors/limits is currently not working.
|
||||
|
||||
#### Breaking changes
|
||||
|
||||
- In 3D: renamed `BallJoint` to `SphericalJoint`.
|
||||
- In 2D: renamed `BallJoint` to `RevoluteJoint`.
|
||||
- Remove the joint motors and limits for the spherical joint (this is a temporary removal until with leave alpha).
|
||||
- All the joint-related structures and methods (`RevoluteJoint`, `PrismaticJoint`, `createJoint`, etc.) have renamed to
|
||||
include `impulse` in the names: `RevoluteImpulseJoint`, `PrismaticImpulseJoint`, `createImpulseJoint`, etc. This is
|
||||
to differentiate them from the new multibody joints.
|
||||
- Remove from the integration parameters all the parameters that are no longer meaningful (`maxPositionIterations`,
|
||||
`jointErp`, `warmstartCoeff`, `allowedAngularError`, `maxLinearCorrection`, `maxAngularCorrection`).
|
||||
|
||||
#### Added
|
||||
|
||||
- Add multibody joints. They are created the same way as impulse joints, except that they are created
|
||||
by `world.createMultibodyJoint` instead of `world.createImpulseJoint`.
|
||||
- Add the ability to lock individual translation axes. Use `rigidBody.restrictTranslation`.
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fixed an issue with velocity-based kinematic bodies applying kinematic rotation improperly.
|
||||
- Fixed the second witness points and normals returned by shape-casts.
|
||||
- Fixed the second local contact normal and points returned by contact manifolds.
|
||||
|
||||
### 0.7.6
|
||||
|
||||
This release updates to Rapier 0.11.1 which contains several bug fixes.
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fix a bug causing large moving colliders to miss some collisions after some time.
|
||||
- Fix invalid forces generated by contacts with position-based kinematic bodies.
|
||||
- Fix a bug where two colliders without parent would not have their collision computed even if the
|
||||
appropriate flags were set.
|
||||
|
||||
### 0.7.5
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fixed an issue where a collider with no parent attached would not be created
|
||||
under some conditions.
|
||||
|
||||
### 0.7.4
|
||||
|
||||
This release was broken and has been unpublished.
|
||||
|
||||
### 0.7.3
|
||||
|
||||
#### Fixed
|
||||
|
||||
- The `collider.halfExtents()` methods now returns a valid value for round cuboids.
|
||||
|
||||
### 0.7.2 (rapier-compat only)
|
||||
|
||||
#### Modified
|
||||
|
||||
- The `rapier-compat` packages don’t need the `Buffer` polyfill anymore.
|
||||
|
||||
### 0.7.1
|
||||
|
||||
#### Modified
|
||||
|
||||
- Update to use Rapier 0.11.0.
|
||||
- The `rapier-compat` packages are now generated by rollup.
|
||||
|
||||
### v0.7.0
|
||||
|
||||
The typescripts bindings for Rapier have
|
||||
a [brand new user-guide](https://rapier.rs/docs/user_guides/javascript/getting_started_js)
|
||||
covering all the features of the physics engine!
|
||||
|
||||
### Breaking change
|
||||
|
||||
- The `World.castRay` and `World.castRayAndGetNormal` methods have a different signature now, making them
|
||||
more flexible.
|
||||
- Rename `ActiveHooks::FILTER_CONTACT_PAIR` to `ActiveHooks.FILTER_CONTACT_PAIRS`.
|
||||
- Rename `ActiveHooks::FILTER_INTERSECTION_PAIR` to `ActiveHooks.FILTER_INTERSECTION_PAIRS`.
|
||||
- Rename `BodyStatus` to `RigidBodyType`.
|
||||
- Rename `RigidBody.bodyStatus()` to `RigidBody.bodyType()`.
|
||||
- Rename `RigidBodyDesc.setMassProperties` to `RigidBodyDesc.setAdditionalMassProperties`.
|
||||
- Rename `RigidBodyDesc.setPrincipalAngularInertia` to `RigidBodyDesc.setAdditionalPrincipalAngularInertia`.
|
||||
- Rename `ColliderDesc.setIsSensor` to `ColliderDesc.setSensor.
|
||||
|
||||
#### Added
|
||||
|
||||
- Add `Ray.pointAt(t)` that conveniently computes `ray.origin + ray.dir * t`.
|
||||
- Add access to joint motors by defining each joint with its own class deriving from `Joint`. Each joint now
|
||||
have its relevant motor configuration
|
||||
methods: `configurMotorModel, configureMotorVelocity, configureMotorPosition, configureMotor`.
|
||||
- Add `World.collidersWithAabbIntersectingAabb` for retrieving the handles of all the colliders intersecting the given
|
||||
AABB.
|
||||
- Add many missing methods for reading/modifying a rigid-body state after its creation:
|
||||
- `RigidBody.lockTranslations`
|
||||
- `RigidBody.lockRotations`
|
||||
- `RigidBody.restrictRotations`
|
||||
- `RigidBody.dominanceGroup`
|
||||
- `RigidBody.setDominanceGroup`
|
||||
- `RigidBody.enableCcd`
|
||||
- Add `RigidBodyDesc.setDominanceGroup` for setting the dominance group of the rigid-body being built.
|
||||
- Add many missing methods for reading/modifying a collider state after its creation:
|
||||
- `Collider.setSendor`
|
||||
- `Collider.setShape`
|
||||
- `Collider.setRestitution`
|
||||
- `Collider.setFriction`
|
||||
- `Collider.frictionCombineRule`
|
||||
- `Collider.setFrictionCombineRule`
|
||||
- `Collider.restitutionCombineRule`
|
||||
- `Collider.setRestitutionCombineRule`
|
||||
- `Collider.setCollisionGroups`
|
||||
- `Collider.setSolverGroups`
|
||||
- `Collider.activeHooks`
|
||||
- `Collider.setActiveHooks`
|
||||
- `Collider.activeEvents`
|
||||
- `Collider.setActiveEvents`
|
||||
- `Collider.activeCollisionTypes`
|
||||
- `Collider.setTranslation`
|
||||
- `Collider.setTranslationWrtParent`
|
||||
- `Collider.setRotation`
|
||||
- `Collider.setRotationWrtParent`
|
||||
- Add `ColliderDesc.setMassProperties` for setting explicitly the mass properties of the collider being built (instead
|
||||
of relying on density).
|
||||
|
||||
#### Modified
|
||||
|
||||
- Colliders are no longer required to be attached to a rigid-body. Therefore, the second argument
|
||||
of `World.createCollider`
|
||||
is now optional.
|
||||
|
||||
### v0.6.0
|
||||
|
||||
#### Breaking changes
|
||||
|
||||
- The `BodyStatus::Kinematic` variant has been replaced by `BodyStatus::KinematicPositionBased` and
|
||||
`BodyStatus::KinematicVelocityBased`. Position-based kinematic bodies are controlled by setting (at each frame) the
|
||||
next
|
||||
kinematic position of the rigid-body (just like before), and the velocity-based kinematic bodies are controlled
|
||||
by setting (at each frame) the velocity of the rigid-body.
|
||||
- The `RigidBodyDesc.newKinematic` has been replaced by `RigidBodyDesc.newKinematicPositionBased` and
|
||||
`RigidBodyDesc.newKinematicVelocityBased` in order to build a position-based or velocity-based kinematic body.
|
||||
- All contact and intersection events are now disabled by default. The can be enabled for each collider individually
|
||||
by setting
|
||||
its `ActiveEvents`: `ColliderDesc.setActiveEvents(ActiveEvents.PROXIMITY_EVENTS | ActiveEvents.ContactEvents)`.
|
||||
|
||||
#### Added
|
||||
|
||||
- It is now possible to read contact information from the narrow-phase using:
|
||||
- `world.narrowPhase.contactsWith(collider1, callback)`
|
||||
- `world.narrowPhase.intersectionsWith(collider1, callback)`
|
||||
- `world.narrowPhase.contactPair(collider1, collider2, callback)`
|
||||
- `world.narrowPhase.intersectionPair(collider1, collider2, callback)`
|
||||
- It is now possible to apply custom collision-detection filtering rules (more flexible than collision groups)
|
||||
based on a JS object by doing the following:
|
||||
- Enable physics hooks for the colliders you want the custom rules to apply to:
|
||||
`ColliderDesc.setActiveHooks(ActiveHooks.FILTER_CONTACT_PAIR | ActiveHooks.FILTER_CONTACT_PAIR)`
|
||||
- Define an object that implements the `PhysicsHooks` interface.
|
||||
- Pass and instance of your physics hooks object as the second argument of the `World.step` method.
|
||||
- It is now possible to enable collision-detection between two non-dynamic bodies (e.g. between a kinematic
|
||||
body and a fixed body) by setting the active collision types of a collider:
|
||||
`ColliderDesc.setActiveCollisionTypes(ActiveCollisionTypes.ALL)`
|
||||
|
||||
### v0.5.3
|
||||
|
||||
- Fix a crash when loading the WASM file on iOS safari.
|
||||
|
||||
### v0.5.2
|
||||
|
||||
- Fix a crash that could happen after adding and then removing a collider right away,
|
||||
before stepping the simulation.
|
||||
|
||||
### v0.5.1
|
||||
|
||||
- Fix a determinism issue after snapshot restoration.
|
||||
|
||||
### v0.5.0
|
||||
|
||||
- Significantly improve the broad-phase performances when very large colliders are used.
|
||||
- Add `RigidBodyDesc::setCcdEnabled` to enable Continuous Collision Detection (CCD) for this rigid-body. CCD ensures
|
||||
that a fast-moving rigid-body doesn't miss a collision (the tunneling problem).
|
||||
|
||||
#### Breaking changes:
|
||||
|
||||
- Removed multiple fields from `IntegrationParameters`. These were unused parameters.
|
||||
|
||||
### v0.4.0
|
||||
|
||||
- Fix a bug in ball/convex shape collision detection causing the ball to ignore penetrations with depths greater than
|
||||
its radius.
|
||||
|
||||
Breaking changes:
|
||||
|
||||
- Removed `IntegrationParameters.restitutionVelocityThreshold`
|
||||
and `IntegrationParameters.set_restitutionVelocityThreshold`.
|
||||
|
||||
### v0.3.1
|
||||
|
||||
- Fix crash happening when creating a collider with a `ColliderDesc.convexHull` shape.
|
||||
- Actually remove the second argument of `RigidBodyDesc.setMass` as mentioned in the 0.3.0 changelog.
|
||||
- Improve snapshotting performances.
|
||||
|
||||
### v0.3.0
|
||||
|
||||
#### Added
|
||||
|
||||
- Added a `RAPIER.version()` function at the root of the package to retrieve the version of Rapier as a string.
|
||||
|
||||
Several geometric queries have been added (the same methods have been added to the
|
||||
`QueryPipeline` too):
|
||||
|
||||
- `World.intersectionsWithRay`: get all colliders intersecting a ray.
|
||||
- `World.intersectionWithShape`: get one collider intersecting a shape.
|
||||
- `World.projectPoint`: get the projection of a point on the closest collider.
|
||||
- `World.intersectionsWithPoint`: get all the colliders containing a point.
|
||||
- `World.castShape`: get the first collider intersecting a shape moving linearly
|
||||
(aka. sweep test).
|
||||
- `World.intersectionsWithShape`: get all the colliders intersecting a shape.
|
||||
|
||||
Several new shape types are now supported:
|
||||
|
||||
- `RoundCuboid`, `Segment`, `Triangle`, `RoundTriangle`, `Polyline`, `ConvexPolygon` (2D only),
|
||||
`RoundConvexPolygon` (2D only), `ConvexPolyhedron` (3D only), `RoundConvexPolyhedron` (3D only),
|
||||
`RoundCone` (3D only).
|
||||
|
||||
It is possible to build `ColliderDesc` using these new shapes:
|
||||
|
||||
- `ColliderDesc.roundCuboid`, `ColliderDesc.segment`, `ColliderDesc.triangle`, `ColliderDesc.roundTriangle`,
|
||||
`ColliderDesc.convexHull`, `ColliderDesc.roundConvexHull`, `ColliderDesc.Polyline`,
|
||||
`ColliderDesc.convexPolyline` (2D only), `ColliderDesc.roundConvexPolyline` (2D only),
|
||||
`ColliderDesc.convexMesh` (3D only),`ColliderDesc.roundConvexMesh` (3D only), `ColliderDesc.roundCone` (3D only).
|
||||
|
||||
It is possible to specify different rules for combining friction and restitution coefficients of the two colliders
|
||||
involved in a contact with:
|
||||
|
||||
- `ColliderDesc.frictionCombineRule`, and `ColliderDesc.restitutionCombineRule`.
|
||||
|
||||
Various RigidBody-related getter and setters have been added:
|
||||
|
||||
- `RigidBodyDesc.newStatic`, `RigidBodyDesc.newDynamic`, and `RigidBodyDesc.newKinematic` are new static method, short
|
||||
equivalent to `new RigidBodyDesc(BodyStatus.Static)`, etc.
|
||||
- `RigidBodyDesc.setGravityScale`, `RigidBody.gravityScale`, `RigidBody.setGravityScale` to get/set the scale factor
|
||||
applied to the gravity affecting a rigid-body. Setting this to 0.0 will make the rigid-body ignore gravity.
|
||||
- `RigidBody.setLinearDamping` and `RigidBody.setAngularDamping` to set the linear and angular damping of the
|
||||
rigid-body.
|
||||
- `RigidBodyDesc.restrictRotations` to prevent rotations along specific coordinate axes. This replaces the three boolean
|
||||
arguments previously passed to `.setPrincipalAngularInertia`.
|
||||
|
||||
#### Breaking changes
|
||||
|
||||
Breaking changes related to rigid-bodies:
|
||||
|
||||
- The `RigidBodyDesc.setTranslation` and `RigidBodyDesc.setLinvel` methods now take the components of the translation
|
||||
directly as arguments instead of a single `Vector`.
|
||||
- The `RigidBodyDesc.setMass` takes only one argument now. Use `RigidBodyDesc.lockTranslations` to lock the
|
||||
translational motion of the rigid-body.
|
||||
- The `RigidBodyDesc.setPrincipalAngularInertia` no longer have boolean parameters to lock rotations.
|
||||
Use `RigidBodyDesc.lockRotations` or `RigidBodyDesc.restrictRotations` to lock the rotational motion of the
|
||||
rigid-body.
|
||||
|
||||
Breaking changes related to colliders:
|
||||
|
||||
- The `ColliderDesc.setTranslation` method now take the components of the translation directly as arguments instead of a
|
||||
single `Vector`.
|
||||
- The `roundRadius` fields have been renamed `borderRadius`.
|
||||
- The `RawShapeType.Polygon` no longer exists. For a 2D convex polygon, use `RawShapeType.ConvexPolygon`
|
||||
instead.
|
||||
- All occurrences of `Trimesh` have been replaced by `TriMesh` (note the change in case).
|
||||
|
||||
Breaking changes related to events:
|
||||
|
||||
- Rename all occurrences of `Proximity` to `Intersection`.
|
||||
- The `Proximity` enum has been removed.
|
||||
- The `drainIntersectionEvents` (previously called `drainProximityEvent`) will now call a callback with
|
||||
arguments `(number, number, boolean)`: two collider handles, and a boolean indicating if they are intersecting.
|
||||
|
||||
Breaking changes related to scene queries:
|
||||
|
||||
- The `QueryPipeline.castRay` method now takes two additional parameters: a boolean indicating if the ray should not
|
||||
propagate if it starts inside of a shape, and a bit mask indicating the group the ray is part of and these it
|
||||
interacts with.
|
||||
- The `World.castRay` and `QueryPipeline.castRay` now return a struct of type `RayColliderHit`
|
||||
which no longer contains the normal at the hit point. Use the new methods `World.castRayAndGetNormal`
|
||||
or `QueryPipeline.castRayAndGetNormal` in order to retrieve the normal too.
|
||||
|
||||
### v0.2.13
|
||||
|
||||
- Fix a bug where `RigidBodyDesc.setMass(m)` with `m != 0.0` would cause the rotations of the created rigid-body to be
|
||||
locked.
|
||||
|
||||
### v0.2.12
|
||||
|
||||
- Add a boolean argument to `RigidBodyDesc.setMass` to indicate if the mass contribution of colliders should be enabled
|
||||
for this rigid-body or not.
|
||||
- Add a `RigidBody.lockRotations` method to lock all the rigid-body rotations resulting from forces.
|
||||
- Add a `RigidBody.lockTranslations` method to lock all the rigid-body translations resulting from forces.
|
||||
- Add a `RigidBody.setPrincipalAngularInertia` method to set the principal inertia of the rigid-body. This gives the
|
||||
ability to lock individual rotation axes of one rigid-body.
|
||||
|
||||
### v0.2.11
|
||||
|
||||
- Fix a bug where removing when immediately adding a collider would cause collisions to fail with the new collider.
|
||||
- Fix a regression causing some colliders added after a few timesteps not to be properly taken into account.
|
||||
|
||||
### v0.2.10
|
||||
|
||||
- Fix a bug where removing a collider would result in a rigid-body being removed instead.
|
||||
- Fix a determinism issue when running simulation on the Apple M1 processor.
|
||||
- Add `JointData.prismatic` and `JointData.fixed` for creating prismatic joint or fixed joints.
|
||||
|
||||
### v0.2.9
|
||||
|
||||
- Add `RigidBody.setLinvel` to set the linear velocity of a rigid-body.
|
||||
- Add `RigidBody.setAngvel` to set the angular velocity of a rigid-body.
|
||||
|
||||
### v0.2.8
|
||||
|
||||
- Add `RigidBodySet.remove` to remove a rigid-body from the set.
|
||||
- Add `ColliderSet.remove` to remove a collider from the set.
|
||||
- Add `JointSet.remove` to remove a joint from the set.
|
||||
- Add `RigidBodyDesc.setLinearDamping` and `RigidBodyDesc.setAngularDamping` for setting the linear and angular damping
|
||||
coefficient of the rigid-body to create.
|
||||
- Add `RigidBodyDesc.setMass`, and `RigidBodyDesc.setMassProperties` for setting the initial mass properties of a
|
||||
rigid-body.
|
||||
- Add `ColliderDesc.setCollisionGroups` to use bit-masks for collision filtering between some pairs of colliders.
|
||||
- Add `ColliderDesc.setSolverGroups` to use bit-masks for making the constraints solver ignore contacts between some
|
||||
pairs of colliders.
|
||||
- Add `ColliderDesc.heightfield` to build a collider with an heightfield shape.
|
||||
- Add `ColliderDesc.trimesh` to build a collider with a triangle mesh shape.
|
||||
|
||||
### v0.2.7
|
||||
|
||||
- Reduce snapshot size and computation times.
|
||||
|
||||
### v0.2.6
|
||||
|
||||
- Fix bug causing an unbounded memory usage when an objects falls indefinitely.
|
||||
|
||||
### v0.2.5
|
||||
|
||||
- Fix wrong result given by `RigidBody.isKinematic()` and `RigidBody.isDynamic()`.
|
||||
|
||||
### v0.2.4
|
||||
|
||||
- Add the support for round cylinder colliders (i.e. cylinders with round edges).
|
||||
|
||||
### v0.2.3
|
||||
|
||||
- Add the support for cone, cylinder, and capsule colliders.
|
||||
|
||||
### v0.2.2
|
||||
|
||||
- Fix regression causing the density and `isSensor` properties of `ColliderDesc` to not be taken into account.
|
||||
- Throw an exception when the parent handle passed to `world.createCollider` is not a number.
|
||||
|
||||
### v0.2.1
|
||||
|
||||
This is a significant rewrite of the JavaScript bindings for rapier. The objective of this rewrite is to make the API
|
||||
closer to Rapier's and remove most need for manual memory management.
|
||||
|
||||
- Calling `.free()` is now required only for objects that live for the whole duration of the simulation. This means that
|
||||
it is no longer necessary to `.free()` vectors, rays, ray intersections, colliders, rigid-bodies, etc. Object that
|
||||
continue to require an explicit `.free()` are:
|
||||
- `World` and `EventQueue`.
|
||||
- Or, if you are not using the `World` directly:
|
||||
`RigidBodySet`, `ColliderSet`, `JointSet`, `IntegrationParameters`, `PhysicsPipeline`, `QueryPipeline`
|
||||
, `SerializationPipeline`, and `EventQueue`.
|
||||
- Collider.parent() now returns the `RigidBodyHandle` of its parent (instead of the `RigidBody` directly).
|
||||
- Colliders are now built with `world.createCollider`, i.e., `body.createCollider(colliderDesc)`
|
||||
becomes `world.createCollider(colliderDesc, bodyHandle)`.
|
||||
- Shape types are not an enumeration instead of strings: `ShapeType.Ball` and `ShapeType.Cuboid` instead of `"ball"`
|
||||
and `"cuboid"`.
|
||||
- `collider.handle` is now a field instead of a function.
|
||||
- `body.handle` is now a field instead of a function.
|
||||
- The world's gravity is now a `Vector` instead of individual components, i.e., `let world = new RAPIER.World(x, y, z);`
|
||||
becomes `let world = new RAPIER.World(new RAPIER.Vector3(x, y, z))`.
|
||||
- Most methods that took individual components as argument (`setPosition`, `setKinematicPosition`, `setRotation`, etc.)
|
||||
now take a `Vector` or `Rotation` structure instead. For example `rigid_body.setKinematicPosition(x, y, z)`
|
||||
becomes `rigid_body.setKinematicPosition(new RAPIER.Vector3(x, y, z))`.
|
||||
- `world.stepWithEvents` becomes `world.step` (the event queue is the last optional argument).
|
||||
- `RigidBodyDesc` and `ColliderDesc` now use the builder pattern. For example
|
||||
`let bodyDesc = new RAPIER.RigidBodyDesc("dynamic"); bodyDesc.setTranslation(x, y, z)` becomes
|
||||
`new RigidBodyDesc(BodyStatus.Dynamic).setTranslation(new Vector(x, y, z))`.
|
||||
- `ray.dir` and `ray.origin` are now fields instead of methods.
|
||||
- 2D rotations are now just a `number` instead of a `Rotation` struct. So instead of doing `rotation.angle`, single use
|
||||
the number as the rotation angle.
|
||||
- 3D rotations are now represented by the interface `Rotation` (with fields `{x,y,z,w}`) or the class `Quaternion`. Any
|
||||
object with these `{x, y, z, w}` fields can be used wherever a `Rotation` is required.
|
||||
- 2D vectors are now represented by the interface `Vector` (with fields `{x,y}`) or the class `Vector2`). Any object
|
||||
with these `{x,y}` fields can be used wherever a `Vector` is required.
|
||||
- 3D vectors are now represented by the interface `Vector` (with fields `{x,y,z}`) or the class `Vector3`). Any object
|
||||
with these `{x,y,z}` fields can be used wherever a `Vector` is required.
|
||||
|
||||
### v0.2.0
|
||||
|
||||
See changelogs for v0.2.1 instead. The NPM package for v0.2.0 were missing some files.
|
||||
|
||||
### v0.1.17
|
||||
|
||||
- Fix bug when ghost forces and/or crashes could be observed when a kinematic body touches a fixed body.
|
||||
|
||||
### v0.1.16
|
||||
|
||||
- Fix kinematic rigid-body not waking up dynamic bodies it touches.
|
||||
- Added `new Ray(origin, direction)` constructor instead of `Ray.new(origin, direction)`.
|
||||
|
||||
### v0.1.15
|
||||
|
||||
- Fix crash when removing a kinematic rigid-body from the World.
|
||||
|
||||
### v0.1.14
|
||||
|
||||
- Fix issues where force application functions took ownership of the JS vector, preventing the user from freeing
|
||||
with `Vector.free()` afterwards.
|
||||
|
||||
### v0.1.13
|
||||
|
||||
- Added `rigidBody.setNextKinematicTranslation` to set the translation of a kinematic rigid-body at the next timestep.
|
||||
- Added `rigidBody.setNextKinematicRotation` to set the rotation of a kinematic rigid-body at the next timestep.
|
||||
- Added `rigidBody.predictedTranslation` to get the translation of a kinematic rigid-body at the next timestep.
|
||||
- Added `rigidBody.predictedRotation` to set the rotation of a kinematic rigid-body at the next timestep.
|
||||
- Added `Ray` and `RayIntersection` structures for ray-casting.
|
||||
- Added `world.castRay` to compute the first hit of a ray with the physics scene.
|
||||
- Fix a bug causing a kinematic rigid-body not to teleport as expected after a `rigidBody.setPosition`.
|
||||
|
||||
### v0.1.12
|
||||
|
||||
- Added `world.removeCollider(collider)` to remove a collider from the physics world.
|
||||
- Added `colliderDesc.setTranslation(...)` to set the relative translation of the collider to build wrt. the rigid-body
|
||||
it is attached to.
|
||||
- Added `colliderDesc.setRotation(...)` to set the relative rotation of the collider to build wrt. the rigid-body it is
|
||||
attached to.
|
||||
|
||||
### v0.1.11
|
||||
|
||||
- Fix a bug causing a crash when the broad-phase proxy handles were recycled.
|
||||
|
||||
### v0.1.10
|
||||
|
||||
- Fix a determinism problem that could cause rigid-body handle allocation to be non-deterministic after a snapshot
|
||||
restoration.
|
||||
|
||||
### v0.1.9
|
||||
|
||||
- Added `world.getCollider(handle)` that retrieves a collider from its integer handle.
|
||||
- Added `joint.handle()` that returns the integer handle of the joint.
|
||||
|
||||
### v0.1.8
|
||||
|
||||
- Added `world.forEachRigidBodyHandle(f)` to apply a closure on the integer handle of each rigid-body on the world.
|
||||
- Added `world.forEachActiveRigidBody(f)` to apply a closure on each rigid-body on the world.
|
||||
- Added `world.forEachActiveRigidBodyHandle(f)` to apply a closure on the integer handle of each rigid-body on the
|
||||
world.
|
||||
- Added `rigidBody.applyForce`, `.applyTorque`, `.applyImpulse`, `.applyTorqueImpulse`, `.applyForceAtPoint`, and
|
||||
`.applyImpulseAtPoint` to apply a manual force or torque to a rigid-body.
|
||||
- Added the `EventQueue` structure that can be used to collect and iterate through physics events.
|
||||
- Added the `Proximity` enum that represents the proximity state of a sensor collider and another collider.
|
||||
- Added the `world.stepWithEvents(eventQueue)` which executes a physics timestep and collects the physics events into
|
||||
the given event queue.
|
||||
|
||||
### v0.1.7
|
||||
|
||||
- Added `world.getRigidBody(handle)` to retrieve a rigid-body from its handle.
|
||||
- Added `world.getJoint(handle)` to retrieve a joint from its handle.
|
||||
- Added `rigidBody.rotation()` to retrieve its world-space orientation as a quaternion.
|
||||
- Added `rigidBody.setTranslation(...)` to set the translation of a rigid-body.
|
||||
- Added `rigidBody.setRotation(...)` to set the orientation of a rigid-body.
|
||||
- Added `rigidBody.wakeUp()` to manually wake up a rigid-body.
|
||||
- Added `rigidBody_desc.setRotation(...)` to set tho orientation of the rigid-body to be created.
|
||||
|
||||
### v0.1.6
|
||||
|
||||
- Added `world.removeRigidBody(...)` to remove a rigid-body from the world.
|
||||
1711
thirdparty/rapier.js/Cargo.lock
generated
vendored
Normal file
1711
thirdparty/rapier.js/Cargo.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
23
thirdparty/rapier.js/Cargo.toml
vendored
Normal file
23
thirdparty/rapier.js/Cargo.toml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
[workspace]
|
||||
members = ["builds/*"]
|
||||
resolver = "2"
|
||||
|
||||
[profile.release]
|
||||
debug = false
|
||||
codegen-units = 1
|
||||
#lto = true
|
||||
strip = true # Workaround for https://github.com/bevyengine/bevy/issues/16030 (the bug only happens in 2D)
|
||||
|
||||
[patch.crates-io]
|
||||
#rapier2d = { path = "../rapier/crates/rapier2d" }
|
||||
#rapier3d = { path = "../rapier/crates/rapier3d" }
|
||||
#parry2d = { path = "../parry/crates/parry2d" }
|
||||
#parry3d = { path = "../parry/crates/parry3d" }
|
||||
#nalgebra = { path = "../nalgebra" }
|
||||
#simba = { path = "../simba" }
|
||||
|
||||
#nalgebra = { git = "https://github.com/dimforge/nalgebra", branch = "dev" }
|
||||
#rapier2d = { git = "https://github.com/dimforge/rapier", rev = "82416e3ca66dcdc34c0f350cec570ef1019a199f" }
|
||||
#rapier3d = { git = "https://github.com/dimforge/rapier", rev = "82416e3ca66dcdc34c0f350cec570ef1019a199f" }
|
||||
#parry2d = { git = "https://github.com/dimforge/parry" }
|
||||
#parry3d = { git = "https://github.com/dimforge/parry" }
|
||||
201
thirdparty/rapier.js/LICENSE
vendored
Normal file
201
thirdparty/rapier.js/LICENSE
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 Dimforge EURL
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
82
thirdparty/rapier.js/README.md
vendored
Normal file
82
thirdparty/rapier.js/README.md
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
<p align="center">
|
||||
<img src="https://www.rapier.rs/img/rapier_logo_color_textpath_dark.svg" alt="crates.io">
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://discord.gg/vt9DJSW">
|
||||
<img src="https://img.shields.io/discord/507548572338880513.svg?logo=discord&colorB=7289DA">
|
||||
</a>
|
||||
<a href="https://github.com/dimforge/rapier.js/actions">
|
||||
<img src="https://github.com/dimforge/rapier.js/workflows/main/badge.svg" alt="Build status">
|
||||
</a>
|
||||
<a href="https://opensource.org/licenses/Apache-2.0">
|
||||
<img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg">
|
||||
</a>
|
||||
</p>
|
||||
<p align = "center">
|
||||
<strong>
|
||||
<a href="https://rapier.rs">Website</a> | <a href="https://rapier.rs/docs/">Documentation</a> |
|
||||
<a href="https://github.com/dimforge/rapier.js/tree/master/testbed2d/src/demos">2D examples (sources)</a> |
|
||||
<a href="https://github.com/dimforge/rapier.js/tree/master/testbed3d/src/demos">3D examples (sources)</a>
|
||||
</strong>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
<p align = "center">
|
||||
<b>2D and 3D physics engines</b>
|
||||
<i>for the JavaScript programming language (official bindings).</i>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## Building packages manually
|
||||
|
||||
From the root of the repository, run:
|
||||
|
||||
```shell
|
||||
./builds/prepare_builds/prepare_all_projects.sh
|
||||
./builds/prepare_builds/build_all_projects.sh
|
||||
```
|
||||
|
||||
Note that `prepare_all_projects.sh` only needs to be run once. It needs to be re-run if any file from the
|
||||
`builds/prepare_builds` directory (and subdirectories) are modified.
|
||||
|
||||
The built packages will be in `builds/rapier2d/pkg`, `builds/rapier3d/pkg`, etc. To build the `-compat` variant of the
|
||||
packages, run `npm run build` in the `rapier-compat` directory. Note that this will only work if you already ran
|
||||
`prepare_all_projects.sh`. The compat packages are then generated in, e.g., `rapier-compat/builds/3d/pkg`.
|
||||
|
||||
## Feature selection
|
||||
|
||||
Multiple NPM packages exist for Rapier, depending on your needs:
|
||||
- [`@dimforge/rapier2d`](https://www.npmjs.com/package/@dimforge/rapier2d) or
|
||||
[`@dimforge/rapier3d`](https://www.npmjs.com/package/@dimforge/rapier3d):
|
||||
The main build of the Rapier physics engine for 2D or 3D physics simulation. This should have wide browser
|
||||
support while offering great performances. This does **not** guarantee cross-platform determinism of the physics
|
||||
simulation (but it is still locally deterministic, on the same machine).
|
||||
- [`@dimforge/rapier2d-simd`](https://www.npmjs.com/package/@dimforge/rapier2d-simd) or
|
||||
[`@dimforge/rapier3d-simd`](https://www.npmjs.com/package/@dimforge/rapier3d-simd):
|
||||
A build with internal SIMD optimizations enabled. More limited browser support (requires support for [simd128](https://caniuse.com/?search=simd)).
|
||||
- [`@dimforge/rapier2d-deterministic`](https://www.npmjs.com/package/@dimforge/rapier2d-deterministic) or
|
||||
[`@dimforge/rapier3d-deterministic`](https://www.npmjs.com/package/@dimforge/rapier3d-deterministic):
|
||||
A less optimized build but with a guarantee of a cross-platform deterministic execution of the physics simulation.
|
||||
|
||||
## Bundler support
|
||||
|
||||
Some bundlers will struggle with the `.wasm` file package into the builds above. Alternative `-compat` versions exist
|
||||
which embed the `.wasm` file into the `.js` sources encoded with base64. This results in a bigger package size, but
|
||||
much wider bundler support.
|
||||
|
||||
Just append `-compat` to the build you are interested in:
|
||||
[`rapier2d-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-compat),
|
||||
[`rapier2d-simd-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-simd-compat),
|
||||
[`rapier2d-deterministic-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-deterministic-compat),
|
||||
[`rapier3d-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-compat),
|
||||
[`rapier3d-simd-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-simd-compat),
|
||||
[`rapier3d-deterministic-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-deterministic-compat).
|
||||
|
||||
## Nightly builds
|
||||
|
||||
Each time a new Pull Request is merged to the `main` branch of the [`rapier.js` repository](https://github.com/dimforge/rapier.js),
|
||||
an automatic _canary_ build is triggered. Builds published to npmjs under the _canary_ tag does not come with any
|
||||
stability guarantee and does not follow semver versioning. But it can be a useful solution to try out the latest
|
||||
features until a proper release is cut.
|
||||
9
thirdparty/rapier.js/builds/prepare_builds/Cargo.toml
vendored
Normal file
9
thirdparty/rapier.js/builds/prepare_builds/Cargo.toml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "prepare_builds"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5" }
|
||||
clap_derive = { version = "4.5" }
|
||||
tera = "1.20"
|
||||
17
thirdparty/rapier.js/builds/prepare_builds/README.md
vendored
Normal file
17
thirdparty/rapier.js/builds/prepare_builds/README.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Prepare builds
|
||||
|
||||
This project helps with making specific package: it takes a few parameter to create a (1) folder ready to compile.
|
||||
|
||||
It uses clap so you can pass `-h` to get more info about its parameters.
|
||||
|
||||
## usage
|
||||
|
||||
At workspace root: `cargo run -p prepare_builds -- -d dim2 -f simd`.
|
||||
|
||||
Or use provided scripts: `./builds/prepare_builds/prepare_all_projects.sh && ./builds/prepare_builds/build_all_projects.sh`
|
||||
|
||||
## Technical considerations
|
||||
|
||||
Askama/rinja was not chosen because compiled templates make it difficult to iterate on a folder and parse all templates.
|
||||
|
||||
This folder is in `builds/` only for the workspace member glob to not complain if `builds/` is inexistent or empty.
|
||||
19
thirdparty/rapier.js/builds/prepare_builds/build_all_projects.sh
vendored
Normal file
19
thirdparty/rapier.js/builds/prepare_builds/build_all_projects.sh
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
for entry in builds/*
|
||||
do
|
||||
if [[ "$(basename "$entry")" == $(basename $(dirname "${BASH_SOURCE[0]}")) ]]; then
|
||||
echo "skipping directory: $entry"
|
||||
continue;
|
||||
fi
|
||||
(
|
||||
cd $entry
|
||||
echo "building $entry"
|
||||
# FIXME: ideally we'd use `npm ci`
|
||||
# but we'd need to have generated the `package-lock` beforehand and committed them in the repository.
|
||||
# I'm not sure yet how to store those `package-lock`s yet though.
|
||||
# They should proably be similar to all packages, but I'm not sure.
|
||||
npm i;
|
||||
npm run build;
|
||||
)
|
||||
done
|
||||
11
thirdparty/rapier.js/builds/prepare_builds/prepare_all_projects.sh
vendored
Normal file
11
thirdparty/rapier.js/builds/prepare_builds/prepare_all_projects.sh
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
features=(non-deterministic deterministic simd)
|
||||
dims=(dim2 dim3)
|
||||
|
||||
for feature in ${features[@]}; do
|
||||
for dim in ${dims[@]}; do
|
||||
echo "preparing dimension $dim with feature $feature"
|
||||
cargo run -p prepare_builds -- -d ${dim} -f ${feature}
|
||||
done
|
||||
done
|
||||
182
thirdparty/rapier.js/builds/prepare_builds/src/main.rs
vendored
Normal file
182
thirdparty/rapier.js/builds/prepare_builds/src/main.rs
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
use std::{
|
||||
error::Error,
|
||||
fs::{self, File},
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use clap::Parser;
|
||||
use clap_derive::{Parser, ValueEnum};
|
||||
use tera::{Context, Tera};
|
||||
|
||||
/// Simple program to greet a person
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
pub struct Args {
|
||||
/// Dimension to use
|
||||
#[arg(short, long)]
|
||||
dim: Dimension,
|
||||
|
||||
/// Features to enable
|
||||
#[arg(short, long)]
|
||||
feature_set: FeatureSet,
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Debug, Clone, Copy)]
|
||||
pub enum Dimension {
|
||||
Dim2,
|
||||
Dim3,
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Default, Debug, Clone, Copy)]
|
||||
pub enum FeatureSet {
|
||||
#[default]
|
||||
NonDeterministic,
|
||||
Deterministic,
|
||||
Simd,
|
||||
}
|
||||
|
||||
/// Values to use when creating the new build folder.
|
||||
pub struct BuildValues {
|
||||
/// Only the number of dimensions, as sometimes it will be prefixed by "dim" and sometimes post-fixed by "d".
|
||||
pub dim: String,
|
||||
/// real name of the additional features to enable in the project
|
||||
pub feature_set: Vec<String>,
|
||||
pub target_dir: PathBuf,
|
||||
pub template_dir: PathBuf,
|
||||
pub additional_rust_flags: String,
|
||||
pub additional_wasm_opt_flags: Vec<String>,
|
||||
pub js_package_name: String,
|
||||
}
|
||||
|
||||
impl BuildValues {
|
||||
pub fn new(args: Args) -> Self {
|
||||
let dim = match args.dim {
|
||||
Dimension::Dim2 => "2",
|
||||
Dimension::Dim3 => "3",
|
||||
};
|
||||
let feature_set = match args.feature_set {
|
||||
FeatureSet::NonDeterministic => vec![],
|
||||
FeatureSet::Deterministic => vec!["enhanced-determinism"],
|
||||
FeatureSet::Simd => vec!["simd-stable"],
|
||||
};
|
||||
let js_package_name = match args.feature_set {
|
||||
FeatureSet::NonDeterministic => format!("rapier{dim}d"),
|
||||
FeatureSet::Deterministic => format!("rapier{dim}d-deterministic"),
|
||||
FeatureSet::Simd => format!("rapier{dim}d-simd"),
|
||||
};
|
||||
|
||||
let root: PathBuf = env!("CARGO_MANIFEST_DIR").into();
|
||||
|
||||
Self {
|
||||
dim: dim.to_string(),
|
||||
feature_set: feature_set.iter().map(|f| f.to_string()).collect(),
|
||||
template_dir: root.join("templates/").clone(),
|
||||
target_dir: root.parent().unwrap().join(&js_package_name).into(),
|
||||
additional_rust_flags: match args.feature_set {
|
||||
FeatureSet::Simd => "RUSTFLAGS='-C target-feature=+simd128'".to_string(),
|
||||
_ => "".to_string(),
|
||||
},
|
||||
additional_wasm_opt_flags: match args.feature_set {
|
||||
FeatureSet::Simd => vec!["--enable-simd".to_string()],
|
||||
_ => vec![],
|
||||
},
|
||||
js_package_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
dbg!(&args);
|
||||
|
||||
let build_values = BuildValues::new(args);
|
||||
copy_top_level_files_in_directory(&build_values.template_dir, &build_values.target_dir)
|
||||
.expect("Failed to copy directory");
|
||||
process_templates(&build_values).expect("Failed to process templates");
|
||||
}
|
||||
|
||||
fn copy_top_level_files_in_directory(
|
||||
src: impl AsRef<Path>,
|
||||
dest: impl AsRef<std::ffi::OsStr>,
|
||||
) -> std::io::Result<()> {
|
||||
let src = src.as_ref();
|
||||
let dest = Path::new(&dest);
|
||||
if dest.exists() {
|
||||
fs::remove_dir_all(&dest)?;
|
||||
}
|
||||
fs::create_dir_all(&dest)?;
|
||||
|
||||
for entry in fs::read_dir(src)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
let dest_path = dest.join(path.file_name().unwrap());
|
||||
|
||||
if !path.is_dir() {
|
||||
fs::copy(&path, &dest_path)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Process all tera templates in the target directory:
|
||||
/// - Remove the extension
|
||||
/// - Render the templates to
|
||||
///
|
||||
fn process_templates(build_values: &BuildValues) -> std::io::Result<()> {
|
||||
let target_dir = build_values.target_dir.clone();
|
||||
|
||||
let mut context = Context::new();
|
||||
context.insert("dimension", &build_values.dim);
|
||||
context.insert("additional_features", &build_values.feature_set);
|
||||
context.insert("additional_rust_flags", &build_values.additional_rust_flags);
|
||||
context.insert(
|
||||
"additional_wasm_opt_flags",
|
||||
&build_values.additional_wasm_opt_flags,
|
||||
);
|
||||
context.insert("js_package_name", &build_values.js_package_name);
|
||||
|
||||
let tera = match Tera::new(target_dir.join("**/*.tera").to_str().unwrap()) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
eprintln!("Parsing error(s): {}", e);
|
||||
::std::process::exit(1);
|
||||
}
|
||||
};
|
||||
dbg!(tera.templates.keys(), &context);
|
||||
|
||||
for entry in fs::read_dir(target_dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
// For tera templates, remove extension.
|
||||
if path.extension() == Some(std::ffi::OsStr::new("tera")) {
|
||||
let mut i = path.iter();
|
||||
|
||||
// Get path from target directory
|
||||
for _ in i
|
||||
.by_ref()
|
||||
.take_while(|c| *c != build_values.target_dir.file_name().unwrap())
|
||||
{}
|
||||
let path_template = i.as_path();
|
||||
match tera.render(path_template.to_str().unwrap(), &context) {
|
||||
Ok(s) => {
|
||||
let old_path = path.clone();
|
||||
let new_path = path.with_extension("");
|
||||
let mut file = File::create(path.join(new_path))?;
|
||||
file.write_all(s.as_bytes())?;
|
||||
std::fs::remove_file(old_path)?;
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error: {}", e);
|
||||
let mut cause = e.source();
|
||||
while let Some(e) = cause {
|
||||
eprintln!("Reason: {}", e);
|
||||
cause = e.source();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
60
thirdparty/rapier.js/builds/prepare_builds/templates/Cargo.toml.tera
vendored
Normal file
60
thirdparty/rapier.js/builds/prepare_builds/templates/Cargo.toml.tera
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
[package]
|
||||
name = "dimforge_{{ js_package_name }}" # Can't be named rapier{{ dimension }}d which conflicts with the dependency.
|
||||
version = "0.19.3"
|
||||
authors = ["Sébastien Crozet <developer@crozet.re>"]
|
||||
description = "{{ dimension }}-dimensional physics engine in Rust - official JS bindings."
|
||||
documentation = "https://rapier.rs/rustdoc/rapier{{ dimension }}d/index.html"
|
||||
homepage = "https://rapier.rs"
|
||||
repository = "https://github.com/dimforge/rapier.js"
|
||||
readme = "README.md"
|
||||
keywords = ["physics", "dynamics", "rigid", "real-time", "joints"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
default = ["dim{{ dimension }}"]
|
||||
dim{{ dimension }} = []
|
||||
|
||||
[lib]
|
||||
name = "rapier_wasm{{ dimension }}d"
|
||||
path = "../../src/lib.rs"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
required-features = ["dim{{ dimension }}"]
|
||||
|
||||
[lints]
|
||||
rust.unexpected_cfgs = { level = "warn", check-cfg = [
|
||||
'cfg(feature, values("dim{% if dimension == "2" %}3{% else %}2{% endif %}"))',
|
||||
] }
|
||||
|
||||
[dependencies]
|
||||
rapier{{ dimension }}d = { version = "0.30.1", features = [
|
||||
"serde-serialize",
|
||||
"debug-render",
|
||||
"profiler",
|
||||
{%- for feature in additional_features %}
|
||||
"{{ feature }}",
|
||||
{%- endfor %}
|
||||
] }
|
||||
# The explicit dependency to parry only needed to pin the patch version.
|
||||
parry{{ dimension }}d = { version = "^0.25.3" }
|
||||
ref-cast = "1"
|
||||
wasm-bindgen = "0.2.100"
|
||||
js-sys = "0.3"
|
||||
nalgebra = "0.34"
|
||||
serde = { version = "1", features = ["derive", "rc"] }
|
||||
bincode = "1"
|
||||
palette = "0.7"
|
||||
|
||||
[package.metadata.wasm-pack.profile.release]
|
||||
# add -g to keep debug symbols
|
||||
wasm-opt = [
|
||||
'-O4',
|
||||
'--dce',
|
||||
# The two options below are needed because of: https://github.com/rustwasm/wasm-pack/issues/1501
|
||||
'--enable-bulk-memory',
|
||||
'--enable-nontrapping-float-to-int',
|
||||
{%- for flag in additional_wasm_opt_flags %}
|
||||
'{{ flag }}',
|
||||
{%- endfor %}
|
||||
]
|
||||
#wasm-opt = ['-g']
|
||||
201
thirdparty/rapier.js/builds/prepare_builds/templates/LICENSE
vendored
Normal file
201
thirdparty/rapier.js/builds/prepare_builds/templates/LICENSE
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 Dimforge EURL
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
70
thirdparty/rapier.js/builds/prepare_builds/templates/README.md.tera
vendored
Normal file
70
thirdparty/rapier.js/builds/prepare_builds/templates/README.md.tera
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
<p align="center">
|
||||
<img src="https://www.rapier.rs/img/rapier_logo_color_textpath_dark.svg" alt="crates.io">
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://discord.gg/vt9DJSW">
|
||||
<img src="https://img.shields.io/discord/507548572338880513.svg?logo=discord&colorB=7289DA">
|
||||
</a>
|
||||
<a href="https://github.com/dimforge/rapier.js/actions">
|
||||
<img src="https://github.com/dimforge/rapier.js/workflows/main/badge.svg" alt="Build status">
|
||||
</a>
|
||||
<a href="https://crates.io/crates/rapier{{ dimension }}d">
|
||||
<img src="https://img.shields.io/crates/v/rapier{{ dimension }}d.svg?style=flat-square" alt="crates.io">
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/@dimforge/rapier{{ dimension }}d">
|
||||
<img src="https://badge.fury.io/js/%40dimforge%2Frapier{{ dimension }}d.svg" alt="npm version">
|
||||
</a>
|
||||
<a href="https://opensource.org/licenses/Apache-2.0">
|
||||
<img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg">
|
||||
</a>
|
||||
</p>
|
||||
<p align = "center">
|
||||
<strong>
|
||||
<a href="https://rapier.rs">Website</a> | <a href="https://rapier.rs/docs/">Documentation</a>
|
||||
</strong>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
<p align = "center">
|
||||
<b>{{ dimension }}D physics engine</b>
|
||||
<i>for the JavaScript programming language (official bindings).</i>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## Feature selection
|
||||
|
||||
Multiple NPM packages exist for Rapier, depending on your needs:
|
||||
- [`@dimforge/rapier2d`](https://www.npmjs.com/package/@dimforge/rapier2d) or
|
||||
[`@dimforge/rapier3d`](https://www.npmjs.com/package/@dimforge/rapier3d):
|
||||
The main build of the Rapier physics engine for 2D or 3D physics simulation. This should have wide browser
|
||||
support while offering great performances. This does **not** guarantee cross-platform determinism of the physics
|
||||
simulation (but it is still locally deterministic, on the same machine).
|
||||
- [`@dimforge/rapier2d-simd`](https://www.npmjs.com/package/@dimforge/rapier2d-simd) or
|
||||
[`@dimforge/rapier3d-simd`](https://www.npmjs.com/package/@dimforge/rapier3d-simd):
|
||||
A build with internal SIMD optimizations enabled. More limited browser support (requires support for [simd128](https://caniuse.com/?search=simd)).
|
||||
- [`@dimforge/rapier2d-deterministic`](https://www.npmjs.com/package/@dimforge/rapier2d-deterministic) or
|
||||
[`@dimforge/rapier3d-deterministic`](https://www.npmjs.com/package/@dimforge/rapier3d-deterministic):
|
||||
A less optimized build but with a guarantee of a cross-platform deterministic execution of the physics simulation.
|
||||
|
||||
## Bundler support
|
||||
|
||||
Some bundlers will struggle with the `.wasm` file package into the builds above. Alternative `-compat` versions exist
|
||||
which embed the `.wasm` file into the `.js` sources encoded with base64. This results in a bigger package size, but
|
||||
much wider bundler support.
|
||||
|
||||
Just append `-compat` to the build you are interested in:
|
||||
[`rapier2d-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-compat),
|
||||
[`rapier2d-simd-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-simd-compat),
|
||||
[`rapier2d-deterministic-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-deterministic-compat),
|
||||
[`rapier3d-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-compat),
|
||||
[`rapier3d-simd-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-simd-compat),
|
||||
[`rapier3d-deterministic-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-deterministic-compat).
|
||||
|
||||
## Nightly builds
|
||||
|
||||
Each time a new Pull Request is merged to the `main` branch of the [`rapier.js` repository](https://github.com/dimforge/rapier.js),
|
||||
an automatic _canary_ build is triggered. Builds published to npmjs under the _canary_ tag does not come with any
|
||||
stability guarantee and does not follow semver versioning. But it can be a useful solution to try out the latest
|
||||
features until a proper release is cut.
|
||||
15
thirdparty/rapier.js/builds/prepare_builds/templates/build_rust.sh.tera
vendored
Normal file
15
thirdparty/rapier.js/builds/prepare_builds/templates/build_rust.sh.tera
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Cleaning rust because changing rust flags may lead to different build results.
|
||||
cargo clean
|
||||
|
||||
{{ additional_rust_flags }} npx wasm-pack build
|
||||
sed -i.bak 's#dimforge_rapier#@dimforge/rapier#g' pkg/package.json
|
||||
sed -i.bak 's/"rapier_wasm{{ dimension }}d_bg.wasm"/"*"/g' pkg/package.json
|
||||
(
|
||||
cd pkg
|
||||
npm pkg delete sideEffects
|
||||
npm pkg set 'sideEffects[0]'="./*.js"
|
||||
)
|
||||
rm pkg/*.bak
|
||||
rm pkg/.gitignore
|
||||
13
thirdparty/rapier.js/builds/prepare_builds/templates/build_typescript.sh.tera
vendored
Normal file
13
thirdparty/rapier.js/builds/prepare_builds/templates/build_typescript.sh.tera
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#! /bin/sh
|
||||
|
||||
mkdir -p ./pkg/src
|
||||
cp -r ../../src.ts/* pkg/src/.
|
||||
rm -f ./pkg/raw.ts
|
||||
echo 'export * from "./rapier_wasm{{ dimension }}d"' > pkg/src/raw.ts
|
||||
# See https://serverfault.com/a/137848
|
||||
find pkg/ -type f -print0 | LC_ALL=C xargs -0 sed -i.bak '\:#if DIM{% if dimension == "2" %}3{% else %}2{% endif %}:,\:#endif:d'
|
||||
npx tsc
|
||||
# NOTE: we keep the typescripts files into the NPM package for source mapping: see #3
|
||||
sed -i.bak 's/"module": "rapier_wasm{{ dimension }}d.js"/"module": "rapier.js"/g' pkg/package.json
|
||||
sed -i.bak 's/"types": "rapier_wasm{{ dimension }}d.d.ts"/"types": "rapier.d.ts"/g' pkg/package.json
|
||||
find pkg/ -type f -name '*.bak' | xargs rm
|
||||
25
thirdparty/rapier.js/builds/prepare_builds/templates/package.json.tera
vendored
Normal file
25
thirdparty/rapier.js/builds/prepare_builds/templates/package.json.tera
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "@dimforge/{{ js_package_name }}",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"exports": "./pkg",
|
||||
"types": "./pkg/rapier.d.ts",
|
||||
"scripts": {
|
||||
"build": "npm run clean && npm run build:wasm && npm run build:ts && npm run build:doc",
|
||||
"build:doc": "typedoc --tsconfig tsconfig_typedoc.json",
|
||||
"build:wasm": "sh ./build_rust.sh",
|
||||
"build:ts": "sh ./build_typescript.sh",
|
||||
"clean": "rimraf pkg"
|
||||
},
|
||||
"//": "Better keep rimraf version in sync with wasm-pack, see https://github.com/rustwasm/wasm-pack/issues/1444",
|
||||
"devDependencies": {
|
||||
"rimraf": "^3.0.2",
|
||||
"typedoc": "^0.25.13"
|
||||
},
|
||||
"dependencies": {
|
||||
"wasm-pack": "^0.12.1"
|
||||
},
|
||||
"sideEffects": [
|
||||
"./*.js"
|
||||
]
|
||||
}
|
||||
13
thirdparty/rapier.js/builds/prepare_builds/templates/tsconfig.json
vendored
Normal file
13
thirdparty/rapier.js/builds/prepare_builds/templates/tsconfig.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./pkg",
|
||||
"module": "ES6",
|
||||
"target": "es6",
|
||||
"lib": ["es6"],
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"rootDirs": ["./pkg", "./pkg/src"]
|
||||
},
|
||||
"files": ["./pkg/src/rapier.ts"]
|
||||
}
|
||||
10
thirdparty/rapier.js/builds/prepare_builds/templates/tsconfig_typedoc.json
vendored
Normal file
10
thirdparty/rapier.js/builds/prepare_builds/templates/tsconfig_typedoc.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./pkg",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"lib": ["es6"]
|
||||
},
|
||||
"files": ["./pkg/rapier.d.ts"]
|
||||
}
|
||||
42
thirdparty/rapier.js/builds/prepare_builds/templates/typedoc.json.tera
vendored
Normal file
42
thirdparty/rapier.js/builds/prepare_builds/templates/typedoc.json.tera
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"$schema": "https://typedoc.org/schema.json",
|
||||
"entryPoints": [
|
||||
"./pkg/rapier.d.ts"
|
||||
],
|
||||
"out": "./docs",
|
||||
"readme": "none",
|
||||
"excludeExternals": true,
|
||||
"excludeNotDocumented": false,
|
||||
"intentionallyNotExported": [
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawBroadPhase",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawCCDSolver",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawColliderSet",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawEventQueue",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawImpulseJointSet",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawMultibodyJointSet",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawIntegrationParameters",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawIslandManager",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawNarrowPhase",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawPhysicsPipeline",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawRigidBodySet",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawSerializationPipeline",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawContactManifold",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawShape",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawGenericJoint",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawJointAxis",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawRotation",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawVector",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawPointColliderProjection",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawPointProjection",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawRayColliderIntersection",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawRayColliderHit",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawRayIntersection",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawColliderShapeCastHit",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawShapeContact",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawShapeCastHit",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawQueryPipeline",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawDeserializedWorld",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawDebugRenderPipeline",
|
||||
"pkg/rapier_wasm{{ dimension }}d.d.ts:RawContactForceEvent"
|
||||
]
|
||||
}
|
||||
12
thirdparty/rapier.js/package.json
vendored
Normal file
12
thirdparty/rapier.js/package.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"scripts": {
|
||||
"fmt": "prettier ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "2.7.1",
|
||||
"typedoc": "0.23.19",
|
||||
"typescript": "4.8.4",
|
||||
"wasm-opt": "1.4.0",
|
||||
"wasm-pack": "0.12.1"
|
||||
}
|
||||
}
|
||||
19
thirdparty/rapier.js/publish_all_canary.sh
vendored
Normal file
19
thirdparty/rapier.js/publish_all_canary.sh
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
for entry in builds/*/pkg
|
||||
do
|
||||
(
|
||||
echo "Publishing $entry"
|
||||
cd $entry; npm version 0.0.0-$(git rev-parse --short HEAD)-$(date '+%Y%m%d') --git-tag-version false;
|
||||
npm publish --tag canary --access public;
|
||||
)
|
||||
done;
|
||||
|
||||
for entry in rapier-compat/builds/*/pkg
|
||||
do
|
||||
(
|
||||
echo "Publishing $entry"
|
||||
cd $entry; npm version 0.0.0-$(git rev-parse --short HEAD)-$(date '+%Y%m%d') --git-tag-version false;
|
||||
npm publish --tag canary --access public;
|
||||
)
|
||||
done;
|
||||
19
thirdparty/rapier.js/publish_all_prod.sh
vendored
Normal file
19
thirdparty/rapier.js/publish_all_prod.sh
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
for entry in builds/*/pkg
|
||||
do
|
||||
(
|
||||
echo "Publishing $entry"
|
||||
cd $entry;
|
||||
npm publish --access public;
|
||||
)
|
||||
done;
|
||||
|
||||
for entry in rapier-compat/builds/*/pkg
|
||||
do
|
||||
(
|
||||
echo "Publishing $entry"
|
||||
cd $entry;
|
||||
npm publish --access public;
|
||||
)
|
||||
done;
|
||||
16
thirdparty/rapier.js/rapier-compat/README.md
vendored
Normal file
16
thirdparty/rapier.js/rapier-compat/README.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# tsconfig json files
|
||||
|
||||
- tsconfig.common.json - shared TypeScript options
|
||||
- tsconfig.pkg2d.json - config for compiling rapier2d-compat
|
||||
- tsconfig.pkg3d.json - config for compiling rapier3d-compat
|
||||
- tconfig.json - for IDE (VSCode) and unit tests. Includes Jest types.
|
||||
|
||||
## Generation steps
|
||||
|
||||
Check `./package.json scripts`, which are used by CI.
|
||||
|
||||
Summary:
|
||||
|
||||
- build rust wasm projects into their dedicated folder in `./builds/`
|
||||
- copy common javascript and generate dimension specific javascript into a common `./pkg` folder
|
||||
- copy that `pkg` folder in each folder from `./builds`
|
||||
50
thirdparty/rapier.js/rapier-compat/build-rust.sh
vendored
Normal file
50
thirdparty/rapier.js/rapier-compat/build-rust.sh
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
help()
|
||||
{
|
||||
printf "Usage: %s: [-d 2|3] [-f deterministim|non-deterministic|simd]\n" $0
|
||||
}
|
||||
|
||||
while getopts :d:f: name
|
||||
do
|
||||
case $name in
|
||||
d)
|
||||
dimension="$OPTARG";;
|
||||
f)
|
||||
feature="$OPTARG";;
|
||||
?) help ; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$dimension" ]]; then
|
||||
help; exit 2;
|
||||
fi
|
||||
if [[ -z "$feature" ]]; then
|
||||
help; exit 3;
|
||||
fi
|
||||
|
||||
if [[ $feature == "non-deterministic" ]]; then
|
||||
feature_postfix=""
|
||||
else
|
||||
feature_postfix="-${feature}"
|
||||
fi
|
||||
|
||||
rust_source_directory="../builds/rapier${dimension}d${feature_postfix}"
|
||||
|
||||
if [ ! -d "$rust_source_directory" ]; then
|
||||
echo "Directory $rust_source_directory does not exist";
|
||||
echo "You may want to generate rust projects first.";
|
||||
help
|
||||
exit 4;
|
||||
fi
|
||||
|
||||
# Working dir in wasm-pack is the project root so we need that "../../"
|
||||
|
||||
if [[ $feature == "simd" ]]; then
|
||||
export additional_rustflags='-C target-feature=+simd128'
|
||||
else
|
||||
export additional_rustflags=''
|
||||
fi
|
||||
|
||||
RUSTFLAGS="${additional_rustflags}" wasm-pack --verbose build --target web --out-dir "../../rapier-compat/builds/${dimension}d${feature_postfix}/wasm-build" "$rust_source_directory"
|
||||
11
thirdparty/rapier.js/rapier-compat/fix_raw_file.sh
vendored
Normal file
11
thirdparty/rapier.js/rapier-compat/fix_raw_file.sh
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
for feature in \
|
||||
2d 2d-deterministic 2d-simd \
|
||||
3d 3d-deterministic 3d-simd
|
||||
do
|
||||
|
||||
echo 'export * from "'"./rapier_wasm$feature"'"' > builds/${feature}/pkg/raw.d.ts
|
||||
echo 'export * from "'"./rapier_wasm$feature"'"' > builds/${feature}/pkg/raw.d.ts
|
||||
|
||||
done;
|
||||
58
thirdparty/rapier.js/rapier-compat/gen_src.sh
vendored
Normal file
58
thirdparty/rapier.js/rapier-compat/gen_src.sh
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
# Copy source and remove #if sections - similar to script in ../rapierXd
|
||||
set -e
|
||||
|
||||
gen_js() {
|
||||
DIM=$1
|
||||
GENOUT="./gen${DIM}"
|
||||
|
||||
# Make output directories
|
||||
mkdir -p ${GENOUT}
|
||||
|
||||
# Copy common sources
|
||||
cp -r ../src.ts/* $GENOUT
|
||||
|
||||
# Copy compat mode override sources
|
||||
rm -f "${GENOUT}/raw.ts" "${GENOUT}/init.ts"
|
||||
cp -r ./src${DIM}/* $GENOUT
|
||||
}
|
||||
|
||||
gen_js "2d"
|
||||
gen_js "3d"
|
||||
|
||||
# See https://serverfault.com/a/137848
|
||||
find gen2d/ -type f -print0 | LC_ALL=C xargs -0 sed -i.bak '\:#if DIM3:,\:#endif:d'
|
||||
find gen3d/ -type f -print0 | LC_ALL=C xargs -0 sed -i.bak '\:#if DIM2:,\:#endif:d'
|
||||
|
||||
# Clean up backup files.
|
||||
find gen2d/ -type f -name '*.bak' | xargs rm
|
||||
find gen3d/ -type f -name '*.bak' | xargs rm
|
||||
|
||||
for features_set in \
|
||||
"2" "2 deterministic" "2 simd" \
|
||||
"3" "3 deterministic" "3 simd"
|
||||
do
|
||||
|
||||
set -- $features_set # Convert the "tuple" into the param args $1 $2...
|
||||
dimension=$1
|
||||
if [ -z "$2" ]; then
|
||||
feature="${1}d";
|
||||
else
|
||||
feature="${1}d-${2}";
|
||||
fi
|
||||
|
||||
mkdir -p ./builds/${feature}/pkg/
|
||||
|
||||
cp ./builds/${feature}/wasm-build/rapier_wasm* ./builds/${feature}/pkg/
|
||||
cp -r ./gen${dimension}d ./builds/${feature}/
|
||||
|
||||
# copy tsconfig, as they contain paths
|
||||
cp ./tsconfig.common.json ./tsconfig.json ./builds/${feature}/
|
||||
cp ./tsconfig.pkg${dimension}d.json ./builds/${feature}/tsconfig.pkg.json
|
||||
|
||||
# "import.meta" causes Babel to choke, but the code path is never taken so just remove it.
|
||||
sed -i.bak 's/import.meta.url/"<deleted>"/g' ./builds/${feature}/pkg/rapier_wasm${dimension}d.js
|
||||
|
||||
# Clean up backup files.
|
||||
find ./builds/${feature}/pkg/ -type f -name '*.bak' | xargs rm
|
||||
|
||||
done
|
||||
59
thirdparty/rapier.js/rapier-compat/package.json
vendored
Normal file
59
thirdparty/rapier.js/rapier-compat/package.json
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "build-rapier",
|
||||
"description": "Build scripts for compatibility package with inlined webassembly as base64.",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build-rust-2d-non-deterministic": "./build-rust.sh -f non-deterministic -d 2",
|
||||
"build-rust-2d-deterministic": "./build-rust.sh -f deterministic -d 2",
|
||||
"build-rust-2d-simd": "./build-rust.sh -f simd -d 2",
|
||||
"build-rust-2d-all": "npm run build-rust-2d-non-deterministic && npm run build-rust-2d-deterministic && npm run build-rust-2d-simd",
|
||||
"build-rust-3d-non-deterministic": "./build-rust.sh -f non-deterministic -d 3",
|
||||
"build-rust-3d-deterministic": "./build-rust.sh -f deterministic -d 3",
|
||||
"build-rust-3d-simd": "./build-rust.sh -f simd -d 3",
|
||||
"build-rust-3d-all": "npm run build-rust-3d-non-deterministic && npm run build-rust-3d-deterministic && npm run build-rust-3d-simd",
|
||||
"build-rust-all": "npm run build-rust-2d-all && npm run build-rust-3d-all",
|
||||
"build-genjs": "sh ./gen_src.sh",
|
||||
"build-js": "rollup --config rollup.config.js --bundleConfigAsCjs",
|
||||
"fix-raw-file": "sh ./fix_raw_file.sh",
|
||||
"build": "npm run clean && npm run build-rust-all && npm run build-genjs && npm run build-js && npm run fix-raw-file",
|
||||
"clean": "rimraf gen2d gen3d builds",
|
||||
"test": "jest --detectOpenHandles",
|
||||
"all": "npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"base64-js": "^1.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^23.0.2",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@rollup/plugin-typescript": "^9.0.2",
|
||||
"@rollup/plugin-terser": "0.1.0",
|
||||
"@types/jest": "^29.2.1",
|
||||
"jest": "^29.2.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^3.2.5",
|
||||
"rollup-plugin-base64": "^1.0.1",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-filesize": "^9.1.2",
|
||||
"ts-jest": "^29.0.3",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^4.8.4"
|
||||
},
|
||||
"jest": {
|
||||
"roots": [
|
||||
"<rootDir>/tests"
|
||||
],
|
||||
"preset": "ts-jest",
|
||||
"collectCoverageFrom": [
|
||||
"builds/**/pkg/**/*.js"
|
||||
],
|
||||
"transformIgnorePatterns": [
|
||||
"[/\\\\]node_modules[/\\\\].+\\.(js|ts)$",
|
||||
"builds/.*/[/\\\\]pkg[/\\\\].+\\.(js|ts)$"
|
||||
],
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"js"
|
||||
]
|
||||
}
|
||||
}
|
||||
85
thirdparty/rapier.js/rapier-compat/rollup.config.js
vendored
Normal file
85
thirdparty/rapier.js/rapier-compat/rollup.config.js
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
import commonjs from "@rollup/plugin-commonjs";
|
||||
import {nodeResolve} from "@rollup/plugin-node-resolve";
|
||||
import typescript from "@rollup/plugin-typescript";
|
||||
import terser from "@rollup/plugin-terser";
|
||||
import path from "path";
|
||||
import {base64} from "rollup-plugin-base64";
|
||||
import copy from "rollup-plugin-copy";
|
||||
import filesize from "rollup-plugin-filesize";
|
||||
|
||||
const config = (dim, features_postfix) => ({
|
||||
input: `builds/${features_postfix}/gen${dim}/rapier.ts`,
|
||||
output: [
|
||||
{
|
||||
file: `builds/${features_postfix}/pkg/rapier.mjs`,
|
||||
format: "es",
|
||||
sourcemap: true,
|
||||
exports: "named",
|
||||
},
|
||||
{
|
||||
file: `builds/${features_postfix}/pkg/rapier.cjs`,
|
||||
format: "cjs",
|
||||
sourcemap: true,
|
||||
exports: "named",
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
copy({
|
||||
targets: [
|
||||
{
|
||||
src: `builds/${features_postfix}/wasm-build/package.json`,
|
||||
dest: `builds/${features_postfix}/pkg/`,
|
||||
transform(content) {
|
||||
let config = JSON.parse(content.toString());
|
||||
config.name = `@dimforge/rapier${features_postfix}-compat`;
|
||||
config.description +=
|
||||
" Compatibility package with inlined webassembly as base64.";
|
||||
config.types = "rapier.d.ts";
|
||||
config.main = "rapier.cjs";
|
||||
config.module = "rapier.mjs";
|
||||
config.exports = {
|
||||
".": {
|
||||
types: "./rapier.d.ts",
|
||||
require: "./rapier.cjs",
|
||||
import: "./rapier.mjs",
|
||||
},
|
||||
};
|
||||
// delete config.module;
|
||||
config.files = ["*"];
|
||||
return JSON.stringify(config, undefined, 2);
|
||||
},
|
||||
},
|
||||
{
|
||||
src: `../rapier${features_postfix}/LICENSE`,
|
||||
dest: `builds/${features_postfix}/pkg`,
|
||||
},
|
||||
{
|
||||
src: `../rapier${features_postfix}/README.md`,
|
||||
dest: `builds/${features_postfix}/pkg`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
base64({include: "**/*.wasm"}),
|
||||
terser(),
|
||||
nodeResolve(),
|
||||
commonjs(),
|
||||
typescript({
|
||||
tsconfig: path.resolve(
|
||||
__dirname,
|
||||
`builds/${features_postfix}/tsconfig.pkg.json`,
|
||||
),
|
||||
sourceMap: true,
|
||||
inlineSources: true,
|
||||
}),
|
||||
filesize(),
|
||||
],
|
||||
});
|
||||
|
||||
export default [
|
||||
config("2d", "2d"),
|
||||
config("2d", "2d-deterministic"),
|
||||
config("2d", "2d-simd"),
|
||||
config("3d", "3d"),
|
||||
config("3d", "3d-deterministic"),
|
||||
config("3d", "3d-simd"),
|
||||
];
|
||||
60
thirdparty/rapier.js/rapier-compat/src2d/init.ts
vendored
Normal file
60
thirdparty/rapier.js/rapier-compat/src2d/init.ts
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* RAPIER initialization module with dynamic WASM loading support.
|
||||
* RAPIER 初始化模块,支持动态 WASM 加载。
|
||||
*/
|
||||
|
||||
import wasmInit from "../pkg/rapier_wasm2d";
|
||||
|
||||
/**
|
||||
* Input types for WASM initialization.
|
||||
* WASM 初始化的输入类型。
|
||||
*/
|
||||
export type InitInput =
|
||||
| RequestInfo // URL string or Request object
|
||||
| URL // URL object
|
||||
| Response // Fetch Response object
|
||||
| BufferSource // ArrayBuffer or TypedArray
|
||||
| WebAssembly.Module; // Pre-compiled module
|
||||
|
||||
let initialized = false;
|
||||
|
||||
/**
|
||||
* Initializes RAPIER.
|
||||
* Has to be called and awaited before using any library methods.
|
||||
*
|
||||
* 初始化 RAPIER。
|
||||
* 必须在使用任何库方法之前调用并等待。
|
||||
*
|
||||
* @param input - WASM source (required). Can be URL, Response, ArrayBuffer, etc.
|
||||
* WASM 源(必需)。可以是 URL、Response、ArrayBuffer 等。
|
||||
*
|
||||
* @example
|
||||
* // Load from URL | 从 URL 加载
|
||||
* await RAPIER.init('wasm/rapier_wasm2d_bg.wasm');
|
||||
*
|
||||
* @example
|
||||
* // Load from fetch response | 从 fetch 响应加载
|
||||
* const response = await fetch('wasm/rapier_wasm2d_bg.wasm');
|
||||
* await RAPIER.init(response);
|
||||
*
|
||||
* @example
|
||||
* // Load from ArrayBuffer | 从 ArrayBuffer 加载
|
||||
* const buffer = await fetch('wasm/rapier_wasm2d_bg.wasm').then(r => r.arrayBuffer());
|
||||
* await RAPIER.init(buffer);
|
||||
*/
|
||||
export async function init(input?: InitInput): Promise<void> {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
await wasmInit(input);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if RAPIER is already initialized.
|
||||
* 检查 RAPIER 是否已初始化。
|
||||
*/
|
||||
export function isInitialized(): boolean {
|
||||
return initialized;
|
||||
}
|
||||
1
thirdparty/rapier.js/rapier-compat/src2d/raw.ts
vendored
Normal file
1
thirdparty/rapier.js/rapier-compat/src2d/raw.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from "../pkg/rapier_wasm2d";
|
||||
12
thirdparty/rapier.js/rapier-compat/src3d/init.ts
vendored
Normal file
12
thirdparty/rapier.js/rapier-compat/src3d/init.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// @ts-ignore
|
||||
import wasmBase64 from "../pkg/rapier_wasm3d_bg.wasm";
|
||||
import wasmInit from "../pkg/rapier_wasm3d";
|
||||
import base64 from "base64-js";
|
||||
|
||||
/**
|
||||
* Initializes RAPIER.
|
||||
* Has to be called and awaited before using any library methods.
|
||||
*/
|
||||
export async function init() {
|
||||
await wasmInit(base64.toByteArray(wasmBase64 as unknown as string).buffer);
|
||||
}
|
||||
1
thirdparty/rapier.js/rapier-compat/src3d/raw.ts
vendored
Normal file
1
thirdparty/rapier.js/rapier-compat/src3d/raw.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from "../pkg/rapier_wasm3d";
|
||||
23
thirdparty/rapier.js/rapier-compat/tests/World2d.test.ts
vendored
Normal file
23
thirdparty/rapier.js/rapier-compat/tests/World2d.test.ts
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import {init, Vector2, World} from "../builds/2d-deterministic/pkg";
|
||||
|
||||
describe("2d/World", () => {
|
||||
let world: World;
|
||||
|
||||
beforeAll(init);
|
||||
|
||||
afterAll(async () => {
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
world = new World(new Vector2(0, 9.8));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
world.free();
|
||||
});
|
||||
|
||||
test("constructor", () => {
|
||||
expect(world.colliders.len()).toBe(0);
|
||||
});
|
||||
});
|
||||
23
thirdparty/rapier.js/rapier-compat/tests/World3d.test.ts
vendored
Normal file
23
thirdparty/rapier.js/rapier-compat/tests/World3d.test.ts
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import {init, Vector3, World} from "../builds/3d-deterministic/pkg";
|
||||
|
||||
describe("3d/World", () => {
|
||||
let world: World;
|
||||
|
||||
beforeAll(init);
|
||||
|
||||
afterAll(async () => {
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
world = new World(new Vector3(0, 9.8, 0));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
world.free();
|
||||
});
|
||||
|
||||
test("constructor", () => {
|
||||
expect(world.colliders.len()).toBe(0);
|
||||
});
|
||||
});
|
||||
15
thirdparty/rapier.js/rapier-compat/tests/math2d.test.ts
vendored
Normal file
15
thirdparty/rapier.js/rapier-compat/tests/math2d.test.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import {Vector2, VectorOps} from "../builds/2d-deterministic/pkg";
|
||||
|
||||
describe("2d/math", () => {
|
||||
test("Vector2", () => {
|
||||
const v = new Vector2(0, 1);
|
||||
expect(v.x).toBe(0);
|
||||
expect(v.y).toBe(1);
|
||||
});
|
||||
|
||||
test("VectorOps", () => {
|
||||
const v = VectorOps.new(0, 1);
|
||||
expect(v.x).toBe(0);
|
||||
expect(v.y).toBe(1);
|
||||
});
|
||||
});
|
||||
17
thirdparty/rapier.js/rapier-compat/tests/math3d.test.ts
vendored
Normal file
17
thirdparty/rapier.js/rapier-compat/tests/math3d.test.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import {Vector3, VectorOps} from "../builds/3d-deterministic/pkg";
|
||||
|
||||
describe("3d/math", () => {
|
||||
test("Vector3", () => {
|
||||
const v = new Vector3(0, 1, 2);
|
||||
expect(v.x).toBe(0);
|
||||
expect(v.y).toBe(1);
|
||||
expect(v.z).toBe(2);
|
||||
});
|
||||
|
||||
test("VectorOps", () => {
|
||||
const v = VectorOps.new(0, 1, 2);
|
||||
expect(v.x).toBe(0);
|
||||
expect(v.y).toBe(1);
|
||||
expect(v.z).toBe(2);
|
||||
});
|
||||
});
|
||||
15
thirdparty/rapier.js/rapier-compat/tsconfig.common.json
vendored
Normal file
15
thirdparty/rapier.js/rapier-compat/tsconfig.common.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "ES6",
|
||||
"target": "es6",
|
||||
"noEmitOnError": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictFunctionTypes": true,
|
||||
"lib": ["es6", "DOM"],
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"declaration": true
|
||||
}
|
||||
}
|
||||
10
thirdparty/rapier.js/rapier-compat/tsconfig.json
vendored
Normal file
10
thirdparty/rapier.js/rapier-compat/tsconfig.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./tsconfig.common.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["es6", "DOM"],
|
||||
"esModuleInterop": true,
|
||||
"types": ["jest"],
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": ["./tests/**/*.test.ts"]
|
||||
}
|
||||
8
thirdparty/rapier.js/rapier-compat/tsconfig.pkg2d.json
vendored
Normal file
8
thirdparty/rapier.js/rapier-compat/tsconfig.pkg2d.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./tsconfig.common.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./gen2d",
|
||||
"outDir": "./2d"
|
||||
},
|
||||
"files": ["./gen2d/rapier.ts"]
|
||||
}
|
||||
8
thirdparty/rapier.js/rapier-compat/tsconfig.pkg3d.json
vendored
Normal file
8
thirdparty/rapier.js/rapier-compat/tsconfig.pkg3d.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./tsconfig.common.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./gen3d",
|
||||
"outDir": "."
|
||||
},
|
||||
"files": ["./gen3d/rapier.ts"]
|
||||
}
|
||||
70
thirdparty/rapier.js/src.ts/coarena.ts
vendored
Normal file
70
thirdparty/rapier.js/src.ts/coarena.ts
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
export class Coarena<T> {
|
||||
fconv: Float64Array;
|
||||
uconv: Uint32Array;
|
||||
data: Array<T>;
|
||||
size: number;
|
||||
|
||||
public constructor() {
|
||||
this.fconv = new Float64Array(1);
|
||||
this.uconv = new Uint32Array(this.fconv.buffer);
|
||||
this.data = new Array<T>();
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
public set(handle: number, data: T) {
|
||||
let i = this.index(handle);
|
||||
while (this.data.length <= i) {
|
||||
this.data.push(null);
|
||||
}
|
||||
|
||||
if (this.data[i] == null) this.size += 1;
|
||||
this.data[i] = data;
|
||||
}
|
||||
|
||||
public len(): number {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public delete(handle: number) {
|
||||
let i = this.index(handle);
|
||||
if (i < this.data.length) {
|
||||
if (this.data[i] != null) this.size -= 1;
|
||||
this.data[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public clear() {
|
||||
this.data = new Array<T>();
|
||||
}
|
||||
|
||||
public get(handle: number): T | null {
|
||||
let i = this.index(handle);
|
||||
if (i < this.data.length) {
|
||||
return this.data[i];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public forEach(f: (elt: T) => void) {
|
||||
for (const elt of this.data) {
|
||||
if (elt != null) f(elt);
|
||||
}
|
||||
}
|
||||
|
||||
public getAll(): Array<T> {
|
||||
return this.data.filter((elt) => elt != null);
|
||||
}
|
||||
|
||||
private index(handle: number): number {
|
||||
/// Extracts the index part of a handle (the lower 32 bits).
|
||||
/// This is done by first injecting the handle into an Float64Array
|
||||
/// which is itself injected into an Uint32Array (at construction time).
|
||||
/// The 0-th value of the Uint32Array will become the `number` integer
|
||||
/// representation of the lower 32 bits.
|
||||
/// Also `this.uconv[1]` then contains the generation number as a `number`,
|
||||
/// which we don’t really need.
|
||||
this.fconv[0] = handle;
|
||||
return this.uconv[0];
|
||||
}
|
||||
}
|
||||
386
thirdparty/rapier.js/src.ts/control/character_controller.ts
vendored
Normal file
386
thirdparty/rapier.js/src.ts/control/character_controller.ts
vendored
Normal file
@@ -0,0 +1,386 @@
|
||||
import {RawKinematicCharacterController, RawCharacterCollision} from "../raw";
|
||||
import {Rotation, Vector, VectorOps} from "../math";
|
||||
import {
|
||||
BroadPhase,
|
||||
Collider,
|
||||
ColliderSet,
|
||||
InteractionGroups,
|
||||
NarrowPhase,
|
||||
Shape,
|
||||
} from "../geometry";
|
||||
import {QueryFilterFlags, World} from "../pipeline";
|
||||
import {IntegrationParameters, RigidBody, RigidBodySet} from "../dynamics";
|
||||
|
||||
/**
|
||||
* A collision between the character and an obstacle hit on its path.
|
||||
*/
|
||||
export class CharacterCollision {
|
||||
/** The collider involved in the collision. Null if the collider no longer exists in the physics world. */
|
||||
public collider: Collider | null;
|
||||
/** The translation delta applied to the character before this collision took place. */
|
||||
public translationDeltaApplied: Vector;
|
||||
/** The translation delta the character would move after this collision if there is no other obstacles. */
|
||||
public translationDeltaRemaining: Vector;
|
||||
/** The time-of-impact between the character and the obstacles. */
|
||||
public toi: number;
|
||||
/** The world-space contact point on the collider when the collision happens. */
|
||||
public witness1: Vector;
|
||||
/** The local-space contact point on the character when the collision happens. */
|
||||
public witness2: Vector;
|
||||
/** The world-space outward contact normal on the collider when the collision happens. */
|
||||
public normal1: Vector;
|
||||
/** The local-space outward contact normal on the character when the collision happens. */
|
||||
public normal2: Vector;
|
||||
}
|
||||
|
||||
/**
|
||||
* A character controller for controlling kinematic bodies and parentless colliders by hitting
|
||||
* and sliding against obstacles.
|
||||
*/
|
||||
export class KinematicCharacterController {
|
||||
private raw: RawKinematicCharacterController;
|
||||
private rawCharacterCollision: RawCharacterCollision;
|
||||
|
||||
private params: IntegrationParameters;
|
||||
private broadPhase: BroadPhase;
|
||||
private narrowPhase: NarrowPhase;
|
||||
private bodies: RigidBodySet;
|
||||
private colliders: ColliderSet;
|
||||
private _applyImpulsesToDynamicBodies: boolean;
|
||||
private _characterMass: number | null;
|
||||
|
||||
constructor(
|
||||
offset: number,
|
||||
params: IntegrationParameters,
|
||||
broadPhase: BroadPhase,
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
) {
|
||||
this.params = params;
|
||||
this.bodies = bodies;
|
||||
this.colliders = colliders;
|
||||
this.broadPhase = broadPhase;
|
||||
this.narrowPhase = narrowPhase;
|
||||
this.raw = new RawKinematicCharacterController(offset);
|
||||
this.rawCharacterCollision = new RawCharacterCollision();
|
||||
this._applyImpulsesToDynamicBodies = false;
|
||||
this._characterMass = null;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
this.rawCharacterCollision.free();
|
||||
}
|
||||
|
||||
this.raw = undefined;
|
||||
this.rawCharacterCollision = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The direction that goes "up". Used to determine where the floor is, and the floor’s angle.
|
||||
*/
|
||||
public up(): Vector {
|
||||
return this.raw.up();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the direction that goes "up". Used to determine where the floor is, and the floor’s angle.
|
||||
*/
|
||||
public setUp(vector: Vector) {
|
||||
let rawVect = VectorOps.intoRaw(vector);
|
||||
return this.raw.setUp(rawVect);
|
||||
rawVect.free();
|
||||
}
|
||||
|
||||
public applyImpulsesToDynamicBodies(): boolean {
|
||||
return this._applyImpulsesToDynamicBodies;
|
||||
}
|
||||
|
||||
public setApplyImpulsesToDynamicBodies(enabled: boolean) {
|
||||
this._applyImpulsesToDynamicBodies = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the custom value of the character mass, if it was set by `this.setCharacterMass`.
|
||||
*/
|
||||
public characterMass(): number | null {
|
||||
return this._characterMass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mass of the character to be used for impulse resolution if `self.applyImpulsesToDynamicBodies`
|
||||
* is set to `true`.
|
||||
*
|
||||
* If no character mass is set explicitly (or if it is set to `null`) it is automatically assumed to be equal
|
||||
* to the mass of the rigid-body the character collider is attached to; or equal to 0 if the character collider
|
||||
* isn’t attached to any rigid-body.
|
||||
*
|
||||
* @param mass - The mass to set.
|
||||
*/
|
||||
public setCharacterMass(mass: number | null) {
|
||||
this._characterMass = mass;
|
||||
}
|
||||
|
||||
/**
|
||||
* A small gap to preserve between the character and its surroundings.
|
||||
*
|
||||
* This value should not be too large to avoid visual artifacts, but shouldn’t be too small
|
||||
* (must not be zero) to improve numerical stability of the character controller.
|
||||
*/
|
||||
public offset(): number {
|
||||
return this.raw.offset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a small gap to preserve between the character and its surroundings.
|
||||
*
|
||||
* This value should not be too large to avoid visual artifacts, but shouldn’t be too small
|
||||
* (must not be zero) to improve numerical stability of the character controller.
|
||||
*/
|
||||
public setOffset(value: number) {
|
||||
this.raw.setOffset(value);
|
||||
}
|
||||
|
||||
/// Increase this number if your character appears to get stuck when sliding against surfaces.
|
||||
///
|
||||
/// This is a small distance applied to the movement toward the contact normals of shapes hit
|
||||
/// by the character controller. This helps shape-casting not getting stuck in an always-penetrating
|
||||
/// state during the sliding calculation.
|
||||
///
|
||||
/// This value should remain fairly small since it can introduce artificial "bumps" when sliding
|
||||
/// along a flat surface.
|
||||
public normalNudgeFactor(): number {
|
||||
return this.raw.normalNudgeFactor();
|
||||
}
|
||||
|
||||
/// Increase this number if your character appears to get stuck when sliding against surfaces.
|
||||
///
|
||||
/// This is a small distance applied to the movement toward the contact normals of shapes hit
|
||||
/// by the character controller. This helps shape-casting not getting stuck in an always-penetrating
|
||||
/// state during the sliding calculation.
|
||||
///
|
||||
/// This value should remain fairly small since it can introduce artificial "bumps" when sliding
|
||||
/// along a flat surface.
|
||||
public setNormalNudgeFactor(value: number) {
|
||||
this.raw.setNormalNudgeFactor(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is sliding against obstacles enabled?
|
||||
*/
|
||||
public slideEnabled(): boolean {
|
||||
return this.raw.slideEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable sliding against obstacles.
|
||||
*/
|
||||
public setSlideEnabled(enabled: boolean) {
|
||||
this.raw.setSlideEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum step height a character can automatically step over.
|
||||
*/
|
||||
public autostepMaxHeight(): number | null {
|
||||
return this.raw.autostepMaxHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum width of free space that must be available after stepping on a stair.
|
||||
*/
|
||||
public autostepMinWidth(): number | null {
|
||||
return this.raw.autostepMinWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the character automatically step over dynamic bodies too?
|
||||
*/
|
||||
public autostepIncludesDynamicBodies(): boolean | null {
|
||||
return this.raw.autostepIncludesDynamicBodies();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is automatically stepping over small objects enabled?
|
||||
*/
|
||||
public autostepEnabled(): boolean {
|
||||
return this.raw.autostepEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enabled automatically stepping over small objects.
|
||||
*
|
||||
* @param maxHeight - The maximum step height a character can automatically step over.
|
||||
* @param minWidth - The minimum width of free space that must be available after stepping on a stair.
|
||||
* @param includeDynamicBodies - Can the character automatically step over dynamic bodies too?
|
||||
*/
|
||||
public enableAutostep(
|
||||
maxHeight: number,
|
||||
minWidth: number,
|
||||
includeDynamicBodies: boolean,
|
||||
) {
|
||||
this.raw.enableAutostep(maxHeight, minWidth, includeDynamicBodies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable automatically stepping over small objects.
|
||||
*/
|
||||
public disableAutostep() {
|
||||
return this.raw.disableAutostep();
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum angle (radians) between the floor’s normal and the `up` vector that the
|
||||
* character is able to climb.
|
||||
*/
|
||||
public maxSlopeClimbAngle(): number {
|
||||
return this.raw.maxSlopeClimbAngle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum angle (radians) between the floor’s normal and the `up` vector that the
|
||||
* character is able to climb.
|
||||
*/
|
||||
public setMaxSlopeClimbAngle(angle: number) {
|
||||
this.raw.setMaxSlopeClimbAngle(angle);
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum angle (radians) between the floor’s normal and the `up` vector before the
|
||||
* character starts to slide down automatically.
|
||||
*/
|
||||
public minSlopeSlideAngle(): number {
|
||||
return this.raw.minSlopeSlideAngle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum angle (radians) between the floor’s normal and the `up` vector before the
|
||||
* character starts to slide down automatically.
|
||||
*/
|
||||
public setMinSlopeSlideAngle(angle: number) {
|
||||
this.raw.setMinSlopeSlideAngle(angle);
|
||||
}
|
||||
|
||||
/**
|
||||
* If snap-to-ground is enabled, should the character be automatically snapped to the ground if
|
||||
* the distance between the ground and its feet are smaller than the specified threshold?
|
||||
*/
|
||||
public snapToGroundDistance(): number | null {
|
||||
return this.raw.snapToGroundDistance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables automatically snapping the character to the ground if the distance between
|
||||
* the ground and its feet are smaller than the specified threshold.
|
||||
*/
|
||||
public enableSnapToGround(distance: number) {
|
||||
this.raw.enableSnapToGround(distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables automatically snapping the character to the ground.
|
||||
*/
|
||||
public disableSnapToGround() {
|
||||
this.raw.disableSnapToGround();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is automatically snapping the character to the ground enabled?
|
||||
*/
|
||||
public snapToGroundEnabled(): boolean {
|
||||
return this.raw.snapToGroundEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the movement the given collider is able to execute after hitting and sliding on obstacles.
|
||||
*
|
||||
* @param collider - The collider to move.
|
||||
* @param desiredTranslationDelta - The desired collider movement.
|
||||
* @param filterFlags - Flags for excluding whole subsets of colliders from the obstacles taken into account.
|
||||
* @param filterGroups - Groups for excluding colliders with incompatible collision groups from the obstacles
|
||||
* taken into account.
|
||||
* @param filterPredicate - Any collider for which this closure returns `false` will be excluded from the
|
||||
* obstacles taken into account.
|
||||
*/
|
||||
public computeColliderMovement(
|
||||
collider: Collider,
|
||||
desiredTranslationDelta: Vector,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterGroups?: InteractionGroups,
|
||||
filterPredicate?: (collider: Collider) => boolean,
|
||||
) {
|
||||
let rawTranslationDelta = VectorOps.intoRaw(desiredTranslationDelta);
|
||||
this.raw.computeColliderMovement(
|
||||
this.params.dt,
|
||||
this.broadPhase.raw,
|
||||
this.narrowPhase.raw,
|
||||
this.bodies.raw,
|
||||
this.colliders.raw,
|
||||
collider.handle,
|
||||
rawTranslationDelta,
|
||||
this._applyImpulsesToDynamicBodies,
|
||||
this._characterMass,
|
||||
filterFlags,
|
||||
filterGroups,
|
||||
this.colliders.castClosure(filterPredicate),
|
||||
);
|
||||
rawTranslationDelta.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* The movement computed by the last call to `this.computeColliderMovement`.
|
||||
*/
|
||||
public computedMovement(): Vector {
|
||||
return VectorOps.fromRaw(this.raw.computedMovement());
|
||||
}
|
||||
|
||||
/**
|
||||
* The result of ground detection computed by the last call to `this.computeColliderMovement`.
|
||||
*/
|
||||
public computedGrounded(): boolean {
|
||||
return this.raw.computedGrounded();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of collisions against obstacles detected along the path of the last call
|
||||
* to `this.computeColliderMovement`.
|
||||
*/
|
||||
public numComputedCollisions(): number {
|
||||
return this.raw.numComputedCollisions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collision against one of the obstacles detected along the path of the last
|
||||
* call to `this.computeColliderMovement`.
|
||||
*
|
||||
* @param i - The i-th collision will be returned.
|
||||
* @param out - If this argument is set, it will be filled with the collision information.
|
||||
*/
|
||||
public computedCollision(
|
||||
i: number,
|
||||
out?: CharacterCollision,
|
||||
): CharacterCollision | null {
|
||||
if (!this.raw.computedCollision(i, this.rawCharacterCollision)) {
|
||||
return null;
|
||||
} else {
|
||||
let c = this.rawCharacterCollision;
|
||||
out = out ?? new CharacterCollision();
|
||||
out.translationDeltaApplied = VectorOps.fromRaw(
|
||||
c.translationDeltaApplied(),
|
||||
);
|
||||
out.translationDeltaRemaining = VectorOps.fromRaw(
|
||||
c.translationDeltaRemaining(),
|
||||
);
|
||||
out.toi = c.toi();
|
||||
out.witness1 = VectorOps.fromRaw(c.worldWitness1());
|
||||
out.witness2 = VectorOps.fromRaw(c.worldWitness2());
|
||||
out.normal1 = VectorOps.fromRaw(c.worldNormal1());
|
||||
out.normal2 = VectorOps.fromRaw(c.worldNormal2());
|
||||
out.collider = this.colliders.get(c.handle());
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
||||
6
thirdparty/rapier.js/src.ts/control/index.ts
vendored
Normal file
6
thirdparty/rapier.js/src.ts/control/index.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
export * from "./character_controller";
|
||||
export * from "./pid_controller";
|
||||
|
||||
// #if DIM3
|
||||
export * from "./ray_cast_vehicle_controller";
|
||||
// #endif
|
||||
207
thirdparty/rapier.js/src.ts/control/pid_controller.ts
vendored
Normal file
207
thirdparty/rapier.js/src.ts/control/pid_controller.ts
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
import {RawPidController} from "../raw";
|
||||
import {Rotation, RotationOps, Vector, VectorOps} from "../math";
|
||||
import {Collider, ColliderSet, InteractionGroups, Shape} from "../geometry";
|
||||
import {QueryFilterFlags, World} from "../pipeline";
|
||||
import {IntegrationParameters, RigidBody, RigidBodySet} from "../dynamics";
|
||||
|
||||
// TODO: unify with the JointAxesMask
|
||||
/**
|
||||
* An enum representing the possible joint axes controlled by a PidController.
|
||||
* They can be ORed together, like:
|
||||
* PidAxesMask.LinX || PidAxesMask.LinY
|
||||
* to get a pid controller that only constraints the translational X and Y axes.
|
||||
*
|
||||
* Possible axes are:
|
||||
*
|
||||
* - `X`: X translation axis
|
||||
* - `Y`: Y translation axis
|
||||
* - `Z`: Z translation axis
|
||||
* - `AngX`: X angular rotation axis (3D only)
|
||||
* - `AngY`: Y angular rotation axis (3D only)
|
||||
* - `AngZ`: Z angular rotation axis
|
||||
*/
|
||||
export enum PidAxesMask {
|
||||
None = 0,
|
||||
LinX = 1 << 0,
|
||||
LinY = 1 << 1,
|
||||
LinZ = 1 << 2,
|
||||
// #if DIM3
|
||||
AngX = 1 << 3,
|
||||
AngY = 1 << 4,
|
||||
// #endif
|
||||
AngZ = 1 << 5,
|
||||
// #if DIM2
|
||||
AllLin = PidAxesMask.LinX | PidAxesMask.LinY,
|
||||
AllAng = PidAxesMask.AngZ,
|
||||
// #endif
|
||||
// #if DIM3
|
||||
AllLin = PidAxesMask.LinX | PidAxesMask.LinY | PidAxesMask.LinZ,
|
||||
AllAng = PidAxesMask.AngX | PidAxesMask.AngY | PidAxesMask.AngZ,
|
||||
// #endif
|
||||
All = PidAxesMask.AllLin | PidAxesMask.AllAng,
|
||||
}
|
||||
|
||||
/**
|
||||
* A controller for controlling dynamic bodies using the
|
||||
* Proportional-Integral-Derivative correction model.
|
||||
*/
|
||||
export class PidController {
|
||||
private raw: RawPidController;
|
||||
|
||||
private params: IntegrationParameters;
|
||||
private bodies: RigidBodySet;
|
||||
|
||||
constructor(
|
||||
params: IntegrationParameters,
|
||||
bodies: RigidBodySet,
|
||||
kp: number,
|
||||
ki: number,
|
||||
kd: number,
|
||||
axes: PidAxesMask,
|
||||
) {
|
||||
this.params = params;
|
||||
this.bodies = bodies;
|
||||
this.raw = new RawPidController(kp, ki, kd, axes);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
public setKp(kp: number, axes: PidAxesMask) {
|
||||
this.raw.set_kp(kp, axes);
|
||||
}
|
||||
|
||||
public setKi(ki: number, axes: PidAxesMask) {
|
||||
this.raw.set_kp(ki, axes);
|
||||
}
|
||||
|
||||
public setKd(kd: number, axes: PidAxesMask) {
|
||||
this.raw.set_kp(kd, axes);
|
||||
}
|
||||
|
||||
public setAxes(axes: PidAxesMask) {
|
||||
this.raw.set_axes_mask(axes);
|
||||
}
|
||||
|
||||
public resetIntegrals() {
|
||||
this.raw.reset_integrals();
|
||||
}
|
||||
|
||||
public applyLinearCorrection(
|
||||
body: RigidBody,
|
||||
targetPosition: Vector,
|
||||
targetLinvel: Vector,
|
||||
) {
|
||||
let rawPos = VectorOps.intoRaw(targetPosition);
|
||||
let rawVel = VectorOps.intoRaw(targetLinvel);
|
||||
this.raw.apply_linear_correction(
|
||||
this.params.dt,
|
||||
this.bodies.raw,
|
||||
body.handle,
|
||||
rawPos,
|
||||
rawVel,
|
||||
);
|
||||
rawPos.free();
|
||||
rawVel.free();
|
||||
}
|
||||
|
||||
// #if DIM2
|
||||
public applyAngularCorrection(
|
||||
body: RigidBody,
|
||||
targetRotation: number,
|
||||
targetAngVel: number,
|
||||
) {
|
||||
this.raw.apply_angular_correction(
|
||||
this.params.dt,
|
||||
this.bodies.raw,
|
||||
body.handle,
|
||||
targetRotation,
|
||||
targetAngVel,
|
||||
);
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #if DIM3
|
||||
public applyAngularCorrection(
|
||||
body: RigidBody,
|
||||
targetRotation: Rotation,
|
||||
targetAngVel: Vector,
|
||||
) {
|
||||
let rawPos = RotationOps.intoRaw(targetRotation);
|
||||
let rawVel = VectorOps.intoRaw(targetAngVel);
|
||||
this.raw.apply_angular_correction(
|
||||
this.params.dt,
|
||||
this.bodies.raw,
|
||||
body.handle,
|
||||
rawPos,
|
||||
rawVel,
|
||||
);
|
||||
rawPos.free();
|
||||
rawVel.free();
|
||||
}
|
||||
// #endif
|
||||
|
||||
public linearCorrection(
|
||||
body: RigidBody,
|
||||
targetPosition: Vector,
|
||||
targetLinvel: Vector,
|
||||
): Vector {
|
||||
let rawPos = VectorOps.intoRaw(targetPosition);
|
||||
let rawVel = VectorOps.intoRaw(targetLinvel);
|
||||
let correction = this.raw.linear_correction(
|
||||
this.params.dt,
|
||||
this.bodies.raw,
|
||||
body.handle,
|
||||
rawPos,
|
||||
rawVel,
|
||||
);
|
||||
rawPos.free();
|
||||
rawVel.free();
|
||||
|
||||
return VectorOps.fromRaw(correction);
|
||||
}
|
||||
|
||||
// #if DIM2
|
||||
public angularCorrection(
|
||||
body: RigidBody,
|
||||
targetRotation: number,
|
||||
targetAngVel: number,
|
||||
): number {
|
||||
return this.raw.angular_correction(
|
||||
this.params.dt,
|
||||
this.bodies.raw,
|
||||
body.handle,
|
||||
targetRotation,
|
||||
targetAngVel,
|
||||
);
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #if DIM3
|
||||
public angularCorrection(
|
||||
body: RigidBody,
|
||||
targetRotation: Rotation,
|
||||
targetAngVel: Vector,
|
||||
): Vector {
|
||||
let rawPos = RotationOps.intoRaw(targetRotation);
|
||||
let rawVel = VectorOps.intoRaw(targetAngVel);
|
||||
let correction = this.raw.angular_correction(
|
||||
this.params.dt,
|
||||
this.bodies.raw,
|
||||
body.handle,
|
||||
rawPos,
|
||||
rawVel,
|
||||
);
|
||||
rawPos.free();
|
||||
rawVel.free();
|
||||
|
||||
return VectorOps.fromRaw(correction);
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
481
thirdparty/rapier.js/src.ts/control/ray_cast_vehicle_controller.ts
vendored
Normal file
481
thirdparty/rapier.js/src.ts/control/ray_cast_vehicle_controller.ts
vendored
Normal file
@@ -0,0 +1,481 @@
|
||||
import {RawDynamicRayCastVehicleController} from "../raw";
|
||||
import {Vector, VectorOps} from "../math";
|
||||
import {
|
||||
BroadPhase,
|
||||
Collider,
|
||||
ColliderSet,
|
||||
InteractionGroups,
|
||||
NarrowPhase,
|
||||
} from "../geometry";
|
||||
import {QueryFilterFlags} from "../pipeline";
|
||||
import {RigidBody, RigidBodyHandle, RigidBodySet} from "../dynamics";
|
||||
|
||||
/**
|
||||
* A character controller to simulate vehicles using ray-casting for the wheels.
|
||||
*/
|
||||
export class DynamicRayCastVehicleController {
|
||||
private raw: RawDynamicRayCastVehicleController;
|
||||
private broadPhase: BroadPhase;
|
||||
private narrowPhase: NarrowPhase;
|
||||
private bodies: RigidBodySet;
|
||||
private colliders: ColliderSet;
|
||||
private _chassis: RigidBody;
|
||||
|
||||
constructor(
|
||||
chassis: RigidBody,
|
||||
broadPhase: BroadPhase,
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
) {
|
||||
this.raw = new RawDynamicRayCastVehicleController(chassis.handle);
|
||||
this.broadPhase = broadPhase;
|
||||
this.narrowPhase = narrowPhase;
|
||||
this.bodies = bodies;
|
||||
this.colliders = colliders;
|
||||
this._chassis = chassis;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the vehicle’s velocity based on its suspension, engine force, and brake.
|
||||
*
|
||||
* This directly updates the velocity of its chassis rigid-body.
|
||||
*
|
||||
* @param dt - Time increment used to integrate forces.
|
||||
* @param filterFlags - Flag to exclude categories of objects from the wheels’ ray-cast.
|
||||
* @param filterGroups - Only colliders compatible with these groups will be hit by the wheels’ ray-casts.
|
||||
* @param filterPredicate - Callback to filter out which collider will be hit by the wheels’ ray-casts.
|
||||
*/
|
||||
public updateVehicle(
|
||||
dt: number,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterGroups?: InteractionGroups,
|
||||
filterPredicate?: (collider: Collider) => boolean,
|
||||
) {
|
||||
this.raw.update_vehicle(
|
||||
dt,
|
||||
this.broadPhase.raw,
|
||||
this.narrowPhase.raw,
|
||||
this.bodies.raw,
|
||||
this.colliders.raw,
|
||||
filterFlags,
|
||||
filterGroups,
|
||||
this.colliders.castClosure(filterPredicate),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The current forward speed of the vehicle.
|
||||
*/
|
||||
public currentVehicleSpeed(): number {
|
||||
return this.raw.current_vehicle_speed();
|
||||
}
|
||||
|
||||
/**
|
||||
* The rigid-body used as the chassis.
|
||||
*/
|
||||
public chassis(): RigidBody {
|
||||
return this._chassis;
|
||||
}
|
||||
|
||||
/**
|
||||
* The chassis’ local _up_ direction (`0 = x, 1 = y, 2 = z`).
|
||||
*/
|
||||
get indexUpAxis(): number {
|
||||
return this.raw.index_up_axis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chassis’ local _up_ direction (`0 = x, 1 = y, 2 = z`).
|
||||
*/
|
||||
set indexUpAxis(axis: number) {
|
||||
this.raw.set_index_up_axis(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* The chassis’ local _forward_ direction (`0 = x, 1 = y, 2 = z`).
|
||||
*/
|
||||
get indexForwardAxis(): number {
|
||||
return this.raw.index_forward_axis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chassis’ local _forward_ direction (`0 = x, 1 = y, 2 = z`).
|
||||
*/
|
||||
set setIndexForwardAxis(axis: number) {
|
||||
this.raw.set_index_forward_axis(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new wheel attached to this vehicle.
|
||||
* @param chassisConnectionCs - The position of the wheel relative to the chassis.
|
||||
* @param directionCs - The direction of the wheel’s suspension, relative to the chassis. The ray-casting will
|
||||
* happen following this direction to detect the ground.
|
||||
* @param axleCs - The wheel’s axle axis, relative to the chassis.
|
||||
* @param suspensionRestLength - The rest length of the wheel’s suspension spring.
|
||||
* @param radius - The wheel’s radius.
|
||||
*/
|
||||
public addWheel(
|
||||
chassisConnectionCs: Vector,
|
||||
directionCs: Vector,
|
||||
axleCs: Vector,
|
||||
suspensionRestLength: number,
|
||||
radius: number,
|
||||
) {
|
||||
let rawChassisConnectionCs = VectorOps.intoRaw(chassisConnectionCs);
|
||||
let rawDirectionCs = VectorOps.intoRaw(directionCs);
|
||||
let rawAxleCs = VectorOps.intoRaw(axleCs);
|
||||
|
||||
this.raw.add_wheel(
|
||||
rawChassisConnectionCs,
|
||||
rawDirectionCs,
|
||||
rawAxleCs,
|
||||
suspensionRestLength,
|
||||
radius,
|
||||
);
|
||||
|
||||
rawChassisConnectionCs.free();
|
||||
rawDirectionCs.free();
|
||||
rawAxleCs.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of wheels attached to this vehicle.
|
||||
*/
|
||||
public numWheels(): number {
|
||||
return this.raw.num_wheels();
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Access to wheel properties.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Getters + setters
|
||||
*/
|
||||
/**
|
||||
* The position of the i-th wheel, relative to the chassis.
|
||||
*/
|
||||
public wheelChassisConnectionPointCs(i: number): Vector | null {
|
||||
return VectorOps.fromRaw(this.raw.wheel_chassis_connection_point_cs(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the i-th wheel, relative to the chassis.
|
||||
*/
|
||||
public setWheelChassisConnectionPointCs(i: number, value: Vector) {
|
||||
let rawValue = VectorOps.intoRaw(value);
|
||||
this.raw.set_wheel_chassis_connection_point_cs(i, rawValue);
|
||||
rawValue.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* The rest length of the i-th wheel’s suspension spring.
|
||||
*/
|
||||
public wheelSuspensionRestLength(i: number): number | null {
|
||||
return this.raw.wheel_suspension_rest_length(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rest length of the i-th wheel’s suspension spring.
|
||||
*/
|
||||
public setWheelSuspensionRestLength(i: number, value: number) {
|
||||
this.raw.set_wheel_suspension_rest_length(i, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum distance the i-th wheel suspension can travel before and after its resting length.
|
||||
*/
|
||||
public wheelMaxSuspensionTravel(i: number): number | null {
|
||||
return this.raw.wheel_max_suspension_travel(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum distance the i-th wheel suspension can travel before and after its resting length.
|
||||
*/
|
||||
public setWheelMaxSuspensionTravel(i: number, value: number) {
|
||||
this.raw.set_wheel_max_suspension_travel(i, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The i-th wheel’s radius.
|
||||
*/
|
||||
public wheelRadius(i: number): number | null {
|
||||
return this.raw.wheel_radius(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the i-th wheel’s radius.
|
||||
*/
|
||||
public setWheelRadius(i: number, value: number) {
|
||||
this.raw.set_wheel_radius(i, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The i-th wheel’s suspension stiffness.
|
||||
*
|
||||
* Increase this value if the suspension appears to not push the vehicle strong enough.
|
||||
*/
|
||||
public wheelSuspensionStiffness(i: number): number | null {
|
||||
return this.raw.wheel_suspension_stiffness(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the i-th wheel’s suspension stiffness.
|
||||
*
|
||||
* Increase this value if the suspension appears to not push the vehicle strong enough.
|
||||
*/
|
||||
public setWheelSuspensionStiffness(i: number, value: number) {
|
||||
this.raw.set_wheel_suspension_stiffness(i, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The i-th wheel’s suspension’s damping when it is being compressed.
|
||||
*/
|
||||
public wheelSuspensionCompression(i: number): number | null {
|
||||
return this.raw.wheel_suspension_compression(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* The i-th wheel’s suspension’s damping when it is being compressed.
|
||||
*/
|
||||
public setWheelSuspensionCompression(i: number, value: number) {
|
||||
this.raw.set_wheel_suspension_compression(i, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The i-th wheel’s suspension’s damping when it is being released.
|
||||
*
|
||||
* Increase this value if the suspension appears to overshoot.
|
||||
*/
|
||||
public wheelSuspensionRelaxation(i: number): number | null {
|
||||
return this.raw.wheel_suspension_relaxation(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the i-th wheel’s suspension’s damping when it is being released.
|
||||
*
|
||||
* Increase this value if the suspension appears to overshoot.
|
||||
*/
|
||||
public setWheelSuspensionRelaxation(i: number, value: number) {
|
||||
this.raw.set_wheel_suspension_relaxation(i, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum force applied by the i-th wheel’s suspension.
|
||||
*/
|
||||
public wheelMaxSuspensionForce(i: number): number | null {
|
||||
return this.raw.wheel_max_suspension_force(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum force applied by the i-th wheel’s suspension.
|
||||
*/
|
||||
public setWheelMaxSuspensionForce(i: number, value: number) {
|
||||
this.raw.set_wheel_max_suspension_force(i, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum amount of braking impulse applied on the i-th wheel to slow down the vehicle.
|
||||
*/
|
||||
public wheelBrake(i: number): number | null {
|
||||
return this.raw.wheel_brake(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum amount of braking impulse applied on the i-th wheel to slow down the vehicle.
|
||||
*/
|
||||
public setWheelBrake(i: number, value: number) {
|
||||
this.raw.set_wheel_brake(i, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The steering angle (radians) for the i-th wheel.
|
||||
*/
|
||||
public wheelSteering(i: number): number | null {
|
||||
return this.raw.wheel_steering(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the steering angle (radians) for the i-th wheel.
|
||||
*/
|
||||
public setWheelSteering(i: number, value: number) {
|
||||
this.raw.set_wheel_steering(i, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The forward force applied by the i-th wheel on the chassis.
|
||||
*/
|
||||
public wheelEngineForce(i: number): number | null {
|
||||
return this.raw.wheel_engine_force(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the forward force applied by the i-th wheel on the chassis.
|
||||
*/
|
||||
public setWheelEngineForce(i: number, value: number) {
|
||||
this.raw.set_wheel_engine_force(i, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public wheelDirectionCs(i: number): Vector | null {
|
||||
return VectorOps.fromRaw(this.raw.wheel_direction_cs(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets 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.
|
||||
*/
|
||||
public setWheelDirectionCs(i: number, value: Vector) {
|
||||
let rawValue = VectorOps.intoRaw(value);
|
||||
this.raw.set_wheel_direction_cs(i, rawValue);
|
||||
rawValue.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* The i-th wheel’s axle axis, relative to the chassis.
|
||||
*
|
||||
* The axis index defined as 0 = X, 1 = Y, 2 = Z.
|
||||
*/
|
||||
public wheelAxleCs(i: number): Vector | null {
|
||||
return VectorOps.fromRaw(this.raw.wheel_axle_cs(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the i-th wheel’s axle axis, relative to the chassis.
|
||||
*
|
||||
* The axis index defined as 0 = X, 1 = Y, 2 = Z.
|
||||
*/
|
||||
public setWheelAxleCs(i: number, value: Vector) {
|
||||
let rawValue = VectorOps.intoRaw(value);
|
||||
this.raw.set_wheel_axle_cs(i, rawValue);
|
||||
rawValue.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter controlling how much traction the tire has.
|
||||
*
|
||||
* The larger the value, the more instantaneous braking will happen (with the risk of
|
||||
* causing the vehicle to flip if it’s too strong).
|
||||
*/
|
||||
public wheelFrictionSlip(i: number): number | null {
|
||||
return this.raw.wheel_friction_slip(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameter controlling how much traction the tire has.
|
||||
*
|
||||
* The larger the value, the more instantaneous braking will happen (with the risk of
|
||||
* causing the vehicle to flip if it’s too strong).
|
||||
*/
|
||||
public setWheelFrictionSlip(i: number, value: number) {
|
||||
this.raw.set_wheel_friction_slip(i, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The multiplier of friction between a tire and the collider it’s on top of.
|
||||
*
|
||||
* The larger the value, the stronger side friction will be.
|
||||
*/
|
||||
public wheelSideFrictionStiffness(i: number): number | null {
|
||||
return this.raw.wheel_side_friction_stiffness(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* The multiplier of friction between a tire and the collider it’s on top of.
|
||||
*
|
||||
* The larger the value, the stronger side friction will be.
|
||||
*/
|
||||
public setWheelSideFrictionStiffness(i: number, value: number) {
|
||||
this.raw.set_wheel_side_friction_stiffness(i, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Getters only.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The i-th wheel’s current rotation angle (radians) on its axle.
|
||||
*/
|
||||
public wheelRotation(i: number): number | null {
|
||||
return this.raw.wheel_rotation(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* The forward impulses applied by the i-th wheel on the chassis.
|
||||
*/
|
||||
public wheelForwardImpulse(i: number): number | null {
|
||||
return this.raw.wheel_forward_impulse(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* The side impulses applied by the i-th wheel on the chassis.
|
||||
*/
|
||||
public wheelSideImpulse(i: number): number | null {
|
||||
return this.raw.wheel_side_impulse(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* The force applied by the i-th wheel suspension.
|
||||
*/
|
||||
public wheelSuspensionForce(i: number): number | null {
|
||||
return this.raw.wheel_suspension_force(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* The (world-space) contact normal between the i-th wheel and the floor.
|
||||
*/
|
||||
public wheelContactNormal(i: number): Vector | null {
|
||||
return VectorOps.fromRaw(this.raw.wheel_contact_normal_ws(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* The (world-space) point hit by the wheel’s ray-cast for the i-th wheel.
|
||||
*/
|
||||
public wheelContactPoint(i: number): Vector | null {
|
||||
return VectorOps.fromRaw(this.raw.wheel_contact_point_ws(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* The suspension length for the i-th wheel.
|
||||
*/
|
||||
public wheelSuspensionLength(i: number): number | null {
|
||||
return this.raw.wheel_suspension_length(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* The (world-space) starting point of the ray-cast for the i-th wheel.
|
||||
*/
|
||||
public wheelHardPoint(i: number): Vector | null {
|
||||
return VectorOps.fromRaw(this.raw.wheel_hard_point_ws(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the i-th wheel in contact with the ground?
|
||||
*/
|
||||
public wheelIsInContact(i: number): boolean {
|
||||
return this.raw.wheel_is_in_contact(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* The collider hit by the ray-cast for the i-th wheel.
|
||||
*/
|
||||
public wheelGroundObject(i: number): Collider | null {
|
||||
return this.colliders.get(this.raw.wheel_ground_object(i));
|
||||
}
|
||||
}
|
||||
25
thirdparty/rapier.js/src.ts/dynamics/ccd_solver.ts
vendored
Normal file
25
thirdparty/rapier.js/src.ts/dynamics/ccd_solver.ts
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import {RawCCDSolver} from "../raw";
|
||||
|
||||
/**
|
||||
* The CCD solver responsible for resolving Continuous Collision Detection.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `ccdSolver.free()`
|
||||
* once you are done using it.
|
||||
*/
|
||||
export class CCDSolver {
|
||||
raw: RawCCDSolver;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this narrow-phase.
|
||||
*/
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawCCDSolver) {
|
||||
this.raw = raw || new RawCCDSolver();
|
||||
}
|
||||
}
|
||||
13
thirdparty/rapier.js/src.ts/dynamics/coefficient_combine_rule.ts
vendored
Normal file
13
thirdparty/rapier.js/src.ts/dynamics/coefficient_combine_rule.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* A rule applied to combine coefficients.
|
||||
*
|
||||
* Use this when configuring the `ColliderDesc` to specify
|
||||
* how friction and restitution coefficient should be combined
|
||||
* in a contact.
|
||||
*/
|
||||
export enum CoefficientCombineRule {
|
||||
Average = 0,
|
||||
Min = 1,
|
||||
Multiply = 2,
|
||||
Max = 3,
|
||||
}
|
||||
681
thirdparty/rapier.js/src.ts/dynamics/impulse_joint.ts
vendored
Normal file
681
thirdparty/rapier.js/src.ts/dynamics/impulse_joint.ts
vendored
Normal file
@@ -0,0 +1,681 @@
|
||||
import {Rotation, Vector, VectorOps, RotationOps} from "../math";
|
||||
import {
|
||||
RawGenericJoint,
|
||||
RawImpulseJointSet,
|
||||
RawRigidBodySet,
|
||||
RawJointAxis,
|
||||
RawJointType,
|
||||
RawMotorModel,
|
||||
} from "../raw";
|
||||
import {RigidBody, RigidBodyHandle} from "./rigid_body";
|
||||
import {RigidBodySet} from "./rigid_body_set";
|
||||
// #if DIM3
|
||||
import {Quaternion} from "../math";
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* The integer identifier of a collider added to a `ColliderSet`.
|
||||
*/
|
||||
export type ImpulseJointHandle = number;
|
||||
|
||||
/**
|
||||
* An enum grouping all possible types of joints:
|
||||
*
|
||||
* - `Revolute`: A revolute joint that removes all degrees of freedom between the affected
|
||||
* bodies except for the rotation along one axis.
|
||||
* - `Fixed`: A fixed joint that removes all relative degrees of freedom between the affected bodies.
|
||||
* - `Prismatic`: A prismatic joint that removes all degrees of freedom between the affected
|
||||
* bodies except for the translation along one axis.
|
||||
* - `Spherical`: (3D only) A spherical joint that removes all relative linear degrees of freedom between the affected bodies.
|
||||
* - `Generic`: (3D only) A joint with customizable degrees of freedom, allowing any of the 6 axes to be locked.
|
||||
*/
|
||||
export enum JointType {
|
||||
Revolute,
|
||||
Fixed,
|
||||
Prismatic,
|
||||
Rope,
|
||||
Spring,
|
||||
// #if DIM3
|
||||
Spherical,
|
||||
Generic,
|
||||
// #endif
|
||||
}
|
||||
|
||||
export enum MotorModel {
|
||||
AccelerationBased,
|
||||
ForceBased,
|
||||
}
|
||||
|
||||
/**
|
||||
* An enum representing the possible joint axes of a generic joint.
|
||||
* They can be ORed together, like:
|
||||
* JointAxesMask.LinX || JointAxesMask.LinY
|
||||
* to get a joint that is only free in the X and Y translational (positional) axes.
|
||||
*
|
||||
* Possible free axes are:
|
||||
*
|
||||
* - `X`: X translation axis
|
||||
* - `Y`: Y translation axis
|
||||
* - `Z`: Z translation axis
|
||||
* - `AngX`: X angular rotation axis
|
||||
* - `AngY`: Y angular rotations axis
|
||||
* - `AngZ`: Z angular rotation axis
|
||||
*/
|
||||
export enum JointAxesMask {
|
||||
LinX = 1 << 0,
|
||||
LinY = 1 << 1,
|
||||
LinZ = 1 << 2,
|
||||
AngX = 1 << 3,
|
||||
AngY = 1 << 4,
|
||||
AngZ = 1 << 5,
|
||||
}
|
||||
|
||||
export class ImpulseJoint {
|
||||
protected rawSet: RawImpulseJointSet; // The ImpulseJoint won't need to free this.
|
||||
protected bodySet: RigidBodySet; // The ImpulseJoint won’t need to free this.
|
||||
handle: ImpulseJointHandle;
|
||||
|
||||
constructor(
|
||||
rawSet: RawImpulseJointSet,
|
||||
bodySet: RigidBodySet,
|
||||
handle: ImpulseJointHandle,
|
||||
) {
|
||||
this.rawSet = rawSet;
|
||||
this.bodySet = bodySet;
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public static newTyped(
|
||||
rawSet: RawImpulseJointSet,
|
||||
bodySet: RigidBodySet,
|
||||
handle: ImpulseJointHandle,
|
||||
): ImpulseJoint {
|
||||
switch (rawSet.jointType(handle)) {
|
||||
case RawJointType.Revolute:
|
||||
return new RevoluteImpulseJoint(rawSet, bodySet, handle);
|
||||
case RawJointType.Prismatic:
|
||||
return new PrismaticImpulseJoint(rawSet, bodySet, handle);
|
||||
case RawJointType.Fixed:
|
||||
return new FixedImpulseJoint(rawSet, bodySet, handle);
|
||||
case RawJointType.Spring:
|
||||
return new SpringImpulseJoint(rawSet, bodySet, handle);
|
||||
case RawJointType.Rope:
|
||||
return new RopeImpulseJoint(rawSet, bodySet, handle);
|
||||
// #if DIM3
|
||||
case RawJointType.Spherical:
|
||||
return new SphericalImpulseJoint(rawSet, bodySet, handle);
|
||||
case RawJointType.Generic:
|
||||
return new GenericImpulseJoint(rawSet, bodySet, handle);
|
||||
// #endif
|
||||
default:
|
||||
return new ImpulseJoint(rawSet, bodySet, handle);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public finalizeDeserialization(bodySet: RigidBodySet) {
|
||||
this.bodySet = bodySet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this joint is still valid (i.e. that it has
|
||||
* not been deleted from the joint set yet).
|
||||
*/
|
||||
public isValid(): boolean {
|
||||
return this.rawSet.contains(this.handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* The first rigid-body this joint it attached to.
|
||||
*/
|
||||
public body1(): RigidBody {
|
||||
return this.bodySet.get(this.rawSet.jointBodyHandle1(this.handle));
|
||||
}
|
||||
|
||||
/**
|
||||
* The second rigid-body this joint is attached to.
|
||||
*/
|
||||
public body2(): RigidBody {
|
||||
return this.bodySet.get(this.rawSet.jointBodyHandle2(this.handle));
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of this joint given as a string.
|
||||
*/
|
||||
public type(): JointType {
|
||||
return this.rawSet.jointType(this.handle) as number as JointType;
|
||||
}
|
||||
|
||||
// #if DIM3
|
||||
/**
|
||||
* The rotation quaternion that aligns this joint's first local axis to the `x` axis.
|
||||
*/
|
||||
public frameX1(): Rotation {
|
||||
return RotationOps.fromRaw(this.rawSet.jointFrameX1(this.handle));
|
||||
}
|
||||
|
||||
// #endif
|
||||
|
||||
// #if DIM3
|
||||
/**
|
||||
* The rotation matrix that aligns this joint's second local axis to the `x` axis.
|
||||
*/
|
||||
public frameX2(): Rotation {
|
||||
return RotationOps.fromRaw(this.rawSet.jointFrameX2(this.handle));
|
||||
}
|
||||
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* The position of the first anchor of this joint.
|
||||
*
|
||||
* The first anchor gives the position of the application point on the
|
||||
* local frame of the first rigid-body it is attached to.
|
||||
*/
|
||||
public anchor1(): Vector {
|
||||
return VectorOps.fromRaw(this.rawSet.jointAnchor1(this.handle));
|
||||
}
|
||||
|
||||
/**
|
||||
* The position of the second anchor of this joint.
|
||||
*
|
||||
* The second anchor gives the position of the application point on the
|
||||
* local frame of the second rigid-body it is attached to.
|
||||
*/
|
||||
public anchor2(): Vector {
|
||||
return VectorOps.fromRaw(this.rawSet.jointAnchor2(this.handle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the first anchor of this joint.
|
||||
*
|
||||
* The first anchor gives the position of the application point on the
|
||||
* local frame of the first rigid-body it is attached to.
|
||||
*/
|
||||
public setAnchor1(newPos: Vector) {
|
||||
const rawPoint = VectorOps.intoRaw(newPos);
|
||||
this.rawSet.jointSetAnchor1(this.handle, rawPoint);
|
||||
rawPoint.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the second anchor of this joint.
|
||||
*
|
||||
* The second anchor gives the position of the application point on the
|
||||
* local frame of the second rigid-body it is attached to.
|
||||
*/
|
||||
public setAnchor2(newPos: Vector) {
|
||||
const rawPoint = VectorOps.intoRaw(newPos);
|
||||
this.rawSet.jointSetAnchor2(this.handle, rawPoint);
|
||||
rawPoint.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls whether contacts are computed between colliders attached
|
||||
* to the rigid-bodies linked by this joint.
|
||||
*/
|
||||
public setContactsEnabled(enabled: boolean) {
|
||||
this.rawSet.jointSetContactsEnabled(this.handle, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if contacts are enabled between colliders attached
|
||||
* to the rigid-bodies linked by this joint.
|
||||
*/
|
||||
public contactsEnabled(): boolean {
|
||||
return this.rawSet.jointContactsEnabled(this.handle);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnitImpulseJoint extends ImpulseJoint {
|
||||
/**
|
||||
* The axis left free by this joint.
|
||||
*/
|
||||
protected rawAxis?(): RawJointAxis;
|
||||
|
||||
/**
|
||||
* Are the limits enabled for this joint?
|
||||
*/
|
||||
public limitsEnabled(): boolean {
|
||||
return this.rawSet.jointLimitsEnabled(this.handle, this.rawAxis());
|
||||
}
|
||||
|
||||
/**
|
||||
* The min limit of this joint.
|
||||
*/
|
||||
public limitsMin(): number {
|
||||
return this.rawSet.jointLimitsMin(this.handle, this.rawAxis());
|
||||
}
|
||||
|
||||
/**
|
||||
* The max limit of this joint.
|
||||
*/
|
||||
public limitsMax(): number {
|
||||
return this.rawSet.jointLimitsMax(this.handle, this.rawAxis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the limits of this joint.
|
||||
*
|
||||
* @param min - The minimum bound of this joint’s free coordinate.
|
||||
* @param max - The maximum bound of this joint’s free coordinate.
|
||||
*/
|
||||
public setLimits(min: number, max: number) {
|
||||
this.rawSet.jointSetLimits(this.handle, this.rawAxis(), min, max);
|
||||
}
|
||||
|
||||
public configureMotorModel(model: MotorModel) {
|
||||
this.rawSet.jointConfigureMotorModel(
|
||||
this.handle,
|
||||
this.rawAxis(),
|
||||
model as number as RawMotorModel,
|
||||
);
|
||||
}
|
||||
|
||||
public configureMotorVelocity(targetVel: number, factor: number) {
|
||||
this.rawSet.jointConfigureMotorVelocity(
|
||||
this.handle,
|
||||
this.rawAxis(),
|
||||
targetVel,
|
||||
factor,
|
||||
);
|
||||
}
|
||||
|
||||
public configureMotorPosition(
|
||||
targetPos: number,
|
||||
stiffness: number,
|
||||
damping: number,
|
||||
) {
|
||||
this.rawSet.jointConfigureMotorPosition(
|
||||
this.handle,
|
||||
this.rawAxis(),
|
||||
targetPos,
|
||||
stiffness,
|
||||
damping,
|
||||
);
|
||||
}
|
||||
|
||||
public configureMotor(
|
||||
targetPos: number,
|
||||
targetVel: number,
|
||||
stiffness: number,
|
||||
damping: number,
|
||||
) {
|
||||
this.rawSet.jointConfigureMotor(
|
||||
this.handle,
|
||||
this.rawAxis(),
|
||||
targetPos,
|
||||
targetVel,
|
||||
stiffness,
|
||||
damping,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class FixedImpulseJoint extends ImpulseJoint {}
|
||||
|
||||
export class RopeImpulseJoint extends ImpulseJoint {}
|
||||
|
||||
export class SpringImpulseJoint extends ImpulseJoint {}
|
||||
|
||||
export class PrismaticImpulseJoint extends UnitImpulseJoint {
|
||||
public rawAxis(): RawJointAxis {
|
||||
return RawJointAxis.LinX;
|
||||
}
|
||||
}
|
||||
|
||||
export class RevoluteImpulseJoint extends UnitImpulseJoint {
|
||||
public rawAxis(): RawJointAxis {
|
||||
return RawJointAxis.AngX;
|
||||
}
|
||||
}
|
||||
|
||||
// #if DIM3
|
||||
export class GenericImpulseJoint extends ImpulseJoint {}
|
||||
|
||||
export class SphericalImpulseJoint extends ImpulseJoint {
|
||||
/* Unsupported by this alpha release.
|
||||
public configureMotorModel(model: MotorModel) {
|
||||
this.rawSet.jointConfigureMotorModel(this.handle, model);
|
||||
}
|
||||
|
||||
public configureMotorVelocity(targetVel: Vector, factor: number) {
|
||||
this.rawSet.jointConfigureBallMotorVelocity(this.handle, targetVel.x, targetVel.y, targetVel.z, factor);
|
||||
}
|
||||
|
||||
public configureMotorPosition(targetPos: Quaternion, stiffness: number, damping: number) {
|
||||
this.rawSet.jointConfigureBallMotorPosition(this.handle, targetPos.w, targetPos.x, targetPos.y, targetPos.z, stiffness, damping);
|
||||
}
|
||||
|
||||
public configureMotor(targetPos: Quaternion, targetVel: Vector, stiffness: number, damping: number) {
|
||||
this.rawSet.jointConfigureBallMotor(this.handle,
|
||||
targetPos.w, targetPos.x, targetPos.y, targetPos.z,
|
||||
targetVel.x, targetVel.y, targetVel.z,
|
||||
stiffness, damping);
|
||||
}
|
||||
*/
|
||||
}
|
||||
// #endif
|
||||
|
||||
export class JointData {
|
||||
anchor1: Vector;
|
||||
anchor2: Vector;
|
||||
axis: Vector;
|
||||
frame1: Rotation;
|
||||
frame2: Rotation;
|
||||
jointType: JointType;
|
||||
limitsEnabled: boolean;
|
||||
limits: Array<number>;
|
||||
axesMask: JointAxesMask;
|
||||
stiffness: number;
|
||||
damping: number;
|
||||
length: number;
|
||||
|
||||
private constructor() {}
|
||||
|
||||
/**
|
||||
* Creates a new joint descriptor that builds a Fixed joint.
|
||||
*
|
||||
* A fixed joint removes all the degrees of freedom between the affected bodies, ensuring their
|
||||
* anchor and local frames coincide in world-space.
|
||||
*
|
||||
* @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param frame1 - The reference orientation of the joint wrt. the first rigid-body.
|
||||
* @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param frame2 - The reference orientation of the joint wrt. the second rigid-body.
|
||||
*/
|
||||
public static fixed(
|
||||
anchor1: Vector,
|
||||
frame1: Rotation,
|
||||
anchor2: Vector,
|
||||
frame2: Rotation,
|
||||
): JointData {
|
||||
let res = new JointData();
|
||||
res.anchor1 = anchor1;
|
||||
res.anchor2 = anchor2;
|
||||
res.frame1 = frame1;
|
||||
res.frame2 = frame2;
|
||||
res.jointType = JointType.Fixed;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static spring(
|
||||
rest_length: number,
|
||||
stiffness: number,
|
||||
damping: number,
|
||||
anchor1: Vector,
|
||||
anchor2: Vector,
|
||||
): JointData {
|
||||
let res = new JointData();
|
||||
res.anchor1 = anchor1;
|
||||
res.anchor2 = anchor2;
|
||||
res.length = rest_length;
|
||||
res.stiffness = stiffness;
|
||||
res.damping = damping;
|
||||
res.jointType = JointType.Spring;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static rope(
|
||||
length: number,
|
||||
anchor1: Vector,
|
||||
anchor2: Vector,
|
||||
): JointData {
|
||||
let res = new JointData();
|
||||
res.anchor1 = anchor1;
|
||||
res.anchor2 = anchor2;
|
||||
res.length = length;
|
||||
res.jointType = JointType.Rope;
|
||||
return res;
|
||||
}
|
||||
|
||||
// #if DIM2
|
||||
|
||||
/**
|
||||
* Create a new joint descriptor that builds revolute joints.
|
||||
*
|
||||
* A revolute joint allows three relative rotational degrees of freedom
|
||||
* by preventing any relative translation between the anchors of the
|
||||
* two attached rigid-bodies.
|
||||
*
|
||||
* @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
*/
|
||||
public static revolute(anchor1: Vector, anchor2: Vector): JointData {
|
||||
let res = new JointData();
|
||||
res.anchor1 = anchor1;
|
||||
res.anchor2 = anchor2;
|
||||
res.jointType = JointType.Revolute;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new joint descriptor that builds a Prismatic joint.
|
||||
*
|
||||
* A prismatic joint removes all the degrees of freedom between the
|
||||
* affected bodies, except for the translation along one axis.
|
||||
*
|
||||
* @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param axis - Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to.
|
||||
*/
|
||||
public static prismatic(
|
||||
anchor1: Vector,
|
||||
anchor2: Vector,
|
||||
axis: Vector,
|
||||
): JointData {
|
||||
let res = new JointData();
|
||||
res.anchor1 = anchor1;
|
||||
res.anchor2 = anchor2;
|
||||
res.axis = axis;
|
||||
res.jointType = JointType.Prismatic;
|
||||
return res;
|
||||
}
|
||||
|
||||
// #endif
|
||||
|
||||
// #if DIM3
|
||||
/**
|
||||
* Create a new joint descriptor that builds generic joints.
|
||||
*
|
||||
* A generic joint allows customizing its degrees of freedom
|
||||
* by supplying a mask of the joint axes that should remain locked.
|
||||
*
|
||||
* @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param axis - The X axis of the joint, expressed in the local-space of the rigid-bodies it is attached to.
|
||||
* @param axesMask - Mask representing the locked axes of the joint. You can use logical OR to select these from
|
||||
* the JointAxesMask enum. For example, passing (JointAxesMask.AngX || JointAxesMask.AngY) will
|
||||
* create a joint locked in the X and Y rotational axes.
|
||||
*/
|
||||
public static generic(
|
||||
anchor1: Vector,
|
||||
anchor2: Vector,
|
||||
axis: Vector,
|
||||
axesMask: JointAxesMask,
|
||||
): JointData {
|
||||
let res = new JointData();
|
||||
res.anchor1 = anchor1;
|
||||
res.anchor2 = anchor2;
|
||||
res.axis = axis;
|
||||
res.axesMask = axesMask;
|
||||
res.jointType = JointType.Generic;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new joint descriptor that builds spherical joints.
|
||||
*
|
||||
* A spherical joint allows three relative rotational degrees of freedom
|
||||
* by preventing any relative translation between the anchors of the
|
||||
* two attached rigid-bodies.
|
||||
*
|
||||
* @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
*/
|
||||
public static spherical(anchor1: Vector, anchor2: Vector): JointData {
|
||||
let res = new JointData();
|
||||
res.anchor1 = anchor1;
|
||||
res.anchor2 = anchor2;
|
||||
res.jointType = JointType.Spherical;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new joint descriptor that builds a Prismatic joint.
|
||||
*
|
||||
* A prismatic joint removes all the degrees of freedom between the
|
||||
* affected bodies, except for the translation along one axis.
|
||||
*
|
||||
* @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param axis - Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to.
|
||||
*/
|
||||
public static prismatic(
|
||||
anchor1: Vector,
|
||||
anchor2: Vector,
|
||||
axis: Vector,
|
||||
): JointData {
|
||||
let res = new JointData();
|
||||
res.anchor1 = anchor1;
|
||||
res.anchor2 = anchor2;
|
||||
res.axis = axis;
|
||||
res.jointType = JointType.Prismatic;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new joint descriptor that builds Revolute joints.
|
||||
*
|
||||
* A revolute joint removes all degrees of freedom between the affected
|
||||
* bodies except for the rotation along one axis.
|
||||
*
|
||||
* @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the
|
||||
* local-space of the rigid-body.
|
||||
* @param axis - Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to.
|
||||
*/
|
||||
public static revolute(
|
||||
anchor1: Vector,
|
||||
anchor2: Vector,
|
||||
axis: Vector,
|
||||
): JointData {
|
||||
let res = new JointData();
|
||||
res.anchor1 = anchor1;
|
||||
res.anchor2 = anchor2;
|
||||
res.axis = axis;
|
||||
res.jointType = JointType.Revolute;
|
||||
return res;
|
||||
}
|
||||
// #endif
|
||||
|
||||
public intoRaw(): RawGenericJoint {
|
||||
let rawA1 = VectorOps.intoRaw(this.anchor1);
|
||||
let rawA2 = VectorOps.intoRaw(this.anchor2);
|
||||
let rawAx;
|
||||
let result;
|
||||
let limitsEnabled = false;
|
||||
let limitsMin = 0.0;
|
||||
let limitsMax = 0.0;
|
||||
|
||||
switch (this.jointType) {
|
||||
case JointType.Fixed:
|
||||
let rawFra1 = RotationOps.intoRaw(this.frame1);
|
||||
let rawFra2 = RotationOps.intoRaw(this.frame2);
|
||||
result = RawGenericJoint.fixed(rawA1, rawFra1, rawA2, rawFra2);
|
||||
rawFra1.free();
|
||||
rawFra2.free();
|
||||
break;
|
||||
case JointType.Spring:
|
||||
result = RawGenericJoint.spring(
|
||||
this.length,
|
||||
this.stiffness,
|
||||
this.damping,
|
||||
rawA1,
|
||||
rawA2,
|
||||
);
|
||||
break;
|
||||
case JointType.Rope:
|
||||
result = RawGenericJoint.rope(this.length, rawA1, rawA2);
|
||||
break;
|
||||
case JointType.Prismatic:
|
||||
rawAx = VectorOps.intoRaw(this.axis);
|
||||
|
||||
if (!!this.limitsEnabled) {
|
||||
limitsEnabled = true;
|
||||
limitsMin = this.limits[0];
|
||||
limitsMax = this.limits[1];
|
||||
}
|
||||
|
||||
// #if DIM2
|
||||
result = RawGenericJoint.prismatic(
|
||||
rawA1,
|
||||
rawA2,
|
||||
rawAx,
|
||||
limitsEnabled,
|
||||
limitsMin,
|
||||
limitsMax,
|
||||
);
|
||||
// #endif
|
||||
|
||||
// #if DIM3
|
||||
result = RawGenericJoint.prismatic(
|
||||
rawA1,
|
||||
rawA2,
|
||||
rawAx,
|
||||
limitsEnabled,
|
||||
limitsMin,
|
||||
limitsMax,
|
||||
);
|
||||
// #endif
|
||||
|
||||
rawAx.free();
|
||||
break;
|
||||
// #if DIM2
|
||||
case JointType.Revolute:
|
||||
result = RawGenericJoint.revolute(rawA1, rawA2);
|
||||
break;
|
||||
// #endif
|
||||
// #if DIM3
|
||||
case JointType.Generic:
|
||||
rawAx = VectorOps.intoRaw(this.axis);
|
||||
// implicit type cast: axesMask is a JointAxesMask bitflag enum,
|
||||
// we're treating it as a u8 on the Rust side
|
||||
let rawAxesMask = this.axesMask;
|
||||
result = RawGenericJoint.generic(
|
||||
rawA1,
|
||||
rawA2,
|
||||
rawAx,
|
||||
rawAxesMask,
|
||||
);
|
||||
break;
|
||||
case JointType.Spherical:
|
||||
result = RawGenericJoint.spherical(rawA1, rawA2);
|
||||
break;
|
||||
case JointType.Revolute:
|
||||
rawAx = VectorOps.intoRaw(this.axis);
|
||||
result = RawGenericJoint.revolute(rawA1, rawA2, rawAx);
|
||||
rawAx.free();
|
||||
break;
|
||||
// #endif
|
||||
}
|
||||
|
||||
rawA1.free();
|
||||
rawA2.free();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
165
thirdparty/rapier.js/src.ts/dynamics/impulse_joint_set.ts
vendored
Normal file
165
thirdparty/rapier.js/src.ts/dynamics/impulse_joint_set.ts
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
import {RawImpulseJointSet} from "../raw";
|
||||
import {Coarena} from "../coarena";
|
||||
import {RigidBodySet} from "./rigid_body_set";
|
||||
import {
|
||||
RevoluteImpulseJoint,
|
||||
FixedImpulseJoint,
|
||||
ImpulseJoint,
|
||||
ImpulseJointHandle,
|
||||
JointData,
|
||||
JointType,
|
||||
PrismaticImpulseJoint,
|
||||
// #if DIM3
|
||||
SphericalImpulseJoint,
|
||||
// #endif
|
||||
} from "./impulse_joint";
|
||||
import {IslandManager} from "./island_manager";
|
||||
import {RigidBodyHandle} from "./rigid_body";
|
||||
import {Collider, ColliderHandle} from "../geometry";
|
||||
|
||||
/**
|
||||
* A set of joints.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `jointSet.free()`
|
||||
* once you are done using it (and all the joints it created).
|
||||
*/
|
||||
export class ImpulseJointSet {
|
||||
raw: RawImpulseJointSet;
|
||||
private map: Coarena<ImpulseJoint>;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this joint set.
|
||||
*/
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
|
||||
if (!!this.map) {
|
||||
this.map.clear();
|
||||
}
|
||||
this.map = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawImpulseJointSet) {
|
||||
this.raw = raw || new RawImpulseJointSet();
|
||||
this.map = new Coarena<ImpulseJoint>();
|
||||
// Initialize the map with the existing elements, if any.
|
||||
if (raw) {
|
||||
raw.forEachJointHandle((handle: ImpulseJointHandle) => {
|
||||
this.map.set(handle, ImpulseJoint.newTyped(raw, null, handle));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public finalizeDeserialization(bodies: RigidBodySet) {
|
||||
this.map.forEach((joint) => joint.finalizeDeserialization(bodies));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new joint and return its integer handle.
|
||||
*
|
||||
* @param bodies - The set of rigid-bodies containing the bodies the joint is attached to.
|
||||
* @param desc - The joint's parameters.
|
||||
* @param parent1 - The handle of the first rigid-body this joint is attached to.
|
||||
* @param parent2 - The handle of the second rigid-body this joint is attached to.
|
||||
* @param wakeUp - Should the attached rigid-bodies be awakened?
|
||||
*/
|
||||
public createJoint(
|
||||
bodies: RigidBodySet,
|
||||
desc: JointData,
|
||||
parent1: RigidBodyHandle,
|
||||
parent2: RigidBodyHandle,
|
||||
wakeUp: boolean,
|
||||
): ImpulseJoint {
|
||||
const rawParams = desc.intoRaw();
|
||||
const handle = this.raw.createJoint(
|
||||
rawParams,
|
||||
parent1,
|
||||
parent2,
|
||||
wakeUp,
|
||||
);
|
||||
rawParams.free();
|
||||
let joint = ImpulseJoint.newTyped(this.raw, bodies, handle);
|
||||
this.map.set(handle, joint);
|
||||
return joint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a joint from this set.
|
||||
*
|
||||
* @param handle - The integer handle of the joint.
|
||||
* @param wakeUp - If `true`, the rigid-bodies attached by the removed joint will be woken-up automatically.
|
||||
*/
|
||||
public remove(handle: ImpulseJointHandle, wakeUp: boolean) {
|
||||
this.raw.remove(handle, wakeUp);
|
||||
this.unmap(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the given closure with the integer handle of each impulse joint attached to this rigid-body.
|
||||
*
|
||||
* @param f - The closure called with the integer handle of each impulse joint attached to the rigid-body.
|
||||
*/
|
||||
public forEachJointHandleAttachedToRigidBody(
|
||||
handle: RigidBodyHandle,
|
||||
f: (handle: ImpulseJointHandle) => void,
|
||||
) {
|
||||
this.raw.forEachJointAttachedToRigidBody(handle, f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function, do not call directly.
|
||||
* @param handle
|
||||
*/
|
||||
public unmap(handle: ImpulseJointHandle) {
|
||||
this.map.delete(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of joints on this set.
|
||||
*/
|
||||
public len(): number {
|
||||
return this.map.len();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this set contain a joint with the given handle?
|
||||
*
|
||||
* @param handle - The joint handle to check.
|
||||
*/
|
||||
public contains(handle: ImpulseJointHandle): boolean {
|
||||
return this.get(handle) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the joint with the given handle.
|
||||
*
|
||||
* Returns `null` if no joint with the specified handle exists.
|
||||
*
|
||||
* @param handle - The integer handle of the joint to retrieve.
|
||||
*/
|
||||
public get(handle: ImpulseJointHandle): ImpulseJoint | null {
|
||||
return this.map.get(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given closure to each joint contained by this set.
|
||||
*
|
||||
* @param f - The closure to apply.
|
||||
*/
|
||||
public forEach(f: (joint: ImpulseJoint) => void) {
|
||||
this.map.forEach(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all joints in the list.
|
||||
*
|
||||
* @returns joint list.
|
||||
*/
|
||||
public getAll(): ImpulseJoint[] {
|
||||
return this.map.getAll();
|
||||
}
|
||||
}
|
||||
10
thirdparty/rapier.js/src.ts/dynamics/index.ts
vendored
Normal file
10
thirdparty/rapier.js/src.ts/dynamics/index.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
export * from "./rigid_body";
|
||||
export * from "./rigid_body_set";
|
||||
export * from "./integration_parameters";
|
||||
export * from "./impulse_joint";
|
||||
export * from "./impulse_joint_set";
|
||||
export * from "./multibody_joint";
|
||||
export * from "./multibody_joint_set";
|
||||
export * from "./coefficient_combine_rule";
|
||||
export * from "./ccd_solver";
|
||||
export * from "./island_manager";
|
||||
126
thirdparty/rapier.js/src.ts/dynamics/integration_parameters.ts
vendored
Normal file
126
thirdparty/rapier.js/src.ts/dynamics/integration_parameters.ts
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
import {RawIntegrationParameters} from "../raw";
|
||||
|
||||
export class IntegrationParameters {
|
||||
raw: RawIntegrationParameters;
|
||||
|
||||
constructor(raw?: RawIntegrationParameters) {
|
||||
this.raw = raw || new RawIntegrationParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the WASM memory used by these integration parameters.
|
||||
*/
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The timestep length (default: `1.0 / 60.0`)
|
||||
*/
|
||||
get dt(): number {
|
||||
return this.raw.dt;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Error Reduction Parameter in `[0, 1]` is the proportion of
|
||||
* the positional error to be corrected at each time step (default: `0.2`).
|
||||
*/
|
||||
get contact_erp(): number {
|
||||
return this.raw.contact_erp;
|
||||
}
|
||||
|
||||
get lengthUnit(): number {
|
||||
return this.raw.lengthUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalized amount of penetration the engine won’t attempt to correct (default: `0.001m`).
|
||||
*
|
||||
* This threshold considered by the physics engine is this value multiplied by the `lengthUnit`.
|
||||
*/
|
||||
get normalizedAllowedLinearError(): number {
|
||||
return this.raw.normalizedAllowedLinearError;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximal normalized distance separating two objects that will generate predictive contacts (default: `0.002`).
|
||||
*
|
||||
* This threshold considered by the physics engine is this value multiplied by the `lengthUnit`.
|
||||
*/
|
||||
get normalizedPredictionDistance(): number {
|
||||
return this.raw.normalizedPredictionDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of solver iterations run by the constraints solver for calculating forces (default: `4`).
|
||||
*/
|
||||
get numSolverIterations(): number {
|
||||
return this.raw.numSolverIterations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of internal Project Gauss Seidel (PGS) iterations run at each solver iteration (default: `1`).
|
||||
*/
|
||||
get numInternalPgsIterations(): number {
|
||||
return this.raw.numInternalPgsIterations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimum number of dynamic bodies in each active island (default: `128`).
|
||||
*/
|
||||
get minIslandSize(): number {
|
||||
return this.raw.minIslandSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum number of substeps performed by the solver (default: `1`).
|
||||
*/
|
||||
get maxCcdSubsteps(): number {
|
||||
return this.raw.maxCcdSubsteps;
|
||||
}
|
||||
|
||||
set dt(value: number) {
|
||||
this.raw.dt = value;
|
||||
}
|
||||
|
||||
set contact_natural_frequency(value: number) {
|
||||
this.raw.contact_natural_frequency = value;
|
||||
}
|
||||
|
||||
set lengthUnit(value: number) {
|
||||
this.raw.lengthUnit = value;
|
||||
}
|
||||
|
||||
set normalizedAllowedLinearError(value: number) {
|
||||
this.raw.normalizedAllowedLinearError = value;
|
||||
}
|
||||
|
||||
set normalizedPredictionDistance(value: number) {
|
||||
this.raw.normalizedPredictionDistance = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of solver iterations run by the constraints solver for calculating forces (default: `4`).
|
||||
*/
|
||||
set numSolverIterations(value: number) {
|
||||
this.raw.numSolverIterations = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of internal Project Gauss Seidel (PGS) iterations run at each solver iteration (default: `1`).
|
||||
*/
|
||||
set numInternalPgsIterations(value: number) {
|
||||
this.raw.numInternalPgsIterations = value;
|
||||
}
|
||||
|
||||
set minIslandSize(value: number) {
|
||||
this.raw.minIslandSize = value;
|
||||
}
|
||||
|
||||
set maxCcdSubsteps(value: number) {
|
||||
this.raw.maxCcdSubsteps = value;
|
||||
}
|
||||
}
|
||||
37
thirdparty/rapier.js/src.ts/dynamics/island_manager.ts
vendored
Normal file
37
thirdparty/rapier.js/src.ts/dynamics/island_manager.ts
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
import {RawIslandManager} from "../raw";
|
||||
import {RigidBodyHandle} from "./rigid_body";
|
||||
|
||||
/**
|
||||
* The CCD solver responsible for resolving Continuous Collision Detection.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `ccdSolver.free()`
|
||||
* once you are done using it.
|
||||
*/
|
||||
export class IslandManager {
|
||||
raw: RawIslandManager;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this narrow-phase.
|
||||
*/
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawIslandManager) {
|
||||
this.raw = raw || new RawIslandManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given closure to the handle of each active rigid-bodies contained by this set.
|
||||
*
|
||||
* A rigid-body is active if it is not sleeping, i.e., if it moved recently.
|
||||
*
|
||||
* @param f - The closure to apply.
|
||||
*/
|
||||
public forEachActiveRigidBodyHandle(f: (handle: RigidBodyHandle) => void) {
|
||||
this.raw.forEachActiveRigidBodyHandle(f);
|
||||
}
|
||||
}
|
||||
222
thirdparty/rapier.js/src.ts/dynamics/multibody_joint.ts
vendored
Normal file
222
thirdparty/rapier.js/src.ts/dynamics/multibody_joint.ts
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
import {
|
||||
RawImpulseJointSet,
|
||||
RawJointAxis,
|
||||
RawJointType,
|
||||
RawMultibodyJointSet,
|
||||
} from "../raw";
|
||||
import {
|
||||
FixedImpulseJoint,
|
||||
ImpulseJointHandle,
|
||||
JointType,
|
||||
MotorModel,
|
||||
PrismaticImpulseJoint,
|
||||
RevoluteImpulseJoint,
|
||||
} from "./impulse_joint";
|
||||
|
||||
// #if DIM3
|
||||
import {Quaternion} from "../math";
|
||||
import {SphericalImpulseJoint} from "./impulse_joint";
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* The integer identifier of a collider added to a `ColliderSet`.
|
||||
*/
|
||||
export type MultibodyJointHandle = number;
|
||||
|
||||
export class MultibodyJoint {
|
||||
protected rawSet: RawMultibodyJointSet; // The MultibodyJoint won't need to free this.
|
||||
handle: MultibodyJointHandle;
|
||||
|
||||
constructor(rawSet: RawMultibodyJointSet, handle: MultibodyJointHandle) {
|
||||
this.rawSet = rawSet;
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public static newTyped(
|
||||
rawSet: RawMultibodyJointSet,
|
||||
handle: MultibodyJointHandle,
|
||||
): MultibodyJoint {
|
||||
switch (rawSet.jointType(handle)) {
|
||||
case RawJointType.Revolute:
|
||||
return new RevoluteMultibodyJoint(rawSet, handle);
|
||||
case RawJointType.Prismatic:
|
||||
return new PrismaticMultibodyJoint(rawSet, handle);
|
||||
case RawJointType.Fixed:
|
||||
return new FixedMultibodyJoint(rawSet, handle);
|
||||
// #if DIM3
|
||||
case RawJointType.Spherical:
|
||||
return new SphericalMultibodyJoint(rawSet, handle);
|
||||
// #endif
|
||||
default:
|
||||
return new MultibodyJoint(rawSet, handle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this joint is still valid (i.e. that it has
|
||||
* not been deleted from the joint set yet).
|
||||
*/
|
||||
public isValid(): boolean {
|
||||
return this.rawSet.contains(this.handle);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * The unique integer identifier of the first rigid-body this joint it attached to.
|
||||
// */
|
||||
// public bodyHandle1(): RigidBodyHandle {
|
||||
// return this.rawSet.jointBodyHandle1(this.handle);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * The unique integer identifier of the second rigid-body this joint is attached to.
|
||||
// */
|
||||
// public bodyHandle2(): RigidBodyHandle {
|
||||
// return this.rawSet.jointBodyHandle2(this.handle);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * The type of this joint given as a string.
|
||||
// */
|
||||
// public type(): JointType {
|
||||
// return this.rawSet.jointType(this.handle);
|
||||
// }
|
||||
//
|
||||
// // #if DIM3
|
||||
// /**
|
||||
// * The rotation quaternion that aligns this joint's first local axis to the `x` axis.
|
||||
// */
|
||||
// public frameX1(): Rotation {
|
||||
// return RotationOps.fromRaw(this.rawSet.jointFrameX1(this.handle));
|
||||
// }
|
||||
//
|
||||
// // #endif
|
||||
//
|
||||
// // #if DIM3
|
||||
// /**
|
||||
// * The rotation matrix that aligns this joint's second local axis to the `x` axis.
|
||||
// */
|
||||
// public frameX2(): Rotation {
|
||||
// return RotationOps.fromRaw(this.rawSet.jointFrameX2(this.handle));
|
||||
// }
|
||||
//
|
||||
// // #endif
|
||||
//
|
||||
// /**
|
||||
// * 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.
|
||||
// */
|
||||
// public anchor1(): Vector {
|
||||
// return VectorOps.fromRaw(this.rawSet.jointAnchor1(this.handle));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 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.
|
||||
// */
|
||||
// public anchor2(): Vector {
|
||||
// return VectorOps.fromRaw(this.rawSet.jointAnchor2(this.handle));
|
||||
// }
|
||||
|
||||
/**
|
||||
* Controls whether contacts are computed between colliders attached
|
||||
* to the rigid-bodies linked by this joint.
|
||||
*/
|
||||
public setContactsEnabled(enabled: boolean) {
|
||||
this.rawSet.jointSetContactsEnabled(this.handle, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if contacts are enabled between colliders attached
|
||||
* to the rigid-bodies linked by this joint.
|
||||
*/
|
||||
public contactsEnabled(): boolean {
|
||||
return this.rawSet.jointContactsEnabled(this.handle);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnitMultibodyJoint extends MultibodyJoint {
|
||||
/**
|
||||
* The axis left free by this joint.
|
||||
*/
|
||||
protected rawAxis?(): RawJointAxis;
|
||||
|
||||
// /**
|
||||
// * Are the limits enabled for this joint?
|
||||
// */
|
||||
// public limitsEnabled(): boolean {
|
||||
// return this.rawSet.jointLimitsEnabled(this.handle, this.rawAxis());
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * The min limit of this joint.
|
||||
// */
|
||||
// public limitsMin(): number {
|
||||
// return this.rawSet.jointLimitsMin(this.handle, this.rawAxis());
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * The max limit of this joint.
|
||||
// */
|
||||
// public limitsMax(): number {
|
||||
// return this.rawSet.jointLimitsMax(this.handle, this.rawAxis());
|
||||
// }
|
||||
//
|
||||
// public configureMotorModel(model: MotorModel) {
|
||||
// this.rawSet.jointConfigureMotorModel(this.handle, this.rawAxis(), model);
|
||||
// }
|
||||
//
|
||||
// public configureMotorVelocity(targetVel: number, factor: number) {
|
||||
// this.rawSet.jointConfigureMotorVelocity(this.handle, this.rawAxis(), targetVel, factor);
|
||||
// }
|
||||
//
|
||||
// public configureMotorPosition(targetPos: number, stiffness: number, damping: number) {
|
||||
// this.rawSet.jointConfigureMotorPosition(this.handle, this.rawAxis(), targetPos, stiffness, damping);
|
||||
// }
|
||||
//
|
||||
// public configureMotor(targetPos: number, targetVel: number, stiffness: number, damping: number) {
|
||||
// this.rawSet.jointConfigureMotor(this.handle, this.rawAxis(), targetPos, targetVel, stiffness, damping);
|
||||
// }
|
||||
}
|
||||
|
||||
export class FixedMultibodyJoint extends MultibodyJoint {}
|
||||
|
||||
export class PrismaticMultibodyJoint extends UnitMultibodyJoint {
|
||||
public rawAxis(): RawJointAxis {
|
||||
return RawJointAxis.LinX;
|
||||
}
|
||||
}
|
||||
|
||||
export class RevoluteMultibodyJoint extends UnitMultibodyJoint {
|
||||
public rawAxis(): RawJointAxis {
|
||||
return RawJointAxis.AngX;
|
||||
}
|
||||
}
|
||||
|
||||
// #if DIM3
|
||||
export class SphericalMultibodyJoint extends MultibodyJoint {
|
||||
/* Unsupported by this alpha release.
|
||||
public configureMotorModel(model: MotorModel) {
|
||||
this.rawSet.jointConfigureMotorModel(this.handle, model);
|
||||
}
|
||||
|
||||
public configureMotorVelocity(targetVel: Vector, factor: number) {
|
||||
this.rawSet.jointConfigureBallMotorVelocity(this.handle, targetVel.x, targetVel.y, targetVel.z, factor);
|
||||
}
|
||||
|
||||
public configureMotorPosition(targetPos: Quaternion, stiffness: number, damping: number) {
|
||||
this.rawSet.jointConfigureBallMotorPosition(this.handle, targetPos.w, targetPos.x, targetPos.y, targetPos.z, stiffness, damping);
|
||||
}
|
||||
|
||||
public configureMotor(targetPos: Quaternion, targetVel: Vector, stiffness: number, damping: number) {
|
||||
this.rawSet.jointConfigureBallMotor(this.handle,
|
||||
targetPos.w, targetPos.x, targetPos.y, targetPos.z,
|
||||
targetVel.x, targetVel.y, targetVel.z,
|
||||
stiffness, damping);
|
||||
}
|
||||
*/
|
||||
}
|
||||
// #endif
|
||||
157
thirdparty/rapier.js/src.ts/dynamics/multibody_joint_set.ts
vendored
Normal file
157
thirdparty/rapier.js/src.ts/dynamics/multibody_joint_set.ts
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
import {RawMultibodyJointSet} from "../raw";
|
||||
import {Coarena} from "../coarena";
|
||||
import {RigidBodySet} from "./rigid_body_set";
|
||||
import {
|
||||
MultibodyJoint,
|
||||
MultibodyJointHandle,
|
||||
RevoluteMultibodyJoint,
|
||||
FixedMultibodyJoint,
|
||||
PrismaticMultibodyJoint,
|
||||
// #if DIM3
|
||||
SphericalMultibodyJoint,
|
||||
// #endif
|
||||
} from "./multibody_joint";
|
||||
import {ImpulseJointHandle, JointData, JointType} from "./impulse_joint";
|
||||
import {IslandManager} from "./island_manager";
|
||||
import {ColliderHandle} from "../geometry";
|
||||
import {RigidBodyHandle} from "./rigid_body";
|
||||
|
||||
/**
|
||||
* A set of joints.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `jointSet.free()`
|
||||
* once you are done using it (and all the joints it created).
|
||||
*/
|
||||
export class MultibodyJointSet {
|
||||
raw: RawMultibodyJointSet;
|
||||
private map: Coarena<MultibodyJoint>;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this joint set.
|
||||
*/
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
|
||||
if (!!this.map) {
|
||||
this.map.clear();
|
||||
}
|
||||
this.map = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawMultibodyJointSet) {
|
||||
this.raw = raw || new RawMultibodyJointSet();
|
||||
this.map = new Coarena<MultibodyJoint>();
|
||||
// Initialize the map with the existing elements, if any.
|
||||
if (raw) {
|
||||
raw.forEachJointHandle((handle: MultibodyJointHandle) => {
|
||||
this.map.set(handle, MultibodyJoint.newTyped(this.raw, handle));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new joint and return its integer handle.
|
||||
*
|
||||
* @param desc - The joint's parameters.
|
||||
* @param parent1 - The handle of the first rigid-body this joint is attached to.
|
||||
* @param parent2 - The handle of the second rigid-body this joint is attached to.
|
||||
* @param wakeUp - Should the attached rigid-bodies be awakened?
|
||||
*/
|
||||
public createJoint(
|
||||
desc: JointData,
|
||||
parent1: RigidBodyHandle,
|
||||
parent2: RigidBodyHandle,
|
||||
wakeUp: boolean,
|
||||
): MultibodyJoint {
|
||||
const rawParams = desc.intoRaw();
|
||||
const handle = this.raw.createJoint(
|
||||
rawParams,
|
||||
parent1,
|
||||
parent2,
|
||||
wakeUp,
|
||||
);
|
||||
rawParams.free();
|
||||
let joint = MultibodyJoint.newTyped(this.raw, handle);
|
||||
this.map.set(handle, joint);
|
||||
return joint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a joint from this set.
|
||||
*
|
||||
* @param handle - The integer handle of the joint.
|
||||
* @param wake_up - If `true`, the rigid-bodies attached by the removed joint will be woken-up automatically.
|
||||
*/
|
||||
public remove(handle: MultibodyJointHandle, wake_up: boolean) {
|
||||
this.raw.remove(handle, wake_up);
|
||||
this.map.delete(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function, do not call directly.
|
||||
* @param handle
|
||||
*/
|
||||
public unmap(handle: MultibodyJointHandle) {
|
||||
this.map.delete(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of joints on this set.
|
||||
*/
|
||||
public len(): number {
|
||||
return this.map.len();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this set contain a joint with the given handle?
|
||||
*
|
||||
* @param handle - The joint handle to check.
|
||||
*/
|
||||
public contains(handle: MultibodyJointHandle): boolean {
|
||||
return this.get(handle) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the joint with the given handle.
|
||||
*
|
||||
* Returns `null` if no joint with the specified handle exists.
|
||||
*
|
||||
* @param handle - The integer handle of the joint to retrieve.
|
||||
*/
|
||||
public get(handle: MultibodyJointHandle): MultibodyJoint | null {
|
||||
return this.map.get(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given closure to each joint contained by this set.
|
||||
*
|
||||
* @param f - The closure to apply.
|
||||
*/
|
||||
public forEach(f: (joint: MultibodyJoint) => void) {
|
||||
this.map.forEach(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the given closure with the integer handle of each multibody joint attached to this rigid-body.
|
||||
*
|
||||
* @param f - The closure called with the integer handle of each multibody joint attached to the rigid-body.
|
||||
*/
|
||||
public forEachJointHandleAttachedToRigidBody(
|
||||
handle: RigidBodyHandle,
|
||||
f: (handle: MultibodyJointHandle) => void,
|
||||
) {
|
||||
this.raw.forEachJointAttachedToRigidBody(handle, f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all joints in the list.
|
||||
*
|
||||
* @returns joint list.
|
||||
*/
|
||||
public getAll(): MultibodyJoint[] {
|
||||
return this.map.getAll();
|
||||
}
|
||||
}
|
||||
1691
thirdparty/rapier.js/src.ts/dynamics/rigid_body.ts
vendored
Normal file
1691
thirdparty/rapier.js/src.ts/dynamics/rigid_body.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
238
thirdparty/rapier.js/src.ts/dynamics/rigid_body_set.ts
vendored
Normal file
238
thirdparty/rapier.js/src.ts/dynamics/rigid_body_set.ts
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
import {RawRigidBodySet, RawRigidBodyType} from "../raw";
|
||||
import {Coarena} from "../coarena";
|
||||
import {VectorOps, RotationOps} from "../math";
|
||||
import {
|
||||
RigidBody,
|
||||
RigidBodyDesc,
|
||||
RigidBodyHandle,
|
||||
RigidBodyType,
|
||||
} from "./rigid_body";
|
||||
import {ColliderSet} from "../geometry";
|
||||
import {ImpulseJointSet} from "./impulse_joint_set";
|
||||
import {MultibodyJointSet} from "./multibody_joint_set";
|
||||
import {IslandManager} from "./island_manager";
|
||||
|
||||
/**
|
||||
* A set of rigid bodies that can be handled by a physics pipeline.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `rigidBodySet.free()`
|
||||
* once you are done using it (and all the rigid-bodies it created).
|
||||
*/
|
||||
export class RigidBodySet {
|
||||
raw: RawRigidBodySet;
|
||||
private map: Coarena<RigidBody>;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this rigid-body set.
|
||||
*/
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
|
||||
if (!!this.map) {
|
||||
this.map.clear();
|
||||
}
|
||||
this.map = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawRigidBodySet) {
|
||||
this.raw = raw || new RawRigidBodySet();
|
||||
this.map = new Coarena<RigidBody>();
|
||||
// deserialize
|
||||
if (raw) {
|
||||
raw.forEachRigidBodyHandle((handle: RigidBodyHandle) => {
|
||||
this.map.set(handle, new RigidBody(raw, null, handle));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method, do not call this explicitly.
|
||||
*/
|
||||
public finalizeDeserialization(colliderSet: ColliderSet) {
|
||||
this.map.forEach((rb) => rb.finalizeDeserialization(colliderSet));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new rigid-body and return its integer handle.
|
||||
*
|
||||
* @param desc - The description of the rigid-body to create.
|
||||
*/
|
||||
public createRigidBody(
|
||||
colliderSet: ColliderSet,
|
||||
desc: RigidBodyDesc,
|
||||
): RigidBody {
|
||||
let rawTra = VectorOps.intoRaw(desc.translation);
|
||||
let rawRot = RotationOps.intoRaw(desc.rotation);
|
||||
let rawLv = VectorOps.intoRaw(desc.linvel);
|
||||
let rawCom = VectorOps.intoRaw(desc.centerOfMass);
|
||||
|
||||
// #if DIM3
|
||||
let rawAv = VectorOps.intoRaw(desc.angvel);
|
||||
let rawPrincipalInertia = VectorOps.intoRaw(
|
||||
desc.principalAngularInertia,
|
||||
);
|
||||
let rawInertiaFrame = RotationOps.intoRaw(
|
||||
desc.angularInertiaLocalFrame,
|
||||
);
|
||||
// #endif
|
||||
|
||||
let handle = this.raw.createRigidBody(
|
||||
desc.enabled,
|
||||
rawTra,
|
||||
rawRot,
|
||||
desc.gravityScale,
|
||||
desc.mass,
|
||||
desc.massOnly,
|
||||
rawCom,
|
||||
rawLv,
|
||||
// #if DIM2
|
||||
desc.angvel,
|
||||
desc.principalAngularInertia,
|
||||
desc.translationsEnabledX,
|
||||
desc.translationsEnabledY,
|
||||
desc.rotationsEnabled,
|
||||
// #endif
|
||||
// #if DIM3
|
||||
rawAv,
|
||||
rawPrincipalInertia,
|
||||
rawInertiaFrame,
|
||||
desc.translationsEnabledX,
|
||||
desc.translationsEnabledY,
|
||||
desc.translationsEnabledZ,
|
||||
desc.rotationsEnabledX,
|
||||
desc.rotationsEnabledY,
|
||||
desc.rotationsEnabledZ,
|
||||
// #endif
|
||||
desc.linearDamping,
|
||||
desc.angularDamping,
|
||||
desc.status as number as RawRigidBodyType,
|
||||
desc.canSleep,
|
||||
desc.sleeping,
|
||||
desc.softCcdPrediction,
|
||||
desc.ccdEnabled,
|
||||
desc.dominanceGroup,
|
||||
desc.additionalSolverIterations,
|
||||
);
|
||||
|
||||
rawTra.free();
|
||||
rawRot.free();
|
||||
rawLv.free();
|
||||
rawCom.free();
|
||||
|
||||
// #if DIM3
|
||||
rawAv.free();
|
||||
rawPrincipalInertia.free();
|
||||
rawInertiaFrame.free();
|
||||
// #endif
|
||||
|
||||
const body = new RigidBody(this.raw, colliderSet, handle);
|
||||
body.userData = desc.userData;
|
||||
|
||||
this.map.set(handle, body);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a rigid-body from this set.
|
||||
*
|
||||
* This will also remove all the colliders and joints attached to the rigid-body.
|
||||
*
|
||||
* @param handle - The integer handle of the rigid-body to remove.
|
||||
* @param colliders - The set of colliders that may contain colliders attached to the removed rigid-body.
|
||||
* @param impulseJoints - The set of impulse joints that may contain joints attached to the removed rigid-body.
|
||||
* @param multibodyJoints - The set of multibody joints that may contain joints attached to the removed rigid-body.
|
||||
*/
|
||||
public remove(
|
||||
handle: RigidBodyHandle,
|
||||
islands: IslandManager,
|
||||
colliders: ColliderSet,
|
||||
impulseJoints: ImpulseJointSet,
|
||||
multibodyJoints: MultibodyJointSet,
|
||||
) {
|
||||
// Unmap the entities that will be removed automatically because of the rigid-body removals.
|
||||
for (let i = 0; i < this.raw.rbNumColliders(handle); i += 1) {
|
||||
colliders.unmap(this.raw.rbCollider(handle, i));
|
||||
}
|
||||
|
||||
impulseJoints.forEachJointHandleAttachedToRigidBody(handle, (handle) =>
|
||||
impulseJoints.unmap(handle),
|
||||
);
|
||||
multibodyJoints.forEachJointHandleAttachedToRigidBody(
|
||||
handle,
|
||||
(handle) => multibodyJoints.unmap(handle),
|
||||
);
|
||||
|
||||
// Remove the rigid-body.
|
||||
this.raw.remove(
|
||||
handle,
|
||||
islands.raw,
|
||||
colliders.raw,
|
||||
impulseJoints.raw,
|
||||
multibodyJoints.raw,
|
||||
);
|
||||
this.map.delete(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of rigid-bodies on this set.
|
||||
*/
|
||||
public len(): number {
|
||||
return this.map.len();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this set contain a rigid-body with the given handle?
|
||||
*
|
||||
* @param handle - The rigid-body handle to check.
|
||||
*/
|
||||
public contains(handle: RigidBodyHandle): boolean {
|
||||
return this.get(handle) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rigid-body with the given handle.
|
||||
*
|
||||
* @param handle - The handle of the rigid-body to retrieve.
|
||||
*/
|
||||
public get(handle: RigidBodyHandle): RigidBody | null {
|
||||
return this.map.get(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given closure to each rigid-body contained by this set.
|
||||
*
|
||||
* @param f - The closure to apply.
|
||||
*/
|
||||
public forEach(f: (body: RigidBody) => void) {
|
||||
this.map.forEach(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given closure to each active rigid-bodies contained by this set.
|
||||
*
|
||||
* A rigid-body is active if it is not sleeping, i.e., if it moved recently.
|
||||
*
|
||||
* @param f - The closure to apply.
|
||||
*/
|
||||
public forEachActiveRigidBody(
|
||||
islands: IslandManager,
|
||||
f: (body: RigidBody) => void,
|
||||
) {
|
||||
islands.forEachActiveRigidBodyHandle((handle) => {
|
||||
f(this.get(handle));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all rigid-bodies in the list.
|
||||
*
|
||||
* @returns rigid-bodies list.
|
||||
*/
|
||||
public getAll(): RigidBody[] {
|
||||
return this.map.getAll();
|
||||
}
|
||||
}
|
||||
27
thirdparty/rapier.js/src.ts/exports.ts
vendored
Normal file
27
thirdparty/rapier.js/src.ts/exports.ts
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import {version as vers, reserve_memory as reserve} from "./raw";
|
||||
|
||||
export function version(): string {
|
||||
return vers();
|
||||
}
|
||||
|
||||
/// Reserves additional memory in WASM land.
|
||||
///
|
||||
/// This will grow the internal WASM memory buffer so that it can fit at least
|
||||
/// the specified amount of extra bytes. This can help reduce future runtime
|
||||
/// overhead due to dynamic internal memory growth once the limit of the
|
||||
/// pre-allocated memory is reached.
|
||||
///
|
||||
/// This feature is still experimental. Due to the nature of the internal
|
||||
/// allocator, there can be situations where the allocator decides to perform
|
||||
/// additional internal memory growth even though not all `extraBytesCount`
|
||||
/// are occupied yet.
|
||||
export function reserveMemory(extraBytesCount: number) {
|
||||
reserve(extraBytesCount);
|
||||
}
|
||||
|
||||
export * from "./math";
|
||||
export * from "./dynamics";
|
||||
export * from "./geometry";
|
||||
export * from "./pipeline";
|
||||
export * from "./init";
|
||||
export * from "./control";
|
||||
520
thirdparty/rapier.js/src.ts/geometry/broad_phase.ts
vendored
Normal file
520
thirdparty/rapier.js/src.ts/geometry/broad_phase.ts
vendored
Normal file
@@ -0,0 +1,520 @@
|
||||
import {RawBroadPhase, RawRayColliderIntersection} from "../raw";
|
||||
import {RigidBodyHandle, RigidBodySet} from "../dynamics";
|
||||
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 {Shape} from "./shape";
|
||||
import {PointColliderProjection} from "./point";
|
||||
import {ColliderShapeCastHit} from "./toi";
|
||||
import {QueryFilterFlags} from "../pipeline";
|
||||
import {NarrowPhase} from "./narrow_phase";
|
||||
|
||||
/**
|
||||
* The broad-phase used for coarse collision-detection.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `broadPhase.free()`
|
||||
* once you are done using it.
|
||||
*/
|
||||
export class BroadPhase {
|
||||
raw: RawBroadPhase;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this broad-phase.
|
||||
*/
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawBroadPhase) {
|
||||
this.raw = raw || new RawBroadPhase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the closest intersection between a ray and a set of collider.
|
||||
*
|
||||
* @param colliders - The set of colliders taking part in this pipeline.
|
||||
* @param ray - The ray to cast.
|
||||
* @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively
|
||||
* limits the length of the ray to `ray.dir.norm() * maxToi`.
|
||||
* @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its
|
||||
* origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain,
|
||||
* whereas `false` implies that all shapes are hollow for this ray-cast.
|
||||
* @param groups - Used to filter the colliders that can or cannot be hit by the ray.
|
||||
* @param filter - The callback to filter out which collider will be hit.
|
||||
*/
|
||||
public castRay(
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
ray: Ray,
|
||||
maxToi: number,
|
||||
solid: boolean,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterGroups?: InteractionGroups,
|
||||
filterExcludeCollider?: ColliderHandle,
|
||||
filterExcludeRigidBody?: RigidBodyHandle,
|
||||
filterPredicate?: (collider: ColliderHandle) => boolean,
|
||||
): RayColliderHit | null {
|
||||
let rawOrig = VectorOps.intoRaw(ray.origin);
|
||||
let rawDir = VectorOps.intoRaw(ray.dir);
|
||||
let result = RayColliderHit.fromRaw(
|
||||
colliders,
|
||||
this.raw.castRay(
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
rawOrig,
|
||||
rawDir,
|
||||
maxToi,
|
||||
solid,
|
||||
filterFlags,
|
||||
filterGroups,
|
||||
filterExcludeCollider,
|
||||
filterExcludeRigidBody,
|
||||
filterPredicate,
|
||||
),
|
||||
);
|
||||
|
||||
rawOrig.free();
|
||||
rawDir.free();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the closest intersection between a ray and a set of collider.
|
||||
*
|
||||
* This also computes the normal at the hit point.
|
||||
* @param colliders - The set of colliders taking part in this pipeline.
|
||||
* @param ray - The ray to cast.
|
||||
* @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively
|
||||
* limits the length of the ray to `ray.dir.norm() * maxToi`.
|
||||
* @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its
|
||||
* origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain,
|
||||
* whereas `false` implies that all shapes are hollow for this ray-cast.
|
||||
* @param groups - Used to filter the colliders that can or cannot be hit by the ray.
|
||||
*/
|
||||
public castRayAndGetNormal(
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
ray: Ray,
|
||||
maxToi: number,
|
||||
solid: boolean,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterGroups?: InteractionGroups,
|
||||
filterExcludeCollider?: ColliderHandle,
|
||||
filterExcludeRigidBody?: RigidBodyHandle,
|
||||
filterPredicate?: (collider: ColliderHandle) => boolean,
|
||||
): RayColliderIntersection | null {
|
||||
let rawOrig = VectorOps.intoRaw(ray.origin);
|
||||
let rawDir = VectorOps.intoRaw(ray.dir);
|
||||
let result = RayColliderIntersection.fromRaw(
|
||||
colliders,
|
||||
this.raw.castRayAndGetNormal(
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
rawOrig,
|
||||
rawDir,
|
||||
maxToi,
|
||||
solid,
|
||||
filterFlags,
|
||||
filterGroups,
|
||||
filterExcludeCollider,
|
||||
filterExcludeRigidBody,
|
||||
filterPredicate,
|
||||
),
|
||||
);
|
||||
|
||||
rawOrig.free();
|
||||
rawDir.free();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast a ray and collects all the intersections between a ray and the scene.
|
||||
*
|
||||
* @param colliders - The set of colliders taking part in this pipeline.
|
||||
* @param ray - The ray to cast.
|
||||
* @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively
|
||||
* limits the length of the ray to `ray.dir.norm() * maxToi`.
|
||||
* @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its
|
||||
* origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain,
|
||||
* whereas `false` implies that all shapes are hollow for this ray-cast.
|
||||
* @param groups - Used to filter the colliders that can or cannot be hit by the ray.
|
||||
* @param callback - The callback called once per hit (in no particular order) between a ray and a collider.
|
||||
* If this callback returns `false`, then the cast will stop and no further hits will be detected/reported.
|
||||
*/
|
||||
public intersectionsWithRay(
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
ray: Ray,
|
||||
maxToi: number,
|
||||
solid: boolean,
|
||||
callback: (intersect: RayColliderIntersection) => boolean,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterGroups?: InteractionGroups,
|
||||
filterExcludeCollider?: ColliderHandle,
|
||||
filterExcludeRigidBody?: RigidBodyHandle,
|
||||
filterPredicate?: (collider: ColliderHandle) => boolean,
|
||||
) {
|
||||
let rawOrig = VectorOps.intoRaw(ray.origin);
|
||||
let rawDir = VectorOps.intoRaw(ray.dir);
|
||||
let rawCallback = (rawInter: RawRayColliderIntersection) => {
|
||||
return callback(
|
||||
RayColliderIntersection.fromRaw(colliders, rawInter),
|
||||
);
|
||||
};
|
||||
|
||||
this.raw.intersectionsWithRay(
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
rawOrig,
|
||||
rawDir,
|
||||
maxToi,
|
||||
solid,
|
||||
rawCallback,
|
||||
filterFlags,
|
||||
filterGroups,
|
||||
filterExcludeCollider,
|
||||
filterExcludeRigidBody,
|
||||
filterPredicate,
|
||||
);
|
||||
|
||||
rawOrig.free();
|
||||
rawDir.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the handle of up to one collider intersecting the given shape.
|
||||
*
|
||||
* @param colliders - The set of colliders taking part in this pipeline.
|
||||
* @param shapePos - The position of the shape used for the intersection test.
|
||||
* @param shapeRot - The orientation of the shape used for the intersection test.
|
||||
* @param shape - The shape used for the intersection test.
|
||||
* @param groups - The bit groups and filter associated to the ray, in order to only
|
||||
* hit the colliders with collision groups compatible with the ray's group.
|
||||
*/
|
||||
public intersectionWithShape(
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
shapePos: Vector,
|
||||
shapeRot: Rotation,
|
||||
shape: Shape,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterGroups?: InteractionGroups,
|
||||
filterExcludeCollider?: ColliderHandle,
|
||||
filterExcludeRigidBody?: RigidBodyHandle,
|
||||
filterPredicate?: (collider: ColliderHandle) => boolean,
|
||||
): ColliderHandle | null {
|
||||
let rawPos = VectorOps.intoRaw(shapePos);
|
||||
let rawRot = RotationOps.intoRaw(shapeRot);
|
||||
let rawShape = shape.intoRaw();
|
||||
let result = this.raw.intersectionWithShape(
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
rawPos,
|
||||
rawRot,
|
||||
rawShape,
|
||||
filterFlags,
|
||||
filterGroups,
|
||||
filterExcludeCollider,
|
||||
filterExcludeRigidBody,
|
||||
filterPredicate,
|
||||
);
|
||||
|
||||
rawPos.free();
|
||||
rawRot.free();
|
||||
rawShape.free();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the projection of a point on the closest collider.
|
||||
*
|
||||
* @param colliders - The set of colliders taking part in this pipeline.
|
||||
* @param point - The point to project.
|
||||
* @param solid - If this is set to `true` then the collider shapes are considered to
|
||||
* be plain (if the point is located inside of a plain shape, its projection is the point
|
||||
* itself). If it is set to `false` the collider shapes are considered to be hollow
|
||||
* (if the point is located inside of an hollow shape, it is projected on the shape's
|
||||
* boundary).
|
||||
* @param groups - The bit groups and filter associated to the point to project, in order to only
|
||||
* project on colliders with collision groups compatible with the ray's group.
|
||||
*/
|
||||
public projectPoint(
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
point: Vector,
|
||||
solid: boolean,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterGroups?: InteractionGroups,
|
||||
filterExcludeCollider?: ColliderHandle,
|
||||
filterExcludeRigidBody?: RigidBodyHandle,
|
||||
filterPredicate?: (collider: ColliderHandle) => boolean,
|
||||
): PointColliderProjection | null {
|
||||
let rawPoint = VectorOps.intoRaw(point);
|
||||
let result = PointColliderProjection.fromRaw(
|
||||
colliders,
|
||||
this.raw.projectPoint(
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
rawPoint,
|
||||
solid,
|
||||
filterFlags,
|
||||
filterGroups,
|
||||
filterExcludeCollider,
|
||||
filterExcludeRigidBody,
|
||||
filterPredicate,
|
||||
),
|
||||
);
|
||||
|
||||
rawPoint.free();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the projection of a point on the closest collider.
|
||||
*
|
||||
* @param colliders - The set of colliders taking part in this pipeline.
|
||||
* @param point - The point to project.
|
||||
* @param groups - The bit groups and filter associated to the point to project, in order to only
|
||||
* project on colliders with collision groups compatible with the ray's group.
|
||||
*/
|
||||
public projectPointAndGetFeature(
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
point: Vector,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterGroups?: InteractionGroups,
|
||||
filterExcludeCollider?: ColliderHandle,
|
||||
filterExcludeRigidBody?: RigidBodyHandle,
|
||||
filterPredicate?: (collider: ColliderHandle) => boolean,
|
||||
): PointColliderProjection | null {
|
||||
let rawPoint = VectorOps.intoRaw(point);
|
||||
let result = PointColliderProjection.fromRaw(
|
||||
colliders,
|
||||
this.raw.projectPointAndGetFeature(
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
rawPoint,
|
||||
filterFlags,
|
||||
filterGroups,
|
||||
filterExcludeCollider,
|
||||
filterExcludeRigidBody,
|
||||
filterPredicate,
|
||||
),
|
||||
);
|
||||
|
||||
rawPoint.free();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all the colliders containing the given point.
|
||||
*
|
||||
* @param colliders - The set of colliders taking part in this pipeline.
|
||||
* @param point - The point used for the containment test.
|
||||
* @param groups - The bit groups and filter associated to the point to test, in order to only
|
||||
* test on colliders with collision groups compatible with the ray's group.
|
||||
* @param callback - A function called with the handles of each collider with a shape
|
||||
* containing the `point`.
|
||||
*/
|
||||
public intersectionsWithPoint(
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
point: Vector,
|
||||
callback: (handle: ColliderHandle) => boolean,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterGroups?: InteractionGroups,
|
||||
filterExcludeCollider?: ColliderHandle,
|
||||
filterExcludeRigidBody?: RigidBodyHandle,
|
||||
filterPredicate?: (collider: ColliderHandle) => boolean,
|
||||
) {
|
||||
let rawPoint = VectorOps.intoRaw(point);
|
||||
|
||||
this.raw.intersectionsWithPoint(
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
rawPoint,
|
||||
callback,
|
||||
filterFlags,
|
||||
filterGroups,
|
||||
filterExcludeCollider,
|
||||
filterExcludeRigidBody,
|
||||
filterPredicate,
|
||||
);
|
||||
|
||||
rawPoint.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts a shape at a constant linear velocity and retrieve the first collider it hits.
|
||||
* This is similar to ray-casting except that we are casting a whole shape instead of
|
||||
* just a point (the ray origin).
|
||||
*
|
||||
* @param colliders - The set of colliders taking part in this pipeline.
|
||||
* @param shapePos - The initial position of the shape to cast.
|
||||
* @param shapeRot - The initial rotation of the shape to cast.
|
||||
* @param shapeVel - The constant velocity of the shape to cast (i.e. the cast direction).
|
||||
* @param shape - The shape to cast.
|
||||
* @param targetDistance − If the shape moves closer to this distance from a collider, a hit
|
||||
* will be returned.
|
||||
* @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively
|
||||
* limits the distance traveled by the shape to `shapeVel.norm() * maxToi`.
|
||||
* @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 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.
|
||||
*/
|
||||
public castShape(
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
shapePos: Vector,
|
||||
shapeRot: Rotation,
|
||||
shapeVel: Vector,
|
||||
shape: Shape,
|
||||
targetDistance: number,
|
||||
maxToi: number,
|
||||
stopAtPenetration: boolean,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterGroups?: InteractionGroups,
|
||||
filterExcludeCollider?: ColliderHandle,
|
||||
filterExcludeRigidBody?: RigidBodyHandle,
|
||||
filterPredicate?: (collider: ColliderHandle) => boolean,
|
||||
): 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,
|
||||
),
|
||||
);
|
||||
|
||||
rawPos.free();
|
||||
rawRot.free();
|
||||
rawVel.free();
|
||||
rawShape.free();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all the colliders intersecting the given shape.
|
||||
*
|
||||
* @param colliders - The set of colliders taking part in this pipeline.
|
||||
* @param shapePos - The position of the shape to test.
|
||||
* @param shapeRot - The orientation of the shape to test.
|
||||
* @param shape - The shape to test.
|
||||
* @param groups - The bit groups and filter associated to the shape to test, in order to only
|
||||
* test on colliders with collision groups compatible with this group.
|
||||
* @param callback - A function called with the handles of each collider intersecting the `shape`.
|
||||
*/
|
||||
public intersectionsWithShape(
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
shapePos: Vector,
|
||||
shapeRot: Rotation,
|
||||
shape: Shape,
|
||||
callback: (handle: ColliderHandle) => boolean,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterGroups?: InteractionGroups,
|
||||
filterExcludeCollider?: ColliderHandle,
|
||||
filterExcludeRigidBody?: RigidBodyHandle,
|
||||
filterPredicate?: (collider: ColliderHandle) => boolean,
|
||||
) {
|
||||
let rawPos = VectorOps.intoRaw(shapePos);
|
||||
let rawRot = RotationOps.intoRaw(shapeRot);
|
||||
let rawShape = shape.intoRaw();
|
||||
|
||||
this.raw.intersectionsWithShape(
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
rawPos,
|
||||
rawRot,
|
||||
rawShape,
|
||||
callback,
|
||||
filterFlags,
|
||||
filterGroups,
|
||||
filterExcludeCollider,
|
||||
filterExcludeRigidBody,
|
||||
filterPredicate,
|
||||
);
|
||||
|
||||
rawPos.free();
|
||||
rawRot.free();
|
||||
rawShape.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the handles of all the colliders with an AABB intersecting the given AABB.
|
||||
*
|
||||
* @param aabbCenter - The center of the AABB to test.
|
||||
* @param aabbHalfExtents - The half-extents of the AABB to test.
|
||||
* @param callback - The callback that will be called with the handles of all the colliders
|
||||
* currently intersecting the given AABB.
|
||||
*/
|
||||
public collidersWithAabbIntersectingAabb(
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
aabbCenter: Vector,
|
||||
aabbHalfExtents: Vector,
|
||||
callback: (handle: ColliderHandle) => boolean,
|
||||
) {
|
||||
let rawCenter = VectorOps.intoRaw(aabbCenter);
|
||||
let rawHalfExtents = VectorOps.intoRaw(aabbHalfExtents);
|
||||
this.raw.collidersWithAabbIntersectingAabb(
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
rawCenter,
|
||||
rawHalfExtents,
|
||||
callback,
|
||||
);
|
||||
rawCenter.free();
|
||||
rawHalfExtents.free();
|
||||
}
|
||||
}
|
||||
1983
thirdparty/rapier.js/src.ts/geometry/collider.ts
vendored
Normal file
1983
thirdparty/rapier.js/src.ts/geometry/collider.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
213
thirdparty/rapier.js/src.ts/geometry/collider_set.ts
vendored
Normal file
213
thirdparty/rapier.js/src.ts/geometry/collider_set.ts
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
import {RawColliderSet} from "../raw";
|
||||
import {Coarena} from "../coarena";
|
||||
import {RotationOps, VectorOps} from "../math";
|
||||
import {Collider, ColliderDesc, ColliderHandle} from "./collider";
|
||||
import {ImpulseJointHandle, IslandManager, RigidBodyHandle} from "../dynamics";
|
||||
import {RigidBodySet} from "../dynamics";
|
||||
|
||||
/**
|
||||
* A set of rigid bodies that can be handled by a physics pipeline.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `colliderSet.free()`
|
||||
* once you are done using it (and all the rigid-bodies it created).
|
||||
*/
|
||||
export class ColliderSet {
|
||||
raw: RawColliderSet;
|
||||
private map: Coarena<Collider>;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this collider set.
|
||||
*/
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
|
||||
if (!!this.map) {
|
||||
this.map.clear();
|
||||
}
|
||||
this.map = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawColliderSet) {
|
||||
this.raw = raw || new RawColliderSet();
|
||||
this.map = new Coarena<Collider>();
|
||||
// Initialize the map with the existing elements, if any.
|
||||
if (raw) {
|
||||
raw.forEachColliderHandle((handle: ColliderHandle) => {
|
||||
this.map.set(handle, new Collider(this, handle, null));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public castClosure<Res>(
|
||||
f?: (collider: Collider) => Res,
|
||||
): (handle: ColliderHandle) => Res | undefined {
|
||||
return (handle) => {
|
||||
if (!!f) {
|
||||
return f(this.get(handle));
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public finalizeDeserialization(bodies: RigidBodySet) {
|
||||
this.map.forEach((collider) =>
|
||||
collider.finalizeDeserialization(bodies),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new collider and return its integer handle.
|
||||
*
|
||||
* @param bodies - The set of bodies where the collider's parent can be found.
|
||||
* @param desc - The collider's description.
|
||||
* @param parentHandle - The integer handle of the rigid-body this collider is attached to.
|
||||
*/
|
||||
public createCollider(
|
||||
bodies: RigidBodySet,
|
||||
desc: ColliderDesc,
|
||||
parentHandle: RigidBodyHandle,
|
||||
): Collider {
|
||||
let hasParent = parentHandle != undefined && parentHandle != null;
|
||||
|
||||
if (hasParent && isNaN(parentHandle))
|
||||
throw Error(
|
||||
"Cannot create a collider with a parent rigid-body handle that is not a number.",
|
||||
);
|
||||
|
||||
let rawShape = desc.shape.intoRaw();
|
||||
let rawTra = VectorOps.intoRaw(desc.translation);
|
||||
let rawRot = RotationOps.intoRaw(desc.rotation);
|
||||
let rawCom = VectorOps.intoRaw(desc.centerOfMass);
|
||||
|
||||
// #if DIM3
|
||||
let rawPrincipalInertia = VectorOps.intoRaw(
|
||||
desc.principalAngularInertia,
|
||||
);
|
||||
let rawInertiaFrame = RotationOps.intoRaw(
|
||||
desc.angularInertiaLocalFrame,
|
||||
);
|
||||
// #endif
|
||||
|
||||
let handle = this.raw.createCollider(
|
||||
desc.enabled,
|
||||
rawShape,
|
||||
rawTra,
|
||||
rawRot,
|
||||
desc.massPropsMode,
|
||||
desc.mass,
|
||||
rawCom,
|
||||
// #if DIM2
|
||||
desc.principalAngularInertia,
|
||||
// #endif
|
||||
// #if DIM3
|
||||
rawPrincipalInertia,
|
||||
rawInertiaFrame,
|
||||
// #endif
|
||||
desc.density,
|
||||
desc.friction,
|
||||
desc.restitution,
|
||||
desc.frictionCombineRule,
|
||||
desc.restitutionCombineRule,
|
||||
desc.isSensor,
|
||||
desc.collisionGroups,
|
||||
desc.solverGroups,
|
||||
desc.activeCollisionTypes,
|
||||
desc.activeHooks,
|
||||
desc.activeEvents,
|
||||
desc.contactForceEventThreshold,
|
||||
desc.contactSkin,
|
||||
hasParent,
|
||||
hasParent ? parentHandle : 0,
|
||||
bodies.raw,
|
||||
);
|
||||
|
||||
rawShape.free();
|
||||
rawTra.free();
|
||||
rawRot.free();
|
||||
rawCom.free();
|
||||
|
||||
// #if DIM3
|
||||
rawPrincipalInertia.free();
|
||||
rawInertiaFrame.free();
|
||||
// #endif
|
||||
|
||||
let parent = hasParent ? bodies.get(parentHandle) : null;
|
||||
let collider = new Collider(this, handle, parent, desc.shape);
|
||||
this.map.set(handle, collider);
|
||||
return collider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a collider from this set.
|
||||
*
|
||||
* @param handle - The integer handle of the collider to remove.
|
||||
* @param bodies - The set of rigid-body containing the rigid-body the collider is attached to.
|
||||
* @param wakeUp - If `true`, the rigid-body the removed collider is attached to will be woken-up automatically.
|
||||
*/
|
||||
public remove(
|
||||
handle: ColliderHandle,
|
||||
islands: IslandManager,
|
||||
bodies: RigidBodySet,
|
||||
wakeUp: boolean,
|
||||
) {
|
||||
this.raw.remove(handle, islands.raw, bodies.raw, wakeUp);
|
||||
this.unmap(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function, do not call directly.
|
||||
* @param handle
|
||||
*/
|
||||
public unmap(handle: ImpulseJointHandle) {
|
||||
this.map.delete(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rigid-body with the given handle.
|
||||
*
|
||||
* @param handle - The handle of the rigid-body to retrieve.
|
||||
*/
|
||||
public get(handle: ColliderHandle): Collider | null {
|
||||
return this.map.get(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of colliders on this set.
|
||||
*/
|
||||
public len(): number {
|
||||
return this.map.len();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this set contain a collider with the given handle?
|
||||
*
|
||||
* @param handle - The collider handle to check.
|
||||
*/
|
||||
public contains(handle: ColliderHandle): boolean {
|
||||
return this.get(handle) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given closure to each collider contained by this set.
|
||||
*
|
||||
* @param f - The closure to apply.
|
||||
*/
|
||||
public forEach(f: (collider: Collider) => void) {
|
||||
this.map.forEach(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all colliders in the list.
|
||||
*
|
||||
* @returns collider list.
|
||||
*/
|
||||
public getAll(): Collider[] {
|
||||
return this.map.getAll();
|
||||
}
|
||||
}
|
||||
62
thirdparty/rapier.js/src.ts/geometry/contact.ts
vendored
Normal file
62
thirdparty/rapier.js/src.ts/geometry/contact.ts
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
import {Vector, VectorOps} from "../math";
|
||||
import {RawShapeContact} from "../raw";
|
||||
|
||||
/**
|
||||
* The contact info between two shapes.
|
||||
*/
|
||||
export class ShapeContact {
|
||||
/**
|
||||
* Distance between the two contact points.
|
||||
* If this is negative, this contact represents a penetration.
|
||||
*/
|
||||
distance: number;
|
||||
|
||||
/**
|
||||
* Position of the contact on the first shape.
|
||||
*/
|
||||
point1: Vector;
|
||||
|
||||
/**
|
||||
* Position of the contact on the second shape.
|
||||
*/
|
||||
point2: Vector;
|
||||
|
||||
/**
|
||||
* Contact normal, pointing towards the exterior of the first shape.
|
||||
*/
|
||||
normal1: Vector;
|
||||
|
||||
/**
|
||||
* Contact normal, pointing towards the exterior of the second shape.
|
||||
* If these contact data are expressed in world-space, this normal is equal to -normal1.
|
||||
*/
|
||||
normal2: Vector;
|
||||
|
||||
constructor(
|
||||
dist: number,
|
||||
point1: Vector,
|
||||
point2: Vector,
|
||||
normal1: Vector,
|
||||
normal2: Vector,
|
||||
) {
|
||||
this.distance = dist;
|
||||
this.point1 = point1;
|
||||
this.point2 = point2;
|
||||
this.normal1 = normal1;
|
||||
this.normal2 = normal2;
|
||||
}
|
||||
|
||||
public static fromRaw(raw: RawShapeContact): ShapeContact {
|
||||
if (!raw) return null;
|
||||
|
||||
const result = new ShapeContact(
|
||||
raw.distance(),
|
||||
VectorOps.fromRaw(raw.point1()),
|
||||
VectorOps.fromRaw(raw.point2()),
|
||||
VectorOps.fromRaw(raw.normal1()),
|
||||
VectorOps.fromRaw(raw.normal2()),
|
||||
);
|
||||
raw.free();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
16
thirdparty/rapier.js/src.ts/geometry/feature.ts
vendored
Normal file
16
thirdparty/rapier.js/src.ts/geometry/feature.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// #if DIM2
|
||||
export enum FeatureType {
|
||||
Vertex,
|
||||
Face,
|
||||
Unknown,
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #if DIM3
|
||||
export enum FeatureType {
|
||||
Vertex,
|
||||
Edge,
|
||||
Face,
|
||||
Unknown,
|
||||
}
|
||||
// #endif
|
||||
11
thirdparty/rapier.js/src.ts/geometry/index.ts
vendored
Normal file
11
thirdparty/rapier.js/src.ts/geometry/index.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
export * from "./broad_phase";
|
||||
export * from "./narrow_phase";
|
||||
export * from "./shape";
|
||||
export * from "./collider";
|
||||
export * from "./collider_set";
|
||||
export * from "./feature";
|
||||
export * from "./ray";
|
||||
export * from "./point";
|
||||
export * from "./toi";
|
||||
export * from "./interaction_groups";
|
||||
export * from "./contact";
|
||||
18
thirdparty/rapier.js/src.ts/geometry/interaction_groups.ts
vendored
Normal file
18
thirdparty/rapier.js/src.ts/geometry/interaction_groups.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Pairwise filtering using bit masks.
|
||||
*
|
||||
* This filtering method is based on two 16-bit values:
|
||||
* - The interaction groups (the 16 left-most bits of `self.0`).
|
||||
* - The interaction mask (the 16 right-most bits of `self.0`).
|
||||
*
|
||||
* An interaction is allowed between two filters `a` and `b` two conditions
|
||||
* are met simultaneously:
|
||||
* - The interaction groups of `a` has at least one bit set to `1` in common with the interaction mask of `b`.
|
||||
* - The interaction groups of `b` has at least one bit set to `1` in common with the interaction mask of `a`.
|
||||
* In other words, interactions are allowed between two filter iff. the following condition is met:
|
||||
*
|
||||
* ```
|
||||
* ((a >> 16) & b) != 0 && ((b >> 16) & a) != 0
|
||||
* ```
|
||||
*/
|
||||
export type InteractionGroups = number;
|
||||
203
thirdparty/rapier.js/src.ts/geometry/narrow_phase.ts
vendored
Normal file
203
thirdparty/rapier.js/src.ts/geometry/narrow_phase.ts
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
import {RawNarrowPhase, RawContactManifold} from "../raw";
|
||||
import {ColliderHandle} from "./collider";
|
||||
import {Vector, VectorOps} from "../math";
|
||||
|
||||
/**
|
||||
* The narrow-phase used for precise collision-detection.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `narrowPhase.free()`
|
||||
* once you are done using it.
|
||||
*/
|
||||
export class NarrowPhase {
|
||||
raw: RawNarrowPhase;
|
||||
tempManifold: TempContactManifold;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this narrow-phase.
|
||||
*/
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawNarrowPhase) {
|
||||
this.raw = raw || new RawNarrowPhase();
|
||||
this.tempManifold = new TempContactManifold(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerates all the colliders potentially in contact with the given collider.
|
||||
*
|
||||
* @param collider1 - The second collider involved in the contact.
|
||||
* @param f - Closure that will be called on each collider that is in contact with `collider1`.
|
||||
*/
|
||||
public contactPairsWith(
|
||||
collider1: ColliderHandle,
|
||||
f: (collider2: ColliderHandle) => void,
|
||||
) {
|
||||
this.raw.contact_pairs_with(collider1, f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerates all the colliders intersecting the given colliders, assuming one of them
|
||||
* is a sensor.
|
||||
*/
|
||||
public intersectionPairsWith(
|
||||
collider1: ColliderHandle,
|
||||
f: (collider2: ColliderHandle) => void,
|
||||
) {
|
||||
this.raw.intersection_pairs_with(collider1, f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through all the contact manifolds between the given pair of colliders.
|
||||
*
|
||||
* @param collider1 - The first collider involved in the contact.
|
||||
* @param collider2 - The second collider involved in the contact.
|
||||
* @param f - Closure that will be called on each contact manifold between the two colliders. If the second argument
|
||||
* passed to this closure is `true`, then the contact manifold data is flipped, i.e., methods like `localNormal1`
|
||||
* actually apply to the `collider2` and fields like `localNormal2` apply to the `collider1`.
|
||||
*/
|
||||
public contactPair(
|
||||
collider1: ColliderHandle,
|
||||
collider2: ColliderHandle,
|
||||
f: (manifold: TempContactManifold, flipped: boolean) => void,
|
||||
) {
|
||||
const rawPair = this.raw.contact_pair(collider1, collider2);
|
||||
|
||||
if (!!rawPair) {
|
||||
const flipped = rawPair.collider1() != collider1;
|
||||
|
||||
let i;
|
||||
for (i = 0; i < rawPair.numContactManifolds(); ++i) {
|
||||
this.tempManifold.raw = rawPair.contactManifold(i);
|
||||
if (!!this.tempManifold.raw) {
|
||||
f(this.tempManifold, flipped);
|
||||
}
|
||||
|
||||
// SAFETY: The RawContactManifold stores a raw pointer that will be invalidated
|
||||
// at the next timestep. So we must be sure to free the pair here
|
||||
// to avoid unsoundness in the Rust code.
|
||||
this.tempManifold.free();
|
||||
}
|
||||
rawPair.free();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if `collider1` and `collider2` intersect and at least one of them is a sensor.
|
||||
* @param collider1 − The first collider involved in the intersection.
|
||||
* @param collider2 − The second collider involved in the intersection.
|
||||
*/
|
||||
public intersectionPair(
|
||||
collider1: ColliderHandle,
|
||||
collider2: ColliderHandle,
|
||||
): boolean {
|
||||
return this.raw.intersection_pair(collider1, collider2);
|
||||
}
|
||||
}
|
||||
|
||||
export class TempContactManifold {
|
||||
raw: RawContactManifold;
|
||||
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
constructor(raw: RawContactManifold) {
|
||||
this.raw = raw;
|
||||
}
|
||||
|
||||
public normal(): Vector {
|
||||
return VectorOps.fromRaw(this.raw.normal());
|
||||
}
|
||||
|
||||
public localNormal1(): Vector {
|
||||
return VectorOps.fromRaw(this.raw.local_n1());
|
||||
}
|
||||
|
||||
public localNormal2(): Vector {
|
||||
return VectorOps.fromRaw(this.raw.local_n2());
|
||||
}
|
||||
|
||||
public subshape1(): number {
|
||||
return this.raw.subshape1();
|
||||
}
|
||||
|
||||
public subshape2(): number {
|
||||
return this.raw.subshape2();
|
||||
}
|
||||
|
||||
public numContacts(): number {
|
||||
return this.raw.num_contacts();
|
||||
}
|
||||
|
||||
public localContactPoint1(i: number): Vector | null {
|
||||
return VectorOps.fromRaw(this.raw.contact_local_p1(i));
|
||||
}
|
||||
|
||||
public localContactPoint2(i: number): Vector | null {
|
||||
return VectorOps.fromRaw(this.raw.contact_local_p2(i));
|
||||
}
|
||||
|
||||
public contactDist(i: number): number {
|
||||
return this.raw.contact_dist(i);
|
||||
}
|
||||
|
||||
public contactFid1(i: number): number {
|
||||
return this.raw.contact_fid1(i);
|
||||
}
|
||||
|
||||
public contactFid2(i: number): number {
|
||||
return this.raw.contact_fid2(i);
|
||||
}
|
||||
|
||||
public contactImpulse(i: number): number {
|
||||
return this.raw.contact_impulse(i);
|
||||
}
|
||||
|
||||
// #if DIM2
|
||||
public contactTangentImpulse(i: number): number {
|
||||
return this.raw.contact_tangent_impulse(i);
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #if DIM3
|
||||
public contactTangentImpulseX(i: number): number {
|
||||
return this.raw.contact_tangent_impulse_x(i);
|
||||
}
|
||||
|
||||
public contactTangentImpulseY(i: number): number {
|
||||
return this.raw.contact_tangent_impulse_y(i);
|
||||
}
|
||||
// #endif
|
||||
|
||||
public numSolverContacts(): number {
|
||||
return this.raw.num_solver_contacts();
|
||||
}
|
||||
|
||||
public solverContactPoint(i: number): Vector {
|
||||
return VectorOps.fromRaw(this.raw.solver_contact_point(i));
|
||||
}
|
||||
|
||||
public solverContactDist(i: number): number {
|
||||
return this.raw.solver_contact_dist(i);
|
||||
}
|
||||
|
||||
public solverContactFriction(i: number): number {
|
||||
return this.raw.solver_contact_friction(i);
|
||||
}
|
||||
|
||||
public solverContactRestitution(i: number): number {
|
||||
return this.raw.solver_contact_restitution(i);
|
||||
}
|
||||
|
||||
public solverContactTangentVelocity(i: number): Vector {
|
||||
return VectorOps.fromRaw(this.raw.solver_contact_tangent_velocity(i));
|
||||
}
|
||||
}
|
||||
98
thirdparty/rapier.js/src.ts/geometry/point.ts
vendored
Normal file
98
thirdparty/rapier.js/src.ts/geometry/point.ts
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
import {Collider, ColliderHandle} from "./collider";
|
||||
import {Vector, VectorOps} from "../math";
|
||||
import {
|
||||
RawFeatureType,
|
||||
RawPointColliderProjection,
|
||||
RawPointProjection,
|
||||
} from "../raw";
|
||||
import {FeatureType} from "./feature";
|
||||
import {ColliderSet} from "./collider_set";
|
||||
|
||||
/**
|
||||
* The projection of a point on a collider.
|
||||
*/
|
||||
export class PointProjection {
|
||||
/**
|
||||
* The projection of the point on the collider.
|
||||
*/
|
||||
point: Vector;
|
||||
/**
|
||||
* Is the point inside of the collider?
|
||||
*/
|
||||
isInside: boolean;
|
||||
|
||||
constructor(point: Vector, isInside: boolean) {
|
||||
this.point = point;
|
||||
this.isInside = isInside;
|
||||
}
|
||||
|
||||
public static fromRaw(raw: RawPointProjection): PointProjection {
|
||||
if (!raw) return null;
|
||||
|
||||
const result = new PointProjection(
|
||||
VectorOps.fromRaw(raw.point()),
|
||||
raw.isInside(),
|
||||
);
|
||||
raw.free();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The projection of a point on a collider (includes the collider handle).
|
||||
*/
|
||||
export class PointColliderProjection {
|
||||
/**
|
||||
* The collider hit by the ray.
|
||||
*/
|
||||
collider: Collider;
|
||||
/**
|
||||
* The projection of the point on the collider.
|
||||
*/
|
||||
point: Vector;
|
||||
/**
|
||||
* Is the point inside of the collider?
|
||||
*/
|
||||
isInside: boolean;
|
||||
|
||||
/**
|
||||
* The type of the geometric feature the point was projected on.
|
||||
*/
|
||||
featureType = FeatureType.Unknown;
|
||||
|
||||
/**
|
||||
* The id of the geometric feature the point was projected on.
|
||||
*/
|
||||
featureId: number | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
collider: Collider,
|
||||
point: Vector,
|
||||
isInside: boolean,
|
||||
featureType?: FeatureType,
|
||||
featureId?: number,
|
||||
) {
|
||||
this.collider = collider;
|
||||
this.point = point;
|
||||
this.isInside = isInside;
|
||||
if (featureId !== undefined) this.featureId = featureId;
|
||||
if (featureType !== undefined) this.featureType = featureType;
|
||||
}
|
||||
|
||||
public static fromRaw(
|
||||
colliderSet: ColliderSet,
|
||||
raw: RawPointColliderProjection,
|
||||
): PointColliderProjection {
|
||||
if (!raw) return null;
|
||||
|
||||
const result = new PointColliderProjection(
|
||||
colliderSet.get(raw.colliderHandle()),
|
||||
VectorOps.fromRaw(raw.point()),
|
||||
raw.isInside(),
|
||||
raw.featureType() as number as FeatureType,
|
||||
raw.featureId(),
|
||||
);
|
||||
raw.free();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
192
thirdparty/rapier.js/src.ts/geometry/ray.ts
vendored
Normal file
192
thirdparty/rapier.js/src.ts/geometry/ray.ts
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
import {Vector, VectorOps} from "../math";
|
||||
import {
|
||||
RawFeatureType,
|
||||
RawRayColliderIntersection,
|
||||
RawRayColliderHit,
|
||||
RawRayIntersection,
|
||||
} from "../raw";
|
||||
import {Collider} from "./collider";
|
||||
import {FeatureType} from "./feature";
|
||||
import {ColliderSet} from "./collider_set";
|
||||
|
||||
/**
|
||||
* A ray. This is a directed half-line.
|
||||
*/
|
||||
export class Ray {
|
||||
/**
|
||||
* The starting point of the ray.
|
||||
*/
|
||||
public origin: Vector;
|
||||
/**
|
||||
* The direction of propagation of the ray.
|
||||
*/
|
||||
public dir: Vector;
|
||||
|
||||
/**
|
||||
* Builds a ray from its origin and direction.
|
||||
*
|
||||
* @param origin - The ray's starting point.
|
||||
* @param dir - The ray's direction of propagation.
|
||||
*/
|
||||
constructor(origin: Vector, dir: Vector) {
|
||||
this.origin = origin;
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
public pointAt(t: number): Vector {
|
||||
return {
|
||||
x: this.origin.x + this.dir.x * t,
|
||||
y: this.origin.y + this.dir.y * t,
|
||||
// #if DIM3
|
||||
z: this.origin.z + this.dir.z * t,
|
||||
// #endif
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The intersection between a ray and a collider.
|
||||
*/
|
||||
export class RayIntersection {
|
||||
/**
|
||||
* The time-of-impact of the ray with the collider.
|
||||
*
|
||||
* The hit point is obtained from the ray's origin and direction: `origin + dir * timeOfImpact`.
|
||||
*/
|
||||
timeOfImpact: number;
|
||||
/**
|
||||
* The normal of the collider at the hit point.
|
||||
*/
|
||||
normal: Vector;
|
||||
|
||||
/**
|
||||
* The type of the geometric feature the point was projected on.
|
||||
*/
|
||||
featureType = FeatureType.Unknown;
|
||||
|
||||
/**
|
||||
* The id of the geometric feature the point was projected on.
|
||||
*/
|
||||
featureId: number | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
timeOfImpact: number,
|
||||
normal: Vector,
|
||||
featureType?: FeatureType,
|
||||
featureId?: number,
|
||||
) {
|
||||
this.timeOfImpact = timeOfImpact;
|
||||
this.normal = normal;
|
||||
if (featureId !== undefined) this.featureId = featureId;
|
||||
if (featureType !== undefined) this.featureType = featureType;
|
||||
}
|
||||
|
||||
public static fromRaw(raw: RawRayIntersection): RayIntersection {
|
||||
if (!raw) return null;
|
||||
|
||||
const result = new RayIntersection(
|
||||
raw.time_of_impact(),
|
||||
VectorOps.fromRaw(raw.normal()),
|
||||
raw.featureType() as number as FeatureType,
|
||||
raw.featureId(),
|
||||
);
|
||||
raw.free();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The intersection between a ray and a collider (includes the collider handle).
|
||||
*/
|
||||
export class RayColliderIntersection {
|
||||
/**
|
||||
* The collider hit by the ray.
|
||||
*/
|
||||
collider: Collider;
|
||||
/**
|
||||
* The time-of-impact of the ray with the collider.
|
||||
*
|
||||
* The hit point is obtained from the ray's origin and direction: `origin + dir * timeOfImpact`.
|
||||
*/
|
||||
timeOfImpact: number;
|
||||
/**
|
||||
* The normal of the collider at the hit point.
|
||||
*/
|
||||
normal: Vector;
|
||||
|
||||
/**
|
||||
* The type of the geometric feature the point was projected on.
|
||||
*/
|
||||
featureType = FeatureType.Unknown;
|
||||
|
||||
/**
|
||||
* The id of the geometric feature the point was projected on.
|
||||
*/
|
||||
featureId: number | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
collider: Collider,
|
||||
timeOfImpact: number,
|
||||
normal: Vector,
|
||||
featureType?: FeatureType,
|
||||
featureId?: number,
|
||||
) {
|
||||
this.collider = collider;
|
||||
this.timeOfImpact = timeOfImpact;
|
||||
this.normal = normal;
|
||||
if (featureId !== undefined) this.featureId = featureId;
|
||||
if (featureType !== undefined) this.featureType = featureType;
|
||||
}
|
||||
|
||||
public static fromRaw(
|
||||
colliderSet: ColliderSet,
|
||||
raw: RawRayColliderIntersection,
|
||||
): RayColliderIntersection {
|
||||
if (!raw) return null;
|
||||
|
||||
const result = new RayColliderIntersection(
|
||||
colliderSet.get(raw.colliderHandle()),
|
||||
raw.time_of_impact(),
|
||||
VectorOps.fromRaw(raw.normal()),
|
||||
raw.featureType() as number as FeatureType,
|
||||
raw.featureId(),
|
||||
);
|
||||
raw.free();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The time of impact between a ray and a collider.
|
||||
*/
|
||||
export class RayColliderHit {
|
||||
/**
|
||||
* The handle of the collider hit by the ray.
|
||||
*/
|
||||
collider: Collider;
|
||||
/**
|
||||
* The time-of-impact of the ray with the collider.
|
||||
*
|
||||
* The hit point is obtained from the ray's origin and direction: `origin + dir * timeOfImpact`.
|
||||
*/
|
||||
timeOfImpact: number;
|
||||
|
||||
constructor(collider: Collider, timeOfImpact: number) {
|
||||
this.collider = collider;
|
||||
this.timeOfImpact = timeOfImpact;
|
||||
}
|
||||
|
||||
public static fromRaw(
|
||||
colliderSet: ColliderSet,
|
||||
raw: RawRayColliderHit,
|
||||
): RayColliderHit {
|
||||
if (!raw) return null;
|
||||
|
||||
const result = new RayColliderHit(
|
||||
colliderSet.get(raw.colliderHandle()),
|
||||
raw.timeOfImpact(),
|
||||
);
|
||||
raw.free();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
1558
thirdparty/rapier.js/src.ts/geometry/shape.ts
vendored
Normal file
1558
thirdparty/rapier.js/src.ts/geometry/shape.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
105
thirdparty/rapier.js/src.ts/geometry/toi.ts
vendored
Normal file
105
thirdparty/rapier.js/src.ts/geometry/toi.ts
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
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.
|
||||
*/
|
||||
export class ShapeCastHit {
|
||||
/**
|
||||
* The time of impact of the two shapes.
|
||||
*/
|
||||
time_of_impact: number;
|
||||
/**
|
||||
* The local-space contact point on the first shape, at
|
||||
* the time of impact.
|
||||
*/
|
||||
witness1: Vector;
|
||||
/**
|
||||
* The local-space contact point on the second shape, at
|
||||
* the time of impact.
|
||||
*/
|
||||
witness2: Vector;
|
||||
/**
|
||||
* The local-space normal on the first shape, at
|
||||
* the time of impact.
|
||||
*/
|
||||
normal1: Vector;
|
||||
/**
|
||||
* The local-space normal on the second shape, at
|
||||
* the time of impact.
|
||||
*/
|
||||
normal2: Vector;
|
||||
|
||||
constructor(
|
||||
time_of_impact: number,
|
||||
witness1: Vector,
|
||||
witness2: Vector,
|
||||
normal1: Vector,
|
||||
normal2: Vector,
|
||||
) {
|
||||
this.time_of_impact = time_of_impact;
|
||||
this.witness1 = witness1;
|
||||
this.witness2 = witness2;
|
||||
this.normal1 = normal1;
|
||||
this.normal2 = normal2;
|
||||
}
|
||||
|
||||
public static fromRaw(
|
||||
colliderSet: ColliderSet,
|
||||
raw: RawShapeCastHit,
|
||||
): 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()),
|
||||
);
|
||||
raw.free();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The intersection between a ray and a collider.
|
||||
*/
|
||||
export class ColliderShapeCastHit extends ShapeCastHit {
|
||||
/**
|
||||
* The handle of the collider hit by the ray.
|
||||
*/
|
||||
collider: Collider;
|
||||
|
||||
constructor(
|
||||
collider: Collider,
|
||||
time_of_impact: number,
|
||||
witness1: Vector,
|
||||
witness2: Vector,
|
||||
normal1: Vector,
|
||||
normal2: Vector,
|
||||
) {
|
||||
super(time_of_impact, witness1, witness2, normal1, normal2);
|
||||
this.collider = collider;
|
||||
}
|
||||
|
||||
public static fromRaw(
|
||||
colliderSet: ColliderSet,
|
||||
raw: RawColliderShapeCastHit,
|
||||
): 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()),
|
||||
);
|
||||
raw.free();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
2
thirdparty/rapier.js/src.ts/init.ts
vendored
Normal file
2
thirdparty/rapier.js/src.ts/init.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Placeholder for the `init` function used in rapier-compat.
|
||||
export {};
|
||||
263
thirdparty/rapier.js/src.ts/math.ts
vendored
Normal file
263
thirdparty/rapier.js/src.ts/math.ts
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
import {RawVector, RawRotation} from "./raw";
|
||||
// #if DIM3
|
||||
import {RawSdpMatrix3} from "./raw";
|
||||
// #endif
|
||||
|
||||
// #if DIM2
|
||||
export interface Vector {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A 2D vector.
|
||||
*/
|
||||
export class Vector2 implements Vector {
|
||||
x: number;
|
||||
y: number;
|
||||
|
||||
constructor(x: number, y: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
export class VectorOps {
|
||||
public static new(x: number, y: number): Vector {
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
|
||||
public static zeros(): Vector {
|
||||
return VectorOps.new(0.0, 0.0);
|
||||
}
|
||||
|
||||
// FIXME: type ram: RawVector?
|
||||
public static fromRaw(raw: RawVector): Vector | null {
|
||||
if (!raw) return null;
|
||||
|
||||
let res = VectorOps.new(raw.x, raw.y);
|
||||
raw.free();
|
||||
return res;
|
||||
}
|
||||
|
||||
public static intoRaw(v: Vector): RawVector {
|
||||
return new RawVector(v.x, v.y);
|
||||
}
|
||||
|
||||
public static copy(out: Vector, input: Vector) {
|
||||
out.x = input.x;
|
||||
out.y = input.y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A rotation angle in radians.
|
||||
*/
|
||||
export type Rotation = number;
|
||||
|
||||
export class RotationOps {
|
||||
public static identity(): number {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
public static fromRaw(raw: RawRotation): Rotation | null {
|
||||
if (!raw) return null;
|
||||
|
||||
let res = raw.angle;
|
||||
raw.free();
|
||||
return res;
|
||||
}
|
||||
|
||||
public static intoRaw(angle: Rotation): RawRotation {
|
||||
return RawRotation.fromAngle(angle);
|
||||
}
|
||||
}
|
||||
|
||||
// #endif
|
||||
|
||||
// #if DIM3
|
||||
export interface Vector {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A 3D vector.
|
||||
*/
|
||||
export class Vector3 implements Vector {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
|
||||
constructor(x: number, y: number, z: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
}
|
||||
|
||||
export class VectorOps {
|
||||
public static new(x: number, y: number, z: number): Vector {
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
public static intoRaw(v: Vector): RawVector {
|
||||
return new RawVector(v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
public static zeros(): Vector {
|
||||
return VectorOps.new(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
// FIXME: type ram: RawVector?
|
||||
public static fromRaw(raw: RawVector): Vector | null {
|
||||
if (!raw) return null;
|
||||
|
||||
let res = VectorOps.new(raw.x, raw.y, raw.z);
|
||||
raw.free();
|
||||
return res;
|
||||
}
|
||||
|
||||
public static copy(out: Vector, input: Vector) {
|
||||
out.x = input.x;
|
||||
out.y = input.y;
|
||||
out.z = input.z;
|
||||
}
|
||||
}
|
||||
|
||||
export interface Rotation {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
w: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A quaternion.
|
||||
*/
|
||||
export class Quaternion implements Rotation {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
w: number;
|
||||
|
||||
constructor(x: number, y: number, z: number, w: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
}
|
||||
}
|
||||
|
||||
export class RotationOps {
|
||||
public static identity(): Rotation {
|
||||
return new Quaternion(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
public static fromRaw(raw: RawRotation): Rotation | null {
|
||||
if (!raw) return null;
|
||||
|
||||
let res = new Quaternion(raw.x, raw.y, raw.z, raw.w);
|
||||
raw.free();
|
||||
return res;
|
||||
}
|
||||
|
||||
public static intoRaw(rot: Rotation): RawRotation {
|
||||
return new RawRotation(rot.x, rot.y, rot.z, rot.w);
|
||||
}
|
||||
|
||||
public static copy(out: Rotation, input: Rotation) {
|
||||
out.x = input.x;
|
||||
out.y = input.y;
|
||||
out.z = input.z;
|
||||
out.w = input.w;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A 3D symmetric-positive-definite matrix.
|
||||
*/
|
||||
export class SdpMatrix3 {
|
||||
/**
|
||||
* Row major list of the upper-triangular part of the symmetric matrix.
|
||||
*/
|
||||
elements: Float32Array;
|
||||
|
||||
/**
|
||||
* Matrix element at row 1, column 1.
|
||||
*/
|
||||
public get m11(): number {
|
||||
return this.elements[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Matrix element at row 1, column 2.
|
||||
*/
|
||||
public get m12(): number {
|
||||
return this.elements[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Matrix element at row 2, column 1.
|
||||
*/
|
||||
public get m21(): number {
|
||||
return this.m12;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matrix element at row 1, column 3.
|
||||
*/
|
||||
public get m13(): number {
|
||||
return this.elements[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Matrix element at row 3, column 1.
|
||||
*/
|
||||
public get m31(): number {
|
||||
return this.m13;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matrix element at row 2, column 2.
|
||||
*/
|
||||
public get m22(): number {
|
||||
return this.elements[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* Matrix element at row 2, column 3.
|
||||
*/
|
||||
public get m23(): number {
|
||||
return this.elements[4];
|
||||
}
|
||||
|
||||
/**
|
||||
* Matrix element at row 3, column 2.
|
||||
*/
|
||||
public get m32(): number {
|
||||
return this.m23;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matrix element at row 3, column 3.
|
||||
*/
|
||||
public get m33(): number {
|
||||
return this.elements[5];
|
||||
}
|
||||
|
||||
constructor(elements: Float32Array) {
|
||||
this.elements = elements;
|
||||
}
|
||||
}
|
||||
|
||||
export class SdpMatrix3Ops {
|
||||
public static fromRaw(raw: RawSdpMatrix3): SdpMatrix3 {
|
||||
const sdpMatrix3 = new SdpMatrix3(raw.elements());
|
||||
raw.free();
|
||||
return sdpMatrix3;
|
||||
}
|
||||
}
|
||||
|
||||
// #endif
|
||||
85
thirdparty/rapier.js/src.ts/pipeline/debug_render_pipeline.ts
vendored
Normal file
85
thirdparty/rapier.js/src.ts/pipeline/debug_render_pipeline.ts
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
import {RawDebugRenderPipeline} from "../raw";
|
||||
import {Vector, VectorOps} from "../math";
|
||||
import {
|
||||
IntegrationParameters,
|
||||
IslandManager,
|
||||
ImpulseJointSet,
|
||||
MultibodyJointSet,
|
||||
RigidBodySet,
|
||||
} from "../dynamics";
|
||||
import {BroadPhase, Collider, ColliderSet, NarrowPhase} from "../geometry";
|
||||
import {QueryFilterFlags} from "./query_pipeline";
|
||||
|
||||
/**
|
||||
* The vertex and color buffers for debug-redering the physics scene.
|
||||
*/
|
||||
export class DebugRenderBuffers {
|
||||
/**
|
||||
* The lines to render. This is a flat array containing all the lines
|
||||
* to render. Each line is described as two consecutive point. Each
|
||||
* point is described as two (in 2D) or three (in 3D) consecutive
|
||||
* floats. For example, in 2D, the array: `[1, 2, 3, 4, 5, 6, 7, 8]`
|
||||
* describes the two segments `[[1, 2], [3, 4]]` and `[[5, 6], [7, 8]]`.
|
||||
*/
|
||||
public vertices: Float32Array;
|
||||
/**
|
||||
* The color buffer. There is one color per vertex, and each color
|
||||
* has four consecutive components (in RGBA format).
|
||||
*/
|
||||
public colors: Float32Array;
|
||||
|
||||
constructor(vertices: Float32Array, colors: Float32Array) {
|
||||
this.vertices = vertices;
|
||||
this.colors = colors;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A pipeline for rendering the physics scene.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `debugRenderPipeline.free()`
|
||||
* once you are done using it (and all the rigid-bodies it created).
|
||||
*/
|
||||
export class DebugRenderPipeline {
|
||||
raw: RawDebugRenderPipeline;
|
||||
public vertices: Float32Array;
|
||||
public colors: Float32Array;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this serialization pipeline.
|
||||
*/
|
||||
free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
this.vertices = undefined;
|
||||
this.colors = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawDebugRenderPipeline) {
|
||||
this.raw = raw || new RawDebugRenderPipeline();
|
||||
}
|
||||
|
||||
public render(
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
impulse_joints: ImpulseJointSet,
|
||||
multibody_joints: MultibodyJointSet,
|
||||
narrow_phase: NarrowPhase,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterPredicate?: (collider: Collider) => boolean,
|
||||
) {
|
||||
this.raw.render(
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
impulse_joints.raw,
|
||||
multibody_joints.raw,
|
||||
narrow_phase.raw,
|
||||
filterFlags,
|
||||
colliders.castClosure(filterPredicate),
|
||||
);
|
||||
this.vertices = this.raw.vertices();
|
||||
this.colors = this.raw.colors();
|
||||
}
|
||||
}
|
||||
158
thirdparty/rapier.js/src.ts/pipeline/event_queue.ts
vendored
Normal file
158
thirdparty/rapier.js/src.ts/pipeline/event_queue.ts
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
import {RawContactForceEvent, RawEventQueue} from "../raw";
|
||||
import {RigidBodyHandle} from "../dynamics";
|
||||
import {Collider, ColliderHandle} from "../geometry";
|
||||
import {Vector, VectorOps} from "../math";
|
||||
|
||||
/**
|
||||
* Flags indicating what events are enabled for colliders.
|
||||
*/
|
||||
export enum ActiveEvents {
|
||||
NONE = 0,
|
||||
/**
|
||||
* Enable collision events.
|
||||
*/
|
||||
COLLISION_EVENTS = 0b0001,
|
||||
/**
|
||||
* Enable contact force events.
|
||||
*/
|
||||
CONTACT_FORCE_EVENTS = 0b0010,
|
||||
}
|
||||
|
||||
/**
|
||||
* Event occurring when the sum of the magnitudes of the
|
||||
* contact forces between two colliders exceed a threshold.
|
||||
*
|
||||
* This object should **not** be stored anywhere. Its properties can only be
|
||||
* read from within the closure given to `EventHandler.drainContactForceEvents`.
|
||||
*/
|
||||
export class TempContactForceEvent {
|
||||
raw: RawContactForceEvent;
|
||||
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The first collider involved in the contact.
|
||||
*/
|
||||
public collider1(): ColliderHandle {
|
||||
return this.raw.collider1();
|
||||
}
|
||||
|
||||
/**
|
||||
* The second collider involved in the contact.
|
||||
*/
|
||||
public collider2(): ColliderHandle {
|
||||
return this.raw.collider2();
|
||||
}
|
||||
|
||||
/**
|
||||
* The sum of all the forces between the two colliders.
|
||||
*/
|
||||
public totalForce(): Vector {
|
||||
return VectorOps.fromRaw(this.raw.total_force());
|
||||
}
|
||||
|
||||
/**
|
||||
* The sum of the magnitudes of each force between the two colliders.
|
||||
*
|
||||
* Note that this is **not** the same as the magnitude of `self.total_force`.
|
||||
* Here we are summing the magnitude of all the forces, instead of taking
|
||||
* the magnitude of their sum.
|
||||
*/
|
||||
public totalForceMagnitude(): number {
|
||||
return this.raw.total_force_magnitude();
|
||||
}
|
||||
|
||||
/**
|
||||
* The world-space (unit) direction of the force with strongest magnitude.
|
||||
*/
|
||||
public maxForceDirection(): Vector {
|
||||
return VectorOps.fromRaw(this.raw.max_force_direction());
|
||||
}
|
||||
|
||||
/**
|
||||
* The magnitude of the largest force at a contact point of this contact pair.
|
||||
*/
|
||||
public maxForceMagnitude(): number {
|
||||
return this.raw.max_force_magnitude();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A structure responsible for collecting events generated
|
||||
* by the physics engine.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `eventQueue.free()`
|
||||
* once you are done using it.
|
||||
*/
|
||||
export class EventQueue {
|
||||
raw: RawEventQueue;
|
||||
|
||||
/**
|
||||
* Creates a new event collector.
|
||||
*
|
||||
* @param autoDrain -setting this to `true` is strongly recommended. If true, the collector will
|
||||
* be automatically drained before each `world.step(collector)`. If false, the collector will
|
||||
* keep all events in memory unless it is manually drained/cleared; this may lead to unbounded use of
|
||||
* RAM if no drain is performed.
|
||||
*/
|
||||
constructor(autoDrain: boolean, raw?: RawEventQueue) {
|
||||
this.raw = raw || new RawEventQueue(autoDrain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this event-queue.
|
||||
*/
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given javascript closure on each collision event of this collector, then clear
|
||||
* the internal collision event buffer.
|
||||
*
|
||||
* @param f - JavaScript closure applied to each collision event. The
|
||||
* closure must take three arguments: two integers representing the handles of the colliders
|
||||
* involved in the collision, and a boolean indicating if the collision started (true) or stopped
|
||||
* (false).
|
||||
*/
|
||||
public drainCollisionEvents(
|
||||
f: (
|
||||
handle1: ColliderHandle,
|
||||
handle2: ColliderHandle,
|
||||
started: boolean,
|
||||
) => void,
|
||||
) {
|
||||
this.raw.drainCollisionEvents(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given javascript closure on each contact force event of this collector, then clear
|
||||
* the internal collision event buffer.
|
||||
*
|
||||
* @param f - JavaScript closure applied to each collision event. The
|
||||
* closure must take one `TempContactForceEvent` argument.
|
||||
*/
|
||||
public drainContactForceEvents(f: (event: TempContactForceEvent) => void) {
|
||||
let event = new TempContactForceEvent();
|
||||
this.raw.drainContactForceEvents((raw: RawContactForceEvent) => {
|
||||
event.raw = raw;
|
||||
f(event);
|
||||
event.free();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all events contained by this collector
|
||||
*/
|
||||
public clear() {
|
||||
this.raw.clear();
|
||||
}
|
||||
}
|
||||
7
thirdparty/rapier.js/src.ts/pipeline/index.ts
vendored
Normal file
7
thirdparty/rapier.js/src.ts/pipeline/index.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export * from "./world";
|
||||
export * from "./physics_pipeline";
|
||||
export * from "./serialization_pipeline";
|
||||
export * from "./event_queue";
|
||||
export * from "./physics_hooks";
|
||||
export * from "./debug_render_pipeline";
|
||||
export * from "./query_pipeline";
|
||||
54
thirdparty/rapier.js/src.ts/pipeline/physics_hooks.ts
vendored
Normal file
54
thirdparty/rapier.js/src.ts/pipeline/physics_hooks.ts
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
import {RigidBodyHandle} from "../dynamics";
|
||||
import {ColliderHandle} from "../geometry";
|
||||
|
||||
export enum ActiveHooks {
|
||||
NONE = 0,
|
||||
FILTER_CONTACT_PAIRS = 0b0001,
|
||||
FILTER_INTERSECTION_PAIRS = 0b0010,
|
||||
// MODIFY_SOLVER_CONTACTS = 0b0100, /* Not supported yet in JS. */
|
||||
}
|
||||
|
||||
export enum SolverFlags {
|
||||
EMPTY = 0b000,
|
||||
COMPUTE_IMPULSE = 0b001,
|
||||
}
|
||||
|
||||
export interface PhysicsHooks {
|
||||
/**
|
||||
* Function that determines if contacts computation should happen between two colliders, and how the
|
||||
* constraints solver should behave for these contacts.
|
||||
*
|
||||
* This will only be executed and taken into account if at least one of the involved colliders contains the
|
||||
* `ActiveHooks.FILTER_CONTACT_PAIR` flag in its active hooks.
|
||||
*
|
||||
* @param collider1 − Handle of the first collider involved in the potential contact.
|
||||
* @param collider2 − Handle of the second collider involved in the potential contact.
|
||||
* @param body1 − Handle of the first body involved in the potential contact.
|
||||
* @param body2 − Handle of the second body involved in the potential contact.
|
||||
*/
|
||||
filterContactPair(
|
||||
collider1: ColliderHandle,
|
||||
collider2: ColliderHandle,
|
||||
body1: RigidBodyHandle,
|
||||
body2: RigidBodyHandle,
|
||||
): SolverFlags | null;
|
||||
|
||||
/**
|
||||
* Function that determines if intersection computation should happen between two colliders (where at least
|
||||
* one is a sensor).
|
||||
*
|
||||
* This will only be executed and taken into account if `one of the involved colliders contains the
|
||||
* `ActiveHooks.FILTER_INTERSECTION_PAIR` flag in its active hooks.
|
||||
*
|
||||
* @param collider1 − Handle of the first collider involved in the potential contact.
|
||||
* @param collider2 − Handle of the second collider involved in the potential contact.
|
||||
* @param body1 − Handle of the first body involved in the potential contact.
|
||||
* @param body2 − Handle of the second body involved in the potential contact.
|
||||
*/
|
||||
filterIntersectionPair(
|
||||
collider1: ColliderHandle,
|
||||
collider2: ColliderHandle,
|
||||
body1: RigidBodyHandle,
|
||||
body2: RigidBodyHandle,
|
||||
): boolean;
|
||||
}
|
||||
85
thirdparty/rapier.js/src.ts/pipeline/physics_pipeline.ts
vendored
Normal file
85
thirdparty/rapier.js/src.ts/pipeline/physics_pipeline.ts
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
import {RawPhysicsPipeline} from "../raw";
|
||||
import {Vector, VectorOps} from "../math";
|
||||
import {
|
||||
IntegrationParameters,
|
||||
ImpulseJointSet,
|
||||
MultibodyJointSet,
|
||||
RigidBodyHandle,
|
||||
RigidBodySet,
|
||||
CCDSolver,
|
||||
IslandManager,
|
||||
} from "../dynamics";
|
||||
import {
|
||||
BroadPhase,
|
||||
ColliderHandle,
|
||||
ColliderSet,
|
||||
NarrowPhase,
|
||||
} from "../geometry";
|
||||
import {EventQueue} from "./event_queue";
|
||||
import {PhysicsHooks} from "./physics_hooks";
|
||||
|
||||
export class PhysicsPipeline {
|
||||
raw: RawPhysicsPipeline;
|
||||
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawPhysicsPipeline) {
|
||||
this.raw = raw || new RawPhysicsPipeline();
|
||||
}
|
||||
|
||||
public step(
|
||||
gravity: Vector,
|
||||
integrationParameters: IntegrationParameters,
|
||||
islands: IslandManager,
|
||||
broadPhase: BroadPhase,
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
impulseJoints: ImpulseJointSet,
|
||||
multibodyJoints: MultibodyJointSet,
|
||||
ccdSolver: CCDSolver,
|
||||
eventQueue?: EventQueue,
|
||||
hooks?: PhysicsHooks,
|
||||
) {
|
||||
let rawG = VectorOps.intoRaw(gravity);
|
||||
|
||||
if (!!eventQueue) {
|
||||
this.raw.stepWithEvents(
|
||||
rawG,
|
||||
integrationParameters.raw,
|
||||
islands.raw,
|
||||
broadPhase.raw,
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
impulseJoints.raw,
|
||||
multibodyJoints.raw,
|
||||
ccdSolver.raw,
|
||||
eventQueue.raw,
|
||||
hooks,
|
||||
!!hooks ? hooks.filterContactPair : null,
|
||||
!!hooks ? hooks.filterIntersectionPair : null,
|
||||
);
|
||||
} else {
|
||||
this.raw.step(
|
||||
rawG,
|
||||
integrationParameters.raw,
|
||||
islands.raw,
|
||||
broadPhase.raw,
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
impulseJoints.raw,
|
||||
multibodyJoints.raw,
|
||||
ccdSolver.raw,
|
||||
);
|
||||
}
|
||||
|
||||
rawG.free();
|
||||
}
|
||||
}
|
||||
57
thirdparty/rapier.js/src.ts/pipeline/query_pipeline.ts
vendored
Normal file
57
thirdparty/rapier.js/src.ts/pipeline/query_pipeline.ts
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
import {RawRayColliderIntersection} from "../raw";
|
||||
import {
|
||||
ColliderHandle,
|
||||
ColliderSet,
|
||||
InteractionGroups,
|
||||
PointColliderProjection,
|
||||
Ray,
|
||||
RayColliderIntersection,
|
||||
RayColliderHit,
|
||||
Shape,
|
||||
ColliderShapeCastHit,
|
||||
} from "../geometry";
|
||||
import {IslandManager, RigidBodyHandle, RigidBodySet} from "../dynamics";
|
||||
import {Rotation, RotationOps, Vector, VectorOps} from "../math";
|
||||
|
||||
// NOTE: must match the bits in the QueryFilterFlags on the Rust side.
|
||||
/**
|
||||
* Flags for excluding whole sets of colliders from a scene query.
|
||||
*/
|
||||
export enum QueryFilterFlags {
|
||||
/**
|
||||
* Exclude from the query any collider attached to a fixed rigid-body and colliders with no rigid-body attached.
|
||||
*/
|
||||
EXCLUDE_FIXED = 0b0000_0001,
|
||||
/**
|
||||
* Exclude from the query any collider attached to a dynamic rigid-body.
|
||||
*/
|
||||
EXCLUDE_KINEMATIC = 0b0000_0010,
|
||||
/**
|
||||
* Exclude from the query any collider attached to a kinematic rigid-body.
|
||||
*/
|
||||
EXCLUDE_DYNAMIC = 0b0000_0100,
|
||||
/**
|
||||
* Exclude from the query any collider that is a sensor.
|
||||
*/
|
||||
EXCLUDE_SENSORS = 0b0000_1000,
|
||||
/**
|
||||
* Exclude from the query any collider that is not a sensor.
|
||||
*/
|
||||
EXCLUDE_SOLIDS = 0b0001_0000,
|
||||
/**
|
||||
* Excludes all colliders not attached to a dynamic rigid-body.
|
||||
*/
|
||||
ONLY_DYNAMIC = QueryFilterFlags.EXCLUDE_FIXED |
|
||||
QueryFilterFlags.EXCLUDE_KINEMATIC,
|
||||
/**
|
||||
* Excludes all colliders not attached to a kinematic rigid-body.
|
||||
*/
|
||||
ONLY_KINEMATIC = QueryFilterFlags.EXCLUDE_DYNAMIC |
|
||||
QueryFilterFlags.EXCLUDE_FIXED,
|
||||
/**
|
||||
* Exclude all colliders attached to a non-fixed rigid-body
|
||||
* (this will not exclude colliders not attached to any rigid-body).
|
||||
*/
|
||||
ONLY_FIXED = QueryFilterFlags.EXCLUDE_DYNAMIC |
|
||||
QueryFilterFlags.EXCLUDE_KINEMATIC,
|
||||
}
|
||||
84
thirdparty/rapier.js/src.ts/pipeline/serialization_pipeline.ts
vendored
Normal file
84
thirdparty/rapier.js/src.ts/pipeline/serialization_pipeline.ts
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
import {RawSerializationPipeline} from "../raw";
|
||||
import {Vector, VectorOps} from "../math";
|
||||
import {
|
||||
IntegrationParameters,
|
||||
IslandManager,
|
||||
ImpulseJointSet,
|
||||
MultibodyJointSet,
|
||||
RigidBodySet,
|
||||
} from "../dynamics";
|
||||
import {BroadPhase, ColliderSet, NarrowPhase} from "../geometry";
|
||||
import {World} from "./world";
|
||||
|
||||
/**
|
||||
* A pipeline for serializing the physics scene.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `serializationPipeline.free()`
|
||||
* once you are done using it (and all the rigid-bodies it created).
|
||||
*/
|
||||
export class SerializationPipeline {
|
||||
raw: RawSerializationPipeline;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this serialization pipeline.
|
||||
*/
|
||||
free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawSerializationPipeline) {
|
||||
this.raw = raw || new RawSerializationPipeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a complete physics state into a single byte array.
|
||||
* @param gravity - The current gravity affecting the simulation.
|
||||
* @param integrationParameters - The integration parameters of the simulation.
|
||||
* @param broadPhase - The broad-phase of the simulation.
|
||||
* @param narrowPhase - The narrow-phase of the simulation.
|
||||
* @param bodies - The rigid-bodies taking part into the simulation.
|
||||
* @param colliders - The colliders taking part into the simulation.
|
||||
* @param impulseJoints - The impulse joints taking part into the simulation.
|
||||
* @param multibodyJoints - The multibody joints taking part into the simulation.
|
||||
*/
|
||||
public serializeAll(
|
||||
gravity: Vector,
|
||||
integrationParameters: IntegrationParameters,
|
||||
islands: IslandManager,
|
||||
broadPhase: BroadPhase,
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
impulseJoints: ImpulseJointSet,
|
||||
multibodyJoints: MultibodyJointSet,
|
||||
): Uint8Array {
|
||||
let rawGra = VectorOps.intoRaw(gravity);
|
||||
|
||||
const res = this.raw.serializeAll(
|
||||
rawGra,
|
||||
integrationParameters.raw,
|
||||
islands.raw,
|
||||
broadPhase.raw,
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
impulseJoints.raw,
|
||||
multibodyJoints.raw,
|
||||
);
|
||||
rawGra.free();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize the complete physics state from a single byte array.
|
||||
*
|
||||
* @param data - The byte array to deserialize.
|
||||
*/
|
||||
public deserializeAll(data: Uint8Array): World {
|
||||
return World.fromRaw(this.raw.deserializeAll(data));
|
||||
}
|
||||
}
|
||||
1312
thirdparty/rapier.js/src.ts/pipeline/world.ts
vendored
Normal file
1312
thirdparty/rapier.js/src.ts/pipeline/world.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3
thirdparty/rapier.js/src.ts/rapier.ts
vendored
Normal file
3
thirdparty/rapier.js/src.ts/rapier.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import * as RAPIER from "./exports";
|
||||
export * from "./exports";
|
||||
export default RAPIER;
|
||||
1
thirdparty/rapier.js/src.ts/raw.ts
vendored
Normal file
1
thirdparty/rapier.js/src.ts/raw.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from "../rapier3d/pkg/rapier_wasm3d";
|
||||
290
thirdparty/rapier.js/src/control/character_controller.rs
vendored
Normal file
290
thirdparty/rapier.js/src/control/character_controller.rs
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
use crate::dynamics::RawRigidBodySet;
|
||||
use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase};
|
||||
use crate::math::RawVector;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use na::{Isometry, Unit};
|
||||
use rapier::control::{
|
||||
CharacterAutostep, CharacterCollision, CharacterLength, EffectiveCharacterMovement,
|
||||
KinematicCharacterController,
|
||||
};
|
||||
use rapier::geometry::{ColliderHandle, ShapeCastHit};
|
||||
use rapier::math::{Point, Real, Vector};
|
||||
use rapier::parry::query::ShapeCastStatus;
|
||||
use rapier::pipeline::{QueryFilter, QueryFilterFlags};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawKinematicCharacterController {
|
||||
controller: KinematicCharacterController,
|
||||
result: EffectiveCharacterMovement,
|
||||
events: Vec<CharacterCollision>,
|
||||
}
|
||||
|
||||
fn length_value(length: CharacterLength) -> Real {
|
||||
match length {
|
||||
CharacterLength::Absolute(val) => val,
|
||||
CharacterLength::Relative(val) => val,
|
||||
}
|
||||
}
|
||||
#[wasm_bindgen]
|
||||
impl RawKinematicCharacterController {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(offset: Real) -> Self {
|
||||
let controller = KinematicCharacterController {
|
||||
offset: CharacterLength::Absolute(offset),
|
||||
autostep: None,
|
||||
snap_to_ground: None,
|
||||
..KinematicCharacterController::default()
|
||||
};
|
||||
|
||||
Self {
|
||||
controller,
|
||||
result: EffectiveCharacterMovement {
|
||||
translation: Vector::zeros(),
|
||||
grounded: false,
|
||||
is_sliding_down_slope: false,
|
||||
},
|
||||
events: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn up(&self) -> RawVector {
|
||||
self.controller.up.into_inner().into()
|
||||
}
|
||||
|
||||
pub fn setUp(&mut self, vector: &RawVector) {
|
||||
self.controller.up = Unit::new_normalize(vector.0);
|
||||
}
|
||||
|
||||
pub fn normalNudgeFactor(&self) -> Real {
|
||||
self.controller.normal_nudge_factor
|
||||
}
|
||||
|
||||
pub fn setNormalNudgeFactor(&mut self, value: Real) {
|
||||
self.controller.normal_nudge_factor = value;
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> Real {
|
||||
length_value(self.controller.offset)
|
||||
}
|
||||
|
||||
pub fn setOffset(&mut self, value: Real) {
|
||||
self.controller.offset = CharacterLength::Absolute(value);
|
||||
}
|
||||
|
||||
pub fn slideEnabled(&self) -> bool {
|
||||
self.controller.slide
|
||||
}
|
||||
|
||||
pub fn setSlideEnabled(&mut self, enabled: bool) {
|
||||
self.controller.slide = enabled
|
||||
}
|
||||
|
||||
pub fn autostepMaxHeight(&self) -> Option<Real> {
|
||||
self.controller.autostep.map(|e| length_value(e.max_height))
|
||||
}
|
||||
|
||||
pub fn autostepMinWidth(&self) -> Option<Real> {
|
||||
self.controller.autostep.map(|e| length_value(e.min_width))
|
||||
}
|
||||
|
||||
pub fn autostepIncludesDynamicBodies(&self) -> Option<bool> {
|
||||
self.controller.autostep.map(|e| e.include_dynamic_bodies)
|
||||
}
|
||||
|
||||
pub fn autostepEnabled(&self) -> bool {
|
||||
self.controller.autostep.is_some()
|
||||
}
|
||||
|
||||
pub fn enableAutostep(&mut self, maxHeight: Real, minWidth: Real, includeDynamicBodies: bool) {
|
||||
self.controller.autostep = Some(CharacterAutostep {
|
||||
min_width: CharacterLength::Absolute(minWidth),
|
||||
max_height: CharacterLength::Absolute(maxHeight),
|
||||
include_dynamic_bodies: includeDynamicBodies,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn disableAutostep(&mut self) {
|
||||
self.controller.autostep = None;
|
||||
}
|
||||
|
||||
pub fn maxSlopeClimbAngle(&self) -> Real {
|
||||
self.controller.max_slope_climb_angle
|
||||
}
|
||||
|
||||
pub fn setMaxSlopeClimbAngle(&mut self, angle: Real) {
|
||||
self.controller.max_slope_climb_angle = angle;
|
||||
}
|
||||
|
||||
pub fn minSlopeSlideAngle(&self) -> Real {
|
||||
self.controller.min_slope_slide_angle
|
||||
}
|
||||
|
||||
pub fn setMinSlopeSlideAngle(&mut self, angle: Real) {
|
||||
self.controller.min_slope_slide_angle = angle
|
||||
}
|
||||
|
||||
pub fn snapToGroundDistance(&self) -> Option<Real> {
|
||||
self.controller.snap_to_ground.map(length_value)
|
||||
}
|
||||
|
||||
pub fn enableSnapToGround(&mut self, distance: Real) {
|
||||
self.controller.snap_to_ground = Some(CharacterLength::Absolute(distance));
|
||||
}
|
||||
|
||||
pub fn disableSnapToGround(&mut self) {
|
||||
self.controller.snap_to_ground = None;
|
||||
}
|
||||
|
||||
pub fn snapToGroundEnabled(&self) -> bool {
|
||||
self.controller.snap_to_ground.is_some()
|
||||
}
|
||||
|
||||
pub fn computeColliderMovement(
|
||||
&mut self,
|
||||
dt: Real,
|
||||
broad_phase: &RawBroadPhase,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
colliders: &mut RawColliderSet,
|
||||
collider_handle: FlatHandle,
|
||||
desired_translation_delta: &RawVector,
|
||||
apply_impulses_to_dynamic_bodies: bool,
|
||||
character_mass: Option<Real>,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) {
|
||||
let handle = crate::utils::collider_handle(collider_handle);
|
||||
if let Some(collider) = colliders.0.get(handle) {
|
||||
let collider_pose = *collider.position();
|
||||
let collider_shape = collider.shared_shape().clone();
|
||||
let collider_parent = collider.parent();
|
||||
|
||||
crate::utils::with_filter(filter_predicate, |predicate| {
|
||||
let query_filter = QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: filter_groups.map(crate::geometry::unpack_interaction_groups),
|
||||
exclude_collider: Some(handle),
|
||||
exclude_rigid_body: collider_parent,
|
||||
predicate,
|
||||
};
|
||||
|
||||
let character_mass = character_mass
|
||||
.or_else(|| {
|
||||
collider_parent
|
||||
.and_then(|h| bodies.0.get(h))
|
||||
.map(|b| b.mass())
|
||||
})
|
||||
.unwrap_or(0.0);
|
||||
|
||||
let mut query_pipeline = broad_phase.0.as_query_pipeline_mut(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&mut bodies.0,
|
||||
&mut colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
self.events.clear();
|
||||
let events = &mut self.events;
|
||||
self.result = self.controller.move_shape(
|
||||
dt,
|
||||
&query_pipeline.as_ref(),
|
||||
&*collider_shape,
|
||||
&collider_pose,
|
||||
desired_translation_delta.0,
|
||||
|event| events.push(event),
|
||||
);
|
||||
|
||||
if apply_impulses_to_dynamic_bodies {
|
||||
self.controller.solve_character_collision_impulses(
|
||||
dt,
|
||||
&mut query_pipeline,
|
||||
&*collider_shape,
|
||||
character_mass,
|
||||
self.events.iter(),
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.result.translation.fill(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn computedMovement(&self) -> RawVector {
|
||||
self.result.translation.into()
|
||||
}
|
||||
|
||||
pub fn computedGrounded(&self) -> bool {
|
||||
self.result.grounded
|
||||
}
|
||||
|
||||
pub fn numComputedCollisions(&self) -> usize {
|
||||
self.events.len()
|
||||
}
|
||||
|
||||
pub fn computedCollision(&self, i: usize, collision: &mut RawCharacterCollision) -> bool {
|
||||
if let Some(coll) = self.events.get(i) {
|
||||
collision.0 = *coll;
|
||||
}
|
||||
|
||||
i < self.events.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawCharacterCollision(CharacterCollision);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawCharacterCollision {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Self(CharacterCollision {
|
||||
handle: ColliderHandle::invalid(),
|
||||
character_pos: Isometry::identity(),
|
||||
translation_applied: Vector::zeros(),
|
||||
translation_remaining: Vector::zeros(),
|
||||
hit: ShapeCastHit {
|
||||
time_of_impact: 0.0,
|
||||
witness1: Point::origin(),
|
||||
witness2: Point::origin(),
|
||||
normal1: Vector::y_axis(),
|
||||
normal2: Vector::y_axis(),
|
||||
status: ShapeCastStatus::Failed,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn handle(&self) -> FlatHandle {
|
||||
utils::flat_handle(self.0.handle.0)
|
||||
}
|
||||
|
||||
pub fn translationDeltaApplied(&self) -> RawVector {
|
||||
self.0.translation_applied.into()
|
||||
}
|
||||
|
||||
pub fn translationDeltaRemaining(&self) -> RawVector {
|
||||
self.0.translation_remaining.into()
|
||||
}
|
||||
|
||||
pub fn toi(&self) -> Real {
|
||||
self.0.hit.time_of_impact
|
||||
}
|
||||
|
||||
pub fn worldWitness1(&self) -> RawVector {
|
||||
self.0.hit.witness1.coords.into() // Already in world-space.
|
||||
}
|
||||
|
||||
pub fn worldWitness2(&self) -> RawVector {
|
||||
(self.0.character_pos * self.0.hit.witness2).coords.into()
|
||||
}
|
||||
|
||||
pub fn worldNormal1(&self) -> RawVector {
|
||||
self.0.hit.normal1.into_inner().into() // Already in world-space.
|
||||
}
|
||||
|
||||
pub fn worldNormal2(&self) -> RawVector {
|
||||
(self.0.character_pos * self.0.hit.normal2.into_inner()).into()
|
||||
}
|
||||
}
|
||||
11
thirdparty/rapier.js/src/control/mod.rs
vendored
Normal file
11
thirdparty/rapier.js/src/control/mod.rs
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
pub use self::character_controller::RawKinematicCharacterController;
|
||||
pub use self::pid_controller::RawPidController;
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub use self::ray_cast_vehicle_controller::RawDynamicRayCastVehicleController;
|
||||
|
||||
mod character_controller;
|
||||
mod pid_controller;
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
mod ray_cast_vehicle_controller;
|
||||
264
thirdparty/rapier.js/src/control/pid_controller.rs
vendored
Normal file
264
thirdparty/rapier.js/src/control/pid_controller.rs
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
use crate::dynamics::RawRigidBodySet;
|
||||
use crate::math::RawVector;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::control::PidController;
|
||||
use rapier::dynamics::AxesMask;
|
||||
use rapier::math::Vector;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
use crate::math::RawRotation;
|
||||
#[cfg(feature = "dim2")]
|
||||
use rapier::math::Rotation;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawPidController {
|
||||
controller: PidController,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawPidController {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(kp: f32, ki: f32, kd: f32, axes_mask: u8) -> Self {
|
||||
let controller = PidController::new(
|
||||
kp,
|
||||
ki,
|
||||
kd,
|
||||
AxesMask::from_bits(axes_mask).unwrap_or(AxesMask::all()),
|
||||
);
|
||||
Self { controller }
|
||||
}
|
||||
|
||||
pub fn set_kp(&mut self, kp: f32, axes: u8) {
|
||||
let axes = AxesMask::from_bits(axes).unwrap_or(AxesMask::all());
|
||||
if axes.contains(AxesMask::LIN_X) {
|
||||
self.controller.pd.lin_kp.x = kp;
|
||||
}
|
||||
if axes.contains(AxesMask::LIN_Y) {
|
||||
self.controller.pd.lin_kp.y = kp;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::LIN_Z) {
|
||||
self.controller.pd.lin_kp.z = kp;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_X) {
|
||||
self.controller.pd.ang_kp.x = kp;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_Y) {
|
||||
self.controller.pd.ang_kp.y = kp;
|
||||
}
|
||||
if axes.contains(AxesMask::ANG_Z) {
|
||||
#[cfg(feature = "dim2")]
|
||||
{
|
||||
self.controller.pd.ang_kp = kp;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
{
|
||||
self.controller.pd.ang_kp.z = kp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_ki(&mut self, ki: f32, axes: u8) {
|
||||
let axes = AxesMask::from_bits(axes).unwrap_or(AxesMask::all());
|
||||
if axes.contains(AxesMask::LIN_X) {
|
||||
self.controller.lin_ki.x = ki;
|
||||
}
|
||||
if axes.contains(AxesMask::LIN_Y) {
|
||||
self.controller.lin_ki.y = ki;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::LIN_Z) {
|
||||
self.controller.lin_ki.z = ki;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_X) {
|
||||
self.controller.ang_ki.x = ki;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_Y) {
|
||||
self.controller.ang_ki.y = ki;
|
||||
}
|
||||
if axes.contains(AxesMask::ANG_Z) {
|
||||
#[cfg(feature = "dim2")]
|
||||
{
|
||||
self.controller.ang_ki = ki;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
{
|
||||
self.controller.ang_ki.z = ki;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_kd(&mut self, kd: f32, axes: u8) {
|
||||
let axes = AxesMask::from_bits(axes).unwrap_or(AxesMask::all());
|
||||
if axes.contains(AxesMask::LIN_X) {
|
||||
self.controller.pd.lin_kd.x = kd;
|
||||
}
|
||||
if axes.contains(AxesMask::LIN_Y) {
|
||||
self.controller.pd.lin_kd.x = kd;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::LIN_Z) {
|
||||
self.controller.pd.lin_kd.x = kd;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_X) {
|
||||
self.controller.pd.ang_kd.x = kd;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
if axes.contains(AxesMask::ANG_Y) {
|
||||
self.controller.pd.ang_kd.y = kd;
|
||||
}
|
||||
if axes.contains(AxesMask::ANG_Z) {
|
||||
#[cfg(feature = "dim2")]
|
||||
{
|
||||
self.controller.pd.ang_kd = kd;
|
||||
}
|
||||
#[cfg(feature = "dim3")]
|
||||
{
|
||||
self.controller.pd.ang_kd.z = kd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_axes_mask(&mut self, axes_mask: u8) {
|
||||
if let Some(mask) = AxesMask::from_bits(axes_mask) {
|
||||
self.controller.pd.axes = mask;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_integrals(&mut self) {
|
||||
self.controller.reset_integrals();
|
||||
}
|
||||
|
||||
pub fn apply_linear_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_translation: &RawVector,
|
||||
target_linvel: &RawVector,
|
||||
) {
|
||||
let rb_handle = utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get_mut(rb_handle) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let correction = self.controller.linear_rigid_body_correction(
|
||||
dt,
|
||||
rb,
|
||||
target_translation.0.into(),
|
||||
target_linvel.0,
|
||||
);
|
||||
rb.set_linvel(*rb.linvel() + correction, true);
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn apply_angular_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_rotation: f32,
|
||||
target_angvel: f32,
|
||||
) {
|
||||
let rb_handle = crate::utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get_mut(rb_handle) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let correction = self.controller.angular_rigid_body_correction(
|
||||
dt,
|
||||
rb,
|
||||
Rotation::new(target_rotation),
|
||||
target_angvel,
|
||||
);
|
||||
rb.set_angvel(rb.angvel() + correction, true);
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn apply_angular_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_rotation: &RawRotation,
|
||||
target_angvel: &RawVector,
|
||||
) {
|
||||
let rb_handle = crate::utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get_mut(rb_handle) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let correction = self.controller.angular_rigid_body_correction(
|
||||
dt,
|
||||
rb,
|
||||
target_rotation.0,
|
||||
target_angvel.0,
|
||||
);
|
||||
rb.set_angvel(rb.angvel() + correction, true);
|
||||
}
|
||||
|
||||
pub fn linear_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_translation: &RawVector,
|
||||
target_linvel: &RawVector,
|
||||
) -> RawVector {
|
||||
let rb_handle = crate::utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get(rb_handle) else {
|
||||
return RawVector(Vector::zeros());
|
||||
};
|
||||
|
||||
self.controller
|
||||
.linear_rigid_body_correction(dt, rb, target_translation.0.into(), target_linvel.0)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn angular_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_rotation: f32,
|
||||
target_angvel: f32,
|
||||
) -> f32 {
|
||||
let rb_handle = crate::utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get(rb_handle) else {
|
||||
return 0.0;
|
||||
};
|
||||
|
||||
self.controller.angular_rigid_body_correction(
|
||||
dt,
|
||||
rb,
|
||||
Rotation::new(target_rotation),
|
||||
target_angvel,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn angular_correction(
|
||||
&mut self,
|
||||
dt: f32,
|
||||
bodies: &RawRigidBodySet,
|
||||
rb_handle: FlatHandle,
|
||||
target_rotation: &RawRotation,
|
||||
target_angvel: &RawVector,
|
||||
) -> RawVector {
|
||||
let rb_handle = crate::utils::body_handle(rb_handle);
|
||||
let Some(rb) = bodies.0.get(rb_handle) else {
|
||||
return RawVector(Vector::zeros());
|
||||
};
|
||||
|
||||
self.controller
|
||||
.angular_rigid_body_correction(dt, rb, target_rotation.0, target_angvel.0)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
336
thirdparty/rapier.js/src/control/ray_cast_vehicle_controller.rs
vendored
Normal file
336
thirdparty/rapier.js/src/control/ray_cast_vehicle_controller.rs
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
use crate::dynamics::RawRigidBodySet;
|
||||
use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase};
|
||||
use crate::math::RawVector;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::control::{DynamicRayCastVehicleController, WheelTuning};
|
||||
use rapier::math::Real;
|
||||
use rapier::pipeline::{QueryFilter, QueryFilterFlags};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawDynamicRayCastVehicleController {
|
||||
controller: DynamicRayCastVehicleController,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawDynamicRayCastVehicleController {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(chassis: FlatHandle) -> Self {
|
||||
Self {
|
||||
controller: DynamicRayCastVehicleController::new(utils::body_handle(chassis)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_vehicle_speed(&self) -> Real {
|
||||
self.controller.current_vehicle_speed
|
||||
}
|
||||
|
||||
pub fn chassis(&self) -> FlatHandle {
|
||||
utils::flat_handle(self.controller.chassis.0)
|
||||
}
|
||||
|
||||
pub fn index_up_axis(&self) -> usize {
|
||||
self.controller.index_up_axis
|
||||
}
|
||||
pub fn set_index_up_axis(&mut self, axis: usize) {
|
||||
self.controller.index_up_axis = axis;
|
||||
}
|
||||
|
||||
pub fn index_forward_axis(&self) -> usize {
|
||||
self.controller.index_forward_axis
|
||||
}
|
||||
pub fn set_index_forward_axis(&mut self, axis: usize) {
|
||||
self.controller.index_forward_axis = axis;
|
||||
}
|
||||
|
||||
pub fn add_wheel(
|
||||
&mut self,
|
||||
chassis_connection_cs: &RawVector,
|
||||
direction_cs: &RawVector,
|
||||
axle_cs: &RawVector,
|
||||
suspension_rest_length: Real,
|
||||
radius: Real,
|
||||
) {
|
||||
self.controller.add_wheel(
|
||||
chassis_connection_cs.0.into(),
|
||||
direction_cs.0,
|
||||
axle_cs.0,
|
||||
suspension_rest_length,
|
||||
radius,
|
||||
&WheelTuning::default(),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn num_wheels(&self) -> usize {
|
||||
self.controller.wheels().len()
|
||||
}
|
||||
|
||||
pub fn update_vehicle(
|
||||
&mut self,
|
||||
dt: Real,
|
||||
broad_phase: &RawBroadPhase,
|
||||
narrow_phase: &RawNarrowPhase,
|
||||
bodies: &mut RawRigidBodySet,
|
||||
colliders: &mut RawColliderSet,
|
||||
filter_flags: u32,
|
||||
filter_groups: Option<u32>,
|
||||
filter_predicate: &js_sys::Function,
|
||||
) {
|
||||
crate::utils::with_filter(filter_predicate, |predicate| {
|
||||
let query_filter = QueryFilter {
|
||||
flags: QueryFilterFlags::from_bits(filter_flags)
|
||||
.unwrap_or(QueryFilterFlags::empty()),
|
||||
groups: filter_groups.map(crate::geometry::unpack_interaction_groups),
|
||||
predicate,
|
||||
exclude_rigid_body: Some(self.controller.chassis),
|
||||
exclude_collider: None,
|
||||
};
|
||||
|
||||
let query_pipeline = broad_phase.0.as_query_pipeline_mut(
|
||||
narrow_phase.0.query_dispatcher(),
|
||||
&mut bodies.0,
|
||||
&mut colliders.0,
|
||||
query_filter,
|
||||
);
|
||||
|
||||
self.controller.update_vehicle(dt, query_pipeline);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Access to wheel properties.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Getters + setters
|
||||
*/
|
||||
pub fn wheel_chassis_connection_point_cs(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.chassis_connection_point_cs.into())
|
||||
}
|
||||
pub fn set_wheel_chassis_connection_point_cs(&mut self, i: usize, value: &RawVector) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.chassis_connection_point_cs = value.0.into();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_rest_length(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.suspension_rest_length)
|
||||
}
|
||||
pub fn set_wheel_suspension_rest_length(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.suspension_rest_length = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_max_suspension_travel(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.max_suspension_travel)
|
||||
}
|
||||
pub fn set_wheel_max_suspension_travel(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.max_suspension_travel = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_radius(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.radius)
|
||||
}
|
||||
pub fn set_wheel_radius(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.radius = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_stiffness(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.suspension_stiffness)
|
||||
}
|
||||
pub fn set_wheel_suspension_stiffness(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.suspension_stiffness = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_compression(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.damping_compression)
|
||||
}
|
||||
pub fn set_wheel_suspension_compression(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.damping_compression = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_relaxation(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.damping_relaxation)
|
||||
}
|
||||
pub fn set_wheel_suspension_relaxation(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.damping_relaxation = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_max_suspension_force(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.max_suspension_force)
|
||||
}
|
||||
pub fn set_wheel_max_suspension_force(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.max_suspension_force = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_brake(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.brake)
|
||||
}
|
||||
pub fn set_wheel_brake(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.brake = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_steering(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.steering)
|
||||
}
|
||||
pub fn set_wheel_steering(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.steering = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_engine_force(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.engine_force)
|
||||
}
|
||||
pub fn set_wheel_engine_force(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.engine_force = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_direction_cs(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.direction_cs.into())
|
||||
}
|
||||
pub fn set_wheel_direction_cs(&mut self, i: usize, value: &RawVector) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.direction_cs = value.0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_axle_cs(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller.wheels().get(i).map(|w| w.axle_cs.into())
|
||||
}
|
||||
pub fn set_wheel_axle_cs(&mut self, i: usize, value: &RawVector) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.axle_cs = value.0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_friction_slip(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.friction_slip)
|
||||
}
|
||||
pub fn set_wheel_friction_slip(&mut self, i: usize, value: Real) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.friction_slip = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wheel_side_friction_stiffness(&self, i: usize) -> Option<f32> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.side_friction_stiffness)
|
||||
}
|
||||
|
||||
pub fn set_wheel_side_friction_stiffness(&mut self, i: usize, stiffness: f32) {
|
||||
if let Some(wheel) = self.controller.wheels_mut().get_mut(i) {
|
||||
wheel.side_friction_stiffness = stiffness;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Getters only.
|
||||
*/
|
||||
pub fn wheel_rotation(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.rotation)
|
||||
}
|
||||
|
||||
pub fn wheel_forward_impulse(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.forward_impulse)
|
||||
}
|
||||
|
||||
pub fn wheel_side_impulse(&self, i: usize) -> Option<Real> {
|
||||
self.controller.wheels().get(i).map(|w| w.side_impulse)
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_force(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.wheel_suspension_force)
|
||||
}
|
||||
|
||||
pub fn wheel_contact_normal_ws(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.raycast_info().contact_normal_ws.into())
|
||||
}
|
||||
|
||||
pub fn wheel_contact_point_ws(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.raycast_info().contact_point_ws.into())
|
||||
}
|
||||
|
||||
pub fn wheel_suspension_length(&self, i: usize) -> Option<Real> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.raycast_info().suspension_length)
|
||||
}
|
||||
|
||||
pub fn wheel_hard_point_ws(&self, i: usize) -> Option<RawVector> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.raycast_info().hard_point_ws.into())
|
||||
}
|
||||
|
||||
pub fn wheel_is_in_contact(&self, i: usize) -> bool {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.map(|w| w.raycast_info().is_in_contact)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn wheel_ground_object(&self, i: usize) -> Option<FlatHandle> {
|
||||
self.controller
|
||||
.wheels()
|
||||
.get(i)
|
||||
.and_then(|w| w.raycast_info().ground_object)
|
||||
.map(|h| utils::flat_handle(h.0))
|
||||
}
|
||||
}
|
||||
13
thirdparty/rapier.js/src/dynamics/ccd_solver.rs
vendored
Normal file
13
thirdparty/rapier.js/src/dynamics/ccd_solver.rs
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
use rapier::dynamics::CCDSolver;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawCCDSolver(pub(crate) CCDSolver);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawCCDSolver {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawCCDSolver(CCDSolver::new())
|
||||
}
|
||||
}
|
||||
215
thirdparty/rapier.js/src/dynamics/impulse_joint.rs
vendored
Normal file
215
thirdparty/rapier.js/src/dynamics/impulse_joint.rs
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
use crate::dynamics::{RawImpulseJointSet, RawJointAxis, RawJointType, RawMotorModel};
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::dynamics::JointAxis;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawImpulseJointSet {
|
||||
/// The type of this joint.
|
||||
pub fn jointType(&self, handle: FlatHandle) -> RawJointType {
|
||||
self.map(handle, |j| j.data.locked_axes.into())
|
||||
}
|
||||
|
||||
/// The unique integer identifier of the first rigid-body this joint it attached to.
|
||||
pub fn jointBodyHandle1(&self, handle: FlatHandle) -> FlatHandle {
|
||||
self.map(handle, |j| utils::flat_handle(j.body1.0))
|
||||
}
|
||||
|
||||
/// The unique integer identifier of the second rigid-body this joint is attached to.
|
||||
pub fn jointBodyHandle2(&self, handle: FlatHandle) -> FlatHandle {
|
||||
self.map(handle, |j| utils::flat_handle(j.body2.0))
|
||||
}
|
||||
|
||||
/// The angular part of the joint’s local frame relative to the first rigid-body it is attached to.
|
||||
pub fn jointFrameX1(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |j| j.data.local_frame1.rotation.into())
|
||||
}
|
||||
|
||||
/// The angular part of the joint’s local frame relative to the second rigid-body it is attached to.
|
||||
pub fn jointFrameX2(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |j| j.data.local_frame2.rotation.into())
|
||||
}
|
||||
|
||||
/// The position of the first anchor of this joint.
|
||||
///
|
||||
/// The first anchor gives the position of the points application point on the
|
||||
/// local frame of the first rigid-body it is attached to.
|
||||
pub fn jointAnchor1(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |j| j.data.local_frame1.translation.vector.into())
|
||||
}
|
||||
|
||||
/// The position of the second anchor of this joint.
|
||||
///
|
||||
/// The second anchor gives the position of the points application point on the
|
||||
/// local frame of the second rigid-body it is attached to.
|
||||
pub fn jointAnchor2(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |j| j.data.local_frame2.translation.vector.into())
|
||||
}
|
||||
|
||||
/// Sets the position of the first local anchor
|
||||
pub fn jointSetAnchor1(&mut self, handle: FlatHandle, newPos: &RawVector) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.set_local_anchor1(newPos.0.into());
|
||||
});
|
||||
}
|
||||
|
||||
/// Sets the position of the second local anchor
|
||||
pub fn jointSetAnchor2(&mut self, handle: FlatHandle, newPos: &RawVector) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.set_local_anchor2(newPos.0.into());
|
||||
})
|
||||
}
|
||||
|
||||
/// Are contacts between the rigid-bodies attached by this joint enabled?
|
||||
pub fn jointContactsEnabled(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |j| j.data.contacts_enabled)
|
||||
}
|
||||
|
||||
/// Sets whether contacts are enabled between the rigid-bodies attached by this joint.
|
||||
pub fn jointSetContactsEnabled(&mut self, handle: FlatHandle, enabled: bool) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.contacts_enabled = enabled;
|
||||
});
|
||||
}
|
||||
|
||||
/// Are the limits for this joint enabled?
|
||||
pub fn jointLimitsEnabled(&self, handle: FlatHandle, axis: RawJointAxis) -> bool {
|
||||
self.map(handle, |j| {
|
||||
j.data.limit_axes.contains(JointAxis::from(axis).into())
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the lower limit along the given joint axis.
|
||||
pub fn jointLimitsMin(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 {
|
||||
self.map(handle, |j| j.data.limits[axis as usize].min)
|
||||
}
|
||||
|
||||
/// If this is a prismatic joint, returns its upper limit.
|
||||
pub fn jointLimitsMax(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 {
|
||||
self.map(handle, |j| j.data.limits[axis as usize].max)
|
||||
}
|
||||
|
||||
/// Enables and sets the joint limits
|
||||
pub fn jointSetLimits(&mut self, handle: FlatHandle, axis: RawJointAxis, min: f32, max: f32) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.set_limits(axis.into(), [min, max]);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn jointConfigureMotorModel(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
axis: RawJointAxis,
|
||||
model: RawMotorModel,
|
||||
) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.motors[axis as usize].model = model.into()
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotorVelocity(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
vx: f32,
|
||||
vy: f32,
|
||||
vz: f32,
|
||||
factor: f32,
|
||||
) {
|
||||
let targetVel = Vector3::new(vx, vy, vz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => j.configure_motor_velocity(targetVel, factor),
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotorPosition(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
qw: f32,
|
||||
qx: f32,
|
||||
qy: f32,
|
||||
qz: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
let quat = Quaternion::new(qw, qx, qy, qz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => {
|
||||
if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) {
|
||||
j.configure_motor_position(unit_quat, stiffness, damping)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotor(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
qw: f32,
|
||||
qx: f32,
|
||||
qy: f32,
|
||||
qz: f32,
|
||||
vx: f32,
|
||||
vy: f32,
|
||||
vz: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
let quat = Quaternion::new(qw, qx, qy, qz);
|
||||
let vel = Vector3::new(vx, vy, vz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => {
|
||||
if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) {
|
||||
j.configure_motor(unit_quat, vel, stiffness, damping)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn jointConfigureMotorVelocity(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
axis: RawJointAxis,
|
||||
targetVel: f32,
|
||||
factor: f32,
|
||||
) {
|
||||
self.jointConfigureMotor(handle, axis, 0.0, targetVel, 0.0, factor)
|
||||
}
|
||||
|
||||
pub fn jointConfigureMotorPosition(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
axis: RawJointAxis,
|
||||
targetPos: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
self.jointConfigureMotor(handle, axis, targetPos, 0.0, stiffness, damping)
|
||||
}
|
||||
|
||||
pub fn jointConfigureMotor(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
axis: RawJointAxis,
|
||||
targetPos: f32,
|
||||
targetVel: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data
|
||||
.set_motor(axis.into(), targetPos, targetVel, stiffness, damping);
|
||||
})
|
||||
}
|
||||
}
|
||||
92
thirdparty/rapier.js/src/dynamics/impulse_joint_set.rs
vendored
Normal file
92
thirdparty/rapier.js/src/dynamics/impulse_joint_set.rs
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
use crate::dynamics::RawGenericJoint;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::dynamics::{ImpulseJoint, ImpulseJointSet};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawImpulseJointSet(pub(crate) ImpulseJointSet);
|
||||
|
||||
impl RawImpulseJointSet {
|
||||
pub(crate) fn map<T>(&self, handle: FlatHandle, f: impl FnOnce(&ImpulseJoint) -> T) -> T {
|
||||
let body = self.0.get(utils::impulse_joint_handle(handle)).expect(
|
||||
"Invalid ImpulseJoint reference. It may have been removed from the physics World.",
|
||||
);
|
||||
f(body)
|
||||
}
|
||||
|
||||
pub(crate) fn map_mut<T>(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
f: impl FnOnce(&mut ImpulseJoint) -> T,
|
||||
) -> T {
|
||||
let body = self
|
||||
.0
|
||||
.get_mut(utils::impulse_joint_handle(handle), true)
|
||||
.expect(
|
||||
"Invalid ImpulseJoint reference. It may have been removed from the physics World.",
|
||||
);
|
||||
f(body)
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawImpulseJointSet {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawImpulseJointSet(ImpulseJointSet::new())
|
||||
}
|
||||
|
||||
pub fn createJoint(
|
||||
&mut self,
|
||||
params: &RawGenericJoint,
|
||||
parent1: FlatHandle,
|
||||
parent2: FlatHandle,
|
||||
wake_up: bool,
|
||||
) -> FlatHandle {
|
||||
utils::flat_handle(
|
||||
self.0
|
||||
.insert(
|
||||
utils::body_handle(parent1),
|
||||
utils::body_handle(parent2),
|
||||
params.0.clone(),
|
||||
wake_up,
|
||||
)
|
||||
.0,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, handle: FlatHandle, wakeUp: bool) {
|
||||
let handle = utils::impulse_joint_handle(handle);
|
||||
self.0.remove(handle, wakeUp);
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
pub fn contains(&self, handle: FlatHandle) -> bool {
|
||||
self.0.get(utils::impulse_joint_handle(handle)).is_some()
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each joint managed by this physics world.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each joint managed by this set. Called as `f(collider)`.
|
||||
pub fn forEachJointHandle(&self, f: &js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
for (handle, _) in self.0.iter() {
|
||||
let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each joint attached to the given rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each joint attached to the rigid-body. Called as `f(collider)`.
|
||||
pub fn forEachJointAttachedToRigidBody(&self, body: FlatHandle, f: &js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
for (_, _, handle, _) in self.0.attached_joints(utils::body_handle(body)) {
|
||||
let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
101
thirdparty/rapier.js/src/dynamics/integration_parameters.rs
vendored
Normal file
101
thirdparty/rapier.js/src/dynamics/integration_parameters.rs
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
use rapier::dynamics::IntegrationParameters;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawIntegrationParameters(pub(crate) IntegrationParameters);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawIntegrationParameters {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawIntegrationParameters(IntegrationParameters::default())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn dt(&self) -> f32 {
|
||||
self.0.dt
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn contact_erp(&self) -> f32 {
|
||||
self.0.contact_erp()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn normalizedAllowedLinearError(&self) -> f32 {
|
||||
self.0.normalized_allowed_linear_error
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn normalizedPredictionDistance(&self) -> f32 {
|
||||
self.0.normalized_prediction_distance
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn numSolverIterations(&self) -> usize {
|
||||
self.0.num_solver_iterations
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn numInternalPgsIterations(&self) -> usize {
|
||||
self.0.num_internal_pgs_iterations
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn minIslandSize(&self) -> usize {
|
||||
self.0.min_island_size
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn maxCcdSubsteps(&self) -> usize {
|
||||
self.0.max_ccd_substeps
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn lengthUnit(&self) -> f32 {
|
||||
self.0.length_unit
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_dt(&mut self, value: f32) {
|
||||
self.0.dt = value;
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_contact_natural_frequency(&mut self, value: f32) {
|
||||
self.0.contact_natural_frequency = value
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_normalizedAllowedLinearError(&mut self, value: f32) {
|
||||
self.0.normalized_allowed_linear_error = value
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_normalizedPredictionDistance(&mut self, value: f32) {
|
||||
self.0.normalized_prediction_distance = value
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_numSolverIterations(&mut self, value: usize) {
|
||||
self.0.num_solver_iterations = value;
|
||||
}
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_numInternalPgsIterations(&mut self, value: usize) {
|
||||
self.0.num_internal_pgs_iterations = value;
|
||||
}
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_minIslandSize(&mut self, value: usize) {
|
||||
self.0.min_island_size = value
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_maxCcdSubsteps(&mut self, value: usize) {
|
||||
self.0.max_ccd_substeps = value
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_lengthUnit(&mut self, value: f32) {
|
||||
self.0.length_unit = value
|
||||
}
|
||||
}
|
||||
31
thirdparty/rapier.js/src/dynamics/island_manager.rs
vendored
Normal file
31
thirdparty/rapier.js/src/dynamics/island_manager.rs
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
use crate::utils;
|
||||
use rapier::dynamics::IslandManager;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawIslandManager(pub(crate) IslandManager);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawIslandManager {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawIslandManager(IslandManager::new())
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each active rigid-body
|
||||
/// managed by this island manager.
|
||||
///
|
||||
/// After a short time of inactivity, a rigid-body is automatically deactivated ("asleep") by
|
||||
/// the physics engine in order to save computational power. A sleeping rigid-body never moves
|
||||
/// unless it is moved manually by the user.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each active rigid-body managed by this
|
||||
/// set. Called as `f(collider)`.
|
||||
pub fn forEachActiveRigidBodyHandle(&self, f: &js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
for handle in self.0.active_bodies() {
|
||||
let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
314
thirdparty/rapier.js/src/dynamics/joint.rs
vendored
Normal file
314
thirdparty/rapier.js/src/dynamics/joint.rs
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use na::Unit;
|
||||
use rapier::dynamics::{
|
||||
FixedJointBuilder, GenericJoint, JointAxesMask, JointAxis, MotorModel, PrismaticJointBuilder,
|
||||
RevoluteJointBuilder, RopeJointBuilder, SpringJointBuilder,
|
||||
};
|
||||
#[cfg(feature = "dim3")]
|
||||
use rapier::dynamics::{GenericJointBuilder, SphericalJointBuilder};
|
||||
use rapier::math::Isometry;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[cfg(feature = "dim2")]
|
||||
pub enum RawJointType {
|
||||
Revolute,
|
||||
Fixed,
|
||||
Prismatic,
|
||||
Rope,
|
||||
Spring,
|
||||
Generic,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[cfg(feature = "dim3")]
|
||||
pub enum RawJointType {
|
||||
Revolute,
|
||||
Fixed,
|
||||
Prismatic,
|
||||
Rope,
|
||||
Spring,
|
||||
Spherical,
|
||||
Generic,
|
||||
}
|
||||
|
||||
/// The type of this joint.
|
||||
#[cfg(feature = "dim2")]
|
||||
impl From<JointAxesMask> for RawJointType {
|
||||
fn from(ty: JointAxesMask) -> RawJointType {
|
||||
let rev_axes = JointAxesMask::LIN_X | JointAxesMask::LIN_Y;
|
||||
let pri_axes = JointAxesMask::LIN_Y | JointAxesMask::ANG_X;
|
||||
let fix_axes = JointAxesMask::LIN_X | JointAxesMask::LIN_Y | JointAxesMask::ANG_X;
|
||||
|
||||
if ty == rev_axes {
|
||||
RawJointType::Revolute
|
||||
} else if ty == pri_axes {
|
||||
RawJointType::Prismatic
|
||||
} else if ty == fix_axes {
|
||||
RawJointType::Fixed
|
||||
} else {
|
||||
RawJointType::Generic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of this joint.
|
||||
#[cfg(feature = "dim3")]
|
||||
impl From<JointAxesMask> for RawJointType {
|
||||
fn from(ty: JointAxesMask) -> RawJointType {
|
||||
let rev_axes = JointAxesMask::LIN_X
|
||||
| JointAxesMask::LIN_Y
|
||||
| JointAxesMask::LIN_Z
|
||||
| JointAxesMask::ANG_Y
|
||||
| JointAxesMask::ANG_Z;
|
||||
let pri_axes = JointAxesMask::LIN_Y
|
||||
| JointAxesMask::LIN_Z
|
||||
| JointAxesMask::ANG_X
|
||||
| JointAxesMask::ANG_Y
|
||||
| JointAxesMask::ANG_Z;
|
||||
let sph_axes = JointAxesMask::ANG_X | JointAxesMask::ANG_Y | JointAxesMask::ANG_Z;
|
||||
let fix_axes = JointAxesMask::LIN_X
|
||||
| JointAxesMask::LIN_Y
|
||||
| JointAxesMask::LIN_Z
|
||||
| JointAxesMask::ANG_X
|
||||
| JointAxesMask::ANG_Y
|
||||
| JointAxesMask::ANG_Z;
|
||||
|
||||
if ty == rev_axes {
|
||||
RawJointType::Revolute
|
||||
} else if ty == pri_axes {
|
||||
RawJointType::Prismatic
|
||||
} else if ty == sph_axes {
|
||||
RawJointType::Spherical
|
||||
} else if ty == fix_axes {
|
||||
RawJointType::Fixed
|
||||
} else {
|
||||
RawJointType::Generic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub enum RawMotorModel {
|
||||
AccelerationBased,
|
||||
ForceBased,
|
||||
}
|
||||
|
||||
impl From<RawMotorModel> for MotorModel {
|
||||
fn from(model: RawMotorModel) -> MotorModel {
|
||||
match model {
|
||||
RawMotorModel::AccelerationBased => MotorModel::AccelerationBased,
|
||||
RawMotorModel::ForceBased => MotorModel::ForceBased,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
#[wasm_bindgen]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum RawJointAxis {
|
||||
LinX,
|
||||
LinY,
|
||||
AngX,
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
#[wasm_bindgen]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum RawJointAxis {
|
||||
LinX,
|
||||
LinY,
|
||||
LinZ,
|
||||
AngX,
|
||||
AngY,
|
||||
AngZ,
|
||||
}
|
||||
|
||||
impl From<RawJointAxis> for JointAxis {
|
||||
fn from(axis: RawJointAxis) -> JointAxis {
|
||||
match axis {
|
||||
RawJointAxis::LinX => JointAxis::LinX,
|
||||
RawJointAxis::LinY => JointAxis::LinY,
|
||||
#[cfg(feature = "dim3")]
|
||||
RawJointAxis::LinZ => JointAxis::LinZ,
|
||||
RawJointAxis::AngX => JointAxis::AngX,
|
||||
#[cfg(feature = "dim3")]
|
||||
RawJointAxis::AngY => JointAxis::AngY,
|
||||
#[cfg(feature = "dim3")]
|
||||
RawJointAxis::AngZ => JointAxis::AngZ,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawGenericJoint(pub(crate) GenericJoint);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawGenericJoint {
|
||||
/// Creates a new joint descriptor that builds generic joints.
|
||||
///
|
||||
/// Generic joints allow arbitrary axes of freedom to be selected
|
||||
/// for the joint from the available 6 degrees of freedom.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn generic(
|
||||
anchor1: &RawVector,
|
||||
anchor2: &RawVector,
|
||||
axis: &RawVector,
|
||||
lockedAxes: u8,
|
||||
) -> Option<RawGenericJoint> {
|
||||
let axesMask: JointAxesMask = JointAxesMask::from_bits(lockedAxes)?;
|
||||
let axis = Unit::try_new(axis.0, 0.0)?;
|
||||
let joint: GenericJoint = GenericJointBuilder::new(axesMask)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.local_axis1(axis)
|
||||
.local_axis2(axis)
|
||||
.into();
|
||||
Some(Self(joint))
|
||||
}
|
||||
|
||||
pub fn spring(
|
||||
rest_length: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
anchor1: &RawVector,
|
||||
anchor2: &RawVector,
|
||||
) -> Self {
|
||||
Self(
|
||||
SpringJointBuilder::new(rest_length, stiffness, damping)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn rope(length: f32, anchor1: &RawVector, anchor2: &RawVector) -> Self {
|
||||
Self(
|
||||
RopeJointBuilder::new(length)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new joint descriptor that builds spherical joints.
|
||||
///
|
||||
/// A spherical joints allows three relative rotational degrees of freedom
|
||||
/// by preventing any relative translation between the anchors of the
|
||||
/// two attached rigid-bodies.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn spherical(anchor1: &RawVector, anchor2: &RawVector) -> Self {
|
||||
Self(
|
||||
SphericalJointBuilder::new()
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new joint descriptor that builds a Prismatic joint.
|
||||
///
|
||||
/// A prismatic joint removes all the degrees of freedom between the
|
||||
/// affected bodies, except for the translation along one axis.
|
||||
///
|
||||
/// Returns `None` if any of the provided axes cannot be normalized.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn prismatic(
|
||||
anchor1: &RawVector,
|
||||
anchor2: &RawVector,
|
||||
axis: &RawVector,
|
||||
limitsEnabled: bool,
|
||||
limitsMin: f32,
|
||||
limitsMax: f32,
|
||||
) -> Option<RawGenericJoint> {
|
||||
let axis = Unit::try_new(axis.0, 0.0)?;
|
||||
let mut joint = PrismaticJointBuilder::new(axis)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into());
|
||||
|
||||
if limitsEnabled {
|
||||
joint = joint.limits([limitsMin, limitsMax]);
|
||||
}
|
||||
|
||||
Some(Self(joint.into()))
|
||||
}
|
||||
|
||||
/// Creates a new joint descriptor that builds a Prismatic joint.
|
||||
///
|
||||
/// A prismatic joint removes all the degrees of freedom between the
|
||||
/// affected bodies, except for the translation along one axis.
|
||||
///
|
||||
/// Returns `None` if any of the provided axes cannot be normalized.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn prismatic(
|
||||
anchor1: &RawVector,
|
||||
anchor2: &RawVector,
|
||||
axis: &RawVector,
|
||||
limitsEnabled: bool,
|
||||
limitsMin: f32,
|
||||
limitsMax: f32,
|
||||
) -> Option<RawGenericJoint> {
|
||||
let axis = Unit::try_new(axis.0, 0.0)?;
|
||||
let mut joint = PrismaticJointBuilder::new(axis)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into());
|
||||
|
||||
if limitsEnabled {
|
||||
joint = joint.limits([limitsMin, limitsMax]);
|
||||
}
|
||||
|
||||
Some(Self(joint.into()))
|
||||
}
|
||||
|
||||
/// Creates a new joint descriptor that builds a Fixed joint.
|
||||
///
|
||||
/// A fixed joint removes all the degrees of freedom between the affected bodies.
|
||||
pub fn fixed(
|
||||
anchor1: &RawVector,
|
||||
axes1: &RawRotation,
|
||||
anchor2: &RawVector,
|
||||
axes2: &RawRotation,
|
||||
) -> RawGenericJoint {
|
||||
let pos1 = Isometry::from_parts(anchor1.0.into(), axes1.0);
|
||||
let pos2 = Isometry::from_parts(anchor2.0.into(), axes2.0);
|
||||
Self(
|
||||
FixedJointBuilder::new()
|
||||
.local_frame1(pos1)
|
||||
.local_frame2(pos2)
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new joint descriptor that builds Revolute joints.
|
||||
///
|
||||
/// A revolute joint removes all degrees of freedom between the affected
|
||||
/// bodies except for the rotation.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn revolute(anchor1: &RawVector, anchor2: &RawVector) -> Option<RawGenericJoint> {
|
||||
Some(Self(
|
||||
RevoluteJointBuilder::new()
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Create a new joint descriptor that builds Revolute joints.
|
||||
///
|
||||
/// A revolute joint removes all degrees of freedom between the affected
|
||||
/// bodies except for the rotation along one axis.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn revolute(
|
||||
anchor1: &RawVector,
|
||||
anchor2: &RawVector,
|
||||
axis: &RawVector,
|
||||
) -> Option<RawGenericJoint> {
|
||||
let axis = Unit::try_new(axis.0, 0.0)?;
|
||||
Some(Self(
|
||||
RevoluteJointBuilder::new(axis)
|
||||
.local_anchor1(anchor1.0.into())
|
||||
.local_anchor2(anchor2.0.into())
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
20
thirdparty/rapier.js/src/dynamics/mod.rs
vendored
Normal file
20
thirdparty/rapier.js/src/dynamics/mod.rs
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
//! Structures related to dynamics: bodies, joints, etc.
|
||||
|
||||
pub use self::ccd_solver::*;
|
||||
pub use self::impulse_joint_set::*;
|
||||
pub use self::integration_parameters::*;
|
||||
pub use self::island_manager::*;
|
||||
pub use self::joint::*;
|
||||
pub use self::multibody_joint_set::*;
|
||||
pub use self::rigid_body_set::*;
|
||||
|
||||
mod ccd_solver;
|
||||
mod impulse_joint;
|
||||
mod impulse_joint_set;
|
||||
mod integration_parameters;
|
||||
mod island_manager;
|
||||
mod joint;
|
||||
mod multibody_joint;
|
||||
mod multibody_joint_set;
|
||||
mod rigid_body;
|
||||
mod rigid_body_set;
|
||||
196
thirdparty/rapier.js/src/dynamics/multibody_joint.rs
vendored
Normal file
196
thirdparty/rapier.js/src/dynamics/multibody_joint.rs
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
use crate::dynamics::{RawJointAxis, RawJointType, RawMultibodyJointSet};
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use crate::utils::FlatHandle;
|
||||
use rapier::dynamics::JointAxis;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawMultibodyJointSet {
|
||||
/// The type of this joint.
|
||||
pub fn jointType(&self, handle: FlatHandle) -> RawJointType {
|
||||
self.map(handle, |j| j.data.locked_axes.into())
|
||||
}
|
||||
|
||||
// /// The unique integer identifier of the first rigid-body this joint it attached to.
|
||||
// pub fn jointBodyHandle1(&self, handle: FlatHandle) -> u32 {
|
||||
// self.map(handle, |j| j.body1.into_raw_parts().0)
|
||||
// }
|
||||
//
|
||||
// /// The unique integer identifier of the second rigid-body this joint is attached to.
|
||||
// pub fn jointBodyHandle2(&self, handle: FlatHandle) -> u32 {
|
||||
// self.map(handle, |j| j.body2.into_raw_parts().0)
|
||||
// }
|
||||
|
||||
/// The angular part of the joint’s local frame relative to the first rigid-body it is attached to.
|
||||
pub fn jointFrameX1(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |j| j.data.local_frame1.rotation.into())
|
||||
}
|
||||
|
||||
/// The angular part of the joint’s local frame relative to the second rigid-body it is attached to.
|
||||
pub fn jointFrameX2(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |j| j.data.local_frame2.rotation.into())
|
||||
}
|
||||
|
||||
/// The position of the first anchor of this joint.
|
||||
///
|
||||
/// The first anchor gives the position of the points application point on the
|
||||
/// local frame of the first rigid-body it is attached to.
|
||||
pub fn jointAnchor1(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |j| j.data.local_frame1.translation.vector.into())
|
||||
}
|
||||
|
||||
/// The position of the second anchor of this joint.
|
||||
///
|
||||
/// The second anchor gives the position of the points application point on the
|
||||
/// local frame of the second rigid-body it is attached to.
|
||||
pub fn jointAnchor2(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |j| j.data.local_frame2.translation.vector.into())
|
||||
}
|
||||
|
||||
/// Are contacts between the rigid-bodies attached by this joint enabled?
|
||||
pub fn jointContactsEnabled(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |j| j.data.contacts_enabled)
|
||||
}
|
||||
|
||||
/// Sets whether contacts are enabled between the rigid-bodies attached by this joint.
|
||||
pub fn jointSetContactsEnabled(&mut self, handle: FlatHandle, enabled: bool) {
|
||||
self.map_mut(handle, |j| {
|
||||
j.data.contacts_enabled = enabled;
|
||||
});
|
||||
}
|
||||
|
||||
/// Are the limits for this joint enabled?
|
||||
pub fn jointLimitsEnabled(&self, handle: FlatHandle, axis: RawJointAxis) -> bool {
|
||||
self.map(handle, |j| {
|
||||
j.data.limit_axes.contains(JointAxis::from(axis).into())
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the lower limit along the given joint axis.
|
||||
pub fn jointLimitsMin(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 {
|
||||
self.map(handle, |j| j.data.limits[axis as usize].min)
|
||||
}
|
||||
|
||||
/// If this is a prismatic joint, returns its upper limit.
|
||||
pub fn jointLimitsMax(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 {
|
||||
self.map(handle, |j| j.data.limits[axis as usize].max)
|
||||
}
|
||||
|
||||
// pub fn jointConfigureMotorModel(
|
||||
// &mut self,
|
||||
// handle: FlatHandle,
|
||||
// axis: RawJointAxis,
|
||||
// model: RawMotorModel,
|
||||
// ) {
|
||||
// self.map_mut(handle, |j| {
|
||||
// j.data.motors[axis as usize].model = model.into()
|
||||
// })
|
||||
// }
|
||||
|
||||
/*
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotorVelocity(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
vx: f32,
|
||||
vy: f32,
|
||||
vz: f32,
|
||||
factor: f32,
|
||||
) {
|
||||
let targetVel = Vector3::new(vx, vy, vz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => j.configure_motor_velocity(targetVel, factor),
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotorPosition(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
qw: f32,
|
||||
qx: f32,
|
||||
qy: f32,
|
||||
qz: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
let quat = Quaternion::new(qw, qx, qy, qz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => {
|
||||
if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) {
|
||||
j.configure_motor_position(unit_quat, stiffness, damping)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn jointConfigureBallMotor(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
qw: f32,
|
||||
qx: f32,
|
||||
qy: f32,
|
||||
qz: f32,
|
||||
vx: f32,
|
||||
vy: f32,
|
||||
vz: f32,
|
||||
stiffness: f32,
|
||||
damping: f32,
|
||||
) {
|
||||
let quat = Quaternion::new(qw, qx, qy, qz);
|
||||
let vel = Vector3::new(vx, vy, vz);
|
||||
|
||||
self.map_mut(handle, |j| match &mut j.params {
|
||||
JointData::SphericalJoint(j) => {
|
||||
if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) {
|
||||
j.configure_motor(unit_quat, vel, stiffness, damping)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
// pub fn jointConfigureMotorVelocity(
|
||||
// &mut self,
|
||||
// handle: FlatHandle,
|
||||
// axis: RawJointAxis,
|
||||
// targetVel: f32,
|
||||
// factor: f32,
|
||||
// ) {
|
||||
// self.jointConfigureMotor(handle, axis, 0.0, targetVel, 0.0, factor)
|
||||
// }
|
||||
//
|
||||
// pub fn jointConfigureMotorPosition(
|
||||
// &mut self,
|
||||
// handle: FlatHandle,
|
||||
// axis: RawJointAxis,
|
||||
// targetPos: f32,
|
||||
// stiffness: f32,
|
||||
// damping: f32,
|
||||
// ) {
|
||||
// self.jointConfigureMotor(handle, axis, targetPos, 0.0, stiffness, damping)
|
||||
// }
|
||||
|
||||
// pub fn jointConfigureMotor(
|
||||
// &mut self,
|
||||
// handle: FlatHandle,
|
||||
// axis: RawJointAxis,
|
||||
// targetPos: f32,
|
||||
// targetVel: f32,
|
||||
// stiffness: f32,
|
||||
// damping: f32,
|
||||
// ) {
|
||||
// self.map_mut(handle, |j| {
|
||||
// j.data.motors[axis as usize].target_pos = targetPos;
|
||||
// j.data.motors[axis as usize].target_vel = targetVel;
|
||||
// j.data.motors[axis as usize].stiffness = stiffness;
|
||||
// j.data.motors[axis as usize].damping = damping;
|
||||
// })
|
||||
// }
|
||||
}
|
||||
85
thirdparty/rapier.js/src/dynamics/multibody_joint_set.rs
vendored
Normal file
85
thirdparty/rapier.js/src/dynamics/multibody_joint_set.rs
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
use crate::dynamics::RawGenericJoint;
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use rapier::dynamics::{MultibodyJoint, MultibodyJointSet};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct RawMultibodyJointSet(pub(crate) MultibodyJointSet);
|
||||
|
||||
impl RawMultibodyJointSet {
|
||||
pub(crate) fn map<T>(&self, handle: FlatHandle, f: impl FnOnce(&MultibodyJoint) -> T) -> T {
|
||||
let (body, link_id) = self
|
||||
.0
|
||||
.get(utils::multibody_joint_handle(handle))
|
||||
.expect("Invalid Joint reference. It may have been removed from the physics World.");
|
||||
f(body.link(link_id).unwrap().joint())
|
||||
}
|
||||
|
||||
pub(crate) fn map_mut<T>(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
f: impl FnOnce(&mut MultibodyJoint) -> T,
|
||||
) -> T {
|
||||
let (body, link_id) = self
|
||||
.0
|
||||
.get_mut(utils::multibody_joint_handle(handle))
|
||||
.expect("Invalid Joint reference. It may have been removed from the physics World.");
|
||||
f(&mut body.link_mut(link_id).unwrap().joint)
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawMultibodyJointSet {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
RawMultibodyJointSet(MultibodyJointSet::new())
|
||||
}
|
||||
|
||||
pub fn createJoint(
|
||||
&mut self,
|
||||
params: &RawGenericJoint,
|
||||
parent1: FlatHandle,
|
||||
parent2: FlatHandle,
|
||||
wakeUp: bool,
|
||||
) -> FlatHandle {
|
||||
// TODO: avoid the unwrap?
|
||||
let parent1 = utils::body_handle(parent1);
|
||||
let parent2 = utils::body_handle(parent2);
|
||||
|
||||
self.0
|
||||
.insert(parent1, parent2, params.0.clone(), wakeUp)
|
||||
.map(|h| utils::flat_handle(h.0))
|
||||
.unwrap_or(FlatHandle::MAX)
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, handle: FlatHandle, wakeUp: bool) {
|
||||
let handle = utils::multibody_joint_handle(handle);
|
||||
self.0.remove(handle, wakeUp);
|
||||
}
|
||||
|
||||
pub fn contains(&self, handle: FlatHandle) -> bool {
|
||||
self.0.get(utils::multibody_joint_handle(handle)).is_some()
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each joint managed by this physics world.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each joint managed by this set. Called as `f(collider)`.
|
||||
pub fn forEachJointHandle(&self, f: &js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
for (handle, _, _, _) in self.0.iter() {
|
||||
let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies the given JavaScript function to the integer handle of each joint attached to the given rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `f(handle)`: the function to apply to the integer handle of each joint attached to the rigid-body. Called as `f(collider)`.
|
||||
pub fn forEachJointAttachedToRigidBody(&self, body: FlatHandle, f: &js_sys::Function) {
|
||||
let this = JsValue::null();
|
||||
for (_, _, handle) in self.0.attached_joints(utils::body_handle(body)) {
|
||||
let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
753
thirdparty/rapier.js/src/dynamics/rigid_body.rs
vendored
Normal file
753
thirdparty/rapier.js/src/dynamics/rigid_body.rs
vendored
Normal file
@@ -0,0 +1,753 @@
|
||||
use crate::dynamics::{RawRigidBodySet, RawRigidBodyType};
|
||||
use crate::geometry::RawColliderSet;
|
||||
#[cfg(feature = "dim3")]
|
||||
use crate::math::RawSdpMatrix3;
|
||||
use crate::math::{RawRotation, RawVector};
|
||||
use crate::utils::{self, FlatHandle};
|
||||
use na::Point;
|
||||
use rapier::dynamics::MassProperties;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl RawRigidBodySet {
|
||||
/// The world-space translation of this rigid-body.
|
||||
pub fn rbTranslation(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| RawVector(rb.position().translation.vector))
|
||||
}
|
||||
|
||||
/// The world-space orientation of this rigid-body.
|
||||
pub fn rbRotation(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |rb| RawRotation(rb.position().rotation))
|
||||
}
|
||||
|
||||
/// Put the given rigid-body to sleep.
|
||||
pub fn rbSleep(&mut self, handle: FlatHandle) {
|
||||
self.map_mut(handle, |rb| rb.sleep());
|
||||
}
|
||||
|
||||
/// Is this rigid-body sleeping?
|
||||
pub fn rbIsSleeping(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_sleeping())
|
||||
}
|
||||
|
||||
/// Is the velocity of this rigid-body not zero?
|
||||
pub fn rbIsMoving(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_moving())
|
||||
}
|
||||
|
||||
/// The world-space predicted translation of this rigid-body.
|
||||
///
|
||||
/// If this rigid-body is kinematic this value is set by the `setNextKinematicTranslation`
|
||||
/// method and is used for estimating the kinematic body velocity at the next timestep.
|
||||
/// For non-kinematic bodies, this value is currently unspecified.
|
||||
pub fn rbNextTranslation(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| {
|
||||
RawVector(rb.next_position().translation.vector)
|
||||
})
|
||||
}
|
||||
|
||||
/// The world-space predicted orientation of this rigid-body.
|
||||
///
|
||||
/// If this rigid-body is kinematic this value is set by the `setNextKinematicRotation`
|
||||
/// method and is used for estimating the kinematic body velocity at the next timestep.
|
||||
/// For non-kinematic bodies, this value is currently unspecified.
|
||||
pub fn rbNextRotation(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |rb| RawRotation(rb.next_position().rotation))
|
||||
}
|
||||
|
||||
/// Sets the translation of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the world-space position of the rigid-body along the `x` axis.
|
||||
/// - `y`: the world-space position of the rigid-body along the `y` axis.
|
||||
/// - `z`: the world-space position of the rigid-body along the `z` axis.
|
||||
/// - `wakeUp`: forces the rigid-body to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetTranslation(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_translation(na::Vector3::new(x, y, z), wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the translation of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the world-space position of the rigid-body along the `x` axis.
|
||||
/// - `y`: the world-space position of the rigid-body along the `y` axis.
|
||||
/// - `wakeUp`: forces the rigid-body to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetTranslation(&mut self, handle: FlatHandle, x: f32, y: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_translation(na::Vector2::new(x, y), wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the rotation quaternion of this rigid-body.
|
||||
///
|
||||
/// This does nothing if a zero quaternion is provided.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the first vector component of the quaternion.
|
||||
/// - `y`: the second vector component of the quaternion.
|
||||
/// - `z`: the third vector component of the quaternion.
|
||||
/// - `w`: the scalar component of the quaternion.
|
||||
/// - `wakeUp`: forces the rigid-body to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetRotation(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
w: f32,
|
||||
wakeUp: bool,
|
||||
) {
|
||||
if let Some(q) = na::Unit::try_new(na::Quaternion::new(w, x, y, z), 0.0) {
|
||||
self.map_mut(handle, |rb| rb.set_rotation(q, wakeUp))
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the rotation angle of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `angle`: the rotation angle, in radians.
|
||||
/// - `wakeUp`: forces the rigid-body to wake-up so it is properly affected by forces if it
|
||||
/// wasn't moving before modifying its position.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetRotation(&mut self, handle: FlatHandle, angle: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_rotation(na::UnitComplex::new(angle), wakeUp)
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the linear velocity of this rigid-body.
|
||||
pub fn rbSetLinvel(&mut self, handle: FlatHandle, linvel: &RawVector, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_linvel(linvel.0, wakeUp);
|
||||
});
|
||||
}
|
||||
|
||||
/// Sets the angular velocity of this rigid-body.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetAngvel(&mut self, handle: FlatHandle, angvel: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_angvel(angvel, wakeUp);
|
||||
});
|
||||
}
|
||||
|
||||
/// Sets the angular velocity of this rigid-body.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetAngvel(&mut self, handle: FlatHandle, angvel: &RawVector, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_angvel(angvel.0, wakeUp);
|
||||
});
|
||||
}
|
||||
|
||||
/// If this rigid body is kinematic, sets its future translation after the next timestep integration.
|
||||
///
|
||||
/// This should be used instead of `rigidBody.setTranslation` to make the dynamic object
|
||||
/// interacting with this kinematic body behave as expected. Internally, Rapier will compute
|
||||
/// an artificial velocity for this rigid-body from its current position and its next kinematic
|
||||
/// position. This velocity will be used to compute forces on dynamic bodies interacting with
|
||||
/// this body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the world-space position of the rigid-body along the `x` axis.
|
||||
/// - `y`: the world-space position of the rigid-body along the `y` axis.
|
||||
/// - `z`: the world-space position of the rigid-body along the `z` axis.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetNextKinematicTranslation(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_next_kinematic_translation(na::Vector3::new(x, y, z));
|
||||
})
|
||||
}
|
||||
|
||||
/// If this rigid body is kinematic, sets its future translation after the next timestep integration.
|
||||
///
|
||||
/// This should be used instead of `rigidBody.setTranslation` to make the dynamic object
|
||||
/// interacting with this kinematic body behave as expected. Internally, Rapier will compute
|
||||
/// an artificial velocity for this rigid-body from its current position and its next kinematic
|
||||
/// position. This velocity will be used to compute forces on dynamic bodies interacting with
|
||||
/// this body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the world-space position of the rigid-body along the `x` axis.
|
||||
/// - `y`: the world-space position of the rigid-body along the `y` axis.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetNextKinematicTranslation(&mut self, handle: FlatHandle, x: f32, y: f32) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_next_kinematic_translation(na::Vector2::new(x, y));
|
||||
})
|
||||
}
|
||||
|
||||
/// If this rigid body is kinematic, sets its future rotation after the next timestep integration.
|
||||
///
|
||||
/// This should be used instead of `rigidBody.setRotation` to make the dynamic object
|
||||
/// interacting with this kinematic body behave as expected. Internally, Rapier will compute
|
||||
/// an artificial velocity for this rigid-body from its current position and its next kinematic
|
||||
/// position. This velocity will be used to compute forces on dynamic bodies interacting with
|
||||
/// this body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `x`: the first vector component of the quaternion.
|
||||
/// - `y`: the second vector component of the quaternion.
|
||||
/// - `z`: the third vector component of the quaternion.
|
||||
/// - `w`: the scalar component of the quaternion.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetNextKinematicRotation(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
w: f32,
|
||||
) {
|
||||
if let Some(q) = na::Unit::try_new(na::Quaternion::new(w, x, y, z), 0.0) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_next_kinematic_rotation(q);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// If this rigid body is kinematic, sets its future rotation after the next timestep integration.
|
||||
///
|
||||
/// This should be used instead of `rigidBody.setRotation` to make the dynamic object
|
||||
/// interacting with this kinematic body behave as expected. Internally, Rapier will compute
|
||||
/// an artificial velocity for this rigid-body from its current position and its next kinematic
|
||||
/// position. This velocity will be used to compute forces on dynamic bodies interacting with
|
||||
/// this body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `angle`: the rotation angle, in radians.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetNextKinematicRotation(&mut self, handle: FlatHandle, angle: f32) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_next_kinematic_rotation(na::UnitComplex::new(angle));
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbRecomputeMassPropertiesFromColliders(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
colliders: &RawColliderSet,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.recompute_mass_properties_from_colliders(&colliders.0)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbSetAdditionalMass(&mut self, handle: FlatHandle, mass: f32, wake_up: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_additional_mass(mass, wake_up);
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetAdditionalMassProperties(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
mass: f32,
|
||||
centerOfMass: &RawVector,
|
||||
principalAngularInertia: &RawVector,
|
||||
angularInertiaFrame: &RawRotation,
|
||||
wake_up: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
let mprops = MassProperties::with_principal_inertia_frame(
|
||||
centerOfMass.0.into(),
|
||||
mass,
|
||||
principalAngularInertia.0,
|
||||
angularInertiaFrame.0,
|
||||
);
|
||||
rb.set_additional_mass_properties(mprops, wake_up)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetAdditionalMassProperties(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
mass: f32,
|
||||
centerOfMass: &RawVector,
|
||||
principalAngularInertia: f32,
|
||||
wake_up: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
let props = MassProperties::new(centerOfMass.0.into(), mass, principalAngularInertia);
|
||||
rb.set_additional_mass_properties(props, wake_up)
|
||||
})
|
||||
}
|
||||
|
||||
/// The linear velocity of this rigid-body.
|
||||
pub fn rbLinvel(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| RawVector(*rb.linvel()))
|
||||
}
|
||||
|
||||
/// The angular velocity of this rigid-body.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbAngvel(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.angvel())
|
||||
}
|
||||
|
||||
/// The angular velocity of this rigid-body.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbAngvel(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| RawVector(*rb.angvel()))
|
||||
}
|
||||
|
||||
/// The velocity of the given world-space point on this rigid-body.
|
||||
pub fn rbVelocityAtPoint(&self, handle: FlatHandle, point: &RawVector) -> RawVector {
|
||||
self.map(handle, |rb| {
|
||||
rb.velocity_at_point(&Point::from(point.0)).into()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbLockTranslations(&mut self, handle: FlatHandle, locked: bool, wake_up: bool) {
|
||||
self.map_mut(handle, |rb| rb.lock_translations(locked, wake_up))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbSetEnabledTranslations(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
allow_x: bool,
|
||||
allow_y: bool,
|
||||
wake_up: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_enabled_translations(allow_x, allow_y, wake_up)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetEnabledTranslations(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
allow_x: bool,
|
||||
allow_y: bool,
|
||||
allow_z: bool,
|
||||
wake_up: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_enabled_translations(allow_x, allow_y, allow_z, wake_up)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbLockRotations(&mut self, handle: FlatHandle, locked: bool, wake_up: bool) {
|
||||
self.map_mut(handle, |rb| rb.lock_rotations(locked, wake_up))
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbSetEnabledRotations(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
allow_x: bool,
|
||||
allow_y: bool,
|
||||
allow_z: bool,
|
||||
wake_up: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_enabled_rotations(allow_x, allow_y, allow_z, wake_up)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbDominanceGroup(&self, handle: FlatHandle) -> i8 {
|
||||
self.map(handle, |rb| rb.dominance_group())
|
||||
}
|
||||
|
||||
pub fn rbSetDominanceGroup(&mut self, handle: FlatHandle, group: i8) {
|
||||
self.map_mut(handle, |rb| rb.set_dominance_group(group))
|
||||
}
|
||||
|
||||
pub fn rbEnableCcd(&mut self, handle: FlatHandle, enabled: bool) {
|
||||
self.map_mut(handle, |rb| rb.enable_ccd(enabled))
|
||||
}
|
||||
|
||||
pub fn rbSetSoftCcdPrediction(&mut self, handle: FlatHandle, prediction: f32) {
|
||||
self.map_mut(handle, |rb| rb.set_soft_ccd_prediction(prediction))
|
||||
}
|
||||
|
||||
/// The mass of this rigid-body.
|
||||
pub fn rbMass(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.mass())
|
||||
}
|
||||
|
||||
/// The inverse of the mass of a rigid-body.
|
||||
///
|
||||
/// If this is zero, the rigid-body is assumed to have infinite mass.
|
||||
pub fn rbInvMass(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.mass_properties().local_mprops.inv_mass)
|
||||
}
|
||||
|
||||
/// The inverse mass taking into account translation locking.
|
||||
pub fn rbEffectiveInvMass(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| rb.mass_properties().effective_inv_mass.into())
|
||||
}
|
||||
|
||||
/// The center of mass of a rigid-body expressed in its local-space.
|
||||
pub fn rbLocalCom(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().local_mprops.local_com.into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The world-space center of mass of the rigid-body.
|
||||
pub fn rbWorldCom(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| rb.mass_properties().world_com.into())
|
||||
}
|
||||
|
||||
/// The inverse of the principal angular inertia of the rigid-body.
|
||||
///
|
||||
/// Components set to zero are assumed to be infinite along the corresponding principal axis.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbInvPrincipalInertia(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties()
|
||||
.local_mprops
|
||||
.inv_principal_inertia
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The inverse of the principal angular inertia of the rigid-body.
|
||||
///
|
||||
/// Components set to zero are assumed to be infinite along the corresponding principal axis.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbInvPrincipalInertia(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties()
|
||||
.local_mprops
|
||||
.inv_principal_inertia
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
/// The principal vectors of the local angular inertia tensor of the rigid-body.
|
||||
pub fn rbPrincipalInertiaLocalFrame(&self, handle: FlatHandle) -> RawRotation {
|
||||
self.map(handle, |rb| {
|
||||
RawRotation::from(
|
||||
rb.mass_properties()
|
||||
.local_mprops
|
||||
.principal_inertia_local_frame,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// The angular inertia along the principal inertia axes of the rigid-body.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbPrincipalInertia(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().local_mprops.principal_inertia().into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The angular inertia along the principal inertia axes of the rigid-body.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbPrincipalInertia(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().local_mprops.principal_inertia().into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The world-space inverse angular inertia tensor of the rigid-body,
|
||||
/// taking into account rotation locking.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbEffectiveWorldInvInertia(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().effective_world_inv_inertia.into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The world-space inverse angular inertia tensor of the rigid-body,
|
||||
/// taking into account rotation locking.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbEffectiveWorldInvInertia(&self, handle: FlatHandle) -> RawSdpMatrix3 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().effective_world_inv_inertia.into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The effective world-space angular inertia (that takes the potential rotation locking into account) of
|
||||
/// this rigid-body.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbEffectiveAngularInertia(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().effective_angular_inertia().into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The effective world-space angular inertia (that takes the potential rotation locking into account) of
|
||||
/// this rigid-body.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbEffectiveAngularInertia(&self, handle: FlatHandle) -> RawSdpMatrix3 {
|
||||
self.map(handle, |rb| {
|
||||
rb.mass_properties().effective_angular_inertia().into()
|
||||
})
|
||||
}
|
||||
|
||||
/// Wakes this rigid-body up.
|
||||
///
|
||||
/// A dynamic rigid-body that does not move during several consecutive frames will
|
||||
/// be put to sleep by the physics engine, i.e., it will stop being simulated in order
|
||||
/// to avoid useless computations.
|
||||
/// This method forces a sleeping rigid-body to wake-up. This is useful, e.g., before modifying
|
||||
/// the position of a dynamic body so that it is properly simulated afterwards.
|
||||
pub fn rbWakeUp(&mut self, handle: FlatHandle) {
|
||||
self.map_mut(handle, |rb| rb.wake_up(true))
|
||||
}
|
||||
|
||||
/// Is Continuous Collision Detection enabled for this rigid-body?
|
||||
pub fn rbIsCcdEnabled(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_ccd_enabled())
|
||||
}
|
||||
pub fn rbSoftCcdPrediction(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.soft_ccd_prediction())
|
||||
}
|
||||
|
||||
/// The number of colliders attached to this rigid-body.
|
||||
pub fn rbNumColliders(&self, handle: FlatHandle) -> usize {
|
||||
self.map(handle, |rb| rb.colliders().len())
|
||||
}
|
||||
|
||||
/// Retrieves the `i-th` collider attached to this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `at`: The index of the collider to retrieve. Must be a number in `[0, this.numColliders()[`.
|
||||
/// This index is **not** the same as the unique identifier of the collider.
|
||||
pub fn rbCollider(&self, handle: FlatHandle, at: usize) -> FlatHandle {
|
||||
self.map(handle, |rb| utils::flat_handle(rb.colliders()[at].0))
|
||||
}
|
||||
|
||||
/// The status of this rigid-body: fixed, dynamic, or kinematic.
|
||||
pub fn rbBodyType(&self, handle: FlatHandle) -> RawRigidBodyType {
|
||||
self.map(handle, |rb| rb.body_type().into())
|
||||
}
|
||||
|
||||
/// Set a new status for this rigid-body: fixed, dynamic, or kinematic.
|
||||
pub fn rbSetBodyType(&mut self, handle: FlatHandle, status: RawRigidBodyType, wake_up: bool) {
|
||||
self.map_mut(handle, |rb| rb.set_body_type(status.into(), wake_up));
|
||||
}
|
||||
|
||||
/// Is this rigid-body fixed?
|
||||
pub fn rbIsFixed(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_fixed())
|
||||
}
|
||||
|
||||
/// Is this rigid-body kinematic?
|
||||
pub fn rbIsKinematic(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_kinematic())
|
||||
}
|
||||
|
||||
/// Is this rigid-body dynamic?
|
||||
pub fn rbIsDynamic(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_dynamic())
|
||||
}
|
||||
|
||||
/// The linear damping coefficient of this rigid-body.
|
||||
pub fn rbLinearDamping(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.linear_damping())
|
||||
}
|
||||
|
||||
/// The angular damping coefficient of this rigid-body.
|
||||
pub fn rbAngularDamping(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.angular_damping())
|
||||
}
|
||||
|
||||
pub fn rbSetLinearDamping(&mut self, handle: FlatHandle, factor: f32) {
|
||||
self.map_mut(handle, |rb| rb.set_linear_damping(factor));
|
||||
}
|
||||
|
||||
pub fn rbSetAngularDamping(&mut self, handle: FlatHandle, factor: f32) {
|
||||
self.map_mut(handle, |rb| rb.set_angular_damping(factor));
|
||||
}
|
||||
|
||||
pub fn rbSetEnabled(&mut self, handle: FlatHandle, enabled: bool) {
|
||||
self.map_mut(handle, |rb| rb.set_enabled(enabled))
|
||||
}
|
||||
|
||||
pub fn rbIsEnabled(&self, handle: FlatHandle) -> bool {
|
||||
self.map(handle, |rb| rb.is_enabled())
|
||||
}
|
||||
|
||||
pub fn rbGravityScale(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.gravity_scale())
|
||||
}
|
||||
|
||||
pub fn rbSetGravityScale(&mut self, handle: FlatHandle, factor: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| rb.set_gravity_scale(factor, wakeUp));
|
||||
}
|
||||
|
||||
/// Resets to zero all user-added forces added to this rigid-body.
|
||||
pub fn rbResetForces(&mut self, handle: FlatHandle, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.reset_forces(wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Resets to zero all user-added torques added to this rigid-body.
|
||||
pub fn rbResetTorques(&mut self, handle: FlatHandle, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.reset_torques(wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds a force at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `force`: the world-space force to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
pub fn rbAddForce(&mut self, handle: FlatHandle, force: &RawVector, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.add_force(force.0, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Applies an impulse at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `impulse`: the world-space impulse to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
pub fn rbApplyImpulse(&mut self, handle: FlatHandle, impulse: &RawVector, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.apply_impulse(impulse.0, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds a torque at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `torque`: the torque to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbAddTorque(&mut self, handle: FlatHandle, torque: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.add_torque(torque, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds a torque at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `torque`: the world-space torque to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbAddTorque(&mut self, handle: FlatHandle, torque: &RawVector, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.add_torque(torque.0, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Applies an impulsive torque at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `torque impulse`: the torque impulse to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbApplyTorqueImpulse(&mut self, handle: FlatHandle, torque_impulse: f32, wakeUp: bool) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.apply_torque_impulse(torque_impulse, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Applies an impulsive torque at the center-of-mass of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `torque impulse`: the world-space torque impulse to apply on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbApplyTorqueImpulse(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
torque_impulse: &RawVector,
|
||||
wakeUp: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.apply_torque_impulse(torque_impulse.0, wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds a force at the given world-space point of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `force`: the world-space force to apply on the rigid-body.
|
||||
/// - `point`: the world-space point where the impulse is to be applied on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
pub fn rbAddForceAtPoint(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
force: &RawVector,
|
||||
point: &RawVector,
|
||||
wakeUp: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.add_force_at_point(force.0, point.0.into(), wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
/// Applies an impulse at the given world-space point of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `impulse`: the world-space impulse to apply on the rigid-body.
|
||||
/// - `point`: the world-space point where the impulse is to be applied on the rigid-body.
|
||||
/// - `wakeUp`: should the rigid-body be automatically woken-up?
|
||||
pub fn rbApplyImpulseAtPoint(
|
||||
&mut self,
|
||||
handle: FlatHandle,
|
||||
impulse: &RawVector,
|
||||
point: &RawVector,
|
||||
wakeUp: bool,
|
||||
) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.apply_impulse_at_point(impulse.0, point.0.into(), wakeUp);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rbAdditionalSolverIterations(&self, handle: FlatHandle) -> usize {
|
||||
self.map(handle, |rb| rb.additional_solver_iterations())
|
||||
}
|
||||
|
||||
pub fn rbSetAdditionalSolverIterations(&mut self, handle: FlatHandle, iters: usize) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.set_additional_solver_iterations(iters as usize);
|
||||
})
|
||||
}
|
||||
|
||||
/// An arbitrary user-defined 32-bit integer
|
||||
pub fn rbUserData(&self, handle: FlatHandle) -> u32 {
|
||||
self.map(handle, |rb| rb.user_data as u32)
|
||||
}
|
||||
|
||||
/// Sets the user-defined 32-bit integer of this rigid-body.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `data`: an arbitrary user-defined 32-bit integer.
|
||||
pub fn rbSetUserData(&mut self, handle: FlatHandle, data: u32) {
|
||||
self.map_mut(handle, |rb| {
|
||||
rb.user_data = data as u128;
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieves the constant force(s) the user added to this rigid-body.
|
||||
/// Returns zero if the rigid-body is not dynamic.
|
||||
pub fn rbUserForce(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| rb.user_force().into())
|
||||
}
|
||||
|
||||
/// Retrieves the constant torque(s) the user added to this rigid-body.
|
||||
/// Returns zero if the rigid-body is not dynamic.
|
||||
#[cfg(feature = "dim2")]
|
||||
pub fn rbUserTorque(&self, handle: FlatHandle) -> f32 {
|
||||
self.map(handle, |rb| rb.user_torque())
|
||||
}
|
||||
|
||||
/// Retrieves the constant torque(s) the user added to this rigid-body.
|
||||
/// Returns zero if the rigid-body is not dynamic.
|
||||
#[cfg(feature = "dim3")]
|
||||
pub fn rbUserTorque(&self, handle: FlatHandle) -> RawVector {
|
||||
self.map(handle, |rb| rb.user_torque().into())
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user