@woosh/meep-engine 2.139.0 → 2.141.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 (199) hide show
  1. package/package.json +1 -1
  2. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.d.ts +3 -3
  3. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.d.ts.map +1 -1
  4. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.js +4 -4
  5. package/src/{engine/physics/broadphase/aabb_transform_oriented.d.ts → core/geom/3d/aabb/aabb3_transform_oriented.d.ts} +2 -2
  6. package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts.map +1 -0
  7. package/src/{engine/physics/broadphase/aabb_transform_oriented.js → core/geom/3d/aabb/aabb3_transform_oriented.js} +1 -1
  8. package/src/core/geom/3d/quaternion/quat3_multiply.d.ts +21 -0
  9. package/src/core/geom/3d/quaternion/quat3_multiply.d.ts.map +1 -0
  10. package/src/core/geom/3d/quaternion/quat3_multiply.js +25 -0
  11. package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts +54 -0
  12. package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts.map +1 -0
  13. package/src/core/geom/3d/quaternion/quat3_to_matrix3.js +69 -0
  14. package/src/core/geom/3d/shape/AbstractShape3D.d.ts +24 -2
  15. package/src/core/geom/3d/shape/AbstractShape3D.d.ts.map +1 -1
  16. package/src/core/geom/3d/shape/AbstractShape3D.js +24 -1
  17. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +148 -0
  18. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -0
  19. package/src/core/geom/3d/shape/HeightMapShape3D.js +451 -0
  20. package/src/core/geom/3d/shape/MeshShape3D.d.ts +210 -0
  21. package/src/core/geom/3d/shape/MeshShape3D.d.ts.map +1 -0
  22. package/src/core/geom/3d/shape/MeshShape3D.js +593 -0
  23. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  24. package/src/core/geom/3d/shape/TransformedShape3D.js +46 -2
  25. package/src/core/geom/3d/shape/Triangle3D.d.ts +95 -0
  26. package/src/core/geom/3d/shape/Triangle3D.d.ts.map +1 -0
  27. package/src/core/geom/3d/shape/Triangle3D.js +318 -0
  28. package/src/core/geom/3d/shape/UnionShape3D.js +13 -0
  29. package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts +30 -0
  30. package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts.map +1 -0
  31. package/src/core/geom/3d/shape/shape_mesh_from_geometry.js +64 -0
  32. package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.js +9 -11
  33. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.d.ts +28 -0
  34. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.d.ts.map +1 -0
  35. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.js +48 -0
  36. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts.map +1 -1
  37. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +40 -18
  38. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts +9 -5
  39. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts.map +1 -1
  40. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.js +38 -10
  41. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts +14 -5
  42. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts.map +1 -1
  43. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.js +47 -5
  44. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts +19 -0
  45. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts.map +1 -1
  46. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.js +75 -13
  47. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts +2 -2
  48. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts.map +1 -1
  49. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.js +1 -1
  50. package/src/core/geom/vec3/v3_dot_array_array.d.ts +3 -3
  51. package/src/core/geom/vec3/v3_dot_array_array.d.ts.map +1 -1
  52. package/src/core/geom/vec3/v3_dot_array_array.js +2 -2
  53. package/src/core/geom/vec3/v3_negate_array.d.ts +3 -3
  54. package/src/core/geom/vec3/v3_negate_array.d.ts.map +1 -1
  55. package/src/core/geom/vec3/v3_negate_array.js +2 -2
  56. package/src/core/geom/vec3/v3_quat3_apply.d.ts +29 -0
  57. package/src/core/geom/vec3/v3_quat3_apply.d.ts.map +1 -0
  58. package/src/core/geom/vec3/v3_quat3_apply.js +39 -0
  59. package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts +30 -0
  60. package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts.map +1 -0
  61. package/src/core/geom/vec3/v3_quat3_apply_inverse.js +41 -0
  62. package/src/core/geom/vec3/v3_triple_cross_product.d.ts +32 -0
  63. package/src/core/geom/vec3/v3_triple_cross_product.d.ts.map +1 -0
  64. package/src/core/geom/vec3/v3_triple_cross_product.js +45 -0
  65. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +16 -3
  66. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
  67. package/src/engine/control/first-person/FirstPersonPlayerController.js +211 -211
  68. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +72 -8
  69. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
  70. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +37 -5
  71. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +101 -3
  72. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  73. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +1789 -1416
  74. package/src/engine/control/first-person/TODO.md +173 -127
  75. package/src/engine/control/first-person/abilities/Slide.d.ts.map +1 -1
  76. package/src/engine/control/first-person/abilities/Slide.js +9 -1
  77. package/src/engine/control/first-person/prototype_first_person_controller.js +88 -2
  78. package/src/engine/control/first-person/test/buildTestPlayer.d.ts.map +1 -1
  79. package/src/engine/control/first-person/test/buildTestPlayer.js +9 -1
  80. package/src/engine/graphics/geometry/CapsuleGeometry.d.ts +42 -0
  81. package/src/engine/graphics/geometry/CapsuleGeometry.d.ts.map +1 -0
  82. package/src/engine/graphics/geometry/CapsuleGeometry.js +171 -0
  83. package/src/engine/physics/BULLET_REVIEW.md +945 -0
  84. package/src/engine/physics/CANNON_REVIEW.md +1300 -0
  85. package/src/engine/physics/JOLT_REVIEW.md +913 -0
  86. package/src/engine/physics/PLAN.md +578 -236
  87. package/src/engine/physics/RAPIER_REVIEW.md +934 -0
  88. package/src/engine/physics/REVIEW_001_ACTION_PLAN.md +642 -0
  89. package/src/engine/physics/REVIEW_002.md +151 -0
  90. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +2 -2
  91. package/src/engine/physics/constraint/DofMode.d.ts +28 -0
  92. package/src/engine/physics/constraint/DofMode.d.ts.map +1 -0
  93. package/src/engine/physics/constraint/DofMode.js +35 -0
  94. package/src/engine/physics/constraint/solve_constraints.d.ts +16 -0
  95. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -0
  96. package/src/engine/physics/constraint/solve_constraints.js +436 -0
  97. package/src/engine/physics/contact/ManifoldStore.d.ts +83 -10
  98. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  99. package/src/engine/physics/contact/ManifoldStore.js +608 -499
  100. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts +2 -2
  101. package/src/engine/physics/ecs/ColliderObserverSystem.d.ts.map +1 -1
  102. package/src/engine/physics/ecs/Joint.d.ts +179 -0
  103. package/src/engine/physics/ecs/Joint.d.ts.map +1 -0
  104. package/src/engine/physics/ecs/Joint.js +234 -0
  105. package/src/engine/physics/ecs/PhysicsSystem.d.ts +180 -20
  106. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  107. package/src/engine/physics/ecs/PhysicsSystem.js +1423 -1159
  108. package/src/engine/physics/fluid/FluidField.d.ts +14 -10
  109. package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
  110. package/src/engine/physics/fluid/FluidField.js +14 -10
  111. package/src/engine/physics/fluid/FluidSimulator.js +1 -1
  112. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +17 -10
  113. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -1
  114. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +18 -11
  115. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +13 -10
  116. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -1
  117. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +18 -13
  118. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +4 -3
  119. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -1
  120. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +15 -11
  121. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +30 -6
  122. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
  123. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +44 -18
  124. package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts +6 -6
  125. package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts.map +1 -1
  126. package/src/engine/physics/gjk/expanding_polytope_algorithm.js +68 -22
  127. package/src/engine/physics/gjk/gjk.d.ts +28 -2
  128. package/src/engine/physics/gjk/gjk.d.ts.map +1 -1
  129. package/src/engine/physics/gjk/gjk.js +421 -378
  130. package/src/engine/physics/gjk/minkowski_support.d.ts +37 -0
  131. package/src/engine/physics/gjk/minkowski_support.d.ts.map +1 -0
  132. package/src/engine/physics/gjk/minkowski_support.js +75 -0
  133. package/src/engine/physics/gjk/mpr.d.ts +56 -0
  134. package/src/engine/physics/gjk/mpr.d.ts.map +1 -0
  135. package/src/engine/physics/gjk/mpr.js +344 -0
  136. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +20 -5
  137. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
  138. package/src/engine/physics/inertia/world_inverse_inertia.js +36 -38
  139. package/src/engine/physics/integration/integrate_position.d.ts +25 -7
  140. package/src/engine/physics/integration/integrate_position.d.ts.map +1 -1
  141. package/src/engine/physics/integration/integrate_position.js +43 -12
  142. package/src/engine/physics/integration/integrate_velocity.d.ts +30 -0
  143. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  144. package/src/engine/physics/integration/integrate_velocity.js +82 -1
  145. package/src/engine/physics/island/IslandBuilder.d.ts +4 -1
  146. package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
  147. package/src/engine/physics/island/IslandBuilder.js +33 -16
  148. package/src/engine/physics/narrowphase/PosedShape.d.ts +0 -8
  149. package/src/engine/physics/narrowphase/PosedShape.d.ts.map +1 -1
  150. package/src/engine/physics/narrowphase/PosedShape.js +28 -30
  151. package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
  152. package/src/engine/physics/narrowphase/box_box_manifold.js +140 -18
  153. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts +30 -0
  154. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -0
  155. package/src/engine/physics/narrowphase/box_triangle_contact.js +811 -0
  156. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
  157. package/src/engine/physics/narrowphase/capsule_contacts.js +10 -56
  158. package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts +71 -0
  159. package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts.map +1 -0
  160. package/src/engine/physics/narrowphase/capsule_triangle_contact.js +375 -0
  161. package/src/engine/physics/narrowphase/compute_penetration.d.ts +91 -0
  162. package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -0
  163. package/src/engine/physics/narrowphase/compute_penetration.js +396 -0
  164. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts +35 -0
  165. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts.map +1 -0
  166. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.js +80 -0
  167. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts +31 -0
  168. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts.map +1 -0
  169. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.js +55 -0
  170. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +42 -0
  171. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -0
  172. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +204 -0
  173. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts +42 -0
  174. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -0
  175. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +94 -0
  176. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts +37 -0
  177. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts.map +1 -0
  178. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.js +37 -0
  179. package/src/engine/physics/narrowphase/narrowphase_step.d.ts +41 -2
  180. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  181. package/src/engine/physics/narrowphase/narrowphase_step.js +1497 -382
  182. package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -1
  183. package/src/engine/physics/narrowphase/sphere_box_contact.js +16 -23
  184. package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts +48 -0
  185. package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts.map +1 -0
  186. package/src/engine/physics/narrowphase/sphere_triangle_contact.js +143 -0
  187. package/src/engine/physics/queries/overlap_shape.d.ts +51 -0
  188. package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -0
  189. package/src/engine/physics/queries/overlap_shape.js +183 -0
  190. package/src/engine/physics/queries/shape_cast.d.ts +56 -0
  191. package/src/engine/physics/queries/shape_cast.d.ts.map +1 -0
  192. package/src/engine/physics/queries/shape_cast.js +387 -0
  193. package/src/engine/physics/solver/solve_contacts.d.ts +146 -32
  194. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
  195. package/src/engine/physics/solver/solve_contacts.js +809 -223
  196. package/src/engine/physics/broadphase/aabb_transform_oriented.d.ts.map +0 -1
  197. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts +0 -20
  198. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts.map +0 -1
  199. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.js +0 -83
