@woosh/meep-engine 2.153.0 → 2.154.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts +112 -0
  3. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -0
  4. package/src/core/geom/3d/shape/ConvexHullShape3D.js +325 -0
  5. package/src/engine/graphics/ecs/trail2d/Trail2D.d.ts +4 -0
  6. package/src/engine/graphics/ecs/trail2d/Trail2D.d.ts.map +1 -1
  7. package/src/engine/graphics/ecs/trail2d/Trail2D.js +21 -0
  8. package/src/engine/physics/PLAN.md +4 -4
  9. package/src/engine/physics/body/BodyStorage.d.ts +3 -1
  10. package/src/engine/physics/body/BodyStorage.d.ts.map +1 -1
  11. package/src/engine/physics/body/BodyStorage.js +452 -450
  12. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  13. package/src/engine/physics/body/SolverBodyState.js +6 -5
  14. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
  15. package/src/engine/physics/broadphase/generate_pairs.js +9 -1
  16. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  17. package/src/engine/physics/ccd/linear_sweep.js +237 -238
  18. package/src/engine/physics/computeInterceptPoint.d.ts.map +1 -1
  19. package/src/engine/physics/computeInterceptPoint.js +8 -3
  20. package/src/engine/physics/contact/ManifoldStore.d.ts +0 -16
  21. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  22. package/src/engine/physics/contact/ManifoldStore.js +1 -38
  23. package/src/engine/physics/ecs/BodyKind.d.ts +3 -2
  24. package/src/engine/physics/ecs/BodyKind.d.ts.map +1 -1
  25. package/src/engine/physics/ecs/BodyKind.js +25 -24
  26. package/src/engine/physics/ecs/PhysicsEvents.d.ts +4 -5
  27. package/src/engine/physics/ecs/PhysicsEvents.d.ts.map +1 -1
  28. package/src/engine/physics/ecs/PhysicsEvents.js +15 -16
  29. package/src/engine/physics/ecs/PhysicsSystem.d.ts +5 -30
  30. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  31. package/src/engine/physics/ecs/PhysicsSystem.js +13 -45
  32. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts.map +1 -1
  33. package/src/engine/physics/ecs/RigidBodySerializationAdapter.js +85 -81
  34. package/src/engine/physics/ecs/is_sensor.d.ts +18 -0
  35. package/src/engine/physics/ecs/is_sensor.d.ts.map +1 -0
  36. package/src/engine/physics/ecs/is_sensor.js +27 -0
  37. package/src/engine/physics/events/ContactEventBuffer.d.ts +2 -1
  38. package/src/engine/physics/events/ContactEventBuffer.d.ts.map +1 -1
  39. package/src/engine/physics/events/ContactEventBuffer.js +84 -83
  40. package/src/engine/physics/gjk/gjk.d.ts +0 -26
  41. package/src/engine/physics/gjk/gjk.d.ts.map +1 -1
  42. package/src/engine/physics/gjk/gjk.js +3 -52
  43. package/src/engine/physics/gjk/gjk_epa_penetration.d.ts +16 -0
  44. package/src/engine/physics/gjk/gjk_epa_penetration.d.ts.map +1 -0
  45. package/src/engine/physics/gjk/gjk_epa_penetration.js +255 -0
  46. package/src/engine/physics/gjk/minkowski_support.d.ts +4 -9
  47. package/src/engine/physics/gjk/minkowski_support.d.ts.map +1 -1
  48. package/src/engine/physics/gjk/minkowski_support.js +70 -75
  49. package/src/engine/physics/gjk/mpr.d.ts +1 -1
  50. package/src/engine/physics/gjk/mpr.d.ts.map +1 -1
  51. package/src/engine/physics/gjk/mpr.js +362 -344
  52. package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
  53. package/src/engine/physics/island/IslandBuilder.js +431 -428
  54. package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
  55. package/src/engine/physics/narrowphase/box_box_manifold.js +4 -81
  56. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -1
  57. package/src/engine/physics/narrowphase/box_triangle_contact.js +4 -39
  58. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
  59. package/src/engine/physics/narrowphase/capsule_contacts.js +459 -462
  60. package/src/engine/physics/narrowphase/clip_against_axis_uv.d.ts.map +1 -1
  61. package/src/engine/physics/narrowphase/clip_against_axis_uv.js +4 -1
  62. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts +83 -0
  63. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts.map +1 -0
  64. package/src/engine/physics/narrowphase/convex_convex_manifold.js +425 -0
  65. package/src/engine/physics/narrowphase/convex_decomposition.d.ts +32 -0
  66. package/src/engine/physics/narrowphase/convex_decomposition.d.ts.map +1 -0
  67. package/src/engine/physics/narrowphase/convex_decomposition.js +293 -0
  68. package/src/engine/physics/narrowphase/mesh_convex_hull.d.ts +41 -0
  69. package/src/engine/physics/narrowphase/mesh_convex_hull.d.ts.map +1 -0
  70. package/src/engine/physics/narrowphase/mesh_convex_hull.js +106 -0
  71. package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.d.ts +8 -0
  72. package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.d.ts.map +1 -0
  73. package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.js +117 -0
  74. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  75. package/src/engine/physics/narrowphase/narrowphase_step.js +105 -102
  76. package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts +29 -0
  77. package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts.map +1 -0
  78. package/src/engine/physics/narrowphase/reduce_manifold_contacts.js +69 -0
  79. package/src/engine/physics/narrowphase/refine_ray_concave.d.ts.map +1 -1
  80. package/src/engine/physics/narrowphase/refine_ray_concave.js +152 -145
  81. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -1
  82. package/src/engine/physics/narrowphase/sphere_box_contact.js +132 -123
  83. package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
  84. package/src/engine/physics/queries/overlap_shape.js +16 -17
  85. package/src/engine/physics/queries/raycast.d.ts +5 -0
  86. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  87. package/src/engine/physics/queries/raycast.js +16 -8
  88. package/src/engine/physics/queries/shape_cast.d.ts.map +1 -1
  89. package/src/engine/physics/queries/shape_cast.js +13 -7
  90. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
  91. package/src/engine/physics/solver/solve_contacts.js +8 -11
  92. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  93. package/src/engine/physics/vehicle/RaycastVehicle.js +339 -333
  94. package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts +0 -13
  95. package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts.map +0 -1
  96. package/src/engine/physics/gjk/expanding_polytope_algorithm.js +0 -399
