@woosh/meep-engine 2.169.2 → 2.169.3

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 (37) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/mat4/m4_decompose.d.ts +5 -9
  3. package/src/core/geom/3d/mat4/m4_decompose.d.ts.map +1 -1
  4. package/src/core/geom/3d/mat4/m4_decompose.js +40 -60
  5. package/src/core/geom/3d/mat4/m4_decompose_array.d.ts +28 -0
  6. package/src/core/geom/3d/mat4/m4_decompose_array.d.ts.map +1 -0
  7. package/src/core/geom/3d/mat4/m4_decompose_array.js +157 -0
  8. package/src/core/primitives/strings/string_jaro_distance.d.ts +2 -2
  9. package/src/core/primitives/strings/string_jaro_distance.js +4 -4
  10. package/src/engine/Engine.d.ts.map +1 -1
  11. package/src/engine/Engine.js +0 -2
  12. package/src/engine/asset/loaders/SoundAssetLoader.d.ts.map +1 -1
  13. package/src/engine/asset/loaders/SoundAssetLoader.js +12 -1
  14. package/src/engine/ecs/gui/GUIElementSystem.d.ts +9 -0
  15. package/src/engine/ecs/gui/GUIElementSystem.d.ts.map +1 -1
  16. package/src/engine/ecs/gui/GUIElementSystem.js +23 -3
  17. package/src/engine/ecs/gui/position/ViewportPositionSystem.d.ts.map +1 -1
  18. package/src/engine/ecs/gui/position/ViewportPositionSystem.js +4 -2
  19. package/src/engine/ecs/transform/Transform64.d.ts +306 -0
  20. package/src/engine/ecs/transform/Transform64.d.ts.map +1 -0
  21. package/src/engine/ecs/transform/Transform64.js +591 -0
  22. package/src/engine/graphics/ecs/mesh/SkeletonUtils.d.ts +3 -3
  23. package/src/engine/graphics/ecs/mesh/SkeletonUtils.js +4 -4
  24. package/src/engine/graphics/ecs/mesh-v2/DeferredBoundsQueue.d.ts +48 -0
  25. package/src/engine/graphics/ecs/mesh-v2/DeferredBoundsQueue.d.ts.map +1 -0
  26. package/src/engine/graphics/ecs/mesh-v2/DeferredBoundsQueue.js +88 -0
  27. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +28 -0
  28. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts.map +1 -1
  29. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +79 -0
  30. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +21 -3
  31. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.d.ts +13 -1
  32. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.d.ts.map +1 -1
  33. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +47 -10
  34. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  35. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +3 -3
  36. package/src/view/minimap/gl/MinimapMarkersGL.d.ts.map +1 -1
  37. package/src/view/minimap/gl/MinimapMarkersGL.js +3 -1
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Collects {@link ShadedGeometry} components whose bounding box has gone stale under
3
+ * {@link ShadedGeometryFlags.DeferredBoundsUpdate}, until the owner of the BVH is ready
4
+ * to take the updates.
5
+ *
6
+ * WHY THIS EXISTS
7
+ *
8
+ * A {@link Transform} signals `position`, `rotation` and `scale` separately, so one
9
+ * logical move produces several change notifications: two when a caller sets position
10
+ * and rotation, three when the transform is written as a matrix (which is what
11
+ * {@link TransformAttachmentSystem} does for every entity in a hierarchy, and what
12
+ * `Transform.copy` does). Updating bounds on each of those recomputes the same box and
13
+ * walks the same path to the BVH root several times over. Parking the component here
14
+ * instead collapses the batch into one update per component per flush.
15
+ *
16
+ * Entries are appended without a membership test; {@link ShadedGeometry} carries the
17
+ * "already queued" bit so enqueueing stays O(1) and a component appears at most once.
18
+ */
19
+ export class DeferredBoundsQueue {
20
+ /**
21
+ * Retained between flushes and overwritten in place rather than re-allocated.
22
+ * Only the first {@link #size} entries are live.
23
+ * @type {ShadedGeometry[]}
24
+ */
25
+ #items = [];
26
+
27
+ /**
28
+ * @type {number}
29
+ */
30
+ #size = 0;
31
+
32
+ /**
33
+ * Number of components waiting for their bounds to be applied.
34
+ * @returns {number}
35
+ */
36
+ get size() {
37
+ return this.#size;
38
+ }
39
+
40
+ /**
41
+ * Park a component whose bounds have gone stale.
42
+ *
43
+ * The caller must not add a component that is already queued — see
44
+ * {@link ShadedGeometry.updateTransform}, which owns that bit.
45
+ * @param {ShadedGeometry} sg
46
+ * @returns {void}
47
+ */
48
+ add(sg) {
49
+ this.#items[this.#size++] = sg;
50
+ }
51
+
52
+ /**
53
+ * Apply every parked update, leaving the BVH consistent with the current transforms.
54
+ *
55
+ * Components that were unlinked while queued, or whose bounds were already settled by
56
+ * a read, are skipped.
57
+ *
58
+ * Must not be re-entered: nothing reached from here writes to a {@link Transform},
59
+ * so no component can go dirty while the batch is being applied.
60
+ * @returns {number} how many components actually had an update applied, which is a
61
+ * useful profiling signal — it is the number of BVH refits the batch cost
62
+ */
63
+ flush() {
64
+ const items = this.#items;
65
+ const size = this.#size;
66
+
67
+ let applied = 0;
68
+
69
+ for (let i = 0; i < size; i++) {
70
+ if (items[i].applyDeferredBoundsUpdate()) {
71
+ applied++;
72
+ }
73
+ }
74
+
75
+ // Drop the references so components unlinked while queued are not held alive
76
+ // until their slot happens to be overwritten — after a teardown the slots may
77
+ // never be reused, and each entry retains a geometry and a material.
78
+ //
79
+ // Done in one sweep rather than per entry inside the loop above: clearing each
80
+ // slot as it was consumed measured ~25% slower per tick on a 2000-mover scene,
81
+ // the store into the object array carrying a GC write barrier each time.
82
+ items.fill(null, 0, size);
83
+
84
+ this.#size = 0;
85
+
86
+ return applied;
87
+ }
88
+ }
@@ -110,6 +110,28 @@ export class ShadedGeometry {
110
110
  * @return {null|number[]}
111
111
  */
112
112
  get transform(): number[];
113
+ /**
114
+ * Attach this component to the queue that collects deferred bounds updates.
115
+ * Called by the system when the component enters the BVH.
116
+ * @param {DeferredBoundsQueue} queue
117
+ * @returns {void}
118
+ */
119
+ bindBoundsQueue(queue: DeferredBoundsQueue): void;
120
+ /**
121
+ * Called by the system when the component leaves the BVH. Any update parked in the
122
+ * queue is abandoned — the entry is left in place and becomes inert, so unlinking
123
+ * stays O(1).
124
+ * @returns {void}
125
+ */
126
+ unbindBoundsQueue(): void;
127
+ /**
128
+ * Recompute the bounding box and push it into the BVH, if a deferred update is pending.
129
+ *
130
+ * This is the single point where a parked update lands; it is driven both by
131
+ * {@link DeferredBoundsQueue.flush} and by any read of the bounding box.
132
+ * @returns {boolean} whether an update was actually pending
133
+ */
134
+ applyDeferredBoundsUpdate(): boolean;
113
135
  /**
114
136
  *
115
137
  * @param {AABB3} destination
@@ -122,6 +144,11 @@ export class ShadedGeometry {
122
144
  * @param {DrawMode} [draw_mode]
123
145
  */
124
146
  from(geometry: THREE.BufferGeometry, material: THREE.Material, draw_mode?: DrawMode): void;
147
+ /**
148
+ * Change handler subscribed to the entity's {@link Transform} while the component is
149
+ * linked; see {@link ShadedGeometrySystem.link}.
150
+ * @returns {void}
151
+ */
125
152
  updateTransform(): void;
126
153
  update_bounds(): void;
127
154
  /**
@@ -132,6 +159,7 @@ export class ShadedGeometry {
132
159
  * @returns {boolean}
133
160
  */
134
161
  query_raycast_nearest(contact: SurfacePoint3, ray: ArrayLike<number> | number[] | Float32Array, transform_matrix4: ArrayLike<number> | number[] | Float32Array): boolean;
162
+ #private;
135
163
  }