@@ -0,0 +1,387 @@
1
+ import { bvh_query_user_data_overlaps_aabb } from "../../../core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.js";
2
+ import { returnTrue } from "../../../core/function/returnTrue.js";
3
+ import { aabb3_transform_oriented } from "../../../core/geom/3d/aabb/aabb3_transform_oriented.js";
4
+ import { body_id_index } from "../body/BodyStorage.js";
5
+ import { gjk } from "../gjk/gjk.js";
6
+ import { mpr } from "../gjk/mpr.js";
7
+ import { PosedShape } from "../narrowphase/PosedShape.js";
8
+
9
+ /**
10
+ * Bisection halts when the search interval is below this fraction of
11
+ * the sweep length. With `MAX_BISECTION = 32` and a unit-length sweep
12
+ * the achieved precision is ≈ 1 / 2³² (well below any practical
13
+ * world-scale tolerance), but we cap on relative tolerance so a
14
+ * 10 m sweep doesn't insist on sub-micron precision.
15
+ * @type {number}
16
+ */
17
+ const TOI_TOLERANCE = 1e-4;
18
+
19
+ /**
20
+ * Maximum bisection iterations. `log2(1 / TOI_TOLERANCE)` is enough
21
+ * for any practical sweep; this is the hard upper bound to prevent
22
+ * pathological inputs (NaN ray, etc.) from hanging the query.
23
+ * @type {number}
24
+ */
25
+ const MAX_BISECTION = 32;
26
+
27
+ /**
28
+ * Coarse linear-search resolution for finding *any* overlap moment
29
+ * along the per-candidate AABB-overlap interval (NOT the full sweep —
30
+ * see `aabb_overlap_interval` for the analytical narrowing that runs
31
+ * upstream). 32 substeps over the AABB-overlap window is dense enough
32
+ * for any sweep where the shape's smallest extent is on the order of
33
+ * its AABB's extent (true for spheres / boxes / capsules); the slab
34
+ * intersection keeps that interval small even for kilometre-scale
35
+ * sweeps, so this isn't the limit it would otherwise be.
36
+ * @type {number}
37
+ */
38
+ const COARSE_STEPS = 32;
39
+
40
+ const swept_aabb = new Float64Array(6);
41
+ const local_aabb = new Float64Array(6);
42
+ const initial_aabb = new Float64Array(6);
43
+ const target_local_aabb = new Float64Array(6);
44
+ const target_world_aabb = new Float64Array(6);
45
+
46
+ // GJK simplex buffer (used to detect overlap during the bisection).
47
+ const simplex_buf = new Float64Array(12);
48
+
49
+ // Scratch for MPR's MTV output — same vec3 convention as EPA: direction
50
+ // is "A's interior into B" with the magnitude being the depth. We use
51
+ // MPR for the contact-normal recovery at the kiss point because it
52
+ // converges reliably on smooth-vs-smooth supports where EPA hits its
53
+ // iteration cap before tightening (sphere-vs-sphere shallow overlap).
54
+ const mpr_result = new Float64Array(3);
55
+
56
+ /**
57
+ * Long-lived PosedShape adapters for the swept shape and the
58
+ * candidate's collider. Both are re-bound per query — the swept one
59
+ * also gets its position field re-written every bisection step
60
+ * without re-running `setup()`, since shape and rotation are
61
+ * constant through the sweep.
62
+ */
63
+ const swept_posed = new PosedShape();
64
+ const candidate_posed = new PosedShape();
65
+
66
+ /**
67
+ * Buffer for the union of static-BVH and dynamic-BVH candidates that
68
+ * overlap the swept AABB. Grows by doubling on the rare overflow.
69
+ * @type {Uint32Array}
70
+ */
71
+ let scratch_candidates = new Uint32Array(64);
72
+
73
+ /**
74
+ * Sweep a convex shape along a ray and find the first body it would
75
+ * hit. Used by character controllers (sweep a capsule along intended
76
+ * movement to find blockers), high-speed projectile movement (avoid
77
+ * tunnelling without paying for full per-body CCD), and any kinematic
78
+ * "where would this body end up if I tried to move it?" query.
79
+ *
80
+ * Pipeline:
81
+ * 1. Build the swept AABB: the shape's local-frame AABB rotated
82
+ * into world by `rotation`, translated to `ray.origin`, then
83
+ * stretched along `ray.direction * ray.tMax`.
84
+ * 2. Query both broadphase BVHs (static + dynamic) for leaves whose
85
+ * AABB overlaps the swept volume.
86
+ * 3. For each candidate, bisect the [0, best_t] interval for the
87
+ * smallest `t` at which the swept shape overlaps the candidate's
88
+ * collider. GJK on each midpoint.
89
+ *
90
+ * Picking `best_t` (rather than always running the full [0, tMax]
91
+ * bisection) is the early-termination optimisation: once we have a
92
+ * hit at some t, no later candidate can produce a smaller TOI by
93
+ * being checked at its full [0, tMax] interval.
94
+ *
95
+ * Output on hit:
96
+ * - `result.t` — sweep distance to impact (in the same units as
97
+ * `ray.direction`'s magnitude; for a unit-direction ray, this is
98
+ * metres).
99
+ * - `result.position` — `ray.origin + t * ray.direction`, i.e. the
100
+ * centre of the swept shape at the moment of first contact. NOT
101
+ * a point on the target's surface; that would need narrowphase
102
+ * refinement which the broadphase-only architecture doesn't have
103
+ * wired up yet.
104
+ * - `result.normal` — target surface's outward normal at the kiss
105
+ * point (unit length), computed by running GJK + EPA against the
106
+ * just-overlapping configuration at the TOI. Falls back to
107
+ * `-ray.direction` on the rare case EPA degenerates (NaN / zero
108
+ * depth) — see comment near the EPA call.
109
+ * - `result.entity` / `result.body_id` — the hit body.
110
+ *
111
+ * Output on miss: untouched; same convention as `raycast`.
112
+ *
113
+ * @param {PhysicsSystem} system
114
+ * @param {Ray3} ray origin + unit direction + `tMax`
115
+ * @param {AbstractShape3D} shape shape being swept, in its local frame
116
+ * @param {{x:number,y:number,z:number,w:number}} rotation fixed orientation
117
+ * @param {PhysicsSurfacePoint} result populated on hit; untouched on miss
118
+ * @param {(entity:number, collider:Collider)=>boolean} [filter] mandatory in
119
+ * contract; defaults to {@link returnTrue}
120
+ * @returns {boolean}
121
+ */
122
+ export function shape_cast(system, ray, shape, rotation, result, filter = returnTrue) {
123
+ const ox = ray.origin_x;
124
+ const oy = ray.origin_y;
125
+ const oz = ray.origin_z;
126
+ const dx = ray.direction_x;
127
+ const dy = ray.direction_y;
128
+ const dz = ray.direction_z;
129
+ const tMax = ray.tMax;
130
+ if (!(tMax > 0) || !Number.isFinite(tMax)) return false;
131
+
132
+ const rx = rotation.x, ry = rotation.y, rz = rotation.z, rw = rotation.w;
133
+
134
+ // ── 1. Swept AABB ──────────────────────────────────────────────
135
+ shape.compute_bounding_box(local_aabb);
136
+ // Rotation around ray.origin gives the shape's initial AABB in
137
+ // world space.
138
+ aabb3_transform_oriented(
139
+ initial_aabb, 0,
140
+ local_aabb[0], local_aabb[1], local_aabb[2],
141
+ local_aabb[3], local_aabb[4], local_aabb[5],
142
+ ox, oy, oz,
143
+ rx, ry, rz, rw
144
+ );
145
+ // Stretch by the sweep displacement. Positive direction components
146
+ // push the +face out; negative components push the −face out.
147
+ swept_aabb[0] = initial_aabb[0];
148
+ swept_aabb[1] = initial_aabb[1];
149
+ swept_aabb[2] = initial_aabb[2];
150
+ swept_aabb[3] = initial_aabb[3];
151
+ swept_aabb[4] = initial_aabb[4];
152
+ swept_aabb[5] = initial_aabb[5];
153
+ if (dx > 0) swept_aabb[3] += dx * tMax; else swept_aabb[0] += dx * tMax;
154
+ if (dy > 0) swept_aabb[4] += dy * tMax; else swept_aabb[1] += dy * tMax;
155
+ if (dz > 0) swept_aabb[5] += dz * tMax; else swept_aabb[2] += dz * tMax;
156
+
157
+ // ── 2. Broadphase: gather candidates from both trees ───────────
158
+ const n_static = bvh_query_user_data_overlaps_aabb(
159
+ scratch_candidates, 0, system.staticBvh, swept_aabb
160
+ );
161
+ const n_dynamic = bvh_query_user_data_overlaps_aabb(
162
+ scratch_candidates, n_static, system.dynamicBvh, swept_aabb
163
+ );
164
+ const n_total = n_static + n_dynamic;
165
+ if (n_total === 0) return false;
166
+
167
+ // ── 3. Narrowphase: per-candidate bisection ────────────────────
168
+ //
169
+ // Re-bind the swept shape's PosedShape once for shape + rotation;
170
+ // we update `px/py/pz` per bisection midpoint without rerunning
171
+ // setup (px/py/pz are public fields by contract).
172
+ swept_posed.shape = shape;
173
+ swept_posed.qx = rx; swept_posed.qy = ry; swept_posed.qz = rz; swept_posed.qw = rw;
174
+
175
+ let best_t = tMax;
176
+ let best_body_id = -1;
177
+ let best_entity = -1;
178
+
179
+ for (let i = 0; i < n_total; i++) {
180
+ const body_id = scratch_candidates[i];
181
+ const body_idx = body_id_index(body_id);
182
+ const entity = system.entityOf(body_id);
183
+ if (entity < 0) continue;
184
+
185
+ const collider = system.__primary_collider(body_idx);
186
+ if (collider === null) continue;
187
+ if (!filter(entity, collider)) continue;
188
+
189
+ const target_tr = system.__transforms[body_idx];
190
+ candidate_posed.setup(collider.shape, target_tr.position, target_tr.rotation);
191
+
192
+ // Already overlapping at t = 0? Return immediately — can't beat
193
+ // this, and the bisection's "no overlap at lo, overlap at hi"
194
+ // invariant doesn't hold.
195
+ swept_posed.px = ox; swept_posed.py = oy; swept_posed.pz = oz;
196
+ if (gjk(simplex_buf, swept_posed, candidate_posed)) {
197
+ best_t = 0;
198
+ best_body_id = body_id;
199
+ best_entity = entity;
200
+ break;
201
+ }
202
+
203
+ // ── Slab intersection: narrow the search interval analytically ─
204
+ //
205
+ // Compute the body's tight world AABB and intersect it with the
206
+ // swept shape's AABB sliding along the sweep direction. The
207
+ // result is the t-interval `[t_aabb_enter, t_aabb_exit]` during
208
+ // which the two AABBs overlap. Outside this interval the actual
209
+ // shapes can't overlap either (AABB is a superset of the
210
+ // shape), so we get to skip all of [0, t_aabb_enter) and
211
+ // (t_aabb_exit, best_t] without testing.
212
+ //
213
+ // This is the key to making `shapeCast` scale to long sweeps:
214
+ // a 1 km cast of a 1 m sphere against another 1 m sphere has an
215
+ // AABB-overlap window of ≈ 2 m (the sum of diameters along the
216
+ // sweep axis), reducing the coarse-step grid from a 30 m
217
+ // resolution (1000/32) to 6 cm (2/32).
218
+ collider.shape.compute_bounding_box(target_local_aabb);
219
+ aabb3_transform_oriented(
220
+ target_world_aabb, 0,
221
+ target_local_aabb[0], target_local_aabb[1], target_local_aabb[2],
222
+ target_local_aabb[3], target_local_aabb[4], target_local_aabb[5],
223
+ target_tr.position.x, target_tr.position.y, target_tr.position.z,
224
+ target_tr.rotation.x, target_tr.rotation.y, target_tr.rotation.z, target_tr.rotation.w
225
+ );
226
+
227
+ let t_aabb_enter = -Infinity;
228
+ let t_aabb_exit = Infinity;
229
+ let skip_candidate = false;
230
+ for (let ax = 0; ax < 3; ax++) {
231
+ const init_min = initial_aabb[ax];
232
+ const init_max = initial_aabb[ax + 3];
233
+ const body_min = target_world_aabb[ax];
234
+ const body_max = target_world_aabb[ax + 3];
235
+ const d_ax = ax === 0 ? dx : (ax === 1 ? dy : dz);
236
+ if (d_ax === 0) {
237
+ // Static along this axis: AABBs must overlap in their
238
+ // initial position or this candidate is unreachable.
239
+ if (init_max < body_min || init_min > body_max) {
240
+ skip_candidate = true;
241
+ break;
242
+ }
243
+ continue;
244
+ }
245
+ // swept_min(t) = init_min + d·t, swept_max(t) = init_max + d·t.
246
+ // Slab-enter: swept_max(t) = body_min → t = (body_min − init_max) / d
247
+ // Slab-exit: swept_min(t) = body_max → t = (body_max − init_min) / d
248
+ const t1 = (body_min - init_max) / d_ax;
249
+ const t2 = (body_max - init_min) / d_ax;
250
+ const lo = t1 < t2 ? t1 : t2;
251
+ const hi = t1 < t2 ? t2 : t1;
252
+ if (lo > t_aabb_enter) t_aabb_enter = lo;
253
+ if (hi < t_aabb_exit) t_aabb_exit = hi;
254
+ }
255
+ if (skip_candidate) continue;
256
+ if (t_aabb_enter > t_aabb_exit) continue;
257
+
258
+ // Clamp to the relevant t-window: [0, best_t]. Anything beyond
259
+ // best_t can't tighten the answer.
260
+ const t_start = t_aabb_enter > 0 ? t_aabb_enter : 0;
261
+ const t_end = t_aabb_exit < best_t ? t_aabb_exit : best_t;
262
+ if (t_start >= t_end) continue;
263
+
264
+ // Coarse-search within the narrowed interval to find any t for
265
+ // which the shapes overlap (their AABBs do by construction; the
266
+ // shapes themselves may not, e.g. two spheres passing alongside).
267
+ const step_dt = (t_end - t_start) / COARSE_STEPS;
268
+ let t_prev = t_start;
269
+ let t_hi = -1;
270
+ for (let s = 1; s <= COARSE_STEPS; s++) {
271
+ const t = t_start + s * step_dt;
272
+ swept_posed.px = ox + dx * t;
273
+ swept_posed.py = oy + dy * t;
274
+ swept_posed.pz = oz + dz * t;
275
+ if (gjk(simplex_buf, swept_posed, candidate_posed)) {
276
+ t_hi = t;
277
+ break;
278
+ }
279
+ t_prev = t;
280
+ }
281
+ if (t_hi < 0) continue;
282
+
283
+ // Bisect [t_prev, t_hi]: invariant is `gjk(t_lo) === false` and
284
+ // `gjk(t_hi) === true`.
285
+ let t_lo = t_prev;
286
+ const stop_width = TOI_TOLERANCE * tMax;
287
+ for (let bi = 0; bi < MAX_BISECTION && (t_hi - t_lo) > stop_width; bi++) {
288
+ const t_mid = (t_lo + t_hi) * 0.5;
289
+ swept_posed.px = ox + dx * t_mid;
290
+ swept_posed.py = oy + dy * t_mid;
291
+ swept_posed.pz = oz + dz * t_mid;
292
+ if (gjk(simplex_buf, swept_posed, candidate_posed)) {
293
+ t_hi = t_mid;
294
+ } else {
295
+ t_lo = t_mid;
296
+ }
297
+ }
298
+
299
+ // Use t_lo (the just-SEPARATING side of the bisection) rather
300
+ // than t_hi (just-overlapping). With the fixed GJK that no
301
+ // longer flags 5 mm-clear gaps as overlap, the bisection is
302
+ // tight; reporting t_lo gives kinematic callers a conservative
303
+ // TOI — the swept shape at the reported moment is provably NOT
304
+ // overlapping the target. The normal-probe below steps a few
305
+ // mm past best_t to get a valid simplex for MPR.
306
+ if (t_lo < best_t) {
307
+ best_t = t_lo;
308
+ best_body_id = body_id;
309
+ best_entity = entity;
310
+ }
311
+ }
312
+
313
+ if (best_body_id === -1) return false;
314
+
315
+ const rp = result.position;
316
+ const rn = result.normal;
317
+
318
+ const swept_x = ox + dx * best_t;
319
+ const swept_y = oy + dy * best_t;
320
+ const swept_z = oz + dz * best_t;
321
+
322
+ rp[0] = swept_x;
323
+ rp[1] = swept_y;
324
+ rp[2] = swept_z;
325
+
326
+ // ── Contact-normal recovery via MPR ────────────────────────────
327
+ //
328
+ // Bisection converges with `swept_posed` somewhere within
329
+ // `stop_width = TOI_TOLERANCE * tMax` of the true contact. At
330
+ // exactly `best_t` the overlap depth is therefore sub-millimetre
331
+ // on practical sweeps. EPA on smooth-vs-smooth supports at this
332
+ // overlap can't tighten before its iteration cap and returns a
333
+ // direction off by ~30° from truth. MPR is the better tool here:
334
+ // it converges in 5-15 iterations on smooth surfaces, same MTV
335
+ // output convention as EPA (direction = A's interior into B,
336
+ // magnitude = depth).
337
+ //
338
+ // We still advance the swept centre by NORMAL_PROBE_OFFSET past
339
+ // best_t (a few mm into the target) before sampling — the extra
340
+ // overlap gives both MPR and the body-centre sign check a more
341
+ // robust geometric basis. The reported `result.t` stays at
342
+ // `best_t`; only the normal probe moves.
343
+ //
344
+ // Sign-validation: MPR's polytope can also settle on either side
345
+ // of the origin for highly symmetric configurations, so we dot
346
+ // against the body-centre axis and flip if needed (same pattern
347
+ // as `narrowphase_step`'s EPA path). The stored normal is the
348
+ // target's outward surface normal — `B → A` direction — i.e. the
349
+ // negated (validated) MTV.
350
+ const NORMAL_PROBE_OFFSET = 0.01;
351
+ const probe_t = best_t + NORMAL_PROBE_OFFSET;
352
+ const probe_x = ox + dx * probe_t;
353
+ const probe_y = oy + dy * probe_t;
354
+ const probe_z = oz + dz * probe_t;
355
+ const best_body_idx = body_id_index(best_body_id);
356
+ const best_collider = system.__primary_collider(best_body_idx);
357
+ let normal_x = -dx, normal_y = -dy, normal_z = -dz;
358
+ if (best_collider !== null) {
359
+ const best_tr = system.__transforms[best_body_idx];
360
+ candidate_posed.setup(best_collider.shape, best_tr.position, best_tr.rotation);
361
+ swept_posed.px = probe_x;
362
+ swept_posed.py = probe_y;
363
+ swept_posed.pz = probe_z;
364
+ if (mpr(mpr_result, 0, swept_posed, candidate_posed)) {
365
+ let ex = mpr_result[0], ey = mpr_result[1], ez = mpr_result[2];
366
+ const depth = Math.sqrt(ex * ex + ey * ey + ez * ez);
367
+ if (depth > 0 && Number.isFinite(depth)) {
368
+ const ab_x = best_tr.position.x - probe_x;
369
+ const ab_y = best_tr.position.y - probe_y;
370
+ const ab_z = best_tr.position.z - probe_z;
371
+ if (ex * ab_x + ey * ab_y + ez * ab_z < 0) {
372
+ ex = -ex; ey = -ey; ez = -ez;
373
+ }
374
+ const inv = 1 / depth;
375
+ normal_x = -ex * inv;
376
+ normal_y = -ey * inv;
377
+ normal_z = -ez * inv;
378
+ }
379
+ }
380
+ }
381
+
382
+ rn[0] = normal_x; rn[1] = normal_y; rn[2] = normal_z;
383
+ result.t = best_t;
384
+ result.entity = best_entity;
385
+ result.body_id = best_body_id;
386
+ return true;
387
+ }
@@ -1,36 +1,150 @@
1
1
  /**
2
- * Sequential-impulse contact solver. Partitions the touched contact set into
3
- * islands (via {@link IslandBuilder}, owned by the PhysicsSystem and rebuilt
4
- * upstream in the pipeline), then iterates each island independently.
5
- *
6
- * Per-island iteration matters for two reasons:
7
- * 1. Impulse propagation converges inside an island without waiting for
8
- * unrelated bodies' Gauss-Seidel updates from previous outer loops.
9
- * 2. Disconnected awake bodies don't pay each other's solver cost — adding
10
- * an unrelated active body to the scene scales O(island_size) rather than
11
- * O(global_active).
12
- *
13
- * Coulomb friction is applied as a disk clamp in the contact tangent plane.
14
- * Position correction is folded into the velocity solve via Baumgarte bias.
15
- *
16
- * The `apply_warm_start` flag gates the warm-start impulse application.
17
- * In a classic PGS call (one solve per tick), pass `true` (default) the
18
- * cached impulses from the previous tick get replayed onto the velocity,
19
- * seeding the iterations near the converged answer. In TGS substepping,
20
- * the PhysicsSystem calls this once per substep; only substep 0 should
21
- * apply warm-start, because subsequent substeps continue from the solver
22
- * state left by the previous substep (the impulses in `data` already
23
- * reflect the current velocity, so re-applying them would double-count).
24
- *
25
- * Inertial: angular response uses the full world-frame inverse inertia
26
- * `R · diag(I⁻¹_local) · R^T` via {@link world_inverse_inertia_apply},
27
- * correct for arbitrary rotations + diagonal local inertia.
28
- *
29
- * @param {ManifoldStore} manifolds
30
- * @param {PhysicsSystem} system PhysicsSystem; reads `system.islands`.
31
- * @param {number} dt step duration (full tick `dt` for PGS, sub-tick for TGS)
2
+ * Stage 1 prepare the contact constraints for an outer step.
3
+ *
4
+ * Packs every touched, non-sensor contact into the flat scratch arrays:
5
+ * local-frame witness anchors, tangent basis, effective masses, friction,
6
+ * the restitution approach velocity, and the warm-start replay (applied
7
+ * once here, not per substep). Computes the SPOOK gains from the SUBSTEP
8
+ * size `dt_sub` because the position correction runs once per substep.
9
+ *
10
+ * @param {ManifoldStore} manifolds
11
+ * @param {PhysicsSystem} system
12
+ * @param {number} dt_sub substep size `dt / substeps`
13
+ * @returns {number} number of contacts prepared (also stored module-side)
14
+ */
15
+ export function prepare_contacts(manifolds: ManifoldStore, system: PhysicsSystem, dt_sub: number): number;
16
+ /**
17
+ * Stage 1b (per substep) warm-start: replay the cached accumulated
18
+ * impulses `(j_n, j_t1, j_t2)` onto persistent velocity using the current
19
+ * (refreshed) lever arms and tangents. Run once per substep, after
20
+ * {@link refresh_contacts} and before {@link solve_velocity}.
21
+ *
22
+ * Per-substep warm-start is the crux of stable TGS: the stored impulse is a
23
+ * per-substep quantity (≈ the impulse to counter one substep of gravity), so
24
+ * replaying it each substep balances that substep's `integrate_velocity_gravity`
25
+ * and a resting contact holds at zero velocity. `solve_velocity` then only
26
+ * has to correct the residual, which converges in a few iterations even for
27
+ * deep chains because each substep carries just `h` of gravity.
28
+ *
29
+ * @param {ManifoldStore} manifolds
30
+ * @param {PhysicsSystem} system
31
+ */
32
+ export function warm_start_contacts(manifolds: ManifoldStore, system: PhysicsSystem): void;
33
+ /**
34
+ * Stage 2 (per substep) — re-derive each contact's geometry from the
35
+ * bodies' current poses and the local witness anchors captured at prepare.
36
+ *
37
+ * For each contact:
38
+ * - rotate the stored local witnesses back to world by the current pose to
39
+ * get the moved contact points `cpA`, `cpB`;
40
+ * - current penetration `depth_now = depth0 − Δseparation`, where
41
+ * `Δseparation = (cpA − wA − (cpB − wB)) · n` is the change since prepare.
42
+ * Anchoring on the trusted prepare-time depth makes the sign convention
43
+ * irrelevant — only the analytic delta uses the anchors;
44
+ * - rebuild the impulse levers `rA`/`rB` from the moved midpoint;
45
+ * - recompute the position-correction bias from `depth_now`.
46
+ *
47
+ * The contact normal and tangents are held fixed for the outer step (valid
48
+ * for the small per-step rotation), so they are not recomputed here.
49
+ *
50
+ * @param {ManifoldStore} manifolds
51
+ * @param {PhysicsSystem} system
52
+ */
53
+ export function refresh_contacts(manifolds: ManifoldStore, system: PhysicsSystem): void;
54
+ /**
55
+ * Stage 2b (per substep) — the concave counterpart of {@link refresh_contacts}.
56
+ *
57
+ * For each concave-involved slot, re-runs the narrowphase geometry at the
58
+ * current substep pose ({@link redetect_pair_geometry}, which rewrites the
59
+ * manifold's witness / normal / depth in place), then re-derives the solver
60
+ * scratch (lever arms, tangent basis, effective masses, position bias) for
61
+ * that slot's contacts from the fresh geometry. This is the whole point of
62
+ * the concave path: a body rocking on a mesh changes which triangle (and
63
+ * normal) it rests on within a single outer step, and freezing that — as the
64
+ * convex analytic refresh does — pumps energy in. Re-detecting gives a
65
+ * correct per-substep normal so the body settles.
66
+ *
67
+ * Cost is ~one narrowphase dispatch per concave slot per substep — acceptable
68
+ * because concave-involved pairs are rare (the common concave case, a convex
69
+ * body on static terrain, is convex on the moving side and never lands here).
70
+ * The contact count is held fixed (redetect updates geometry only), so the
71
+ * scratch stays aligned with prepare.
72
+ *
73
+ * Must run before {@link refresh_contacts} / {@link warm_start_contacts} each
74
+ * substep. `rest_bias` (captured at prepare) and the `scratch_max_jn`
75
+ * restitution gate are preserved.
76
+ *
77
+ * @param {ManifoldStore} manifolds
78
+ * @param {PhysicsSystem} system reads `__body_collider_lists`, `__bodies`,
79
+ * `__transforms`.
80
+ */
81
+ export function redetect_concave_contacts(manifolds: ManifoldStore, system: PhysicsSystem): void;
82
+ /**
83
+ * Stage 3 (per substep) — velocity iterations enforcing pure
84
+ * non-penetration (`vn → 0`) plus Coulomb-disk friction. No bias: depth
85
+ * correction is the position pass, restitution is the one-shot pass.
86
+ *
87
+ * @param {ManifoldStore} manifolds
88
+ * @param {PhysicsSystem} system
89
+ * @param {number} iters
90
+ */
91
+ export function solve_velocity(manifolds: ManifoldStore, system: PhysicsSystem, iters: number): void;
92
+ /**
93
+ * Stage 4 (once, after the substep loop) — one-shot restitution
94
+ * (Box2D-v3 `b2ApplyRestitution`, Catto 2018). Drives `vn → -e · vn_approach`
95
+ * exactly once per closing contact, gated on (a) the contact having been
96
+ * closing faster than the threshold at prepare, and (b) a compressive
97
+ * normal impulse having formed during the velocity solve. The added impulse
98
+ * accumulates into the same normal-impulse slot so it composes with
99
+ * warm-start next frame.
100
+ *
101
+ * @param {ManifoldStore} manifolds
102
+ * @param {PhysicsSystem} system
103
+ */
104
+ export function apply_restitution(manifolds: ManifoldStore, system: PhysicsSystem): void;
105
+ /**
106
+ * Stage 5 (per substep) — split-impulse position correction. Normal-only
107
+ * (friction in the pseudo-velocity pass is ill-defined). Reads the per-body
108
+ * pseudo-velocity, applies a clamped normal impulse driven by the refreshed
109
+ * `bias_position`, and writes the increment back into the pseudo buffer. The
110
+ * pose integrator folds pseudo-velocity into `pos += v · dt` and discards it.
111
+ *
112
+ * The pseudo buffer must be zeroed by the caller before this stage each
113
+ * substep (it's a per-substep correction). The position accumulator
114
+ * `scratch_pos_jn` is likewise reset here per substep.
115
+ *
116
+ * @param {ManifoldStore} manifolds
117
+ * @param {PhysicsSystem} system
118
+ * @param {number} pos_iters
119
+ */
120
+ export function solve_position(manifolds: ManifoldStore, system: PhysicsSystem, pos_iters: number): void;
121
+ /**
122
+ * Convenience single-step driver: prepare → refresh → velocity →
123
+ * restitution → position, all at the full `dt` (one substep). Equivalent to
124
+ * the Phase-2 solver. The substepped path in `PhysicsSystem.fixedUpdate`
125
+ * calls the stages directly; this entry point exists for callers/tests that
126
+ * want a one-shot solve.
127
+ *
128
+ * The position pass writes `system.__pseudo_velocity`; the caller must zero
129
+ * that buffer before this call and fold it into the pose afterwards.
130
+ *
131
+ * @param {ManifoldStore} manifolds
132
+ * @param {PhysicsSystem} system
133
+ * @param {number} dt
32
134
  * @param {number} [iters]
33
- * @param {boolean} [apply_warm_start]
135
+ * @param {number} [pos_iters]
136
+ */
137
+ export function solve_contacts(manifolds: ManifoldStore, system: PhysicsSystem, dt: number, iters?: number, pos_iters?: number): void;
138
+ /**
139
+ * Velocity-iteration count per substep. With substepping the per-substep
140
+ * count can be lower than a single-step PGS solver would need, because the
141
+ * outer loop revisits the contact set `substeps` times.
142
+ * @type {number}
143
+ */
144
+ export const DEFAULT_VELOCITY_ITERATIONS: number;
145
+ /**
146
+ * Position-iteration count per substep (split-impulse pseudo-velocity pass).
147
+ * @type {number}
34
148
  */
