@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
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "description": "Pure JavaScript game engine. Fully featured and production ready.",
7
7
  "type": "module",
8
8
  "author": "Alexander Goldring",
9
- "version": "2.153.0",
9
+ "version": "2.154.0",
10
10
  "main": "build/meep.module.js",
11
11
  "module": "build/meep.module.js",
12
12
  "exports": {
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Convex polyhedron collider.
3
+ *
4
+ * Holds a convex triangle surface (`vertices` + outward-CCW `indices`) and the
5
+ * derived face half-spaces. Because it is convex (`is_convex === true`, the
6
+ * default), it routes straight through the narrowphase's GJK + EPA path via
7
+ * {@link support} — no tetrahedralisation, no per-triangle decomposition, no
8
+ * BVH. This is the right shape for authored convex geometry (props, crates,
9
+ * gems, low-poly rocks, an icosphere) and is far cheaper to construct than
10
+ * {@link MeshShape3D}, which tetrahedralises its interior.
11
+ *
12
+ * Contract:
13
+ * - `support` is exact for any convex point set (deepest vertex along the
14
+ * direction) — the precondition GJK relies on.
15
+ * - `contains_point` is the convex half-space test (behind every face plane).
16
+ * - `signed_distance` / `nearest_point_on_surface` scan the surface triangles
17
+ * (O(F)); these are query-path helpers, not on the collision hot path.
18
+ *
19
+ * The input is assumed convex with outward-facing CCW winding — build it via
20
+ * {@link ConvexHullShape3D.from}. A genuine non-convex mesh belongs in
21
+ * {@link MeshShape3D} (and, once decomposition lands, will be represented as a
22
+ * set of these pieces).
23
+ *
24
+ * @author Alex Goldring
25
+ * @copyright Company Named Limited (c) 2026
26
+ */
27
+ export class ConvexHullShape3D extends AbstractShape3D {
28
+ /**
29
+ * Build from a convex triangle surface. Vertices must lie on the hull and
30
+ * faces must wind CCW when viewed from outside.
31
+ *
32
+ * @param {Float32Array} vertices flat `(x, y, z)` per vertex
33
+ * @param {Uint32Array} indices three uint32 per triangle, outward CCW
34
+ * @returns {ConvexHullShape3D}
35
+ */
36
+ static from(vertices: Float32Array, indices: Uint32Array): ConvexHullShape3D;
37
+ /**
38
+ * Hull vertex positions, flat `(x, y, z)` per vertex, in the body's
39
+ * local frame. Fed to {@link support}.
40
+ * @type {Float32Array}
41
+ */
42
+ vertices: Float32Array;
43
+ /**
44
+ * Surface triangle indices, three uint32 per face (outward CCW). Used by
45
+ * the surface-scan query helpers (signed distance / nearest point).
46
+ * @type {Uint32Array}
47
+ */
48
+ indices: Uint32Array;
49
+ /**
50
+ * Polygon-face representation for the contact clipper (CSR): face `f`'s
51
+ * vertex loop is `face_loops[face_offsets[f] .. face_offsets[f+1]]`,
52
+ * ordered CCW (outward). Currently one triangle per face; a coplanar-merge
53
+ * pass will collapse coplanar triangles into larger polygon faces.
54
+ * @type {Uint32Array}
55
+ */
56
+ face_offsets: Uint32Array;
57
+ /** @type {Uint32Array} */
58
+ face_loops: Uint32Array;
59
+ /**
60
+ * Face half-spaces, four doubles per face `(nx, ny, nz, d)` with unit
61
+ * outward normal and `d = n · v` — point is inside iff `n · p − d ≤ 0`
62
+ * for every face. Derived in {@link recompute}.
63
+ * @private
64
+ * @type {Float64Array}
65
+ */
66
+ private __planes;
67
+ /** @private @type {Float64Array} */
68
+ private __bbox;
69
+ /** @private @type {number} */
70
+ private __volume;
71
+ /** @private @type {number} */
72
+ private __surface_area;
73
+ /**
74
+ * Refresh the cached bbox / face planes / volume / surface area from the
75
+ * current `vertices` / `indices`.
76
+ */
77
+ recompute(): void;
78
+ compute_bounding_box(result: any): void;
79
+ /**
80
+ * GJK support: the hull vertex furthest along the direction. Exact for a
81
+ * convex point set. Linear scan over the vertices — fine for the modest
82
+ * vertex counts of authored hulls; a hill-climb over vertex adjacency is
83
+ * the acceleration for very large hulls.
84
+ */
85
+ support(result: any, result_offset: any, direction_x: any, direction_y: any, direction_z: any): void;
86
+ /**
87
+ * Convex half-space test: inside iff the point is behind (or on) every face
88
+ * plane. Exact for a convex polytope.
89
+ */
90
+ contains_point(point: any): boolean;
91
+ /**
92
+ * Unsigned nearest-surface distance via a per-triangle scan, signed by
93
+ * {@link contains_point}. Same approach as {@link MeshShape3D}; O(F).
94
+ */
95
+ signed_distance_at_point(point: any): number;
96
+ signed_distance_gradient_at_point(result: any, point: any): number;
97
+ nearest_point_on_surface(result: any, reference: any): void;
98
+ sample_random_point_in_volume(result: any, result_offset: any, random: any): void;
99
+ /**
100
+ * @param {ConvexHullShape3D} other
101
+ * @returns {boolean}
102
+ */
103
+ equals(other: ConvexHullShape3D): boolean;
104
+ /**
105
+ * Fast type-check marker.
106
+ * @readonly
107
+ * @type {boolean}
108
+ */
109
+ readonly isConvexHullShape3D: boolean;
110
+ }
111
+ import { AbstractShape3D } from "./AbstractShape3D.js";
112
+ //# sourceMappingURL=ConvexHullShape3D.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConvexHullShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/ConvexHullShape3D.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH;IA+CI;;;;;;;OAOG;IACH,sBAJW,YAAY,WACZ,WAAW,GACT,iBAAiB,CAQ7B;IAxDG;;;;OAIG;IACH,UAFU,YAAY,CAEa;IAEnC;;;;OAIG;IACH,SAFU,WAAW,CAEY;IAEjC;;;;;;OAMG;IACH,cAFU,WAAW,CAEiB;IACtC,0BAA0B;IAC1B,YADW,WAAW,CACc;IAEpC;;;;;;OAMG;IACH,iBAAmC;IAEnC,oCAAoC;IACpC,eAAiC;IACjC,8BAA8B;IAC9B,iBAAiB;IACjB,8BAA8B;IAC9B,uBAAuB;IAmB3B;;;OAGG;IACH,kBAmDC;IAKD,wCAIC;IAED;;;;;OAKG;IACH,qGAgBC;IAED;;;OAGG;IACH,oCAgBC;IAED;;;OAGG;IACH,6CAwBC;IAED,mEAEC;IAED,4DAwBC;IAED,kFAmBC;IAED;;;OAGG;IACH,cAHW,iBAAiB,GACf,OAAO,CAanB;IAcL;;;;OAIG;IACH,8BAFU,OAAO,CAE8B;CAP9C;gCAxT+B,sBAAsB"}
@@ -0,0 +1,325 @@
1
+ import { computeHashFloat } from "../../../primitives/numbers/computeHashFloat.js";
2
+ import { computeTriangleClosestPointToPointBarycentric } from "../triangle/computeTriangleClosestPointToPointBarycentric.js";
3
+ import { AbstractShape3D } from "./AbstractShape3D.js";
4
+ import { compute_signed_distance_gradient_by_sampling } from "./util/compute_signed_distance_gradient_by_sampling.js";
5
+
6
+ /**
7
+ * Convex polyhedron collider.
8
+ *
9
+ * Holds a convex triangle surface (`vertices` + outward-CCW `indices`) and the
10
+ * derived face half-spaces. Because it is convex (`is_convex === true`, the
11
+ * default), it routes straight through the narrowphase's GJK + EPA path via
12
+ * {@link support} — no tetrahedralisation, no per-triangle decomposition, no
13
+ * BVH. This is the right shape for authored convex geometry (props, crates,
14
+ * gems, low-poly rocks, an icosphere) and is far cheaper to construct than
15
+ * {@link MeshShape3D}, which tetrahedralises its interior.
16
+ *
17
+ * Contract:
18
+ * - `support` is exact for any convex point set (deepest vertex along the
19
+ * direction) — the precondition GJK relies on.
20
+ * - `contains_point` is the convex half-space test (behind every face plane).
21
+ * - `signed_distance` / `nearest_point_on_surface` scan the surface triangles
22
+ * (O(F)); these are query-path helpers, not on the collision hot path.
23
+ *
24
+ * The input is assumed convex with outward-facing CCW winding — build it via
25
+ * {@link ConvexHullShape3D.from}. A genuine non-convex mesh belongs in
26
+ * {@link MeshShape3D} (and, once decomposition lands, will be represented as a
27
+ * set of these pieces).
28
+ *
29
+ * @author Alex Goldring
30
+ * @copyright Company Named Limited (c) 2026
31
+ */
32
+ export class ConvexHullShape3D extends AbstractShape3D {
33
+
34
+ constructor() {
35
+ super();
36
+
37
+ /**
38
+ * Hull vertex positions, flat `(x, y, z)` per vertex, in the body's
39
+ * local frame. Fed to {@link support}.
40
+ * @type {Float32Array}
41
+ */
42
+ this.vertices = new Float32Array(0);
43
+
44
+ /**
45
+ * Surface triangle indices, three uint32 per face (outward CCW). Used by
46
+ * the surface-scan query helpers (signed distance / nearest point).
47
+ * @type {Uint32Array}
48
+ */
49
+ this.indices = new Uint32Array(0);
50
+
51
+ /**
52
+ * Polygon-face representation for the contact clipper (CSR): face `f`'s
53
+ * vertex loop is `face_loops[face_offsets[f] .. face_offsets[f+1]]`,
54
+ * ordered CCW (outward). Currently one triangle per face; a coplanar-merge
55
+ * pass will collapse coplanar triangles into larger polygon faces.
56
+ * @type {Uint32Array}
57
+ */
58
+ this.face_offsets = new Uint32Array(0);
59
+ /** @type {Uint32Array} */
60
+ this.face_loops = new Uint32Array(0);
61
+
62
+ /**
63
+ * Face half-spaces, four doubles per face `(nx, ny, nz, d)` with unit
64
+ * outward normal and `d = n · v` — point is inside iff `n · p − d ≤ 0`
65
+ * for every face. Derived in {@link recompute}.
66
+ * @private
67
+ * @type {Float64Array}
68
+ */
69
+ this.__planes = new Float64Array(0);
70
+
71
+ /** @private @type {Float64Array} */
72
+ this.__bbox = new Float64Array(6);
73
+ /** @private @type {number} */
74
+ this.__volume = 0;
75
+ /** @private @type {number} */
76
+ this.__surface_area = 0;
77
+ }
78
+
79
+ /**
80
+ * Build from a convex triangle surface. Vertices must lie on the hull and
81
+ * faces must wind CCW when viewed from outside.
82
+ *
83
+ * @param {Float32Array} vertices flat `(x, y, z)` per vertex
84
+ * @param {Uint32Array} indices three uint32 per triangle, outward CCW
85
+ * @returns {ConvexHullShape3D}
86
+ */
87
+ static from(vertices, indices) {
88
+ const s = new ConvexHullShape3D();
89
+ s.vertices = vertices;
90
+ s.indices = indices;
91
+ s.recompute();
92
+ return s;
93
+ }
94
+
95
+ /**
96
+ * Refresh the cached bbox / face planes / volume / surface area from the
97
+ * current `vertices` / `indices`.
98
+ */
99
+ recompute() {
100
+ const v = this.vertices;
101
+ const idx = this.indices;
102
+
103
+ let mnx = Infinity, mny = Infinity, mnz = Infinity;
104
+ let mxx = -Infinity, mxy = -Infinity, mxz = -Infinity;
105
+ const vc = v.length / 3;
106
+ for (let i = 0; i < vc; i++) {
107
+ const x = v[i * 3], y = v[i * 3 + 1], z = v[i * 3 + 2];
108
+ if (x < mnx) mnx = x; if (x > mxx) mxx = x;
109
+ if (y < mny) mny = y; if (y > mxy) mxy = y;
110
+ if (z < mnz) mnz = z; if (z > mxz) mxz = z;
111
+ }
112
+ if (vc === 0) { mnx = mny = mnz = mxx = mxy = mxz = 0; }
113
+ const b = this.__bbox;
114
+ b[0] = mnx; b[1] = mny; b[2] = mnz; b[3] = mxx; b[4] = mxy; b[5] = mxz;
115
+
116
+ const tri = idx.length / 3;
117
+ const planes = new Float64Array(tri * 4);
118
+ let area = 0;
119
+ let vol6 = 0; // 6× the signed volume (Σ a·(b×c) over outward faces)
120
+ for (let f = 0; f < tri; f++) {
121
+ const ia = idx[f * 3] * 3, ib = idx[f * 3 + 1] * 3, ic = idx[f * 3 + 2] * 3;
122
+ const ax = v[ia], ay = v[ia + 1], az = v[ia + 2];
123
+ const bx = v[ib], by = v[ib + 1], bz = v[ib + 2];
124
+ const cx = v[ic], cy = v[ic + 1], cz = v[ic + 2];
125
+
126
+ const e1x = bx - ax, e1y = by - ay, e1z = bz - az;
127
+ const e2x = cx - ax, e2y = cy - ay, e2z = cz - az;
128
+ let nx = e1y * e2z - e1z * e2y;
129
+ let ny = e1z * e2x - e1x * e2z;
130
+ let nz = e1x * e2y - e1y * e2x;
131
+ const len = Math.sqrt(nx * nx + ny * ny + nz * nz) || 1;
132
+ area += 0.5 * len;
133
+ vol6 += ax * (by * cz - bz * cy) + ay * (bz * cx - bx * cz) + az * (bx * cy - by * cx);
134
+
135
+ nx /= len; ny /= len; nz /= len;
136
+ const o = f * 4;
137
+ planes[o] = nx; planes[o + 1] = ny; planes[o + 2] = nz;
138
+ planes[o + 3] = nx * ax + ny * ay + nz * az;
139
+ }
140
+ this.__planes = planes;
141
+ this.__surface_area = area;
142
+ this.__volume = Math.abs(vol6) / 6;
143
+
144
+ // Polygon faces for the clipper. v1: one triangle per face (the contact
145
+ // clipper consumes polygon loops; a tetrahedral piece is exactly this).
146
+ const fo = new Uint32Array(tri + 1);
147
+ for (let f = 0; f <= tri; f++) fo[f] = f * 3;
148
+ this.face_offsets = fo;
149
+ this.face_loops = idx;
150
+ }
151
+
152
+ get volume() { return this.__volume; }
153
+ get surface_area() { return this.__surface_area; }
154
+
155
+ compute_bounding_box(result) {
156
+ const b = this.__bbox;
157
+ result[0] = b[0]; result[1] = b[1]; result[2] = b[2];
158
+ result[3] = b[3]; result[4] = b[4]; result[5] = b[5];
159
+ }
160
+
161
+ /**
162
+ * GJK support: the hull vertex furthest along the direction. Exact for a
163
+ * convex point set. Linear scan over the vertices — fine for the modest
164
+ * vertex counts of authored hulls; a hill-climb over vertex adjacency is
165
+ * the acceleration for very large hulls.
166
+ */
167
+ support(result, result_offset, direction_x, direction_y, direction_z) {
168
+ const v = this.vertices;
169
+ const vc = v.length / 3;
170
+ if (vc === 0) {
171
+ result[result_offset] = 0; result[result_offset + 1] = 0; result[result_offset + 2] = 0;
172
+ return;
173
+ }
174
+ let best = -Infinity;
175
+ let bi = 0;
176
+ for (let i = 0; i < vc; i++) {
177
+ const d = direction_x * v[i * 3] + direction_y * v[i * 3 + 1] + direction_z * v[i * 3 + 2];
178
+ if (d > best) { best = d; bi = i; }
179
+ }
180
+ result[result_offset] = v[bi * 3];
181
+ result[result_offset + 1] = v[bi * 3 + 1];
182
+ result[result_offset + 2] = v[bi * 3 + 2];
183
+ }
184
+
185
+ /**
186
+ * Convex half-space test: inside iff the point is behind (or on) every face
187
+ * plane. Exact for a convex polytope.
188
+ */
189
+ contains_point(point) {
190
+ const px = point[0], py = point[1], pz = point[2];
191
+ const b = this.__bbox;
192
+ if (px < b[0] || py < b[1] || pz < b[2] || px > b[3] || py > b[4] || pz > b[5]) {
193
+ return false;
194
+ }
195
+ const planes = this.__planes;
196
+ const f = planes.length / 4;
197
+ const EPS = 1e-6;
198
+ for (let i = 0; i < f; i++) {
199
+ const o = i * 4;
200
+ if (planes[o] * px + planes[o + 1] * py + planes[o + 2] * pz - planes[o + 3] > EPS) {
201
+ return false;
202
+ }
203
+ }
204
+ return true;
205
+ }
206
+
207
+ /**
208
+ * Unsigned nearest-surface distance via a per-triangle scan, signed by
209
+ * {@link contains_point}. Same approach as {@link MeshShape3D}; O(F).
210
+ */
211
+ signed_distance_at_point(point) {
212
+ const v = this.vertices;
213
+ const idx = this.indices;
214
+ const tri = idx.length / 3;
215
+ const px = point[0], py = point[1], pz = point[2];
216
+
217
+ let best_d2 = Infinity;
218
+ const baryc = scratch_barycentric;
219
+ for (let i = 0; i < tri; i++) {
220
+ const ia = idx[i * 3] * 3, ib = idx[i * 3 + 1] * 3, ic = idx[i * 3 + 2] * 3;
221
+ const ax = v[ia], ay = v[ia + 1], az = v[ia + 2];
222
+ const bx = v[ib], by = v[ib + 1], bz = v[ib + 2];
223
+ const cx = v[ic], cy = v[ic + 1], cz = v[ic + 2];
224
+ computeTriangleClosestPointToPointBarycentric(baryc, 0, px, py, pz, ax, ay, az, bx, by, bz, cx, cy, cz);
225
+ const u = baryc[0], w = baryc[1], t = 1 - u - w;
226
+ const qx = u * ax + w * bx + t * cx;
227
+ const qy = u * ay + w * by + t * cy;
228
+ const qz = u * az + w * bz + t * cz;
229
+ const dx = qx - px, dy = qy - py, dz = qz - pz;
230
+ const d2 = dx * dx + dy * dy + dz * dz;
231
+ if (d2 < best_d2) best_d2 = d2;
232
+ }
233
+ const dist = Math.sqrt(best_d2);
234
+ return this.contains_point(point) ? -dist : dist;
235
+ }
236
+
237
+ signed_distance_gradient_at_point(result, point) {
238
+ return compute_signed_distance_gradient_by_sampling(result, this, point);
239
+ }
240
+
241
+ nearest_point_on_surface(result, reference) {
242
+ const v = this.vertices;
243
+ const idx = this.indices;
244
+ const tri = idx.length / 3;
245
+ const px = reference[0], py = reference[1], pz = reference[2];
246
+
247
+ let best_d2 = Infinity;
248
+ let bx_ = 0, by_ = 0, bz_ = 0;
249
+ const baryc = scratch_barycentric;
250
+ for (let i = 0; i < tri; i++) {
251
+ const ia = idx[i * 3] * 3, ib = idx[i * 3 + 1] * 3, ic = idx[i * 3 + 2] * 3;
252
+ const ax = v[ia], ay = v[ia + 1], az = v[ia + 2];
253
+ const bx = v[ib], by = v[ib + 1], bz = v[ib + 2];
254
+ const cx = v[ic], cy = v[ic + 1], cz = v[ic + 2];
255
+ computeTriangleClosestPointToPointBarycentric(baryc, 0, px, py, pz, ax, ay, az, bx, by, bz, cx, cy, cz);
256
+ const u = baryc[0], w = baryc[1], t = 1 - u - w;
257
+ const qx = u * ax + w * bx + t * cx;
258
+ const qy = u * ay + w * by + t * cy;
259
+ const qz = u * az + w * bz + t * cz;
260
+ const dx = qx - px, dy = qy - py, dz = qz - pz;
261
+ const d2 = dx * dx + dy * dy + dz * dz;
262
+ if (d2 < best_d2) { best_d2 = d2; bx_ = qx; by_ = qy; bz_ = qz; }
263
+ }
264
+ result[0] = bx_; result[1] = by_; result[2] = bz_;
265
+ }
266
+
267
+ sample_random_point_in_volume(result, result_offset, random) {
268
+ const b = this.__bbox;
269
+ const lx = b[0], ly = b[1], lz = b[2];
270
+ const sx = b[3] - b[0], sy = b[4] - b[1], sz = b[5] - b[2];
271
+ const probe = scratch_point;
272
+ for (let attempt = 0; attempt < 256; attempt++) {
273
+ probe[0] = lx + random() * sx;
274
+ probe[1] = ly + random() * sy;
275
+ probe[2] = lz + random() * sz;
276
+ if (this.contains_point(probe)) {
277
+ result[result_offset] = probe[0];
278
+ result[result_offset + 1] = probe[1];
279
+ result[result_offset + 2] = probe[2];
280
+ return;
281
+ }
282
+ }
283
+ result[result_offset] = lx + sx * 0.5;
284
+ result[result_offset + 1] = ly + sy * 0.5;
285
+ result[result_offset + 2] = lz + sz * 0.5;
286
+ }
287
+
288
+ /**
289
+ * @param {ConvexHullShape3D} other
290
+ * @returns {boolean}
291
+ */
292
+ equals(other) {
293
+ if (!super.equals(other)) return false;
294
+ if (this.vertices.length !== other.vertices.length) return false;
295
+ if (this.indices.length !== other.indices.length) return false;
296
+ for (let i = 0; i < this.vertices.length; i++) {
297
+ if (this.vertices[i] !== other.vertices[i]) return false;
298
+ }
299
+ for (let i = 0; i < this.indices.length; i++) {
300
+ if (this.indices[i] !== other.indices[i]) return false;
301
+ }
302
+ return true;
303
+ }
304
+
305
+ hash() {
306
+ const v_count = this.vertices.length / 3 | 0;
307
+ const t_count = this.indices.length / 3 | 0;
308
+ let h = (v_count * 31 + t_count) | 0;
309
+ if (this.vertices.length >= 3) {
310
+ h = (h * 31 + (computeHashFloat(this.vertices[0]))) | 0;
311
+ h = (h * 31 + (computeHashFloat(this.vertices[this.vertices.length - 1]))) | 0;
312
+ }
313
+ return h | 0;
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Fast type-check marker.
319
+ * @readonly
320
+ * @type {boolean}
321
+ */
322
+ ConvexHullShape3D.prototype.isConvexHullShape3D = true;
323
+
324
+ const scratch_barycentric = new Float64Array(2);
325
+ const scratch_point = new Float64Array(3);
@@ -90,6 +90,10 @@ declare class Trail2D {
90
90
  */
91
91
  build(segment_count: number): void;
92
92
  mesh: import("three").Mesh<import("three").BufferGeometry, import("three").Material | import("three").Material[]>;
93
+ /**
94
+ * Clear the trail's geometry and reset its state.
95
+ */
96
+ clear(): void;
93
97
  fromJSON({ maxAge, width, textureURL, offset, color }: {
94
98
  maxAge?: number;
95
99
  width?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"Trail2D.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/trail2d/Trail2D.js"],"names":[],"mappings":";AAmBA;IAkJI,oCAMC;IAtJD;;;OAGG;IACH,QAFU,MAAM,CAES;IAEzB;;;OAGG;IACH,OAFU,MAAM,CAEM;IAEtB;;;OAGG;IACH,MAFU,MAAM,CAEP;IAET;;;OAGG;IACH,eAFU,MAAM,CAEE;IAElB;;;OAGG;IACH,qBAFU,MAAM,CAEQ;IAExB;;;OAGG;IACH,gBAFU,KAAK,CAEe;IAE9B;;;;OAIG;IACH,iBAFU,OAAO,CAEM;IAEvB;;;OAGG;IACH,QAFU,OAAO,GAAC,IAAI,CAER;IAEd;;;OAGG;IACH,UAFU,mBAAmB,CAEQ;IAErC;;;OAGG;IACH,cAFU,SAAS,CAEG;IAEtB;;;OAGG;IACH,cAAsB;IAEtB,gBAQC;IAMD,4BAEC;IAND,yBAEC;IAMD;;;;OAIG;IACH,cAHW,MAAM,GAAC,YAAY,GACjB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,YAAY,GACjB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,YAAY,SACnB,OAAO,QAQjB;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,YAAY,GACjB,OAAO,CAInB;IAED;;;OAGG;IACH,qBAFW,MAAM,QAehB;IADG,kHAAgB;IAWpB;;;;;;;;;;;aAcC;IAGD;;;;;;;;;;;;;;;MAQC;IAED;;;OAGG;IACH,cAFW,OAAO,WASjB;IAED;;;;;;;OAOG;IACH,cANW,MAAM,KACN,MAAM,KACN,MAAM,YACN,MAAM,GACJ,OAAO,CA2CnB;CAEJ;;;;;;sBAvQqB,iCAAiC;oBACnC,kCAAkC;wBAI9B,0BAA0B;oCACd,sCAAsC;0BAPhD,yCAAyC;6BAStC,mBAAmB;kCADd,wBAAwB"}
1
+ {"version":3,"file":"Trail2D.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/trail2d/Trail2D.js"],"names":[],"mappings":";AAoBA;IAsKI,oCAMC;IA1KD;;;OAGG;IACH,QAFU,MAAM,CAES;IAEzB;;;OAGG;IACH,OAFU,MAAM,CAEM;IAEtB;;;OAGG;IACH,MAFU,MAAM,CAEP;IAET;;;OAGG;IACH,eAFU,MAAM,CAEE;IAElB;;;OAGG;IACH,qBAFU,MAAM,CAEQ;IAExB;;;OAGG;IACH,gBAFU,KAAK,CAEe;IAE9B;;;;OAIG;IACH,iBAFU,OAAO,CAEM;IAEvB;;;OAGG;IACH,QAFU,OAAO,GAAC,IAAI,CAER;IAEd;;;OAGG;IACH,UAFU,mBAAmB,CAEQ;IAErC;;;OAGG;IACH,cAFU,SAAS,CAEG;IAEtB;;;OAGG;IACH,cAAsB;IAEtB,gBAQC;IAMD,4BAEC;IAND,yBAEC;IAMD;;;;OAIG;IACH,cAHW,MAAM,GAAC,YAAY,GACjB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,YAAY,GACjB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,YAAY,SACnB,OAAO,QAQjB;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,YAAY,GACjB,OAAO,CAInB;IAED;;;OAGG;IACH,qBAFW,MAAM,QAehB;IADG,kHAAgB;IAGpB;;OAEG;IACH,cAeC;IAUD;;;;;;;;;;;aAcC;IAGD;;;;;;;;;;;;;;;MAQC;IAED;;;OAGG;IACH,cAFW,OAAO,WASjB;IAED;;;;;;;OAOG;IACH,cANW,MAAM,KACN,MAAM,KACN,MAAM,YACN,MAAM,GACJ,OAAO,CA2CnB;CAEJ;;;;;;sBA3RqB,iCAAiC;oBACnC,kCAAkC;wBAI9B,0BAA0B;oCACd,sCAAsC;0BAPhD,yCAAyC;6BAStC,mBAAmB;kCADd,wBAAwB"}
@@ -1,3 +1,4 @@
1
+ import { FLOAT32_MAX } from "../../../../core/binary/FLOAT32_MAX.js";
1
2
  import { BvhClient } from "../../../../core/bvh2/bvh3/BvhClient.js";
2
3
  import { Color } from "../../../../core/color/Color.js";
3
4
  import Vector3 from "../../../../core/geom/Vector3.js";
@@ -163,6 +164,26 @@ class Trail2D {
163
164
  this.mesh = mesh;
164
165
  }
165
166
 
167
+ /**
168
+ * Clear the trail's geometry and reset its state.
169
+ */
170
+ clear() {
171
+ const ribbon = this.ribbon;
172
+
173
+ if (ribbon === null) {
174
+ // nothing to clear
175
+ return;
176
+ }
177
+
178
+ const n = ribbon.getCount();
179
+
180
+ for (let i = 0; i < n; i++) {
181
+ ribbon.setPointAttribute_Scalar(i, RIBBON_ATTRIBUTE_ADDRESS_AGE, FLOAT32_MAX);
182
+ ribbon.setPointAlpha(i, 0);
183
+ }
184
+
185
+ }
186
+
166
187
  static fromJSON(json) {
167
188
  const r = new Trail2D();
168
189
 
@@ -117,10 +117,10 @@ Architectural references for design choices:
117
117
  call. A 100-block stack hit at the base wakes top-down in one frame
118
118
  rather than over 100 frames of broadphase propagation.
119
119
  - `DisableSleep` on any island member exempts the whole island.
120
- - ContactBegin / Stay / End buffer + dispatch through both
121
- `PhysicsSystem.onContactBegin/Stay/End` Signals and the per-entity
122
- `entity.sendEvent(PhysicsEvents.ContactBegin, ...)` channel (when a
123
- dataset is attached).
120
+ - ContactBegin / Stay / End buffer + dispatch through the per-entity
121
+ `dataset.sendEvent(entity, PhysicsEvents.ContactBegin, ...)` channel the
122
+ sole contact-event path, delivered to each entity of the pair when a
123
+ dataset is attached.
124
124
 
125
125
  ### Islands
126
126
  - **Union-find** with path halving + union by min-index over the awake-body
@@ -68,7 +68,9 @@ export class BodyStorage {
68
68
  */
69
69
  get size(): number;
70
70
  /**
71
- * Total slot capacity. Always a power of two by construction.
71
+ * Total slot capacity. Starts at the (power-of-two) default and grows by
72
+ * doubling; a caller-supplied non-power-of-two initial capacity is honoured
73
+ * as-is, so this is not guaranteed to be a power of two.
72
74
  * @returns {number}
73
75
  */
74
76
  get capacity(): number;
@@ -1 +1 @@
1
- {"version":3,"file":"BodyStorage.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/body/BodyStorage.js"],"names":[],"mappings":"AA2BA;;;;;;GAMG;AACH,oCAJW,MAAM,cACN,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,sCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,2CAHW,MAAM,GACJ,MAAM,CAIlB;AAlCD;;;;GAIG;AACH,gCAFU,MAAM,CAEoB;AA+BpC;;;;;;;;;;;;;;;;;;GAkBG;AACH;IAEI;;;OAGG;IACH,+BAFW,MAAM,EAqChB;IA9BG,mBAAqB;IAGrB,gBAAgB;IAEhB,uBAAqC;IACrC,0BAAwC;IACxC,oBAAkC;IAClC,qBAAmC;IAGnC,oBAAkC;IAGlC,0BAAwC;IACxC,wBAAsC;IACtC,sBAAsB;IAGtB,yBAAuC;IACvC,qBAAqB;IAMrB,iCAAkC;IAMtC;;;OAGG;IACH,mBAEC;IAED;;;OAGG;IACH,uBAEC;IAED;;;OAGG;IACH,0BAEC;IAED;;;;OAIG;IACH,8BAEC;IAED;;;;;;;OAOG;IACH,iBAHW,MAAM,GACJ,MAAM,CA0BlB;IAED;;;;;OAKG;IACH,qBAFW,MAAM,QAwBhB;IAED;;;;OAIG;IACH,yBAHW,MAAM,GACJ,OAAO,CAWnB;IAED;;;OAGG;IACH,iBAHW,MAAM,GACJ,MAAM,CAOlB;IAED;;;;;;OAMG;IACH,wBAHW,MAAM,GACJ,MAAM,CAKlB;IAED;;;OAGG;IACH,qBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,eAHW,MAAM,GACJ,QAAQ,GAAC,MAAM,CAI3B;IAED;;;OAGG;IACH,gBAHW,MAAM,QACN,QAAQ,GAAC,MAAM,QAIzB;IAED;;;OAGG;IACH,gBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,iBAHW,MAAM,SACN,MAAM,QAIhB;IAED;;;;OAIG;IACH,yBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;;OAIG;IACH,YAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,kBAFW,MAAM,QAShB;IAED;;;OAGG;IACH,qBAFW,MAAM,QAShB;IAED;;;;OAIG;IACH,0BAOC;IAED;;OAEG;IACH,eAiCC;IAID;;;OAGG;IACH,oBAgBC;IAED;;;OAGG;IACH,mBAqBC;CACJ;yBAhcwB,oBAAoB"}
1
+ {"version":3,"file":"BodyStorage.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/body/BodyStorage.js"],"names":[],"mappings":"AA2BA;;;;;;GAMG;AACH,oCAJW,MAAM,cACN,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,sCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,2CAHW,MAAM,GACJ,MAAM,CAIlB;AAlCD;;;;GAIG;AACH,gCAFU,MAAM,CAEoB;AA+BpC;;;;;;;;;;;;;;;;;;GAkBG;AACH;IAEI;;;OAGG;IACH,+BAFW,MAAM,EAqChB;IA9BG,mBAAqB;IAGrB,gBAAgB;IAEhB,uBAAqC;IACrC,0BAAwC;IACxC,oBAAkC;IAClC,qBAAmC;IAGnC,oBAAkC;IAGlC,0BAAwC;IACxC,wBAAsC;IACtC,sBAAsB;IAGtB,yBAAuC;IACvC,qBAAqB;IAMrB,iCAAkC;IAMtC;;;OAGG;IACH,mBAEC;IAED;;;;;OAKG;IACH,uBAEC;IAED;;;OAGG;IACH,0BAEC;IAED;;;;OAIG;IACH,8BAEC;IAED;;;;;;;OAOG;IACH,iBAHW,MAAM,GACJ,MAAM,CA0BlB;IAED;;;;;OAKG;IACH,qBAFW,MAAM,QAwBhB;IAED;;;;OAIG;IACH,yBAHW,MAAM,GACJ,OAAO,CAWnB;IAED;;;OAGG;IACH,iBAHW,MAAM,GACJ,MAAM,CAOlB;IAED;;;;;;OAMG;IACH,wBAHW,MAAM,GACJ,MAAM,CAKlB;IAED;;;OAGG;IACH,qBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,eAHW,MAAM,GACJ,QAAQ,GAAC,MAAM,CAI3B;IAED;;;OAGG;IACH,gBAHW,MAAM,QACN,QAAQ,GAAC,MAAM,QAIzB;IAED;;;OAGG;IACH,gBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,iBAHW,MAAM,SACN,MAAM,QAIhB;IAED;;;;OAIG;IACH,yBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;;OAIG;IACH,YAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,kBAFW,MAAM,QAShB;IAED;;;OAGG;IACH,qBAFW,MAAM,QAShB;IAED;;;;OAIG;IACH,0BAOC;IAED;;OAEG;IACH,eAiCC;IAID;;;OAGG;IACH,oBAgBC;IAED;;;OAGG;IACH,mBAqBC;CACJ;yBAlcwB,oBAAoB"}