136
164
  export namespace ShadedGeometry {
137
165
  let typeName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"ShadedGeometry.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js"],"names":[],"mappings":"AAuCA;;;GAGG;AACH;IA+LI;;;;;;OAMG;IACH,sBALW,MAAM,cAAc,YACpB,MAAM,QAAQ,cACd,QAAQ,GACP,cAAc,CAQzB;IA1MG;;;OAGG;IACH,UAFU,MAAM,cAAc,GAAC,IAAI,CAEf;IACpB;;;OAGG;IACH,UAFU,MAAM,QAAQ,GAAC,IAAI,CAET;IAEpB;;;OAGG;IACH,gBAFU,MAAM,QAAQ,GAAC,IAAI,CAEH;IAE1B,sBAAiC;IAEjC;;;;OAIG;IACH,iBAAkB;IAElB;;;;OAIG;IACH,sBAAyB;IAEzB;;;OAGG;IACH,MAFU,QAAQ,GAAC,MAAM,CAEK;IAE9B;;;OAGG;IACH,aAFU,MAAM,CAEI;IAEpB;;;OAGG;IACH,OAFU,MAAM,CAEU;IAG9B;;;;OAIG;IACH,cAHW,MAAM,GAAC,mBAAmB,GACxB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,mBAAmB,GACxB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,mBAAmB,SAC1B,OAAO,QAQjB;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,mBAAmB,GACxB,OAAO,CAInB;IAED;;;OAGG;IACH,QAFY,MAAM,CASjB;IAED;;;;OAIG;IACH,cAHW,cAAc,GACZ,OAAO,CAUnB;IAED;;;OAGG;IACH,YAFW,cAAc,QASxB;IAED;;;OAGG;IACH,SAFa,cAAc,CAQ1B;IAED;;;OAGG;IACH,qBAEC;IAED;;;;OAIG;IACH,0BAEC;IAED;;;OAGG;IACH,4BAFW,KAAK,QAMf;IAED;;;;;OAKG;IACH,eAJW,MAAM,cAAc,YACpB,MAAM,QAAQ,cACd,QAAQ,QAWlB;IAiBD,wBAIC;IAED,sBAMC;IAED;;;;;;OAMG;IACH,mDAJW,UAAU,MAAM,CAAC,GAAC,MAAM,EAAE,GAAC,YAAY,qBACvC,UAAU,MAAM,CAAC,GAAC,MAAM,EAAE,GAAC,YAAY,GACrC,OAAO,CA4BnB;CACJ;;kBAIS,MAAM;sBAON,OAAO;;0BAnTS,yCAAyC;yBAM1C,eAAe;oCACJ,0BAA0B;sBANxC,wCAAwC"}