35
- export function solve_contacts(manifolds: ManifoldStore, system: PhysicsSystem, dt: number, iters?: number, apply_warm_start?: boolean): void;
149
+ export const DEFAULT_POSITION_ITERATIONS: number;
36
150
  //# sourceMappingURL=solve_contacts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"solve_contacts.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/solver/solve_contacts.js"],"names":[],"mappings":"AAyQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,oFAJW,MAAM,UACN,MAAM,qBACN,OAAO,QAoBjB"}
1
+ {"version":3,"file":"solve_contacts.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/solver/solve_contacts.js"],"names":[],"mappings":"AAgcA;;;;;;;;;;;;;GAaG;AACH,0FAHW,MAAM,GACJ,MAAM,CA4JlB;AAED;;;;;;;;;;;;;;;GAeG;AACH,2FAuCC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wFAgEC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,iGAmFC;AAED;;;;;;;;GAQG;AACH,uFAFW,MAAM,QA2GhB;AAED;;;;;;;;;;;GAWG;AACH,yFA4DC;AAED;;;;;;;;;;;;;;GAcG;AACH,2FAFW,MAAM,QA4EhB;AAED;;;;;;;;;;;;;;;GAeG;AACH,oFAJW,MAAM,UACN,MAAM,cACN,MAAM,QAahB;AAxlCD;;;;;GAKG;AACH,0CAFU,MAAM,CAEuB;AAEvC;;;GAGG;AACH,0CAFU,MAAM,CAEsB"}