@@ -1 +1 @@
1
- {"version":3,"file":"SolverBodyState.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/body/SolverBodyState.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,+CAA+C;AAC/C,6BAA8B;AAC9B,oFAAoF;AACpF,4BAA6B;AAC7B,4BAA6B;AAC7B,4BAA6B;AAC7B,oFAAoF;AACpF,uBAAwB;AACxB,uBAAwB;AACxB,uBAAwB;AACxB,uBAAwB;AACxB,kCAAkC;AAClC,yBAA0B;AAC1B,yBAA0B;AAC1B,0BAA2B;AAC3B,mCAAmC;AACnC,0BAA2B;AAC3B,0BAA2B;AAC3B,0BAA2B;AAE3B,wBAAwB;AACxB,4BAA6B;AAE7B;IACI,uCAoCC;IAjCG;;;OAGG;IACH,MAFU,YAAY,CAEwB;IAE9C;;;;;OAKG;IACH,gBAAkC;IAElC;;;;OAIG;IACH,mBAAsC;IAEtC,eAAe;IACf,yBAAyB;IAEzB;;;;OAIG;IACH,cAAc;IAEd,eAAe;IACf,mBAAqB;IAGzB;;;OAGG;IACH,6BAEC;IAED;;;;;OAKG;IACH,WAFW,MAAM,QAiBhB;IAED;;;;;;;;OAQG;IACH,YAJW,MAAM,6CA8ChB;IAED;;;;;;;OAOG;IACH,gBAFW,WAAW,QAoBrB;IAED;;;OAGG;IACH,eAcC;CACJ"}
1
+ {"version":3,"file":"SolverBodyState.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/body/SolverBodyState.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,+CAA+C;AAC/C,6BAA8B;AAC9B,oFAAoF;AACpF,4BAA6B;AAC7B,4BAA6B;AAC7B,4BAA6B;AAC7B,oFAAoF;AACpF,uBAAwB;AACxB,uBAAwB;AACxB,uBAAwB;AACxB,uBAAwB;AACxB,kCAAkC;AAClC,yBAA0B;AAC1B,yBAA0B;AAC1B,0BAA2B;AAC3B,mCAAmC;AACnC,0BAA2B;AAC3B,0BAA2B;AAC3B,0BAA2B;AAE3B,wBAAwB;AACxB,4BAA6B;AAE7B;IACI,uCAoCC;IAjCG;;;OAGG;IACH,MAFU,YAAY,CAEwB;IAE9C;;;;;OAKG;IACH,gBAAkC;IAElC;;;;OAIG;IACH,mBAAsC;IAEtC,eAAe;IACf,yBAAyB;IAEzB;;;;OAIG;IACH,cAAc;IAEd,eAAe;IACf,mBAAqB;IAGzB;;;OAGG;IACH,6BAEC;IAED;;;;;OAKG;IACH,WAFW,MAAM,QAiBhB;IAED;;;;;;;;OAQG;IACH,YAJW,MAAM,6CA8ChB;IAED;;;;;;;OAOG;IACH,gBAFW,WAAW,QAoBrB;IAED;;;OAGG;IACH,eAeC;CACJ"}
@@ -238,11 +238,12 @@ export class SolverBodyState {
238
238
  const next_data = new Float64Array(cap * SBS_STRIDE);
239
239
  const next_stamp = new Int32Array(cap);
240
240
  const next_gathered = new Uint32Array(cap);
241
- // No need to copy `data` — it is fully repopulated by `gather` each
242
- // step before any read. `__stamp` must NOT carry stale gen values into
243
- // the grown region; a fresh zero-filled array plus the live `__gen`
244
- // (always >= 1 after begin) guarantees grown slots read as un-gathered.
245
- next_stamp.set(this.__stamp);
241
+ // No need to copy `data` — it is fully repopulated by `gather` each step
242
+ // before any read. `__stamp` is intentionally NOT copied either: a fresh
243
+ // zero-filled array plus the live `__gen` (always >= 1 after begin's gen
244
+ // roll) makes every slot read as un-gathered, which is exactly what the
245
+ // grown region needs; copying stale gen values back in would be dead work
246
+ // (they are all < the live gen anyway).
246
247
  this.data = next_data;
247
248
  this.__stamp = next_stamp;
248
249
  this.__gathered = next_gathered;
@@ -1 +1 @@
1
- {"version":3,"file":"generate_pairs.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/broadphase/generate_pairs.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,uIATW,MAAM,MAAM;IAAC,QAAQ,WAAW;IAAC,SAAS,YAAY;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC,CAAC,+CAElF,MAAM,OAAO,MAAM,KAAK,OAAO,oCA8EhD"}
1
+ {"version":3,"file":"generate_pairs.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/broadphase/generate_pairs.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,uIATW,MAAM,MAAM;IAAC,QAAQ,WAAW;IAAC,SAAS,YAAY;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC,CAAC,+CAElF,MAAM,OAAO,MAAM,KAAK,OAAO,oCAqFhD"}
@@ -1,5 +1,6 @@
1
1
  import { assert } from "../../../core/assert.js";
2
2
  import { bvh_query_user_data_overlaps_aabb } from "../../../core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.js";
3
+ import { pack_body_id } from "../body/BodyStorage.js";
3
4
 
4
5
  const scratch_aabb = new Float64Array(6);
5
6
  const candidates = new Uint32Array(1024);
@@ -56,7 +57,7 @@ export function generate_pairs(
56
57
  if (list === undefined || list.length === 0) continue;
57
58
 
58
59
  const gen = storage.generation_at(body_idx);
59
- const my_packed = (body_idx << 8) | gen;
60
+ const my_packed = pack_body_id(body_idx, gen); // single-source the bit layout
60
61
 
61
62
  for (let k = 0; k < list.length; k++) {
62
63
  const node = list[k].bvhNode;
@@ -73,6 +74,12 @@ export function generate_pairs(
73
74
  // past the buffer end, so the loop below would read `undefined`
74
75
  // candidates and build garbage pairs. Guard the buffer size.
75
76
  assert.lessThan(n, candidates.length, 'generate_pairs: dynamic broadphase overflowed the candidate buffer');
77
+ // Production-safe clamp: the assert is stripped at bundle time, so
78
+ // without this an overflowing query (count past the buffer) would read
79
+ // `undefined` candidates and fabricate NaN-keyed garbage pairs. Drop
80
+ // the overflow deterministically — the fat AABBs persist, so any
81
+ // missed pair is re-detected next frame.
82
+ if (n > candidates.length) n = candidates.length;
76
83
  for (let c = 0; c < n; c++) {
77
84
  const other = candidates[c];
78
85
  if (other === my_packed) continue;
@@ -94,6 +101,7 @@ export function generate_pairs(
94
101
  scratch_aabb
95
102
  );
96
103
  assert.lessThan(n, candidates.length, 'generate_pairs: static broadphase overflowed the candidate buffer');
104
+ if (n > candidates.length) n = candidates.length; // prod-safe clamp (see dynamic loop above)
97
105
  for (let c = 0; c < n; c++) {
98
106
  const other = candidates[c];
99
107
  const idA = my_packed < other ? my_packed : other;
@@ -1 +1 @@
1
- {"version":3,"file":"linear_sweep.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/ccd/linear_sweep.js"],"names":[],"mappings":"AA8FA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,0CAbW,OAAO,yBAAyB,EAAE,aAAa,SAC/C,OAAO,gDAAgD,EAAE,eAAe,YACxE;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,MACrC,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,kBACN,MAAM,UACN,mBAAmB,GACjB,MAAM,CAmClB;AAED;;;;;;;;;;;;;GAaG;AACH,oCAFW,OAAO,yBAAyB,EAAE,aAAa,QAwEzD;AAvOD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,qCAFU,MAAM,CAE2B;oCArDP,mCAAmC"}
1
+ {"version":3,"file":"linear_sweep.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/ccd/linear_sweep.js"],"names":[],"mappings":"AA8FA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,0CAbW,OAAO,yBAAyB,EAAE,aAAa,SAC/C,OAAO,gDAAgD,EAAE,eAAe,YACxE;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,MACrC,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,kBACN,MAAM,UACN,mBAAmB,GACjB,MAAM,CAmClB;AAED;;;;;;;;;;;;;GAaG;AACH,oCAFW,OAAO,yBAAyB,EAAE,aAAa,QAuEzD;AAtOD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,qCAFU,MAAM,CAE2B;oCArDP,mCAAmC"}
@@ -1,238 +1,237 @@
1
- import { Ray3 } from "../../../core/geom/3d/ray/Ray3.js";
2
- import { BodyKind } from "../ecs/BodyKind.js";
3
- import { RigidBodyFlags } from "../ecs/RigidBodyFlags.js";
4
- import { PhysicsSurfacePoint } from "../queries/PhysicsSurfacePoint.js";
5
- import { shape_cast } from "../queries/shape_cast.js";
6
-
7
- /**
8
- * Continuous collision detection — linear shape-cast (the "speculative margin
9
- * floor, upgraded to an opt-in per-body sweep" item from PLAN.md).
10
- *
11
- * The discrete pipeline detects contacts by overlap at step boundaries: a body
12
- * that moves more than its own thickness in one step can start a step on one
13
- * side of a thin wall and end on the other, never overlapping it on any frame
14
- * the broadphase samples — it tunnels. The speculative fat-AABB margin
15
- * (`compute_fat_world_aabb`) covers moderate speeds; genuinely fast movers
16
- * (bullets, dropped debris, a body flung by an explosion) need a swept test.
17
- *
18
- * Approach (Box2D `b2_continuousPhysics`-style conservative advancement): after
19
- * the substep solver has produced each body's final pose, sweep a CCD-flagged
20
- * fast mover's primary collider along its NET step translation
21
- * (start-of-step → final pose) using the existing {@link shape_cast} TOI engine.
22
- * On the first blocker, clamp the body to the contact pose and remove the
23
- * inbound normal component of its velocity (an inelastic stop) — the next
24
- * discrete step then resolves the now-touching contact with the real
25
- * material / restitution.
26
- *
27
- * Scope (v1, deliberate):
28
- * - LINEAR sweep only: the orientation is held fixed through the sweep (the
29
- * per-step angular motion is small at the fixed-step rate).
30
- * - PRIMARY same-entity collider: a compound body sweeps its first collider;
31
- * child-entity colliders (whose transform is synced outside the step) are
32
- * not swept.
33
- * - EXACT against static geometry (the static BVH holds tight, never-moved
34
- * leaves); APPROXIMATE against other dynamic bodies (they have moved this
35
- * step too, but the sweep sees their start-of-step broadphase AABBs) — the
36
- * speculative-margin floor for the dynamic-vs-dynamic case.
37
- * - The CCD stop itself is inelastic; the impact does not bounce. Restitution
38
- * applies on the next discrete contact.
39
- */
40
-
41
- /**
42
- * Minimum per-step displacement (metres) before a CCD sweep is worth running.
43
- * Its ONLY job is to skip a body that didn't meaningfully move — a resting /
44
- * sleeping-soon body whose displacement is sub-millimetre jitter — which avoids
45
- * a degenerate zero-length sweep and saves the query cost.
46
- *
47
- * It must NOT be tied to the body's own size. Tunnelling risk is governed by the
48
- * *obstacle's* thickness, not the mover's: a 2 m sphere drifting at 0.5 m/step
49
- * still passes clean through a 1 cm floor. A small absolute slop catches that;
50
- * gating on a fraction of the body's extent would (wrongly) wait until the body
51
- * moved more than its own radius and miss every thin-obstacle tunnel below that
52
- * speed. The discrete narrowphase still owns any obstacle thicker than a body's
53
- * per-step move, so CCD reliably prevents tunnelling of obstacles thicker than
54
- * this slop.
55
- * @type {number}
56
- */
57
- export const CCD_MIN_SWEEP_DISTANCE = 1e-3;
58
-
59
- /**
60
- * Impact distances at or below this (metres) mean the body was already
61
- * overlapping the target at the start of the step — i.e. a resting / sliding
62
- * contact the discrete solver owns, not a tunnel. The sweep ignores these so
63
- * CCD never clamps a body to a surface it is merely sitting or sliding on.
64
- * @type {number}
65
- */
66
- const CCD_INITIAL_OVERLAP_EPS = 1e-6;
67
-
68
- // ── Module scratch ──────────────────────────────────────────────────────────
69
- // CCD runs inside the step loop; reuse buffers so the pass allocates nothing.
70
-
71
- /** Swept ray, re-seeded per sweep (origin, unit direction, tMax). */
72
- const _ray = new Ray3();
73
-
74
- /** Sweep result reused across bodies inside {@link ccd_resolve}. */
75
- const _hit = new PhysicsSurfacePoint();
76
-
77
- /**
78
- * Entity whose colliders the current sweep must ignore (the moving body's own).
79
- * Module-scoped so {@link _exclude_self} stays a stable, non-allocating
80
- * reference handed to {@link shape_cast}.
81
- * @type {number}
82
- */
83
- let _exclude_entity = -1;
84
-
85
- /**
86
- * Self-exclusion filter for the sweep: drop candidates owned by the moving
87
- * body's own entity (otherwise the body would "hit itself" at `t = 0`).
88
- * @param {number} entity
89
- * @returns {boolean}
90
- */
91
- function _exclude_self(entity) {
92
- return entity !== _exclude_entity;
93
- }
94
-
95
- /**
96
- * Sweep `shape` (held at the fixed `rotation`) linearly from `(fx,fy,fz)` to
97
- * `(tx,ty,tz)` through both broadphase trees, ignoring colliders owned by
98
- * `exclude_entity`.
99
- *
100
- * Returns the traversable fraction of the segment in `[0, 1]`: `1` means the
101
- * path is clear; a value `< 1` means a blocker was hit at that fraction and
102
- * `result` has been filled — `result.position` is the swept-shape centre at
103
- * first contact, `result.normal` is the blocker's outward surface normal
104
- * (B → A), `result.entity` / `result.body_id` the blocker.
105
- *
106
- * @param {import("../ecs/PhysicsSystem.js").PhysicsSystem} system
107
- * @param {import("../../../core/geom/3d/shape/AbstractShape3D.js").AbstractShape3D} shape
108
- * @param {{x:number,y:number,z:number,w:number}} rotation fixed orientation
109
- * @param {number} fx
110
- * @param {number} fy
111
- * @param {number} fz
112
- * @param {number} tx
113
- * @param {number} ty
114
- * @param {number} tz
115
- * @param {number} exclude_entity entity to ignore (the swept body itself)
116
- * @param {PhysicsSurfacePoint} result populated on hit; untouched on a clear path
117
- * @returns {number} traversable fraction in [0, 1]
118
- */
119
- export function ccd_sweep_segment(
120
- system, shape, rotation,
121
- fx, fy, fz, tx, ty, tz,
122
- exclude_entity, result,
123
- ) {
124
- const dx = tx - fx;
125
- const dy = ty - fy;
126
- const dz = tz - fz;
127
- const len = Math.sqrt(dx * dx + dy * dy + dz * dz);
128
- if (len === 0) return 1;
129
-
130
- const inv = 1 / len;
131
- _ray[0] = fx; _ray[1] = fy; _ray[2] = fz;
132
- _ray[3] = dx * inv; _ray[4] = dy * inv; _ray[5] = dz * inv;
133
- _ray[6] = len; // tMax in metres — direction is unit length
134
-
135
- _exclude_entity = exclude_entity;
136
- if (!shape_cast(system, _ray, shape, rotation, result, _exclude_self)) {
137
- return 1;
138
- }
139
-
140
- // An impact at t ≈ 0 means the swept shape was already overlapping the
141
- // target at the segment start — a resting / sliding contact, not a tunnel.
142
- // The discrete solver owns it; clamping here would freeze a body onto a
143
- // surface it is sitting or sliding on. Treat as a clear path.
144
- if (result.t <= CCD_INITIAL_OVERLAP_EPS) return 1;
145
-
146
- // result.t is the impact distance along the unit direction; normalise to a
147
- // segment fraction. shape_cast reports the just-SEPARATING side of its
148
- // bisection, so the swept shape at `result.t` is provably not overlapping —
149
- // safe to place the body there.
150
- const frac = result.t * inv;
151
- return frac < 1 ? frac : 1;
152
- }
153
-
154
- /**
155
- * Post-solve continuous-collision pass over the awake set. For each awake
156
- * Dynamic body flagged {@link RigidBodyFlags.CCD} that moved more than
157
- * {@link CCD_MIN_SWEEP_DISTANCE} this step, sweep its primary collider along the
158
- * step's net translation and stop it at the first blocker (clamp pose + remove
159
- * inbound normal velocity).
160
- *
161
- * Start-of-step positions are captured into `system.__ccd_start_pos` (3 doubles
162
- * per body index) before the substep loop; this pass reads the final pose from
163
- * the live Transform. Iterates the awake list in storage order, so it is
164
- * deterministic.
165
- *
166
- * @param {import("../ecs/PhysicsSystem.js").PhysicsSystem} system
167
- */
168
- export function ccd_resolve(system) {
169
- const storage = system.storage;
170
- const count = storage.awake_count;
171
- const lists = system.__body_collider_lists;
172
- const start = system.__ccd_start_pos;
173
- const CCD = RigidBodyFlags.CCD;
174
-
175
- for (let i = 0; i < count; i++) {
176
- const idx = storage.awake_at(i);
177
-
178
- const rb = system.__bodies[idx];
179
- if (rb === undefined) continue;
180
- if ((rb.flags & CCD) === 0) continue;
181
- if (rb.kind !== BodyKind.Dynamic) continue;
182
-
183
- const list = lists[idx];
184
- if (list === undefined || list.length === 0) continue;
185
- const primary = list[0];
186
- const tr = primary.transform;
187
- const p = tr.position;
188
-
189
- const base = idx * 3;
190
- const sx = start[base];
191
- const sy = start[base + 1];
192
- const sz = start[base + 2];
193
- const ex = p[0];
194
- const ey = p[1];
195
- const ez = p[2];
196
-
197
- const dx = ex - sx;
198
- const dy = ey - sy;
199
- const dz = ez - sz;
200
- const disp2 = dx * dx + dy * dy + dz * dz;
201
- if (disp2 === 0) continue;
202
-
203
- // Motion gate: skip a body that barely moved (resting / negligible
204
- // jitter) avoids a degenerate sweep and the query cost. NOT tied to
205
- // body size: a body tunnels a thin obstacle at speeds well below its
206
- // own extent, so the threshold is a small absolute slop. A resting /
207
- // sliding body that does clear it is still safe — the sweep ignores its
208
- // initial-overlap contact (see CCD_INITIAL_OVERLAP_EPS).
209
- if (disp2 <= CCD_MIN_SWEEP_DISTANCE * CCD_MIN_SWEEP_DISTANCE) continue;
210
-
211
- const shape = primary.collider.shape;
212
- const frac = ccd_sweep_segment(
213
- system, shape, tr.rotation,
214
- sx, sy, sz, ex, ey, ez,
215
- primary.entity, _hit,
216
- );
217
- if (frac >= 1) continue; // clear path — no tunnelling this step
218
-
219
- // Clamp the body to the first-contact pose (swept-shape centre at the
220
- // TOI), so it cannot end the step on the far side of the blocker.
221
- const hp = _hit.position;
222
- p.set(hp[0], hp[1], hp[2]);
223
-
224
- // Remove the inbound normal component of velocity (inelastic stop).
225
- // `_hit.normal` is the blocker's outward surface normal; the body is
226
- // moving into it (v·n < 0). Zeroing that component leaves the tangential
227
- // slide intact and never adds energy. The next discrete step applies the
228
- // real restitution / friction on the established contact.
229
- const n = _hit.normal;
230
- const lv = rb.linearVelocity;
231
- const vn = lv[0] * n[0] + lv[1] * n[1] + lv[2] * n[2];
232
- if (vn < 0) {
233
- lv[0] -= vn * n[0];
234
- lv[1] -= vn * n[1];
235
- lv[2] -= vn * n[2];
236
- }
237
- }
238
- }
1
+ import { Ray3 } from "../../../core/geom/3d/ray/Ray3.js";
2
+ import { BodyKind } from "../ecs/BodyKind.js";
3
+ import { RigidBodyFlags } from "../ecs/RigidBodyFlags.js";
4
+ import { PhysicsSurfacePoint } from "../queries/PhysicsSurfacePoint.js";
5
+ import { shape_cast } from "../queries/shape_cast.js";
6
+
7
+ /**
8
+ * Continuous collision detection — linear shape-cast (the "speculative margin
9
+ * floor, upgraded to an opt-in per-body sweep" item from PLAN.md).
10
+ *
11
+ * The discrete pipeline detects contacts by overlap at step boundaries: a body
12
+ * that moves more than its own thickness in one step can start a step on one
13
+ * side of a thin wall and end on the other, never overlapping it on any frame
14
+ * the broadphase samples — it tunnels. The speculative fat-AABB margin
15
+ * (`compute_fat_world_aabb`) covers moderate speeds; genuinely fast movers
16
+ * (bullets, dropped debris, a body flung by an explosion) need a swept test.
17
+ *
18
+ * Approach (Box2D `b2_continuousPhysics`-style conservative advancement): after
19
+ * the substep solver has produced each body's final pose, sweep a CCD-flagged
20
+ * fast mover's primary collider along its NET step translation
21
+ * (start-of-step → final pose) using the existing {@link shape_cast} TOI engine.
22
+ * On the first blocker, clamp the body to the contact pose and remove the
23
+ * inbound normal component of its velocity (an inelastic stop) — the next
24
+ * discrete step then resolves the now-touching contact with the real
25
+ * material / restitution.
26
+ *
27
+ * Scope (v1, deliberate):
28
+ * - LINEAR sweep only: the orientation is held fixed through the sweep (the
29
+ * per-step angular motion is small at the fixed-step rate).
30
+ * - PRIMARY same-entity collider: a compound body sweeps its first collider;
31
+ * child-entity colliders (whose transform is synced outside the step) are
32
+ * not swept.
33
+ * - EXACT against static geometry (the static BVH holds tight, never-moved
34
+ * leaves); APPROXIMATE against other dynamic bodies (they have moved this
35
+ * step too, but the sweep sees their start-of-step broadphase AABBs) — the
36
+ * speculative-margin floor for the dynamic-vs-dynamic case.
37
+ * - The CCD stop itself is inelastic; the impact does not bounce. Restitution
38
+ * applies on the next discrete contact.
39
+ */
40
+
41
+ /**
42
+ * Minimum per-step displacement (metres) before a CCD sweep is worth running.
43
+ * Its ONLY job is to skip a body that didn't meaningfully move — a resting /
44
+ * sleeping-soon body whose displacement is sub-millimetre jitter — which avoids
45
+ * a degenerate zero-length sweep and saves the query cost.
46
+ *
47
+ * It must NOT be tied to the body's own size. Tunnelling risk is governed by the
48
+ * *obstacle's* thickness, not the mover's: a 2 m sphere drifting at 0.5 m/step
49
+ * still passes clean through a 1 cm floor. A small absolute slop catches that;
50
+ * gating on a fraction of the body's extent would (wrongly) wait until the body
51
+ * moved more than its own radius and miss every thin-obstacle tunnel below that
52
+ * speed. The discrete narrowphase still owns any obstacle thicker than a body's
53
+ * per-step move, so CCD reliably prevents tunnelling of obstacles thicker than
54
+ * this slop.
55
+ * @type {number}
56
+ */
57
+ export const CCD_MIN_SWEEP_DISTANCE = 1e-3;
58
+
59
+ /**
60
+ * Impact distances at or below this (metres) mean the body was already
61
+ * overlapping the target at the start of the step — i.e. a resting / sliding
62
+ * contact the discrete solver owns, not a tunnel. The sweep ignores these so
63
+ * CCD never clamps a body to a surface it is merely sitting or sliding on.
64
+ * @type {number}
65
+ */
66
+ const CCD_INITIAL_OVERLAP_EPS = 1e-6;
67
+
68
+ // ── Module scratch ──────────────────────────────────────────────────────────
69
+ // CCD runs inside the step loop; reuse buffers so the pass allocates nothing.
70
+
71
+ /** Swept ray, re-seeded per sweep (origin, unit direction, tMax). */
72
+ const _ray = new Ray3();
73
+
74
+ /** Sweep result reused across bodies inside {@link ccd_resolve}. */
75
+ const _hit = new PhysicsSurfacePoint();
76
+
77
+ /**
78
+ * Entity whose colliders the current sweep must ignore (the moving body's own).
79
+ * Module-scoped so {@link _exclude_self} stays a stable, non-allocating
80
+ * reference handed to {@link shape_cast}.
81
+ * @type {number}
82
+ */
83
+ let _exclude_entity = -1;
84
+
85
+ /**
86
+ * Self-exclusion filter for the sweep: drop candidates owned by the moving
87
+ * body's own entity (otherwise the body would "hit itself" at `t = 0`).
88
+ * @param {number} entity
89
+ * @returns {boolean}
90
+ */
91
+ function _exclude_self(entity) {
92
+ return entity !== _exclude_entity;
93
+ }
94
+
95
+ /**
96
+ * Sweep `shape` (held at the fixed `rotation`) linearly from `(fx,fy,fz)` to
97
+ * `(tx,ty,tz)` through both broadphase trees, ignoring colliders owned by
98
+ * `exclude_entity`.
99
+ *
100
+ * Returns the traversable fraction of the segment in `[0, 1]`: `1` means the
101
+ * path is clear; a value `< 1` means a blocker was hit at that fraction and
102
+ * `result` has been filled — `result.position` is the swept-shape centre at
103
+ * first contact, `result.normal` is the blocker's outward surface normal
104
+ * (B → A), `result.entity` / `result.body_id` the blocker.
105
+ *
106
+ * @param {import("../ecs/PhysicsSystem.js").PhysicsSystem} system
107
+ * @param {import("../../../core/geom/3d/shape/AbstractShape3D.js").AbstractShape3D} shape
108
+ * @param {{x:number,y:number,z:number,w:number}} rotation fixed orientation
109
+ * @param {number} fx
110
+ * @param {number} fy
111
+ * @param {number} fz
112
+ * @param {number} tx
113
+ * @param {number} ty
114
+ * @param {number} tz
115
+ * @param {number} exclude_entity entity to ignore (the swept body itself)
116
+ * @param {PhysicsSurfacePoint} result populated on hit; untouched on a clear path
117
+ * @returns {number} traversable fraction in [0, 1]
118
+ */
119
+ export function ccd_sweep_segment(
120
+ system, shape, rotation,
121
+ fx, fy, fz, tx, ty, tz,
122
+ exclude_entity, result,
123
+ ) {
124
+ const dx = tx - fx;
125
+ const dy = ty - fy;
126
+ const dz = tz - fz;
127
+ const len = Math.sqrt(dx * dx + dy * dy + dz * dz);
128
+ if (len === 0) return 1;
129
+
130
+ const inv = 1 / len;
131
+ _ray[0] = fx; _ray[1] = fy; _ray[2] = fz;
132
+ _ray[3] = dx * inv; _ray[4] = dy * inv; _ray[5] = dz * inv;
133
+ _ray[6] = len; // tMax in metres — direction is unit length
134
+
135
+ _exclude_entity = exclude_entity;
136
+ if (!shape_cast(system, _ray, shape, rotation, result, _exclude_self)) {
137
+ return 1;
138
+ }
139
+
140
+ // An impact at t ≈ 0 means the swept shape was already overlapping the
141
+ // target at the segment start — a resting / sliding contact, not a tunnel.
142
+ // The discrete solver owns it; clamping here would freeze a body onto a
143
+ // surface it is sitting or sliding on. Treat as a clear path.
144
+ if (result.t <= CCD_INITIAL_OVERLAP_EPS) return 1;
145
+
146
+ // result.t is the impact distance along the unit direction; normalise to a
147
+ // segment fraction. shape_cast reports the just-SEPARATING side of its
148
+ // bisection, so the swept shape at `result.t` is provably not overlapping —
149
+ // safe to place the body there.
150
+ const frac = result.t * inv;
151
+ return frac < 1 ? frac : 1;
152
+ }
153
+
154
+ /**
155
+ * Post-solve continuous-collision pass over the awake set. For each awake
156
+ * Dynamic body flagged {@link RigidBodyFlags.CCD} that moved more than
157
+ * {@link CCD_MIN_SWEEP_DISTANCE} this step, sweep its primary collider along the
158
+ * step's net translation and stop it at the first blocker (clamp pose + remove
159
+ * inbound normal velocity).
160
+ *
161
+ * Start-of-step positions are captured into `system.__ccd_start_pos` (3 doubles
162
+ * per body index) before the substep loop; this pass reads the final pose from
163
+ * the live Transform. Iterates the awake list in storage order, so it is
164
+ * deterministic.
165
+ *
166
+ * @param {import("../ecs/PhysicsSystem.js").PhysicsSystem} system
167
+ */
168
+ export function ccd_resolve(system) {
169
+ const storage = system.storage;
170
+ const count = storage.awake_count;
171
+ const lists = system.__body_collider_lists;
172
+ const start = system.__ccd_start_pos;
173
+ const CCD = RigidBodyFlags.CCD;
174
+
175
+ for (let i = 0; i < count; i++) {
176
+ const idx = storage.awake_at(i);
177
+
178
+ const rb = system.__bodies[idx];
179
+ if (rb === undefined) continue;
180
+ if ((rb.flags & CCD) === 0) continue;
181
+ if (rb.kind !== BodyKind.Dynamic) continue;
182
+
183
+ const list = lists[idx];
184
+ if (list === undefined || list.length === 0) continue;
185
+ const primary = list[0];
186
+ const tr = primary.transform;
187
+ const p = tr.position;
188
+
189
+ const base = idx * 3;
190
+ const sx = start[base];
191
+ const sy = start[base + 1];
192
+ const sz = start[base + 2];
193
+ const ex = p[0];
194
+ const ey = p[1];
195
+ const ez = p[2];
196
+
197
+ const dx = ex - sx;
198
+ const dy = ey - sy;
199
+ const dz = ez - sz;
200
+ const disp2 = dx * dx + dy * dy + dz * dz;
201
+
202
+ // Motion gate: skip a body that barely moved (resting / negligible
203
+ // jitter) avoids a degenerate sweep and the query cost. NOT tied to
204
+ // body size: a body tunnels a thin obstacle at speeds well below its
205
+ // own extent, so the threshold is a small absolute slop. A resting /
206
+ // sliding body that does clear it is still safe the sweep ignores its
207
+ // initial-overlap contact (see CCD_INITIAL_OVERLAP_EPS).
208
+ if (disp2 <= CCD_MIN_SWEEP_DISTANCE * CCD_MIN_SWEEP_DISTANCE) continue;
209
+
210
+ const shape = primary.collider.shape;
211
+ const frac = ccd_sweep_segment(
212
+ system, shape, tr.rotation,
213
+ sx, sy, sz, ex, ey, ez,
214
+ primary.entity, _hit,
215
+ );
216
+ if (frac >= 1) continue; // clear path — no tunnelling this step
217
+
218
+ // Clamp the body to the first-contact pose (swept-shape centre at the
219
+ // TOI), so it cannot end the step on the far side of the blocker.
220
+ const hp = _hit.position;
221
+ p.set(hp[0], hp[1], hp[2]);
222
+
223
+ // Remove the inbound normal component of velocity (inelastic stop).
224
+ // `_hit.normal` is the blocker's outward surface normal; the body is
225
+ // moving into it (v·n < 0). Zeroing that component leaves the tangential
226
+ // slide intact and never adds energy. The next discrete step applies the
227
+ // real restitution / friction on the established contact.
228
+ const n = _hit.normal;
229
+ const lv = rb.linearVelocity;
230
+ const vn = lv[0] * n[0] + lv[1] * n[1] + lv[2] * n[2];
231
+ if (vn < 0) {
232
+ lv[0] -= vn * n[0];
233
+ lv[1] -= vn * n[1];
234
+ lv[2] -= vn * n[2];
235
+ }
236
+ }
237
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"computeInterceptPoint.d.ts","sourceRoot":"","sources":["../../../../src/engine/physics/computeInterceptPoint.js"],"names":[],"mappings":"AASA;;;;;;;;;GASG;AACH,+HAHW,MAAM,GACL,OAAO,CAyDlB"}
1
+ {"version":3,"file":"computeInterceptPoint.d.ts","sourceRoot":"","sources":["../../../../src/engine/physics/computeInterceptPoint.js"],"names":[],"mappings":"AASA;;;;;;;;;GASG;AACH,+HAHW,MAAM,GACL,OAAO,CA8DlB"}
@@ -60,9 +60,14 @@ export function computeInterceptPoint(
60
60
 
61
61
  if (t >= 0) {
62
62
 
63
- result.copy(targetVelocity);
64
- result.multiplyScalar(t);
65
- result.add(target);
63
+ // Single write, computed from the inputs up front, so it is correct
64
+ // even when `result` aliases `target` (a copy-then-add would read
65
+ // `target` after overwriting it, doubling the velocity term).
66
+ result.set(
67
+ target.x + targetVelocity.x * t,
68
+ target.y + targetVelocity.y * t,
69
+ target.z + targetVelocity.z * t,
70
+ );
66
71
 
67
72
  return true;
68
73
 
@@ -82,7 +82,6 @@ export class ManifoldStore {
82
82
  __high_water: number;
83
83
  __data: Float64Array;
84
84
  __meta: Uint32Array;
85
- __slot_axis: Float64Array;
86
85
  __pair_index: PairUint32Map;
87
86
  __live_slots: Uint32Array;
88
87
  __live_pos: Int32Array;
@@ -268,21 +267,6 @@ export class ManifoldStore {
268
267
  * @returns {Float64Array}
269
268
  */
270
269
  get data_buffer(): Float64Array;
271
- /**
272
- * Per-slot cached GJK separating axis buffer. Hot-path GJK callers
273
- * pass this together with {@link slot_axis_offset} to
274
- * `gjk_with_axis(...)` so the cached axis seeds the next iteration.
275
- * Buffer identity is stable until grow.
276
- * @returns {Float64Array}
277
- */
278
- get slot_axis_buffer(): Float64Array;
279
- /**
280
- * Float offset into {@link slot_axis_buffer} where this slot's
281
- * cached axis lives (3 floats: x, y, z).
282
- * @param {number} slot
283
- * @returns {number}
284
- */
285
- slot_axis_offset(slot: number): number;
286
270
  /**
287
271
  * Word offset into {@link data_buffer} where the first contact of `slot`
288
272
  * begins. Subsequent contacts within the slot are at
@@ -1 +1 @@
1
- {"version":3,"file":"ManifoldStore.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/contact/ManifoldStore.js"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wCAFU,MAAM,CAE2B;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,6BAFU,MAAM,CAEiB;AAEjC;;;;GAIG;AACH,wCAFU,MAAM,CAE4B;AAE5C;;;GAGG;AACH,+BAFU,MAAM,CAE2D;AAyB3E;;;GAGG;AACH,mCAFU,MAAM,CAEuB;AAIvC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;IAEI;;OAEG;IACH,+BAFW,MAAM,EA6BhB;IAzBG,mBAA+C;IAC/C,qBAAqB;IAErB,qBAAkE;IAClE,oBAAiE;IAQjE,0BAAwD;IAExD,4BAA0D;IAG1D,0BAAoD;IACpD,uBAAiD;IAEjD,qBAAqB;IAGrB,yBAAmD;IACnD,qBAAqB;IAGzB;;OAEG;IACH,oBAEC;IAED;;OAEG;IACH,uBAEC;IAED;;;;;;;OAOG;IACH,UAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAKlB;IAED;;;;;;;;OAQG;IACH,aAJW,MAAM,OACN,MAAM,GACJ,MAAM,CA+BlB;IAED;;;OAGG;IACH,YAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,YAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,oBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,iBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;OAGG;IACH,uBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;;;OAKG;IACH,WAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;OAKG;IACH,qBAFW,MAAM,QAQhB;IAED;;;;;;;;;;;;;OAaG;IACH,mBAFW,MAAM,QAKhB;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,kBAnBW,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,SACN,MAAM,eACN,MAAM,aAGN,MAAM,gBAEN,MAAM,QAwBhB;IAED;;;;;OAKG;IACH,kBAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;OAKG;IACH,qBAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;;;;;;;;;;OAeG;IACH,qBAHW,MAAM,OACN,MAAM,QAOhB;IAED;;;;;OAKG;IACH,oBAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;OAMG;IACH,kBALW,MAAM,OACN,MAAM,OACN,MAAM,EAAE,GAAC,YAAY,cACrB,MAAM,QAOhB;IAED;;;;;;OAMG;IACH,uBAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAIlB;IAED,iEAAiE;IACjE,uBADY,MAAM,OAAe,MAAM,GAAgB,MAAM,CAG5D;IAED,iEAAiE;IACjE,uBADY,MAAM,OAAe,MAAM,GAAgB,MAAM,CAG5D;IAED,iEAAiE;IACjE,oBADY,MAAM,OAAe,MAAM,GAAgB,MAAM,CAG5D;IAED;;;;;OAKG;IACH,gCAEC;IAED;;;;;;OAMG;IACH,qCAEC;IAED;;;;;OAKG;IACH,uBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;OAMG;IACH,uBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,sBA6BC;IAED;;;OAGG;IACH,wBAcC;IAED;;;OAGG;IACH,uBAkBC;IAED;;OAEG;IACH,eA+BC;IAED;;;OAGG;IACH,oBAaC;IAED;;;OAGG;IACH,mBAqBC;CACJ;8BAhoBqD,2CAA2C"}
1
+ {"version":3,"file":"ManifoldStore.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/contact/ManifoldStore.js"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wCAFU,MAAM,CAE2B;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,6BAFU,MAAM,CAEiB;AAEjC;;;;GAIG;AACH,wCAFU,MAAM,CAE4B;AAE5C;;;GAGG;AACH,+BAFU,MAAM,CAE2D;AAyB3E;;;GAGG;AACH,mCAFU,MAAM,CAEuB;AAIvC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;IAEI;;OAEG;IACH,+BAFW,MAAM,EAqBhB;IAjBG,mBAA+C;IAC/C,qBAAqB;IAErB,qBAAkE;IAClE,oBAAiE;IAEjE,4BAA0D;IAG1D,0BAAoD;IACpD,uBAAiD;IAEjD,qBAAqB;IAGrB,yBAAmD;IACnD,qBAAqB;IAGzB;;OAEG;IACH,oBAEC;IAED;;OAEG;IACH,uBAEC;IAED;;;;;;;OAOG;IACH,UAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAKlB;IAED;;;;;;;;OAQG;IACH,aAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAwBlB;IAED;;;OAGG;IACH,YAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,YAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,oBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,iBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;OAGG;IACH,uBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;;;OAKG;IACH,WAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;OAKG;IACH,qBAFW,MAAM,QAQhB;IAED;;;;;;;;;;;;;OAaG;IACH,mBAFW,MAAM,QAKhB;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,kBAnBW,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,OACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,SACN,MAAM,eACN,MAAM,aAGN,MAAM,gBAEN,MAAM,QAwBhB;IAED;;;;;OAKG;IACH,kBAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;OAKG;IACH,qBAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;;;;;;;;;;OAeG;IACH,qBAHW,MAAM,OACN,MAAM,QAOhB;IAED;;;;;OAKG;IACH,oBAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;OAMG;IACH,kBALW,MAAM,OACN,MAAM,OACN,MAAM,EAAE,GAAC,YAAY,cACrB,MAAM,QAOhB;IAED;;;;;;OAMG;IACH,uBAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAIlB;IAED,iEAAiE;IACjE,uBADY,MAAM,OAAe,MAAM,GAAgB,MAAM,CAG5D;IAED,iEAAiE;IACjE,uBADY,MAAM,OAAe,MAAM,GAAgB,MAAM,CAG5D;IAED,iEAAiE;IACjE,oBADY,MAAM,OAAe,MAAM,GAAgB,MAAM,CAG5D;IAED;;;;;OAKG;IACH,gCAEC;IAED;;;;;;OAMG;IACH,uBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,sBA6BC;IAED;;;OAGG;IACH,wBAcC;IAED;;;OAGG;IACH,uBAkBC;IAED;;OAEG;IACH,eA8BC;IAED;;;OAGG;IACH,oBAaC;IAED;;;OAGG;IACH,mBAqBC;CACJ;8BA3lBqD,2CAA2C"}