1
+ {"version":3,"file":"ShadedGeometry.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js"],"names":[],"mappings":"AAwCA;;;GAGG;AACH;IA8PI;;;;;;OAMG;IACH,sBALW,MAAM,cAAc,YACpB,MAAM,QAAQ,cACd,QAAQ,GACP,cAAc,CAQzB;IAzPG;;;OAGG;IACH,UAFU,MAAM,cAAc,GAAC,IAAI,CAEf;IACpB;;;OAGG;IACH,UAFU,MAAM,QAAQ,GAAC,IAAI,CAET;IAEpB;;;OAGG;IACH,gBAFU,MAAM,QAAQ,GAAC,IAAI,CAEH;IAE1B,sBAAiC;IAEjC;;;;OAIG;IACH,iBAAkB;IAElB;;;;OAIG;IACH,sBAAyB;IAEzB;;;OAGG;IACH,MAFU,QAAQ,GAAC,MAAM,CAEK;IAE9B;;;OAGG;IACH,aAFU,MAAM,CAEI;IAEpB;;;OAGG;IACH,OAFU,MAAM,CAEU;IAG9B;;;;OAIG;IACH,cAHW,MAAM,GAAC,mBAAmB,GACxB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,mBAAmB,GACxB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,mBAAmB,SAC1B,OAAO,QAQjB;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,mBAAmB,GACxB,OAAO,CAInB;IAED;;;OAGG;IACH,QAFY,MAAM,CASjB;IAED;;;;OAIG;IACH,cAHW,cAAc,GACZ,OAAO,CAUnB;IAED;;;OAGG;IACH,YAFW,cAAc,QASxB;IAED;;;OAGG;IACH,SAFa,cAAc,CAQ1B;IAED;;;OAGG;IACH,qBAEC;IAED;;;;OAIG;IACH,0BAEC;IAED;;;;;OAKG;IACH,6CAFa,IAAI,CAMhB;IAED;;;;;OAKG;IACH,qBAFa,IAAI,CAKhB;IAED;;;;;;OAMG;IACH,6BAFa,OAAO,CAcnB;IAED;;;OAGG;IACH,4BAFW,KAAK,QASf;IAED;;;;;OAKG;IACH,eAJW,MAAM,cAAc,YACpB,MAAM,QAAQ,cACd,QAAQ,QAWlB;IAiBD;;;;OAIG;IACH,mBAFa,IAAI,CAgBhB;IAED,sBAMC;IAED;;;;;;OAMG;IACH,mDAJW,UAAU,MAAM,CAAC,GAAC,MAAM,EAAE,GAAC,YAAY,qBACvC,UAAU,MAAM,CAAC,GAAC,MAAM,EAAE,GAAC,YAAY,GACrC,OAAO,CA4BnB;;CACJ;;kBAIS,MAAM;sBAON,OAAO;;0BAjYS,yCAAyC;yBAM1C,eAAe;oCACJ,0BAA0B;sBANxC,wCAAwC"}
@@ -1,4 +1,5 @@
1
1
  import { m4_invert } from "../../../../core/geom/3d/mat4/m4_invert.js";
2
+ import { assert } from "../../../../core/assert.js";
2
3
  import { BvhClient } from "../../../../core/bvh2/bvh3/BvhClient.js";
3
4
  import { AABB3 } from "../../../../core/geom/3d/aabb/AABB3.js";
4
5
  import { aabb3_from_three_geometry } from "../../../../core/geom/3d/aabb/aabb3_from_three_geometry.js";
@@ -42,6 +43,22 @@ const scratch_ray_0 = new Float32Array(6);
42
43
  * This is roughly equivalent to single draw call, note that his is not a hierarchical data structure, if you want that - you will need to combine multiple entities, each with a `ShadedGeometry` component
43
44
  */
44
45
  export class ShadedGeometry {
46
+ /**
47
+ * Set when a transform change has been observed but the bounding box and the BVH have
48
+ * not been brought up to date yet. Only ever set under
49
+ * {@link ShadedGeometryFlags.DeferredBoundsUpdate}, and doubles as the "already queued"
50
+ * bit for {@link #bounds_queue}.
51
+ * @type {boolean}
52
+ */
53
+ #bounds_dirty = false;
54
+
55
+ /**
56
+ * Transient, assigned in the system. Where this component parks itself when its bounds
57
+ * go stale under {@link ShadedGeometryFlags.DeferredBoundsUpdate}.
58
+ * @type {DeferredBoundsQueue|null}
59
+ */
60
+ #bounds_queue = null;
61
+
45
62
  constructor() {
46
63
  /**
47
64
  *
@@ -205,11 +222,58 @@ export class ShadedGeometry {
205
222
  return this.__c_transform.matrix;
206
223
  }
207
224
 
225
+ /**
226
+ * Attach this component to the queue that collects deferred bounds updates.
227
+ * Called by the system when the component enters the BVH.
228
+ * @param {DeferredBoundsQueue} queue
229
+ * @returns {void}
230
+ */
231
+ bindBoundsQueue(queue) {
232
+ assert.defined(queue, 'queue');
233
+
234
+ this.#bounds_queue = queue;
235
+ }
236
+
237
+ /**
238
+ * Called by the system when the component leaves the BVH. Any update parked in the
239
+ * queue is abandoned — the entry is left in place and becomes inert, so unlinking
240
+ * stays O(1).
241
+ * @returns {void}
242
+ */
243
+ unbindBoundsQueue() {
244
+ this.#bounds_dirty = false;
245
+ this.#bounds_queue = null;
246
+ }
247
+
248
+ /**
249
+ * Recompute the bounding box and push it into the BVH, if a deferred update is pending.
250
+ *
251
+ * This is the single point where a parked update lands; it is driven both by
252
+ * {@link DeferredBoundsQueue.flush} and by any read of the bounding box.
253
+ * @returns {boolean} whether an update was actually pending
254
+ */
255
+ applyDeferredBoundsUpdate() {
256
+ if (!this.#bounds_dirty) {
257
+ return false;
258
+ }
259
+
260
+ this.#bounds_dirty = false;
261
+
262
+ this.update_bounds();
263
+
264
+ this.__bvh_leaf.write_bounds();
265
+
266
+ return true;
267
+ }
268
+
208
269
  /**
209
270
  *
210
271
  * @param {AABB3} destination
211
272
  */
212
273
  getBoundingBox(destination) {
274
+ // settle a pending deferred update, so a read never observes a stale box
275
+ this.applyDeferredBoundsUpdate();
276
+
213
277
  const aabb = this.__bvh_leaf.bounds;
214
278
 
215
279
  destination.readFromArray(aabb);
@@ -247,7 +311,22 @@ export class ShadedGeometry {
247
311
  return r;
248
312
  }
249
313
 
314
+ /**
315
+ * Change handler subscribed to the entity's {@link Transform} while the component is
316
+ * linked; see {@link ShadedGeometrySystem.link}.
317
+ * @returns {void}
318
+ */
250
319
  updateTransform() {
320
+ if (this.getFlag(ShadedGeometryFlags.DeferredBoundsUpdate)) {
321
+ if (!this.#bounds_dirty) {
322
+ this.#bounds_dirty = true;
323
+
324
+ this.#bounds_queue.add(this);
325
+ }
326
+
327
+ return;
328
+ }
329
+
251
330
  this.update_bounds();
252
331
 
253
332
  this.__bvh_leaf.write_bounds();
@@ -19,9 +19,27 @@ export const ShadedGeometryFlags = {
19
19
  Visible: 16,
20
20
 
21
21
  /**
22
- * Bounds are updated whenever transforms change, we can defer this until next frame render request
23
- * This lets us back updated and do less work overall
24
- * TODO implement, currently it's ignored
22
+ * Bounds are updated whenever transforms change; with this set that work is deferred
23
+ * until the tree is next read (a render request, a query, or a read of the bounding
24
+ * box), and every change observed in between collapses into a single update.
25
+ *
26
+ * This is a trade, not a free win, and which way it goes depends entirely on how many
27
+ * times the transform is written between reads:
28
+ *
29
+ * - Set it on anything whose transform is written more than once per frame. A
30
+ * {@link Transform} signals `position`, `rotation` and `scale` separately, so a
31
+ * mover that changes all three pays three bounds recomputations and three walks to
32
+ * the BVH root, and everything driven through a transform hierarchy writes all
33
+ * three every time (the hierarchy hands its children a matrix, and decomposing it
34
+ * touches each). Measured on a 20k-mesh scene with 2k movers: 3x fewer updates,
35
+ * ~20-25% off the frame.
36
+ * - Leave it off for a mesh whose transform is written exactly once. There is
37
+ * nothing to collapse, and the same work now spans two passes over the components
38
+ * instead of one — measured ~10-20% worse on the same scene.
39
+ * - Costs nothing on a mesh that does not move; an empty flush is one length test.
40
+ *
41
+ * @see ShadedGeometrySystem.flushBoundsUpdates
42
+ * @see ShadedGeometryDeferredBounds.bench.spec.js
25
43
  */
26
44
  DeferredBoundsUpdate: 32,
27
45
  };
@@ -44,10 +44,22 @@ export class ShadedGeometrySystem extends System<any> {
44
44
  __optimization_task: Task;
45
45
  __maintenance_task: Task;
46
46
  /**
47
- *
47
+ * NOTE: components carrying {@link ShadedGeometryFlags.DeferredBoundsUpdate} only reach
48
+ * the tree at a {@link flushBoundsUpdates}, so a caller reaching for the tree directly
49
+ * must flush first. Every query on this system already does.
48
50
  * @returns {BVH}
49
51
  */
50
52
  get bvh(): BVH;
53
+ /**
54
+ * Apply every bounds update parked by components carrying
55
+ * {@link ShadedGeometryFlags.DeferredBoundsUpdate}, bringing {@link bvh} in line with
56
+ * the current transforms.
57
+ *
58
+ * Cheap when nothing is pending, which is why every query calls it unconditionally.
59
+ * @returns {number} how many meshes had their bounds applied, i.e. how many BVH
60
+ * refits this flush cost
61
+ */
62
+ flushBoundsUpdates(): number;
51
63
  /**
52
64
  * NOTE: DO NOT MODIFY RESULTS
53
65
  * @returns {Map<number,number>}
@@ -1 +1 @@
1
- {"version":3,"file":"ShadedGeometrySystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js"],"names":[],"mappings":"AA8DA;IASI;;;OAGG;IACH,4BAmEC;IAjEG,2DAA+C;IAE/C;;;;OAIG;IACH,iBAAsB;IAEtB;;;;OAIG;IACH,uBAA0B;IAE1B;;;;OAIG;IACH,wBAAgC;IAEhC;;;;OAIG;IACH,4BAAoC;IAEpC;;;;OAIG;IACH,kCAA0C;IAE1C;;;;OAIG;IACH,qBAA6B;IAI7B,0BAYE;IAEF,yBAIC;IAIL;;;OAGG;IACH,eAEC;IAED;;;OAGG;IACH,4BAFa,IAAI,MAAM,EAAC,MAAM,CAAC,CAI9B;IAED;;;;OAIG;IACH,+BAHW,MAAM,+CAsBhB;IAED;;;;OAIG;IACH,iCAHW,MAAM,GACL,OAAO,CAmBlB;IAED;;;;OAIG;IACH,4BASC;IAED;;;;OAIG;IACH,8BAMC;IAED,2CAkCC;IAED,4CAmBC;IAED;;;;;OAKG;IACH,SAJW,cAAc,KACd,SAAS,UACT,MAAM,QA2ChB;IAED;;;;;OAKG;IACH,WAJW,cAAc,KACd,SAAS,UACT,MAAM,QA4BhB;IAED;;;;;;OAMG;IACH,4BALW,MAAM,EAAE,iBACR,MAAM,UACN,MAAM,EAAE,GAAC,UAAU,MAAM,CAAC,GACxB,MAAM,CAQlB;IAED;;;;;;;;;;;OAWG;IACH,kBAVW,MAAM,YACN,MAAM,YACN,MAAM,eACN,MAAM,eACN,MAAM,eACN,MAAM,6BACG,MAAM,QAAQ,cAAc,KAAK,OAAO,kCAE/C;QAAC,MAAM,EAAC,MAAM,CAAC;QAAC,IAAI,EAAC,cAAc,CAAC;QAAC,OAAO,EAAE,aAAa,CAAA;KAAC,EAAE,CA8D1E;IAGD;;;;;;;;;;;;OAYG;IACH,wBAXW,aAAa,YACb,MAAM,YACN,MAAM,YACN,MAAM,eACN,MAAM,eACN,MAAM,eACN,MAAM,6BACG,MAAM,QAAQ,cAAc,KAAK,OAAO,kCAE/C;QAAC,MAAM,EAAC,MAAM,CAAC;QAAC,IAAI,EAAC,cAAc,CAAA;KAAC,GAAC,SAAS,CAmF1D;;CACJ;uBApiBsB,wBAAwB;0BACrB,qCAAqC;+BAIhC,qBAAqB;iBATnC,uCAAuC;oBAZpC,mCAAmC;8BAUzB,2CAA2C"}
1
+ {"version":3,"file":"ShadedGeometrySystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js"],"names":[],"mappings":"AA8DA;IAiBI;;;OAGG;IACH,4BAmEC;IAjEG,2DAA+C;IAE/C;;;;OAIG;IACH,iBAAsB;IAEtB;;;;OAIG;IACH,uBAA0B;IAE1B;;;;OAIG;IACH,wBAAgC;IAEhC;;;;OAIG;IACH,4BAAoC;IAEpC;;;;OAIG;IACH,kCAA0C;IAE1C;;;;OAIG;IACH,qBAA6B;IAI7B,0BAYE;IAEF,yBAIC;IAIL;;;;;OAKG;IACH,eAEC;IAED;;;;;;;;OAQG;IACH,sBAHa,MAAM,CAKlB;IAED;;;OAGG;IACH,4BAFa,IAAI,MAAM,EAAC,MAAM,CAAC,CAI9B;IAED;;;;OAIG;IACH,+BAHW,MAAM,+CAsBhB;IAED;;;;OAIG;IACH,iCAHW,MAAM,GACL,OAAO,CAmBlB;IAED;;;;OAIG;IACH,4BASC;IAED;;;;OAIG;IACH,8BAMC;IAED,2CA0CC;IAED,4CAmBC;IAED;;;;;OAKG;IACH,SAJW,cAAc,KACd,SAAS,UACT,MAAM,QAuChB;IAED;;;;;OAKG;IACH,WAJW,cAAc,KACd,SAAS,UACT,MAAM,QAgChB;IAED;;;;;;OAMG;IACH,4BALW,MAAM,EAAE,iBACR,MAAM,UACN,MAAM,EAAE,GAAC,UAAU,MAAM,CAAC,GACxB,MAAM,CAUlB;IAED;;;;;;;;;;;OAWG;IACH,kBAVW,MAAM,YACN,MAAM,YACN,MAAM,eACN,MAAM,eACN,MAAM,eACN,MAAM,6BACG,MAAM,QAAQ,cAAc,KAAK,OAAO,kCAE/C;QAAC,MAAM,EAAC,MAAM,CAAC;QAAC,IAAI,EAAC,cAAc,CAAC;QAAC,OAAO,EAAE,aAAa,CAAA;KAAC,EAAE,CAgE1E;IAGD;;;;;;;;;;;;OAYG;IACH,wBAXW,aAAa,YACb,MAAM,YACN,MAAM,YACN,MAAM,eACN,MAAM,eACN,MAAM,eACN,MAAM,6BACG,MAAM,QAAQ,cAAc,KAAK,OAAO,kCAE/C;QAAC,MAAM,EAAC,MAAM,CAAC;QAAC,IAAI,EAAC,cAAc,CAAA;KAAC,GAAC,SAAS,CAqF1D;;CACJ;uBA1kBsB,wBAAwB;0BACrB,qCAAqC;+BAKhC,qBAAqB;iBAVnC,uCAAuC;oBAXpC,mCAAmC;8BASzB,2CAA2C"}
@@ -1,6 +1,5 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
2
  import { BVH } from "../../../../core/bvh2/bvh3/BVH.js";
3
- import { make_bvh_depth_range_computer } from "../make_bvh_depth_range_computer.js";
4
3
  import { bvh_query_leaves_generic } from "../../../../core/bvh2/bvh3/query/bvh_query_leaves_generic.js";
5
4
  import {
6
5
  bvh_query_user_data_intersects_frustum
@@ -17,7 +16,8 @@ import TaskState from "../../../../core/process/task/TaskState.js";
17
16
  import { iteratorTask } from "../../../../core/process/task/util/iteratorTask.js";
18
17
  import { System } from "../../../ecs/System.js";
19
18
  import { Transform } from "../../../ecs/transform/Transform.js";
20
- import { isForwardPlusLightingSkipped } from "../../render/forward_plus/plugin/isForwardPlusLightingSkipped.js";
19
+ import { make_bvh_depth_range_computer } from "../make_bvh_depth_range_computer.js";
20
+ import { DeferredBoundsQueue } from "./DeferredBoundsQueue.js";
21
21
  import { RuntimeDrawMethodOptimizer } from "./render/optimization/RuntimeDrawMethodOptimizer.js";
22
22
  import { ShadedGeometryRendererContext } from "./render/ShadedGeometryRendererContext.js";
23
23
  import { ShadedGeometry } from "./ShadedGeometry.js";
@@ -69,6 +69,14 @@ export class ShadedGeometrySystem extends System {
69
69
  */
70
70
  #material_references = new Map();
71
71
 
72
+ /**
73
+ * Bounds updates parked by components carrying
74
+ * {@link ShadedGeometryFlags.DeferredBoundsUpdate}, drained by
75
+ * {@link flushBoundsUpdates} before anything reads {@link bvh}.
76
+ * @type {DeferredBoundsQueue}
77
+ */
78
+ #deferred_bounds = new DeferredBoundsQueue();
79
+
72
80
  /**
73
81
  *
74
82
  * @param {Engine} engine
@@ -144,13 +152,28 @@ export class ShadedGeometrySystem extends System {
144
152
 
145
153
 
146
154
  /**
147
- *
155
+ * NOTE: components carrying {@link ShadedGeometryFlags.DeferredBoundsUpdate} only reach
156
+ * the tree at a {@link flushBoundsUpdates}, so a caller reaching for the tree directly
157
+ * must flush first. Every query on this system already does.
148
158
  * @returns {BVH}
149
159
  */
150
160
  get bvh() {
151
161
  return this.__bvh_binary;
152
162
  }
153
163
 
164
+ /**
165
+ * Apply every bounds update parked by components carrying
166
+ * {@link ShadedGeometryFlags.DeferredBoundsUpdate}, bringing {@link bvh} in line with
167
+ * the current transforms.
168
+ *
169
+ * Cheap when nothing is pending, which is why every query calls it unconditionally.
170
+ * @returns {number} how many meshes had their bounds applied, i.e. how many BVH
171
+ * refits this flush cost
172
+ */
173
+ flushBoundsUpdates() {
174
+ return this.#deferred_bounds.flush();
175
+ }
176
+
154
177
  /**
155
178
  * NOTE: DO NOT MODIFY RESULTS
156
179
  * @returns {Map<number,number>}
@@ -262,10 +285,18 @@ export class ShadedGeometrySystem extends System {
262
285
  return 0;
263
286
  }
264
287
 
288
+ this.flushBoundsUpdates();
289
+
265
290
  return ctx.collect(destination, destination_offset, graphics.renderer, view, this.__bvh_binary, ecd);
266
291
  });
267
292
 
268
- this.__render_layer.compute_depth_range = make_bvh_depth_range_computer(this.__bvh_binary);
293
+ const compute_depth_range = make_bvh_depth_range_computer(this.__bvh_binary);
294
+
295
+ this.__render_layer.compute_depth_range = (result, frustum, nx, ny, nz, plane_constant) => {
296
+ this.flushBoundsUpdates();
297
+
298
+ compute_depth_range(result, frustum, nx, ny, nz, plane_constant);
299
+ };
269
300
 
270
301
  this.__optimization_task.state.set(TaskState.INITIAL);
271
302
  engine.executor.run(this.__optimization_task);
@@ -318,16 +349,12 @@ export class ShadedGeometrySystem extends System {
318
349
  // exists we simply overwrite it rather than guarding a can't-happen case
319
350
  this.#material_references.set(entity, material_reference);
320
351
 
321
- assert.ok(
322
- !isForwardPlusLightingSkipped(material_manager, sg.material),
323
- 'lit material was not transformed for Forward+ clustered lighting,'
324
- + ' ensure the Forward+ plugin is registered before entities are linked'
325
- );
326
-
327
352
  sg.__c_transform = t;
328
353
 
329
354
  sg.update_bounds();
330
355
 
356
+ sg.bindBoundsQueue(this.#deferred_bounds);
357
+
331
358
  t.subscribe(sg.updateTransform, sg);
332
359
 
333
360
  // remember entity for lookups
@@ -353,6 +380,10 @@ export class ShadedGeometrySystem extends System {
353
380
  unlink(sg, t, entity) {
354
381
  t.unsubscribe(sg.updateTransform, sg);
355
382
 
383
+ // abandon any deferred update still parked in the queue, it would otherwise be
384
+ // applied to a leaf that no longer belongs to this tree
385
+ sg.unbindBoundsQueue();
386
+
356
387
  // disconnect BVH
357
388
  sg.__bvh_leaf.unlink();
358
389
 
@@ -390,6 +421,8 @@ export class ShadedGeometrySystem extends System {
390
421
  result_offset,
391
422
  planes
392
423
  ) {
424
+ this.flushBoundsUpdates();
425
+
393
426
  return bvh_query_user_data_intersects_frustum(result, result_offset, this.__bvh_binary, planes);
394
427
  }
395
428
 
@@ -414,6 +447,8 @@ export class ShadedGeometrySystem extends System {
414
447
 
415
448
  const hits = [];
416
449
 
450
+ this.flushBoundsUpdates();
451
+
417
452
  const bvh = this.__bvh_binary;
418
453
 
419
454
  const hit_count = bvh_query_leaves_generic(hits, 0, bvh, bvh.root, BVHQueryIntersectsRay.from([origin_x, origin_y, origin_z, direction_x, direction_y, direction_z]));
@@ -494,6 +529,8 @@ export class ShadedGeometrySystem extends System {
494
529
 
495
530
  const hits = [];
496
531
 
532
+ this.flushBoundsUpdates();
533
+
497
534
  const bvh = this.__bvh_binary;
498
535
 
499
536
  const hit_count = bvh_query_leaves_generic(hits, 0, bvh, bvh.root, BVHQueryIntersectsRay.from([origin_x, origin_y, origin_z, direction_x, direction_y, direction_z]));
@@ -64,11 +64,11 @@ export class FluidObstacleSystem extends System<any> {
64
64
  /**
65
65
  * @param {FluidComponent} fluid
66
66
  */
67
- static "__#189@#refresh_masks"(fluid: FluidComponent): void;
67
+ static "__#191@#refresh_masks"(fluid: FluidComponent): void;
68
68
  /**
69
69
  * @param {FluidComponent} fluid
70
70
  */
71
- static "__#189@#clear_field"(fluid: FluidComponent): void;
71
+ static "__#191@#clear_field"(fluid: FluidComponent): void;
72
72
  /**
73
73
  * Mark every cell of `fluid` whose centre lies within `inflation` of the
74
74
  * posed shape as solid. Iteration is clipped to the shape's world AABB
@@ -80,7 +80,7 @@ export class FluidObstacleSystem extends System<any> {
80
80
  * @param {number} inflation world-units SDF threshold
81
81
  * @param {Float64Array} point length-3 scratch
82
82
  */
83
- static "__#189@#voxelize"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array): void;
83
+ static "__#191@#voxelize"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array): void;
84
84
  /**
85
85
  * Write the obstacle's translation velocity onto every face of every cell
86
86
  * it voxelized — the moving-wall boundary condition. Runs AFTER the mask
@@ -100,7 +100,7 @@ export class FluidObstacleSystem extends System<any> {
100
100
  * @param {number} wvy
101
101
  * @param {number} wvz
102
102
  */
103
- static "__#189@#stamp_wall_velocity"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array, wvx: number, wvy: number, wvz: number): void;
103
+ static "__#191@#stamp_wall_velocity"(fluid: FluidComponent, posed: PosedShape3D, aabb: Float64Array, inflation: number, point: Float64Array, wvx: number, wvy: number, wvz: number): void;
104
104
  constructor();
105
105
  dependencies: (typeof FluidObstacle)[];
106
106
  components_used: (ResourceAccessSpecification<typeof Transform> | ResourceAccessSpecification<typeof RigidBody> | ResourceAccessSpecification<typeof Collider> | ResourceAccessSpecification<typeof FluidComponent> | ResourceAccessSpecification<typeof FluidObstacle>)[];
@@ -38,7 +38,7 @@ export class FluidSystem extends System<any> {
38
38
  * @param {FluidEffectorsComponent} effectors_component
39
39
  * @param {Transform} transform
40
40
  */
41
- static "__#188@#sync_effectors_from_transform"(effectors_component: FluidEffectorsComponent, transform: Transform): void;
41
+ static "__#190@#sync_effectors_from_transform"(effectors_component: FluidEffectorsComponent, transform: Transform): void;
42
42
  /**
43
43
  * Visitor for the (FluidComponent, Transform) traversal — keeps the field's
44
44
  * grid origin locked to a cell-aligned position near the transform.
@@ -61,7 +61,7 @@ export class FluidSystem extends System<any> {
61
61
  * @param {FluidComponent} component
62
62
  * @param {Transform} transform
63
63
  */
64
- static "__#188@#reanchor_field"(component: FluidComponent, transform: Transform): void;
64
+ static "__#190@#reanchor_field"(component: FluidComponent, transform: Transform): void;
65
65
  /**
66
66
  * Write the world-to-grid affine for a FluidComponent into `out`. Axis-aligned,
67
67
  * uniform-scale, so the matrix is sparse:
@@ -76,7 +76,7 @@ export class FluidSystem extends System<any> {
76
76
  * @param {Float32Array} out length-16
77
77
  * @param {FluidComponent} component
78
78
  */
79
- static "__#188@#build_world_to_grid"(out: Float32Array, component: FluidComponent): void;
79
+ static "__#190@#build_world_to_grid"(out: Float32Array, component: FluidComponent): void;
80
80
  constructor();
81
81
  dependencies: (typeof FluidComponent)[];
82
82
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"MinimapMarkersGL.d.ts","sourceRoot":"","sources":["../../../../../src/view/minimap/gl/MinimapMarkersGL.js"],"names":[],"mappings":"AAoBA;;;;;;;GAOG;AACH;IACI;;;;OAIG;IACH,oFAwGC;IApGG;;;OAGG;IACH,sCAAkC;IAElC;;;OAGG;IACH,gCAAgC;IAEhC,2BAAkD;IAIlD,yCAA+B;IAMf,SAFN,IAAI,MAAM,EAAE,QAAQ,CAAC,CAES;IActB,WAFR,aAAa,CAEoD;IAE3E,+BAA+F;IAgD/F,qBAAuB;IAGvB,oDAA2E;IAM3E;;;OAGG;IACH,cAFU,OAAO,CAEQ;IAG7B,uBAyDC;IAED,sCAKC;IAGD;;;;OAIG;IACH,0BAEC;IAED,0BAMC;IAED,sBAuBC;CA0EJ;kCAzTiC,wBAAwB;6BAP7B,uCAAuC;6BACvC,+DAA+D;yBAInE,eAAe;8BAYV,sEAAsE;+BAfrE,uCAAuC;uBAHlC,OAAO"}
1
+ {"version":3,"file":"MinimapMarkersGL.d.ts","sourceRoot":"","sources":["../../../../../src/view/minimap/gl/MinimapMarkersGL.js"],"names":[],"mappings":"AAoBA;;;;;;;GAOG;AACH;IACI;;;;OAIG;IACH,oFAwGC;IApGG;;;OAGG;IACH,sCAAkC;IAElC;;;OAGG;IACH,gCAAgC;IAEhC,2BAAkD;IAIlD,yCAA+B;IAMf,SAFN,IAAI,MAAM,EAAE,QAAQ,CAAC,CAES;IActB,WAFR,aAAa,CAEoD;IAE3E,+BAA+F;IAgD/F,qBAAuB;IAGvB,oDAA2E;IAM3E;;;OAGG;IACH,cAFU,OAAO,CAEQ;IAG7B,uBAyDC;IAED,sCAKC;IAGD;;;;OAIG;IACH,0BAEC;IAED,0BAMC;IAED,sBAuBC;CA4EJ;kCA3TiC,wBAAwB;6BAP7B,uCAAuC;6BACvC,+DAA+D;yBAInE,eAAe;8BAYV,sEAAsE;+BAfrE,uCAAuC;uBAHlC,OAAO"}
@@ -272,7 +272,9 @@ export class MinimapMarkersGL extends MinimapWorldLayer {
272
272
 
273
273
  atlas.on.painted.add(this.handleAtlasUpdate, this);
274
274
  this.shutdownHooks.push(() => {
275
- atlas.on.painted.remove(this.handleAtlasUpdate);
275
+ // the context has to be passed here too, Signal.remove matches on the handle
276
+ // *and* the context, so a remove without one never matches this handler
277
+ atlas.on.painted.remove(this.handleAtlasUpdate, this);
276
278
  });
277
279
 
278
280