@voluma/vlam 0.3.2 → 0.4.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 (40) hide show
  1. package/README.md +2 -2
  2. package/dist/core/compute-sorter.d.ts +7 -1
  3. package/dist/core/index.d.ts +2 -2
  4. package/dist/core/radix-sorter.d.ts +6 -0
  5. package/dist/core/sort-worker-protocol.d.ts +2 -0
  6. package/dist/core/sorter.d.ts +4 -4
  7. package/dist/core/splat-mesh-types.d.ts +22 -5
  8. package/dist/core/splat-mesh.d.ts +11 -2
  9. package/dist/core/splat-sort-bounds.d.ts +17 -0
  10. package/dist/core/worker-sorter.d.ts +7 -5
  11. package/dist/formats/lcc.js +276 -277
  12. package/dist/formats/lcc.js.map +1 -1
  13. package/dist/formats/rad/index.d.ts +1 -1
  14. package/dist/formats/rad/parse-rad.d.ts +1 -1
  15. package/dist/formats/rad.js.map +1 -1
  16. package/dist/index.js +3 -3
  17. package/dist/lod-scheduler-ChoZyEeq.js +466 -0
  18. package/dist/lod-scheduler-ChoZyEeq.js.map +1 -0
  19. package/dist/radix-sorter-tSffmerk.js +181 -0
  20. package/dist/radix-sorter-tSffmerk.js.map +1 -0
  21. package/dist/relighting-qaANKC4Z.js +997 -0
  22. package/dist/relighting-qaANKC4Z.js.map +1 -0
  23. package/dist/{splat-mesh-CsLOQb08.js → splat-mesh-B1KlWHvx.js} +545 -513
  24. package/dist/splat-mesh-B1KlWHvx.js.map +1 -0
  25. package/dist/splat-mesh-types-BZIko-_9.js.map +1 -1
  26. package/dist/static-lod.js +1 -1
  27. package/dist/streaming/lod-scheduler.d.ts +32 -0
  28. package/dist/streaming/lod-source.d.ts +15 -9
  29. package/dist/streaming/streamed-splat-mesh.d.ts +38 -22
  30. package/dist/streaming.js +959 -927
  31. package/dist/streaming.js.map +1 -1
  32. package/dist/unified.js +17 -17
  33. package/package.json +1 -1
  34. package/dist/lod-scheduler-B0a_uBlv.js +0 -383
  35. package/dist/lod-scheduler-B0a_uBlv.js.map +0 -1
  36. package/dist/radix-sorter-BrbUg_CV.js +0 -178
  37. package/dist/radix-sorter-BrbUg_CV.js.map +0 -1
  38. package/dist/relighting-Tiwep8yd.js +0 -977
  39. package/dist/relighting-Tiwep8yd.js.map +0 -1
  40. package/dist/splat-mesh-CsLOQb08.js.map +0 -1
@@ -1,18 +1,18 @@
1
1
  var pt = Object.defineProperty;
2
- var ft = (g, u, e) => u in g ? pt(g, u, { enumerable: !0, configurable: !0, writable: !0, value: e }) : g[u] = e;
3
- var o = (g, u, e) => ft(g, typeof u != "symbol" ? u + "" : u, e);
2
+ var ft = (g, u, t) => u in g ? pt(g, u, { enumerable: !0, configurable: !0, writable: !0, value: t }) : g[u] = t;
3
+ var o = (g, u, t) => ft(g, typeof u != "symbol" ? u + "" : u, t);
4
4
  import { r as Y, M as gt, a as mt } from "./splat-mesh-types-BZIko-_9.js";
5
5
  import * as d from "three/webgpu";
6
6
  import { uniform as b } from "three/tsl";
7
- import { z as wt, e as xt, m as St, b as vt, D as yt, c as Rt, A as Z, B as bt, E as Tt, W as At, F as K, G as Q, H as J, I as Mt, i as It, j as kt, y as Pt, n as Ct, r as Ut, J as z, C as tt, f as Dt } from "./relighting-Tiwep8yd.js";
7
+ import { A as wt, f as xt, n as St, c as vt, D as yt, d as Rt, B as Z, E as bt, F as Tt, W as At, G as K, H as Q, I as J, J as Mt, j as It, k as kt, z as Pt, o as Ct, r as Ut, K as q, L as Dt, C as tt, g as Bt } from "./relighting-qaANKC4Z.js";
8
8
  import { l as et, w as O } from "./logging-BfPdd7NJ.js";
9
- import { d as Bt } from "./splat-budget-DuVZspPQ.js";
9
+ import { d as Et } from "./splat-budget-DuVZspPQ.js";
10
10
  import { e as G } from "./half-float-Cs4FDq8Q.js";
11
- import { a as Et, r as Wt, n as Lt } from "./sh-pack-D5wAe5gg.js";
12
- function Ft() {
11
+ import { a as Wt, r as Lt, n as Ft } from "./sh-pack-D5wAe5gg.js";
12
+ function Vt() {
13
13
  return new d.Matrix4().makeRotationX(Math.PI);
14
14
  }
15
- function Vt(g) {
15
+ function _t(g) {
16
16
  switch (g) {
17
17
  case "ply":
18
18
  case "splat":
@@ -20,7 +20,7 @@ function Vt(g) {
20
20
  case "sog":
21
21
  case "rad":
22
22
  case "streamed-sog":
23
- return Ft();
23
+ return Vt();
24
24
  case "spz":
25
25
  case "lcc":
26
26
  case "lcc2":
@@ -28,78 +28,82 @@ function Vt(g) {
28
28
  return null;
29
29
  }
30
30
  }
31
- const lt = `let w = new Float32Array(0), x = new Float32Array(0);
32
- const f = new Uint32Array(65536);
33
- let E = 0, S = new Uint32Array(0), M = new Float32Array(0), I = new Uint32Array(0), R = new Uint32Array(0), Y = new Uint32Array(0);
34
- function j(e) {
35
- e <= E || (E = e, S = new Uint32Array(e), M = new Float32Array(e), I = new Uint32Array(e), R = new Uint32Array(e), Y = new Uint32Array(e));
31
+ const lt = `let h = new Float32Array(0), R = new Float32Array(0);
32
+ const a = new Uint32Array(65536);
33
+ let k = 0, Y = new Uint32Array(0), b = new Float32Array(0), I = new Uint32Array(0), E = new Uint32Array(0), K = new Uint32Array(0);
34
+ function W(n) {
35
+ n <= k || (k = n, Y = new Uint32Array(n), b = new Float32Array(n), I = new Uint32Array(n), E = new Uint32Array(n), K = new Uint32Array(n));
36
36
  }
37
- function q(e, r, n) {
38
- const D = e[2], K = e[6], _ = e[10], k = e[14];
39
- let c = 0;
40
- for (let t = 0; t < r.length; t += 2) c += r[t + 1];
41
- j(c);
42
- let d = 1 / 0, F = -1 / 0, X = 0;
37
+ function $(n, r, o, D) {
38
+ const z = n[0], B = n[4], T = n[8], j = n[12], q = n[1], G = n[5], H = n[9], J = n[13], L = n[2], N = n[6], O = n[10], P = n[14];
39
+ let l = 0;
40
+ for (let t = 0; t < r.length; t += 2) l += r[t + 1];
41
+ W(l);
42
+ let p = 1 / 0, F = -1 / 0, X = 0;
43
43
  for (let t = 0; t < r.length; t += 2) {
44
- const i = r[t], o = i + r[t + 1];
45
- for (let s = i; s < o; s++) {
46
- const a = s * 4, h = x[s], l = n ? h * 16 : 0, u = w[a], U = w[a + 1], g = w[a + 2], B = n ? n[l] * u + n[l + 4] * U + n[l + 8] * g + n[l + 12] : u, T = n ? n[l + 1] * u + n[l + 5] * U + n[l + 9] * g + n[l + 13] : U, Z = n ? n[l + 2] * u + n[l + 6] * U + n[l + 10] * g + n[l + 14] : g, A = D * B + K * T + _ * Z + k;
47
- S[X] = s, M[X] = A, X++, A < d && (d = A), A > F && (F = A);
44
+ const A = r[t], s = A + r[t + 1];
45
+ for (let e = A; e < s; e++) {
46
+ const f = e * 4, d = R[e], c = o ? d * 16 : 0, u = h[f], U = h[f + 1], g = h[f + 2], M = o ? o[c] * u + o[c + 4] * U + o[c + 8] * g + o[c + 12] : u, x = o ? o[c + 1] * u + o[c + 5] * U + o[c + 9] * g + o[c + 13] : U, S = o ? o[c + 2] * u + o[c + 6] * U + o[c + 10] * g + o[c + 14] : g, _ = L * M + N * x + O * S + P, i = D === "radial" ? -Math.hypot(
47
+ z * M + B * x + T * S + j,
48
+ q * M + G * x + H * S + J,
49
+ _
50
+ ) : _;
51
+ Y[X] = e, b[X] = i, X++, i < p && (p = i), i > F && (F = i);
48
52
  }
49
53
  }
50
- const z = 16777215 / (F - d || 1);
51
- let y = R;
52
- for (let t = 0; t < c; t++)
53
- I[t] = (M[t] - d) * z, y[t] = t;
54
- let p = Y;
54
+ const Q = 16777215 / (F - p || 1);
55
+ let y = E;
56
+ for (let t = 0; t < l; t++)
57
+ I[t] = (b[t] - p) * Q, y[t] = t;
58
+ let w = K;
55
59
  for (let t = 0; t < 24; t += 16) {
56
- f.fill(0);
57
- for (let o = 0; o < c; o++) {
58
- const s = I[y[o]] >>> t & 65535;
59
- f[s] = f[s] + 1;
60
+ a.fill(0);
61
+ for (let s = 0; s < l; s++) {
62
+ const e = I[y[s]] >>> t & 65535;
63
+ a[e] = a[e] + 1;
60
64
  }
61
- let i = 0;
62
- for (let o = 0; o < 65536; o++) {
63
- const s = f[o];
64
- f[o] = i, i += s;
65
+ let A = 0;
66
+ for (let s = 0; s < 65536; s++) {
67
+ const e = a[s];
68
+ a[s] = A, A += e;
65
69
  }
66
- for (let o = 0; o < c; o++) {
67
- const s = y[o], a = I[s] >>> t & 65535, h = f[a];
68
- p[h] = s, f[a] = h + 1;
70
+ for (let s = 0; s < l; s++) {
71
+ const e = y[s], f = I[e] >>> t & 65535, d = a[f];
72
+ w[d] = e, a[f] = d + 1;
69
73
  }
70
- [y, p] = [p, y];
74
+ [y, w] = [w, y];
71
75
  }
72
- R = y, Y = p;
73
- const b = new Uint32Array(c);
74
- for (let t = 0; t < c; t++) b[t] = S[y[t]];
75
- return b;
76
+ E = y, K = w;
77
+ const Z = new Uint32Array(l);
78
+ for (let t = 0; t < l; t++) Z[t] = Y[y[t]];
79
+ return Z;
76
80
  }
77
- self.onmessage = (e) => {
78
- const r = e.data;
81
+ self.onmessage = (n) => {
82
+ const r = n.data;
79
83
  if (r.type === "init") {
80
- w = new Float32Array(r.capacity * 4), x = new Float32Array(r.capacity);
84
+ h = new Float32Array(r.capacity * 4), R = new Float32Array(r.capacity);
81
85
  return;
82
86
  }
83
87
  if (r.type === "write") {
84
- w.set(r.centers, r.start * 4), r.sourceIds && x.set(r.sourceIds, r.start);
88
+ h.set(r.centers, r.start * 4), r.sourceIds && R.set(r.sourceIds, r.start);
85
89
  return;
86
90
  }
87
- const n = q(r.modelView, r.spans, r.matrices), D = { type: "order", order: n };
88
- self.postMessage(D, [n.buffer]);
91
+ const o = $(r.modelView, r.spans, r.matrices, r.sortMetric), D = { type: "order", order: o };
92
+ self.postMessage(D, [o.buffer]);
89
93
  };
90
- //# sourceMappingURL=sort-worker-CDRn-GLW.js.map
94
+ //# sourceMappingURL=sort-worker-MzY_zfJ3.js.map
91
95
  `, it = typeof self < "u" && self.Blob && new Blob(["URL.revokeObjectURL(import.meta.url);", lt], { type: "text/javascript;charset=utf-8" });
92
- function _t(g) {
96
+ function zt(g) {
93
97
  let u;
94
98
  try {
95
99
  if (u = it && (self.URL || self.webkitURL).createObjectURL(it), !u) throw "";
96
- const e = new Worker(u, {
100
+ const t = new Worker(u, {
97
101
  type: "module",
98
102
  name: g == null ? void 0 : g.name
99
103
  });
100
- return e.addEventListener("error", () => {
104
+ return t.addEventListener("error", () => {
101
105
  (self.URL || self.webkitURL).revokeObjectURL(u);
102
- }), e;
106
+ }), t;
103
107
  } catch {
104
108
  return new Worker(
105
109
  "data:text/javascript;charset=utf-8," + encodeURIComponent(lt),
@@ -111,11 +115,12 @@ function _t(g) {
111
115
  }
112
116
  }
113
117
  class qt {
114
- constructor(u) {
118
+ constructor(u, t = "depth") {
115
119
  o(this, "kind", "worker");
116
120
  o(this, "worker");
117
121
  o(this, "splatIndexAttribute");
118
122
  o(this, "host");
123
+ o(this, "sortMetric");
119
124
  o(this, "inFlight", !1);
120
125
  /** Set by {@link dispose}; drops any already-delivered order message. */
121
126
  o(this, "disposed", !1);
@@ -126,23 +131,24 @@ class qt {
126
131
  o(this, "lastSubmittedAt", -1 / 0);
127
132
  o(this, "lastCompletedAt", -1 / 0);
128
133
  o(this, "lastLatencyMs", Number.NaN);
129
- this.host = u, this.splatIndexAttribute = u.splatIndexAttribute, this.worker = new _t(), this.worker.onmessage = (t) => {
130
- this.applyOrder(t.data.order);
131
- }, this.worker.onerror = (t) => {
132
- et("sort worker error - retrying on a later frame.", t.message), this.inFlight = !1;
134
+ this.host = u, this.sortMetric = t, this.splatIndexAttribute = u.splatIndexAttribute, this.worker = new zt(), this.worker.onmessage = (i) => {
135
+ this.applyOrder(i.data.order);
136
+ }, this.worker.onerror = (i) => {
137
+ et("sort worker error - retrying on a later frame.", i.message), this.inFlight = !1;
133
138
  }, this.worker.onmessageerror = () => {
134
139
  et("sort worker message deserialization failed."), this.inFlight = !1;
135
140
  };
136
141
  const e = { type: "init", capacity: u.capacity };
137
142
  this.worker.postMessage(e), this.pushCenters([{ start: 0, count: Math.ceil(u.capacity / u.rowWidth) }]);
138
143
  }
139
- sort(u, e, t) {
144
+ sort(u, t, e) {
140
145
  if (this.disposed || this.inFlight) return !1;
141
146
  this.inFlight = !0, this.submittedCount++, this.lastSubmittedAt = performance.now(), this.pushCenters(this.host.takeDirtyRows());
142
147
  const i = this.host.getActiveSpans();
143
148
  this.sentSpans = i;
144
149
  const s = {
145
150
  type: "sort",
151
+ sortMetric: this.sortMetric,
146
152
  modelView: new Float32Array(u.elements),
147
153
  spans: i,
148
154
  matrices: this.host.perSource ? new Float32Array(this.host.perSource.matrices) : void 0
@@ -164,42 +170,42 @@ class qt {
164
170
  }
165
171
  /** Sends written pool rows to keep the worker's centers mirror current. */
166
172
  pushCenters(u) {
167
- var t;
168
- const e = this.host.rowWidth;
173
+ var e;
174
+ const t = this.host.rowWidth;
169
175
  for (const i of u) {
170
176
  const s = this.host.centers.slice(
171
- i.start * e * 4,
172
- (i.start + i.count) * e * 4
173
- ), r = i.start * e, n = i.count * e, a = (t = this.host.perSource) == null ? void 0 : t.sourceIds.slice(r, r + n), c = { type: "write", start: r, centers: s, sourceIds: a };
174
- this.worker.postMessage(c, [s.buffer]);
177
+ i.start * t * 4,
178
+ (i.start + i.count) * t * 4
179
+ ), r = i.start * t, n = i.count * t, a = (e = this.host.perSource) == null ? void 0 : e.sourceIds.slice(r, r + n), h = { type: "write", start: r, centers: s, sourceIds: a };
180
+ this.worker.postMessage(h, [s.buffer]);
175
181
  }
176
182
  }
177
183
  applyOrder(u) {
178
184
  var s, r;
179
185
  if (this.inFlight = !1, this.completedCount++, this.lastCompletedAt = performance.now(), this.lastLatencyMs = this.lastCompletedAt - this.lastSubmittedAt, this.disposed) return;
180
- const e = this.host.getActiveSpans(), t = this.sentSpans;
181
- if (this.sentSpans = null, !t || t.length !== e.length) return;
182
- for (let n = 0; n < t.length; n++)
183
- if (t[n] !== e[n]) return;
186
+ const t = this.host.getActiveSpans(), e = this.sentSpans;
187
+ if (this.sentSpans = null, !e || e.length !== t.length) return;
188
+ for (let n = 0; n < e.length; n++)
189
+ if (e[n] !== t[n]) return;
184
190
  const i = this.splatIndexAttribute.array;
185
191
  for (let n = 0; n < u.length; n++)
186
192
  i[n] = u[n];
187
193
  this.splatIndexAttribute.addUpdateRange(0, u.length), this.splatIndexAttribute.needsUpdate = !0, (r = (s = this.host).onOrderApplied) == null || r.call(s);
188
194
  }
189
195
  }
190
- const zt = (1 << 24) - 1, st = new d.Vector2(), V = new d.Raycaster(), rt = new d.Vector3();
191
- function Ot(g, u, e) {
192
- return ((g & 255) << 16 | (u & 255) << 8 | e & 255) / zt;
196
+ const Ot = (1 << 24) - 1, st = new d.Vector2(), V = new d.Raycaster(), rt = new d.Vector3();
197
+ function Gt(g, u, t) {
198
+ return ((g & 255) << 16 | (u & 255) << 8 | t & 255) / Ot;
193
199
  }
194
- function Gt(g, u, e) {
195
- return u + g * (e - u);
200
+ function Ht(g, u, t) {
201
+ return u + g * (t - u);
196
202
  }
197
- function Ht(g, u, e, t, i) {
198
- st.set(g, u), V.setFromCamera(st, t), rt.copy(V.ray.direction).transformDirection(t.matrixWorldInverse);
199
- const s = e / -rt.z;
203
+ function Nt(g, u, t, e, i) {
204
+ st.set(g, u), V.setFromCamera(st, e), rt.copy(V.ray.direction).transformDirection(e.matrixWorldInverse);
205
+ const s = t / -rt.z;
200
206
  return i.copy(V.ray.origin).addScaledVector(V.ray.direction, s), { point: i, distance: i.distanceTo(V.ray.origin) };
201
207
  }
202
- class Nt {
208
+ class Xt {
203
209
  constructor(u) {
204
210
  /** Alpha below which a splat is transparent enough to pick through. */
205
211
  o(this, "alphaThreshold", b(0.1));
@@ -222,8 +228,8 @@ class Nt {
222
228
  get uniforms() {
223
229
  return { alphaThreshold: this.alphaThreshold, near: this.near, far: this.far };
224
230
  }
225
- pick(u, e, t, i) {
226
- const s = this.queue.then(() => this.run(u, e, t, i));
231
+ pick(u, t, e, i) {
232
+ const s = this.queue.then(() => this.run(u, t, e, i));
227
233
  return this.queue = s.then(
228
234
  () => {
229
235
  },
@@ -240,32 +246,32 @@ class Nt {
240
246
  this.material && (this.material.needsUpdate = !0);
241
247
  }
242
248
  dispose() {
243
- var u, e;
244
- (u = this.material) == null || u.dispose(), this.material = null, this.scene.clear(), this.proxy = null, (e = this.target) == null || e.dispose(), this.target = null, this.pickCamera = null;
249
+ var u, t;
250
+ (u = this.material) == null || u.dispose(), this.material = null, this.scene.clear(), this.proxy = null, (t = this.target) == null || t.dispose(), this.target = null, this.pickCamera = null;
245
251
  }
246
- async run(u, e, t, i) {
252
+ async run(u, t, e, i) {
247
253
  if (this.host.isDisposed() || this.host.getActiveCount() === 0 || u.x < -1 || u.x > 1 || u.y < -1 || u.y > 1) return null;
248
- if (wt(e))
254
+ if (wt(t))
249
255
  throw new Error(
250
256
  "SplatMesh.pick: an XR array camera has no single frustum to pick through. Pass one eye (renderer.xr.getCamera().cameras[i]) or a mono camera, and give `ndc` in that eye’s viewport."
251
257
  );
252
- e.updateMatrixWorld(!0), this.host.updateWorldMatrix(), this.host.prepare(e, t);
258
+ t.updateMatrixWorld(!0), this.host.updateWorldMatrix(), this.host.prepare(t, e);
253
259
  const s = Math.max(1, Math.floor(this.host.getViewportSize().x)), r = Math.max(1, Math.floor(this.host.getViewportSize().y)), n = Math.floor((u.x * 0.5 + 0.5) * s), a = Math.floor((u.y * 0.5 + 0.5) * r);
254
260
  if (n < 0 || a < 0 || n >= s || a >= r) return null;
255
- this.ensureResources(e);
256
- const c = this.target, h = this.proxy, l = this.pickCamera;
257
- this.cropCameraToPixel(l, e, s, r, n, a), this.host.setView(l, 1, 1);
258
- const f = "near" in e && typeof e.near == "number" ? e.near : 0.1, x = "far" in e && typeof e.far == "number" ? e.far : 1e3;
261
+ this.ensureResources(t);
262
+ const h = this.target, c = this.proxy, l = this.pickCamera;
263
+ this.cropCameraToPixel(l, t, s, r, n, a), this.host.setView(l, 1, 1);
264
+ const f = "near" in t && typeof t.near == "number" ? t.near : 0.1, x = "far" in t && typeof t.far == "number" ? t.far : 1e3;
259
265
  this.near.value = f, this.far.value = x, this.alphaThreshold.value = (i == null ? void 0 : i.alphaThreshold) !== void 0 ? i.alphaThreshold : 0.1;
260
- const p = this.host.mesh, w = t.getRenderTarget(), m = t.getScissorTest();
261
- t.getClearColor(this.savedClearColor);
262
- const S = t.getClearAlpha(), A = t.autoClear;
263
- h.matrix.copy(p.matrixWorld), h.matrixWorld.copy(p.matrixWorld), h.visible = this.host.getPickVisible(), h.layers.mask = p.layers.mask, h.renderOrder = p.renderOrder, c.viewport.set(0, 0, 1, 1), c.scissor.set(0, 0, 1, 1);
266
+ const p = this.host.mesh, w = e.getRenderTarget(), m = e.getScissorTest();
267
+ e.getClearColor(this.savedClearColor);
268
+ const S = e.getClearAlpha(), A = e.autoClear;
269
+ c.matrix.copy(p.matrixWorld), c.matrixWorld.copy(p.matrixWorld), c.visible = this.host.getPickVisible(), c.layers.mask = p.layers.mask, c.renderOrder = p.renderOrder, h.viewport.set(0, 0, 1, 1), h.scissor.set(0, 0, 1, 1);
264
270
  const R = (() => {
265
271
  try {
266
- return t.setRenderTarget(c), t.setScissorTest(!1), t.setClearColor(0, 0), t.autoClear = !0, t.clear(), t.setScissorTest(!0), t.autoClear = !1, t.render(this.scene, l), t.readRenderTargetPixelsAsync(c, 0, 0, 1, 1);
272
+ return e.setRenderTarget(h), e.setScissorTest(!1), e.setClearColor(0, 0), e.autoClear = !0, e.clear(), e.setScissorTest(!0), e.autoClear = !1, e.render(this.scene, l), e.readRenderTargetPixelsAsync(h, 0, 0, 1, 1);
267
273
  } finally {
268
- this.host.setView(e, s, r), t.setRenderTarget(w), t.setScissorTest(m), t.setClearColor(this.savedClearColor, S), t.autoClear = A;
274
+ this.host.setView(t, s, r), e.setRenderTarget(w), e.setScissorTest(m), e.setClearColor(this.savedClearColor, S), e.autoClear = A;
269
275
  }
270
276
  })();
271
277
  let y;
@@ -278,7 +284,7 @@ class Nt {
278
284
  if (this.host.isDisposed()) return null;
279
285
  const M = y[0], U = y[1], I = y[2];
280
286
  if (y[3] === 0) return null;
281
- const B = Gt(Ot(M, U, I), f, x), { point: E, distance: W } = Ht(u.x, u.y, B, e, this.point);
287
+ const B = Ht(Gt(M, U, I), f, x), { point: E, distance: W } = Nt(u.x, u.y, B, t, this.point);
282
288
  return { point: E.clone(), distance: W };
283
289
  }
284
290
  ensureResources(u) {
@@ -290,24 +296,24 @@ class Nt {
290
296
  })), this.material === null && (this.material = new d.NodeMaterial(), this.host.applyPickGraph(this.material), this.proxy = new d.Mesh(this.host.mesh.geometry, this.material), this.proxy.matrixAutoUpdate = !1, this.proxy.frustumCulled = !1, this.scene.add(this.proxy)), (this.pickCamera === null || this.pickCamera.constructor !== u.constructor) && (this.pickCamera = u.clone());
291
297
  }
292
298
  /** Maps one original framebuffer pixel onto the complete 1×1 pick target. */
293
- cropCameraToPixel(u, e, t, i, s, r) {
294
- u.copy(e);
295
- const n = u.projectionMatrix, a = n.elements, c = 2 * s + 1 - t, h = 2 * r + 1 - i;
299
+ cropCameraToPixel(u, t, e, i, s, r) {
300
+ u.copy(t);
301
+ const n = u.projectionMatrix, a = n.elements, h = 2 * s + 1 - e, c = 2 * r + 1 - i;
296
302
  for (let l = 0; l < 4; l++) {
297
303
  const f = a[l * 4 + 3];
298
- a[l * 4] = a[l * 4] * t - c * f, a[l * 4 + 1] = a[l * 4 + 1] * i - h * f;
304
+ a[l * 4] = a[l * 4] * e - h * f, a[l * 4 + 1] = a[l * 4 + 1] * i - c * f;
299
305
  }
300
306
  u.projectionMatrixInverse.copy(n).invert();
301
307
  }
302
308
  }
303
- const Xt = 1024, jt = 1 << 21;
304
- class $t {
309
+ const jt = 1024, $t = 1 << 21;
310
+ class Yt {
305
311
  /**
306
312
  * @param centers - The pool's CPU centers (stride 4: x,y,z,_ per splat).
307
313
  * @param poolIndices - The pool indices to index (e.g. the active list).
308
314
  * @param count - How many entries of `poolIndices` are valid.
309
315
  */
310
- constructor(u, e, t) {
316
+ constructor(u, t, e) {
311
317
  /** Populated-region minimum corner (local space). */
312
318
  o(this, "min", new Float64Array(3));
313
319
  /** Per-axis cell size (local units). */
@@ -321,13 +327,13 @@ class $t {
321
327
  /** Pool centers array this grid points into (RGBA stride 4). */
322
328
  o(this, "centers");
323
329
  o(this, "count");
324
- if (this.centers = u, this.count = t, t === 0) {
330
+ if (this.centers = u, this.count = e, e === 0) {
325
331
  this.dims.set([1, 1, 1]), this.cellSize.set([1, 1, 1]), this.cellStart = new Int32Array(2), this.items = new Uint32Array(0);
326
332
  return;
327
333
  }
328
334
  const i = [1 / 0, 1 / 0, 1 / 0], s = [-1 / 0, -1 / 0, -1 / 0];
329
- for (let p = 0; p < t; p++) {
330
- const w = e[p] * 4;
335
+ for (let p = 0; p < e; p++) {
336
+ const w = t[p] * 4;
331
337
  for (let m = 0; m < 3; m++) {
332
338
  const S = u[w + m];
333
339
  S < i[m] && (i[m] = S), S > s[m] && (s[m] = S);
@@ -338,34 +344,34 @@ class $t {
338
344
  s[1] - i[1],
339
345
  s[2] - i[2]
340
346
  ], n = r.filter((p) => p > 0), a = n.reduce((p, w) => p * w, 1);
341
- let c = n.length > 0 ? Math.pow(a / t, 1 / n.length) : 1;
342
- (!(c > 0) || !Number.isFinite(c)) && (c = 1);
343
- const h = (p) => {
347
+ let h = n.length > 0 ? Math.pow(a / e, 1 / n.length) : 1;
348
+ (!(h > 0) || !Number.isFinite(h)) && (h = 1);
349
+ const c = (p) => {
344
350
  for (let w = 0; w < 3; w++) {
345
351
  const m = r[w];
346
- this.dims[w] = m > 0 ? Math.max(1, Math.min(Xt, Math.round(m / p) || 1)) : 1, this.cellSize[w] = this.dims[w] > 0 && m / this.dims[w] || 1, this.min[w] = i[w];
352
+ this.dims[w] = m > 0 ? Math.max(1, Math.min(jt, Math.round(m / p) || 1)) : 1, this.cellSize[w] = this.dims[w] > 0 && m / this.dims[w] || 1, this.min[w] = i[w];
347
353
  }
348
354
  };
349
- for (h(c); this.dims[0] * this.dims[1] * this.dims[2] > jt; )
350
- c *= 1.5, h(c);
355
+ for (c(h); this.dims[0] * this.dims[1] * this.dims[2] > $t; )
356
+ h *= 1.5, c(h);
351
357
  const l = this.dims[0] * this.dims[1] * this.dims[2], f = new Int32Array(l + 1);
352
- for (let p = 0; p < t; p++) f[this.cellOf(e[p]) + 1]++;
358
+ for (let p = 0; p < e; p++) f[this.cellOf(t[p]) + 1]++;
353
359
  for (let p = 0; p < l; p++) f[p + 1] += f[p];
354
- this.cellStart = f, this.items = new Uint32Array(t);
360
+ this.cellStart = f, this.items = new Uint32Array(e);
355
361
  const x = Int32Array.from(f.subarray(0, l));
356
- for (let p = 0; p < t; p++) {
357
- const w = e[p];
362
+ for (let p = 0; p < e; p++) {
363
+ const w = t[p];
358
364
  this.items[x[this.cellOf(w)]++] = w;
359
365
  }
360
366
  }
361
367
  /** The cell index of pool splat `p`, clamped into range. */
362
368
  cellOf(u) {
363
- const e = u * 4, t = this.axisCell(0, this.centers[e]), i = this.axisCell(1, this.centers[e + 1]);
364
- return (this.axisCell(2, this.centers[e + 2]) * this.dims[1] + i) * this.dims[0] + t;
369
+ const t = u * 4, e = this.axisCell(0, this.centers[t]), i = this.axisCell(1, this.centers[t + 1]);
370
+ return (this.axisCell(2, this.centers[t + 2]) * this.dims[1] + i) * this.dims[0] + e;
365
371
  }
366
- axisCell(u, e) {
367
- const t = Math.floor((e - this.min[u]) / this.cellSize[u]);
368
- return Math.max(0, Math.min(this.dims[u] - 1, t));
372
+ axisCell(u, t) {
373
+ const e = Math.floor((t - this.min[u]) / this.cellSize[u]);
374
+ return Math.max(0, Math.min(this.dims[u] - 1, e));
369
375
  }
370
376
  /**
371
377
  * Visits every indexed splat within `radius` (local units) of the local
@@ -373,18 +379,18 @@ class $t {
373
379
  * axis span and each candidate is distance-filtered here, so the callback
374
380
  * only ever sees splats truly within the radius.
375
381
  */
376
- forEachWithin(u, e, t, i, s) {
382
+ forEachWithin(u, t, e, i, s) {
377
383
  if (this.count === 0 || i < 0) return;
378
- const r = i * i, n = [0, 0, 0], a = [0, 0, 0], c = [u, e, t];
379
- for (let h = 0; h < 3; h++) {
380
- const l = Math.ceil(i / this.cellSize[h]), f = this.axisCell(h, c[h]);
381
- n[h] = Math.max(0, f - l), a[h] = Math.min(this.dims[h] - 1, f + l);
384
+ const r = i * i, n = [0, 0, 0], a = [0, 0, 0], h = [u, t, e];
385
+ for (let c = 0; c < 3; c++) {
386
+ const l = Math.ceil(i / this.cellSize[c]), f = this.axisCell(c, h[c]);
387
+ n[c] = Math.max(0, f - l), a[c] = Math.min(this.dims[c] - 1, f + l);
382
388
  }
383
- for (let h = n[2]; h <= a[2]; h++)
389
+ for (let c = n[2]; c <= a[2]; c++)
384
390
  for (let l = n[1]; l <= a[1]; l++) {
385
- const f = (h * this.dims[1] + l) * this.dims[0], x = this.cellStart[f + n[0]], p = this.cellStart[f + a[0] + 1];
391
+ const f = (c * this.dims[1] + l) * this.dims[0], x = this.cellStart[f + n[0]], p = this.cellStart[f + a[0] + 1];
386
392
  for (let w = x; w < p; w++) {
387
- const m = this.items[w], S = m * 4, A = this.centers[S] - u, R = this.centers[S + 1] - e, y = this.centers[S + 2] - t, M = A * A + R * R + y * y;
393
+ const m = this.items[w], S = m * 4, A = this.centers[S] - u, R = this.centers[S + 1] - t, y = this.centers[S + 2] - e, M = A * A + R * R + y * y;
388
394
  M <= r && s(m, M);
389
395
  }
390
396
  }
@@ -393,35 +399,35 @@ class $t {
393
399
  * The nearest indexed splat to the local point within `radius`, or null.
394
400
  * Returns its pool index and squared local distance.
395
401
  */
396
- nearest(u, e, t, i) {
402
+ nearest(u, t, e, i) {
397
403
  let s = -1, r = 1 / 0;
398
- return this.forEachWithin(u, e, t, i, (n, a) => {
404
+ return this.forEachWithin(u, t, e, i, (n, a) => {
399
405
  a < r && (r = a, s = n);
400
406
  }), s < 0 ? null : { poolIndex: s, distSq: r };
401
407
  }
402
408
  }
403
- const Yt = 4, v = class v extends d.Mesh {
404
- constructor(e, t = {}) {
409
+ const Zt = 4, v = class v extends d.Mesh {
410
+ constructor(t, e = {}) {
405
411
  var W, L;
406
- const i = bt(t.sortIntervalMs), s = ((W = Bt()) == null ? void 0 : W.isMobile) === !0, r = ct(t.maxStdDev) ?? 3, n = Jt(t.minSplatSizePx) ?? (s ? 1.5 : 0), a = !("capacity" in e), c = a ? e.count : e.capacity;
407
- if (c <= 0) throw new Error("SplatMesh capacity must be positive.");
408
- const h = (t.shBands ?? (Y(t.performanceProfile) === "smooth" ? 0 : gt)) !== 0, l = a ? h ? ((L = e.shPacked) == null ? void 0 : L.bands) ?? 0 : 0 : t.shBands ?? 0, f = t.pool, x = () => new Dt({
409
- capacity: c,
410
- floatTextures: t.poolFloatTextures,
412
+ const i = bt(e.sortIntervalMs), s = ((W = Et()) == null ? void 0 : W.isMobile) === !0, r = ht(e.maxStdDev) ?? 3, n = te(e.minSplatSizePx) ?? (s ? 1.5 : 0), a = !("capacity" in t), h = a ? t.count : t.capacity;
413
+ if (h <= 0) throw new Error("SplatMesh capacity must be positive.");
414
+ const c = (e.shBands ?? (Y(e.performanceProfile) === "smooth" ? 0 : gt)) !== 0, l = a ? c ? ((L = t.shPacked) == null ? void 0 : L.bands) ?? 0 : 0 : e.shBands ?? 0, f = e.pool, x = () => new Bt({
415
+ capacity: h,
416
+ floatTextures: e.poolFloatTextures,
411
417
  packedShBands: l,
412
418
  packedShTextureCount: l === 0 ? 0 : Math.ceil(J(l) / 4),
413
- ...t.maxTextureSize === void 0 ? {} : { maxTextureSize: t.maxTextureSize }
419
+ ...e.maxTextureSize === void 0 ? {} : { maxTextureSize: e.maxTextureSize }
414
420
  }), p = f !== void 0 && l !== f.packedShBands;
415
421
  p && O(
416
422
  `a mesh with shBands ${l} cannot share a pool built for ${f == null ? void 0 : f.packedShBands}; it allocated its own pool instead.`
417
423
  );
418
424
  const w = f === void 0 || p, m = w ? x() : f, S = Math.min(
419
425
  m.capacity,
420
- Math.ceil(c / v.DATA_TEXTURE_WIDTH) * v.DATA_TEXTURE_WIDTH
421
- ), A = m.centersTexture, R = m.colorsTexture, y = m.covarianceATexture, M = m.covarianceBTexture, U = a && e.sh && h ? Tt(
422
- e.sh.palette,
423
- e.sh.paletteWidth,
424
- e.sh.paletteHeight,
426
+ Math.ceil(h / v.DATA_TEXTURE_WIDTH) * v.DATA_TEXTURE_WIDTH
427
+ ), A = m.centersTexture, R = m.colorsTexture, y = m.covarianceATexture, M = m.covarianceBTexture, U = a && t.sh && c ? Tt(
428
+ t.sh.palette,
429
+ t.sh.paletteWidth,
430
+ t.sh.paletteHeight,
425
431
  d.FloatType
426
432
  ) : null, I = m.shPackedTextures, D = new d.InstancedBufferGeometry();
427
433
  D.setIndex([0, 1, 2, 0, 2, 3]), D.setAttribute(
@@ -569,7 +575,7 @@ const Yt = 4, v = class v extends d.Mesh {
569
575
  o(this, "screenBandMin", b(0));
570
576
  o(this, "screenBandMax", b(0));
571
577
  /** The pick pass and everything it allocates; see `splat-mesh-picking.ts`. */
572
- o(this, "picker", new Nt({
578
+ o(this, "picker", new Xt({
573
579
  mesh: this,
574
580
  isDisposed: () => this.disposed,
575
581
  getActiveCount: () => this.activeCount,
@@ -577,12 +583,12 @@ const Yt = 4, v = class v extends d.Mesh {
577
583
  getPickVisible: () => this.effectiveVisibility,
578
584
  hasSorter: () => this.sorter !== null,
579
585
  updateWorldMatrix: () => this.updateWorldMatrix(!0, !1),
580
- prepare: (e, t) => {
581
- this.flushPendingUploads(t), this.refreshProjectionUniforms(e, t), this.sorter !== null && this.requestSortIfNeeded(e, t);
586
+ prepare: (t, e) => {
587
+ this.flushPendingUploads(e), this.refreshProjectionUniforms(t, e), this.sorter !== null && this.requestSortIfNeeded(t, e);
582
588
  },
583
- setView: (e, t, i) => this.writeViewUniforms(e, t, i),
584
- applyPickGraph: (e) => Z(
585
- e,
589
+ setView: (t, e, i) => this.writeViewUniforms(t, e, i),
590
+ applyPickGraph: (t) => Z(
591
+ t,
586
592
  "pick",
587
593
  this.graphInputs(this.materialInputs.textures, this.materialInputs.sh)
588
594
  )
@@ -595,8 +601,10 @@ const Yt = 4, v = class v extends d.Mesh {
595
601
  * storage-attribute GPU buffers that never sat in a geometry. */
596
602
  o(this, "lastRenderer", null);
597
603
  o(this, "currentModelView", new d.Matrix4());
604
+ /** Pose components that can actually change the selected sort key. */
605
+ o(this, "currentSortState", new d.Matrix4());
598
606
  /** Initialized to an impossible matrix so the first frame always sorts. */
599
- o(this, "lastSortedModelView", new d.Matrix4().makeScale(0, 0, 0));
607
+ o(this, "lastSortedState", new d.Matrix4().makeScale(0, 0, 0));
600
608
  o(this, "sortScheduler");
601
609
  /** One-frame queue-headroom hint used before a staged atomic commit. */
602
610
  o(this, "deferSortRequestOnce", !1);
@@ -605,6 +613,7 @@ const Yt = 4, v = class v extends d.Mesh {
605
613
  /** The active list the current depth order was built from. */
606
614
  o(this, "sortedActiveListVersion", -1);
607
615
  o(this, "sortStrategy");
616
+ o(this, "sortMetric");
608
617
  /** Resolved only when `sortStrategy === 'radix'`; see {@link ensureRadixSorter}. */
609
618
  o(this, "RadixSorterCtor", null);
610
619
  o(this, "radixSorterLoad", null);
@@ -641,17 +650,17 @@ const Yt = 4, v = class v extends d.Mesh {
641
650
  o(this, "orientation");
642
651
  /** Set once the pool has been checked against the device texture limit. */
643
652
  o(this, "textureLimitChecked", !1);
644
- if (this.pool = m, this.ownsPool = w, m.register(this), this.sortScheduler = new At(i, s), this.sortStrategy = t.sortStrategy ?? "counting", this.sortStrategy === "radix" && this.ensureRadixSorter(), this.performanceProfileValue = Y(t.performanceProfile), this.maxStdDevValue = r, this.minSplatSizePx = n, this.antialias = t.antialias ?? (a ? e.antialias ?? !1 : !1), this.projectedFilterProfile = t.projectedFilterProfile ?? "default", this.srgbOutput = t.srgbOutput ?? !1, this.maxSplatScreenRadius = H(t.maxSplatScreenRadius), this.minSplatScreenRadius = H(t.minSplatScreenRadius), this.screenBandMin.value = this.minSplatScreenRadius, this.screenBandMax.value = this.maxSplatScreenRadius, this.foveationMode = mt(t.foveationMode), this.foveationTargetPx = ee(t.foveationTargetPx), this.foveationDrawBudget = se(t.foveationDrawBudget), this.foveationLimitPx = this.foveationTargetPx, this.maxSplatAspect = H(t.maxSplatAspect), this.lodAlpha = t.lodAlpha ?? !1, this.orientation = t.orientation ?? "y-up", this.splatIndexAttribute = E, this.sourceIndexAttribute = new d.StorageBufferAttribute(new Uint32Array(S), 1), this.dataTextures = m.coreTextures, this.isStatic = a, this.shEnabled = U !== null, this.shRange = { min: K(), max: K() }, this.frustumCulled = !1, U && (this.dataTextures = [...this.dataTextures, U]), I.length > 0 && (this.dataTextures = [...this.dataTextures, ...I]), this.materialInputs = {
653
+ if (this.pool = m, this.ownsPool = w, m.register(this), this.sortScheduler = new At(i, s), this.sortStrategy = e.sortStrategy ?? "counting", this.sortMetric = e.sortMetric ?? "depth", (this.sortStrategy === "radix" || this.sortStrategy === "exact") && this.ensureRadixSorter(), this.performanceProfileValue = Y(e.performanceProfile), this.maxStdDevValue = r, this.minSplatSizePx = n, this.antialias = e.antialias ?? (a ? t.antialias ?? !1 : !1), this.projectedFilterProfile = e.projectedFilterProfile ?? "default", this.srgbOutput = e.srgbOutput ?? !1, this.maxSplatScreenRadius = H(e.maxSplatScreenRadius), this.minSplatScreenRadius = H(e.minSplatScreenRadius), this.screenBandMin.value = this.minSplatScreenRadius, this.screenBandMax.value = this.maxSplatScreenRadius, this.foveationMode = mt(e.foveationMode), this.foveationTargetPx = ie(e.foveationTargetPx), this.foveationDrawBudget = re(e.foveationDrawBudget), this.foveationLimitPx = this.foveationTargetPx, this.maxSplatAspect = H(e.maxSplatAspect), this.lodAlpha = e.lodAlpha ?? !1, this.orientation = e.orientation ?? "y-up", this.splatIndexAttribute = E, this.sourceIndexAttribute = new d.StorageBufferAttribute(new Uint32Array(S), 1), this.dataTextures = m.coreTextures, this.isStatic = a, this.shEnabled = U !== null, this.shRange = { min: K(), max: K() }, this.frustumCulled = !1, U && (this.dataTextures = [...this.dataTextures, U]), I.length > 0 && (this.dataTextures = [...this.dataTextures, ...I]), this.materialInputs = {
645
654
  textures: { centersTexture: A, colorsTexture: R, covarianceATexture: y, covarianceBTexture: M },
646
- sh: a && e.sh && U ? { mode: "palette", bands: e.sh.bands, paletteTexture: U } : l !== 0 ? {
655
+ sh: a && t.sh && U ? { mode: "palette", bands: t.sh.bands, paletteTexture: U } : l !== 0 ? {
647
656
  mode: "packed",
648
657
  bands: l,
649
658
  textures: I,
650
659
  range: this.shRange
651
660
  } : null
652
661
  }, this.buildMaterial(this.materialInputs.textures, this.materialInputs.sh), a) {
653
- this.staticRange = this.appendRange(e), this.pendingUploadRows = [], this.poolFloatTextures === "float16" && this.syncHalfFloatPoolImages();
654
- const C = this.orientation === "y-up" ? Vt(e.format) : null;
662
+ this.staticRange = this.appendRange(t), this.pendingUploadRows = [], this.poolFloatTextures === "float16" && this.syncHalfFloatPoolImages();
663
+ const C = this.orientation === "y-up" ? _t(t.format) : null;
655
664
  C && (this.matrix.copy(C), this.matrix.decompose(this.position, this.quaternion, this.scale), this.matrixWorldNeedsUpdate = !0);
656
665
  }
657
666
  }
@@ -677,8 +686,8 @@ const Yt = 4, v = class v extends d.Mesh {
677
686
  get freeRowSpans() {
678
687
  return this.pool.freeRowSpans;
679
688
  }
680
- set freeRowSpans(e) {
681
- this.pool.freeRowSpans = e;
689
+ set freeRowSpans(t) {
690
+ this.pool.freeRowSpans = t;
682
691
  }
683
692
  get poolFloatTextures() {
684
693
  return this.pool.floatTextures;
@@ -697,8 +706,8 @@ const Yt = 4, v = class v extends d.Mesh {
697
706
  * asked for - useful for a debug readout.
698
707
  */
699
708
  get shBands() {
700
- var e;
701
- return ((e = this.materialInputs.sh) == null ? void 0 : e.bands) ?? 0;
709
+ var t;
710
+ return ((t = this.materialInputs.sh) == null ? void 0 : t.bands) ?? 0;
702
711
  }
703
712
  /**
704
713
  * The contribution-culling profile currently in effect (resolved at
@@ -716,8 +725,8 @@ const Yt = 4, v = class v extends d.Mesh {
716
725
  * material graph, {@link StreamedSplatMesh.setBudget} returns its clamp.
717
726
  * Every mutator has a matching readable property.
718
727
  */
719
- setPerformanceProfile(e) {
720
- e !== this.performanceProfileValue && (this.performanceProfileValue = e, this.buildMaterial(this.materialInputs.textures, this.materialInputs.sh));
728
+ setPerformanceProfile(t) {
729
+ t !== this.performanceProfileValue && (this.performanceProfileValue = t, this.buildMaterial(this.materialInputs.textures, this.materialInputs.sh));
721
730
  }
722
731
  /**
723
732
  * Gaussian cutoff radius currently in effect, in standard deviations.
@@ -733,9 +742,9 @@ const Yt = 4, v = class v extends d.Mesh {
733
742
  * view; raising it restores the faint outer tail. Rebuilds the material
734
743
  * graph, same convention as {@link setPerformanceProfile}.
735
744
  */
736
- setMaxStdDev(e) {
737
- const t = ct(e);
738
- t === void 0 || t === this.maxStdDevValue || (this.maxStdDevValue = t, this.cachedUnifiedView = null, this.buildMaterial(this.materialInputs.textures, this.materialInputs.sh));
745
+ setMaxStdDev(t) {
746
+ const e = ht(t);
747
+ e === void 0 || e === this.maxStdDevValue || (this.maxStdDevValue = e, this.cachedUnifiedView = null, this.buildMaterial(this.materialInputs.textures, this.materialInputs.sh));
739
748
  }
740
749
  /**
741
750
  * Copies a decoded scene (or chunk) into the pool and activates it.
@@ -745,40 +754,40 @@ const Yt = 4, v = class v extends d.Mesh {
745
754
  * @returns A handle to pass to {@link removeRange}.
746
755
  * @throws {Error} when the remaining pool capacity cannot fit the range.
747
756
  */
748
- appendRange(e) {
749
- return this.appendRangeWithState(e, !0);
757
+ appendRange(t) {
758
+ return this.appendRangeWithState(t, !0);
750
759
  }
751
760
  /** Appends uploaded data without exposing it to draw/sort until activated. */
752
- appendInactiveRange(e) {
753
- return this.appendRangeWithState(e, !1);
761
+ appendInactiveRange(t) {
762
+ return this.appendRangeWithState(t, !1);
754
763
  }
755
764
  /** Reserves an inactive pool range whose data can be filled over multiple frames. */
756
- reserveInactiveRange(e) {
757
- if (!Number.isInteger(e) || e < 0)
765
+ reserveInactiveRange(t) {
766
+ if (!Number.isInteger(t) || t < 0)
758
767
  throw new RangeError("SplatMesh.reserveInactiveRange: count must be a non-negative integer.");
759
- if (e === 0) {
768
+ if (t === 0) {
760
769
  const a = Object.freeze({ count: 0 });
761
770
  return this.ranges.set(a, { startRow: 0, rowCount: 0, start: 0, count: 0, active: !1 }), a;
762
771
  }
763
- const t = v.DATA_TEXTURE_WIDTH, i = Math.ceil(e / t), s = Q(this.freeRowSpans, i, this.poolRows), r = s * t, n = Object.freeze({ count: e });
764
- this.ranges.set(n, { startRow: s, rowCount: i, start: r, count: e, active: !1 });
772
+ const e = v.DATA_TEXTURE_WIDTH, i = Math.ceil(t / e), s = Q(this.freeRowSpans, i, this.poolRows), r = s * e, n = Object.freeze({ count: t });
773
+ this.ranges.set(n, { startRow: s, rowCount: i, start: r, count: t, active: !1 });
765
774
  for (const a of this.channels.values())
766
- a.backing.fill(a.fill, r, r + i * t), a.pendingRows.push({ start: s, count: i });
775
+ a.backing.fill(a.fill, r, r + i * e), a.pendingRows.push({ start: s, count: i });
767
776
  return n;
768
777
  }
769
778
  /** Writes one contiguous segment of a reserved inactive range. */
770
- writeInactiveRange(e, t, i) {
771
- const s = this.ranges.get(e);
779
+ writeInactiveRange(t, e, i) {
780
+ const s = this.ranges.get(t);
772
781
  if (!s) throw new Error("SplatMesh.writeInactiveRange: unknown range handle.");
773
782
  if (s.active) throw new Error("SplatMesh.writeInactiveRange: range is already active.");
774
- if (!Number.isInteger(i) || i < 0 || i + t.count > s.count)
783
+ if (!Number.isInteger(i) || i < 0 || i + e.count > s.count)
775
784
  throw new RangeError("SplatMesh.writeInactiveRange: write exceeds the reserved range.");
776
- if (t.count === 0) return;
777
- this.warnOnIgnoredSh(t, "writeInactiveRange");
785
+ if (e.count === 0) return;
786
+ this.warnOnIgnoredSh(e, "writeInactiveRange");
778
787
  const r = s.start + i;
779
- this.writeSplatRows(r, t);
780
- const n = v.DATA_TEXTURE_WIDTH, a = Math.floor(r / n), c = Math.floor((r + t.count - 1) / n);
781
- this.markRowsWritten(a, c - a + 1), F.setFromArray(t.positions), this.localBounds.union(F), this.boundsDirty = !0;
788
+ this.writeSplatRows(r, e);
789
+ const n = v.DATA_TEXTURE_WIDTH, a = Math.floor(r / n), h = Math.floor((r + e.count - 1) / n);
790
+ this.markRowsWritten(a, h - a + 1), F.setFromArray(e.positions), this.localBounds.union(F), this.boundsDirty = !0;
782
791
  }
783
792
  /**
784
793
  * Overwrites splats at `offset` within a range **in place** - unlike
@@ -787,31 +796,31 @@ const Yt = 4, v = class v extends d.Mesh {
787
796
  * touched rows for upload; the caller must {@link invalidateSort} once per
788
797
  * batch since splat depths changed.
789
798
  */
790
- overwriteRangeData(e, t, i) {
791
- const s = this.ranges.get(e);
799
+ overwriteRangeData(t, e, i) {
800
+ const s = this.ranges.get(t);
792
801
  if (!s) throw new Error("SplatMesh.overwriteRangeData: unknown range handle.");
793
- if (!Number.isInteger(i) || i < 0 || i + t.count > s.count)
802
+ if (!Number.isInteger(i) || i < 0 || i + e.count > s.count)
794
803
  throw new RangeError("SplatMesh.overwriteRangeData: write exceeds the range.");
795
- if (t.count === 0) return;
796
- this.warnOnIgnoredSh(t, "overwriteRangeData");
804
+ if (e.count === 0) return;
805
+ this.warnOnIgnoredSh(e, "overwriteRangeData");
797
806
  const r = s.start + i;
798
- this.writeSplatRows(r, t);
799
- const n = v.DATA_TEXTURE_WIDTH, a = Math.floor(r / n), c = Math.floor((r + t.count - 1) / n);
800
- this.markRowsWritten(a, c - a + 1), F.setFromArray(t.positions), this.localBounds.union(F), this.boundsDirty = !0, this.contentRevision++;
807
+ this.writeSplatRows(r, e);
808
+ const n = v.DATA_TEXTURE_WIDTH, a = Math.floor(r / n), h = Math.floor((r + e.count - 1) / n);
809
+ this.markRowsWritten(a, h - a + 1), F.setFromArray(e.positions), this.localBounds.union(F), this.boundsDirty = !0, this.contentRevision++;
801
810
  }
802
811
  /**
803
812
  * Zeros splats `[offset, offset + count)` of a range so they draw nothing
804
813
  * (zero covariance → degenerate quad, zero color). Used to free frontier slab
805
814
  * slots that leave the frontier. Queues the rows for upload.
806
815
  */
807
- degenerateRange(e, t, i) {
808
- const s = this.ranges.get(e);
816
+ degenerateRange(t, e, i) {
817
+ const s = this.ranges.get(t);
809
818
  if (!s) throw new Error("SplatMesh.degenerateRange: unknown range handle.");
810
819
  if (i <= 0) return;
811
- if (!Number.isInteger(t) || t < 0 || t + i > s.count)
820
+ if (!Number.isInteger(e) || e < 0 || e + i > s.count)
812
821
  throw new RangeError("SplatMesh.degenerateRange: range out of bounds.");
813
- const r = s.start + t, { centers: n, colors: a, covarianceA: c, covarianceB: h } = this.backing;
814
- n.fill(0, r * 4, (r + i) * 4), a.fill(0, r * 4, (r + i) * 4), c.fill(0, r * 4, (r + i) * 4), h.fill(0, r * 4, (r + i) * 4);
822
+ const r = s.start + e, { centers: n, colors: a, covarianceA: h, covarianceB: c } = this.backing;
823
+ n.fill(0, r * 4, (r + i) * 4), a.fill(0, r * 4, (r + i) * 4), h.fill(0, r * 4, (r + i) * 4), c.fill(0, r * 4, (r + i) * 4);
815
824
  const l = v.DATA_TEXTURE_WIDTH, f = Math.floor(r / l), x = Math.floor((r + i - 1) / l);
816
825
  this.markRowsWritten(f, x - f + 1), this.contentRevision++;
817
826
  }
@@ -820,15 +829,15 @@ const Yt = 4, v = class v extends d.Mesh {
820
829
  * Shared by the append and staged-write paths, which differ only in where
821
830
  * the rows come from and when they are activated.
822
831
  */
823
- writeSplatRows(e, t) {
832
+ writeSplatRows(t, e) {
824
833
  const { centers: i, colors: s, covarianceA: r, covarianceB: n } = this.backing;
825
- s.set(t.colors, e * 4);
826
- const a = t.count, c = t.positions, h = t.covariances, l = this.shEnabled && t.sh ? t.sh.labels : null, f = t.frontierParent ?? null;
834
+ s.set(e.colors, t * 4);
835
+ const a = e.count, h = e.positions, c = e.covariances, l = this.shEnabled && e.sh ? e.sh.labels : null, f = e.frontierParent ?? null;
827
836
  for (let x = 0; x < a; x++) {
828
- const p = (e + x) * 4, w = x * 3, m = x * 6;
829
- i[p + 0] = c[w + 0], i[p + 1] = c[w + 1], i[p + 2] = c[w + 2], r[p + 0] = h[m + 0], r[p + 1] = h[m + 1], r[p + 2] = h[m + 2], r[p + 3] = h[m + 3], n[p + 0] = h[m + 4], n[p + 1] = h[m + 5], n[p + 2] = l ? l[x] : 0, n[p + 3] = f ? f[x] : 0;
837
+ const p = (t + x) * 4, w = x * 3, m = x * 6;
838
+ i[p + 0] = h[w + 0], i[p + 1] = h[w + 1], i[p + 2] = h[w + 2], r[p + 0] = c[m + 0], r[p + 1] = c[m + 1], r[p + 2] = c[m + 2], r[p + 3] = c[m + 3], n[p + 0] = c[m + 4], n[p + 1] = c[m + 5], n[p + 2] = l ? l[x] : 0, n[p + 3] = f ? f[x] : 0;
830
839
  }
831
- this.writePackedSh(e, t);
840
+ this.writePackedSh(t, e);
832
841
  }
833
842
  /**
834
843
  * Scatters a chunk's packed SH words into the per-group pool textures.
@@ -838,24 +847,24 @@ const Yt = 4, v = class v extends d.Mesh {
838
847
  * else's view-dependent color. Zero is not neutral (the range is signed and
839
848
  * rarely symmetric), so the code for "0.0" in this scene's range is.
840
849
  */
841
- writePackedSh(e, t) {
850
+ writePackedSh(t, e) {
842
851
  if (this.packedShBands === 0) return;
843
- const i = this.backing.shPacked, s = J(this.packedShBands), r = t.shPacked;
852
+ const i = this.backing.shPacked, s = J(this.packedShBands), r = e.shPacked;
844
853
  if (r && r.bands === this.packedShBands) {
845
854
  this.applyShRange(r);
846
- const a = this.currentShRange(), c = a !== null && !Et(r.range, a);
847
- for (let h = 0; h < t.count; h++)
855
+ const a = this.currentShRange(), h = a !== null && !Wt(r.range, a);
856
+ for (let c = 0; c < e.count; c++)
848
857
  for (let l = 0; l < s; l++) {
849
- const f = r.packed[h * s + l];
850
- i[l >> 2][(e + h) * 4 + (l & 3)] = c ? Wt(f, r.range, a) : f;
858
+ const f = r.packed[c * s + l];
859
+ i[l >> 2][(t + c) * 4 + (l & 3)] = h ? Lt(f, r.range, a) : f;
851
860
  }
852
861
  return;
853
862
  }
854
863
  this.shRangeSet || (this.wrotePreLockNeutralSh = !0);
855
864
  const n = this.neutralShWord();
856
- for (let a = 0; a < t.count; a++)
857
- for (let c = 0; c < s; c++)
858
- i[c >> 2][(e + a) * 4 + (c & 3)] = n;
865
+ for (let a = 0; a < e.count; a++)
866
+ for (let h = 0; h < s; h++)
867
+ i[h >> 2][(t + a) * 4 + (h & 3)] = n;
859
868
  }
860
869
  /**
861
870
  * Adopts the first packed-SH chunk's dequantization range as the scene's one
@@ -863,40 +872,40 @@ const Yt = 4, v = class v extends d.Mesh {
863
872
  * chunk measures its own extent, so later chunks are requantized into this
864
873
  * one at write time ({@link writePackedSh}) rather than ignored.
865
874
  */
866
- applyShRange(e) {
867
- if (!this.shRangeSet && (this.shRange.min.value.set(e.range.min[0], e.range.min[1], e.range.min[2]), this.shRange.max.value.set(e.range.max[0], e.range.max[1], e.range.max[2]), this.shRangeSet = !0, this.wrotePreLockNeutralSh)) {
868
- const t = this.neutralShWord();
869
- for (const i of this.backing.shPacked) i.fill(t);
875
+ applyShRange(t) {
876
+ if (!this.shRangeSet && (this.shRange.min.value.set(t.range.min[0], t.range.min[1], t.range.min[2]), this.shRange.max.value.set(t.range.max[0], t.range.max[1], t.range.max[2]), this.shRangeSet = !0, this.wrotePreLockNeutralSh)) {
877
+ const e = this.neutralShWord();
878
+ for (const i of this.backing.shPacked) i.fill(e);
870
879
  this.markRowsWritten(0, this.poolRows), this.wrotePreLockNeutralSh = !1;
871
880
  }
872
881
  }
873
882
  /** The scene's locked packed-SH range as a plain tuple, or null if unset. */
874
883
  currentShRange() {
875
884
  if (!this.shRangeSet) return null;
876
- const { min: e, max: t } = this.shRange;
885
+ const { min: t, max: e } = this.shRange;
877
886
  return {
878
- min: [e.value.x, e.value.y, e.value.z],
879
- max: [t.value.x, t.value.y, t.value.z]
887
+ min: [t.value.x, t.value.y, t.value.z],
888
+ max: [e.value.x, e.value.y, e.value.z]
880
889
  };
881
890
  }
882
891
  /** The packed word decoding to 0 in every channel under the scene's range. */
883
892
  neutralShWord() {
884
- const e = this.currentShRange();
885
- return e ? Lt(e) : 0;
893
+ const t = this.currentShRange();
894
+ return t ? Ft(t) : 0;
886
895
  }
887
896
  /** Warns once per call site when a source's SH cannot be stored. */
888
- warnOnIgnoredSh(e, t) {
889
- e.sh && !this.isStatic && O(
890
- `SplatMesh.${t}: palette shN data on appended ranges is ignored in dynamic-capacity mode (per-file palettes cannot be merged into a shared pool).`
891
- ), e.shPacked && this.packedShBands === 0 && O(
892
- `SplatMesh.${t}: per-splat SH was supplied but the pool has none allocated ` + (this.isStatic ? "(the static source had no `shPacked` at construction)." : "(construct the mesh with `shBands` to store it).")
897
+ warnOnIgnoredSh(t, e) {
898
+ t.sh && !this.isStatic && O(
899
+ `SplatMesh.${e}: palette shN data on appended ranges is ignored in dynamic-capacity mode (per-file palettes cannot be merged into a shared pool).`
900
+ ), t.shPacked && this.packedShBands === 0 && O(
901
+ `SplatMesh.${e}: per-splat SH was supplied but the pool has none allocated ` + (this.isStatic ? "(the static source had no `shPacked` at construction)." : "(construct the mesh with `shBands` to store it).")
893
902
  );
894
903
  }
895
904
  /** Atomically includes or excludes a resident range on the next active-list rebuild. */
896
- setRangeActive(e, t) {
897
- const i = this.ranges.get(e);
905
+ setRangeActive(t, e) {
906
+ const i = this.ranges.get(t);
898
907
  if (!i) throw new Error("SplatMesh.setRangeActive: unknown range handle.");
899
- i.active !== t && (i.active = t, t ? this.activateRecord(i) : this.deactivateRecord(i), this.contentRevision++);
908
+ i.active !== e && (i.active = e, e ? this.activateRecord(i) : this.deactivateRecord(i), this.contentRevision++);
900
909
  }
901
910
  /**
902
911
  * Activates only the first `prefix` splats of a range (see
@@ -905,10 +914,10 @@ const Yt = 4, v = class v extends d.Mesh {
905
914
  * work to the *drawn* frontier instead of the whole pool-sized slab. Write
906
915
  * APIs (`overwriteRangeData` / `degenerateRange`) still address the full range.
907
916
  */
908
- setRangeActivePrefix(e, t) {
909
- const i = this.ranges.get(e);
917
+ setRangeActivePrefix(t, e) {
918
+ const i = this.ranges.get(t);
910
919
  if (!i) throw new Error("SplatMesh.setRangeActivePrefix: unknown range handle.");
911
- const s = Math.max(0, Math.min(i.count, Math.floor(t))), r = i.active ? i.activePrefix ?? i.count : 0;
920
+ const s = Math.max(0, Math.min(i.count, Math.floor(e))), r = i.active ? i.activePrefix ?? i.count : 0;
912
921
  s !== r && (i.active && (this.deactivateRecord(i), i.active = !1), i.activePrefix = s, s > 0 && (i.active = !0, this.activateRecord(i)), this.contentRevision++);
913
922
  }
914
923
  /**
@@ -918,14 +927,14 @@ const Yt = 4, v = class v extends d.Mesh {
918
927
  * an arbitrary hierarchy frontier, but the referenced pool rows must remain
919
928
  * resident for the lifetime of the mesh.
920
929
  */
921
- replaceActiveIndices(e) {
922
- const t = this.sourceIndexAttribute.array;
923
- if (e.length > t.length)
930
+ replaceActiveIndices(t) {
931
+ const e = this.sourceIndexAttribute.array;
932
+ if (t.length > e.length)
924
933
  throw new RangeError("SplatMesh.replaceActiveIndices: frontier exceeds pool capacity.");
925
934
  this.activeSlotByPoolIndex.fill(4294967295);
926
- for (let s = 0; s < e.length; s++) {
927
- const r = e[s];
928
- if (r >= t.length)
935
+ for (let s = 0; s < t.length; s++) {
936
+ const r = t[s];
937
+ if (r >= e.length)
929
938
  throw new RangeError(
930
939
  "SplatMesh.replaceActiveIndices: frontier contains an invalid pool index."
931
940
  );
@@ -933,50 +942,50 @@ const Yt = 4, v = class v extends d.Mesh {
933
942
  throw new Error(
934
943
  "SplatMesh.replaceActiveIndices: frontier contains duplicate pool indices."
935
944
  );
936
- t[s] = r, this.activeSlotByPoolIndex[r] = s;
945
+ e[s] = r, this.activeSlotByPoolIndex[r] = s;
937
946
  }
938
947
  const i = this.activeCount;
939
- this.activeCount = e.length, this.commitActiveListMutation(0, Math.max(i, this.activeCount)), this.queryEpoch++, this.contentRevision++;
948
+ this.activeCount = t.length, this.commitActiveListMutation(0, Math.max(i, this.activeCount)), this.queryEpoch++, this.contentRevision++;
940
949
  }
941
950
  /** Fast identity-frontier variant that avoids allocating a large index array. */
942
- replaceActivePrefix(e) {
943
- const t = this.sourceIndexAttribute.array, i = Math.max(0, Math.min(t.length, Math.floor(e)));
951
+ replaceActivePrefix(t) {
952
+ const e = this.sourceIndexAttribute.array, i = Math.max(0, Math.min(e.length, Math.floor(t)));
944
953
  this.activeSlotByPoolIndex.fill(4294967295);
945
954
  for (let r = 0; r < i; r++)
946
- t[r] = r, this.activeSlotByPoolIndex[r] = r;
955
+ e[r] = r, this.activeSlotByPoolIndex[r] = r;
947
956
  const s = this.activeCount;
948
957
  this.activeCount = i, this.commitActiveListMutation(0, Math.max(s, i)), this.queryEpoch++, this.contentRevision++;
949
958
  }
950
959
  /** Replaces a static mesh's resident cut without increasing its fixed pool allocation. */
951
- replaceStaticData(e) {
960
+ replaceStaticData(t) {
952
961
  if (!this.isStatic || !this.staticRange)
953
962
  throw new Error("SplatMesh.replaceStaticData: mesh was not constructed from static data.");
954
- if (e.count > this.capacity)
963
+ if (t.count > this.capacity)
955
964
  throw new RangeError("SplatMesh.replaceStaticData: cut exceeds pool capacity.");
956
- this.overwriteRangeData(this.staticRange, e, 0), this.setRangeActivePrefix(this.staticRange, e.count), this.invalidateSort();
965
+ this.overwriteRangeData(this.staticRange, t, 0), this.setRangeActivePrefix(this.staticRange, t.count), this.invalidateSort();
957
966
  }
958
- appendRangeWithState(e, t) {
959
- if (e.count === 0) {
960
- const h = Object.freeze({ count: 0 });
961
- return this.ranges.set(h, { startRow: 0, rowCount: 0, start: 0, count: 0, active: t }), h;
967
+ appendRangeWithState(t, e) {
968
+ if (t.count === 0) {
969
+ const c = Object.freeze({ count: 0 });
970
+ return this.ranges.set(c, { startRow: 0, rowCount: 0, start: 0, count: 0, active: e }), c;
962
971
  }
963
- const i = v.DATA_TEXTURE_WIDTH, s = Math.ceil(e.count / i), r = Q(this.freeRowSpans, s, this.poolRows), n = r * i;
964
- this.warnOnIgnoredSh(e, "appendRange"), this.writeSplatRows(n, e);
965
- const a = Object.freeze({ count: e.count }), c = { startRow: r, rowCount: s, start: n, count: e.count, active: t };
966
- this.ranges.set(a, c), this.markRowsWritten(r, s);
967
- for (const h of this.channels.values())
968
- h.backing.fill(h.fill, n, n + s * i), h.pendingRows.push({ start: r, count: s });
969
- return F.setFromArray(e.positions), this.localBounds.union(F), this.boundsDirty = !0, t && this.activateRecord(c), this.contentRevision++, a;
972
+ const i = v.DATA_TEXTURE_WIDTH, s = Math.ceil(t.count / i), r = Q(this.freeRowSpans, s, this.poolRows), n = r * i;
973
+ this.warnOnIgnoredSh(t, "appendRange"), this.writeSplatRows(n, t);
974
+ const a = Object.freeze({ count: t.count }), h = { startRow: r, rowCount: s, start: n, count: t.count, active: e };
975
+ this.ranges.set(a, h), this.markRowsWritten(r, s);
976
+ for (const c of this.channels.values())
977
+ c.backing.fill(c.fill, n, n + s * i), c.pendingRows.push({ start: r, count: s });
978
+ return F.setFromArray(t.positions), this.localBounds.union(F), this.boundsDirty = !0, e && this.activateRecord(h), this.contentRevision++, a;
970
979
  }
971
980
  /**
972
981
  * Deactivates a previously appended range and frees its pool rows for
973
982
  * reuse. The bounding sphere used for depth quantization stays a
974
983
  * conservative superset until new ranges grow it again.
975
984
  */
976
- removeRange(e) {
977
- const t = this.ranges.get(e);
978
- if (!t) throw new Error("SplatMesh.removeRange: unknown range handle.");
979
- t.active && this.deactivateRecord(t), this.ranges.delete(e), t.rowCount > 0 && (this.freeRowSpans = Mt(this.freeRowSpans, t.startRow, t.rowCount)), this.contentRevision++;
985
+ removeRange(t) {
986
+ const e = this.ranges.get(t);
987
+ if (!e) throw new Error("SplatMesh.removeRange: unknown range handle.");
988
+ e.active && this.deactivateRecord(e), this.ranges.delete(t), e.rowCount > 0 && (this.freeRowSpans = Mt(this.freeRowSpans, e.startRow, e.rowCount)), this.contentRevision++;
980
989
  }
981
990
  /** Maximum number of splats the pool can hold (row-aligned internally). */
982
991
  get capacity() {
@@ -994,8 +1003,8 @@ const Yt = 4, v = class v extends d.Mesh {
994
1003
  */
995
1004
  getUnifiedSourceView() {
996
1005
  this.updateWorldMatrix(!0, !1), this.refreshSortBounds();
997
- const e = this.cachedUnifiedView;
998
- return e !== null && e.contentRevision === this.contentRevision && e.graphRevision === this.graphRevision && e.activeCount === this.activeCount && e.sh === this.materialInputs.sh && e.modifiers === this.modifierList && e.hasSourcePlacement === (this.perSourceSort !== null) && e.centersTexture === this.centersTexture && e.colorsTexture === this.materialInputs.textures.colorsTexture && this.cachedUnifiedViewMatrixWorld.equals(this.matrixWorld) && this.cachedUnifiedViewLocalBounds.equals(this.boundingSphereLocal) ? e : (this.cachedUnifiedViewMatrixWorld.copy(this.matrixWorld), this.cachedUnifiedViewLocalBounds.copy(this.boundingSphereLocal), this.cachedUnifiedViewWorldBounds.copy(this.boundingSphereLocal).applyMatrix4(this.matrixWorld), this.cachedUnifiedView = {
1006
+ const t = this.cachedUnifiedView;
1007
+ return t !== null && t.contentRevision === this.contentRevision && t.graphRevision === this.graphRevision && t.activeCount === this.activeCount && t.sh === this.materialInputs.sh && t.modifiers === this.modifierList && t.hasSourcePlacement === (this.perSourceSort !== null) && t.centersTexture === this.centersTexture && t.colorsTexture === this.materialInputs.textures.colorsTexture && this.cachedUnifiedViewMatrixWorld.equals(this.matrixWorld) && this.cachedUnifiedViewLocalBounds.equals(this.boundingSphereLocal) ? t : (this.cachedUnifiedViewMatrixWorld.copy(this.matrixWorld), this.cachedUnifiedViewLocalBounds.copy(this.boundingSphereLocal), this.cachedUnifiedViewWorldBounds.copy(this.boundingSphereLocal).applyMatrix4(this.matrixWorld), this.cachedUnifiedView = {
999
1008
  capacity: this.capacity,
1000
1009
  sourceIndex: this.sourceIndexAttribute,
1001
1010
  activeCount: this.activeCount,
@@ -1028,8 +1037,8 @@ const Yt = 4, v = class v extends d.Mesh {
1028
1037
  * mirrors this resolved visibility so existing per-source hit testing works.
1029
1038
  * Internal consumers should clear the state with `null` before disposing.
1030
1039
  */
1031
- setUnifiedPickVisibility(e) {
1032
- this.unifiedPickVisibility = e;
1040
+ setUnifiedPickVisibility(t) {
1041
+ this.unifiedPickVisibility = t;
1033
1042
  }
1034
1043
  /**
1035
1044
  * The visibility that actually decides whether this mesh's splats reach the
@@ -1051,9 +1060,9 @@ const Yt = 4, v = class v extends d.Mesh {
1051
1060
  * falling back to {@link compact}.
1052
1061
  */
1053
1062
  get freeSplatCapacity() {
1054
- let e = 0;
1055
- for (const t of this.freeRowSpans) e += t.count;
1056
- return e * v.DATA_TEXTURE_WIDTH;
1063
+ let t = 0;
1064
+ for (const e of this.freeRowSpans) t += e.count;
1065
+ return t * v.DATA_TEXTURE_WIDTH;
1057
1066
  }
1058
1067
  /**
1059
1068
  * Declares a named per-splat data channel - one extra value per pool slot,
@@ -1069,19 +1078,19 @@ const Yt = 4, v = class v extends d.Mesh {
1069
1078
  *
1070
1079
  * @throws {Error} if a channel of this name already exists.
1071
1080
  */
1072
- defineChannel(e, t = {}) {
1073
- if (this.channels.has(e))
1074
- throw new Error(`SplatMesh.defineChannel: channel "${e}" already defined.`);
1075
- const i = t.type ?? "float", s = v.DATA_TEXTURE_WIDTH, r = s * this.poolRows, n = i === "byte" ? new Uint8Array(r) : new Float32Array(r), a = t.fill ?? 0;
1081
+ defineChannel(t, e = {}) {
1082
+ if (this.channels.has(t))
1083
+ throw new Error(`SplatMesh.defineChannel: channel "${t}" already defined.`);
1084
+ const i = e.type ?? "float", s = v.DATA_TEXTURE_WIDTH, r = s * this.poolRows, n = i === "byte" ? new Uint8Array(r) : new Float32Array(r), a = e.fill ?? 0;
1076
1085
  a && n.fill(a);
1077
- const c = i === "byte" ? d.UnsignedByteType : d.FloatType, h = new d.DataTexture(
1086
+ const h = i === "byte" ? d.UnsignedByteType : d.FloatType, c = new d.DataTexture(
1078
1087
  n,
1079
1088
  s,
1080
1089
  this.poolRows,
1081
1090
  d.RedFormat,
1082
- c
1091
+ h
1083
1092
  );
1084
- h.needsUpdate = !0, this.channels.set(e, { type: i, fill: a, backing: n, texture: h, textureType: c, pendingRows: [] });
1093
+ c.needsUpdate = !0, this.channels.set(t, { type: i, fill: a, backing: n, texture: c, textureType: h, pendingRows: [] });
1085
1094
  }
1086
1095
  /**
1087
1096
  * Writes channel values for a resident range, at `[offset, offset + data.length)`
@@ -1091,20 +1100,20 @@ const Yt = 4, v = class v extends d.Mesh {
1091
1100
  *
1092
1101
  * @throws {Error} for an unknown channel or range, or a write past the range.
1093
1102
  */
1094
- writeChannel(e, t, i, s = 0) {
1095
- const r = this.channels.get(t);
1096
- if (!r) throw new Error(`SplatMesh.writeChannel: channel "${t}" is not defined.`);
1097
- const n = this.ranges.get(e);
1103
+ writeChannel(t, e, i, s = 0) {
1104
+ const r = this.channels.get(e);
1105
+ if (!r) throw new Error(`SplatMesh.writeChannel: channel "${e}" is not defined.`);
1106
+ const n = this.ranges.get(t);
1098
1107
  if (!n) throw new Error("SplatMesh.writeChannel: unknown range handle.");
1099
1108
  if (s < 0 || s + i.length > n.count)
1100
1109
  throw new Error(
1101
1110
  `SplatMesh.writeChannel: write of ${i.length} at offset ${s} exceeds range count ${n.count}.`
1102
1111
  );
1103
1112
  if (i.length === 0) return;
1104
- const a = v.DATA_TEXTURE_WIDTH, c = n.start + s;
1105
- r.backing.set(i, c);
1106
- const h = Math.floor(c / a), l = Math.floor((c + i.length - 1) / a);
1107
- r.pendingRows.push({ start: h, count: l - h + 1 }), this.contentRevision++;
1113
+ const a = v.DATA_TEXTURE_WIDTH, h = n.start + s;
1114
+ r.backing.set(i, h);
1115
+ const c = Math.floor(h / a), l = Math.floor((h + i.length - 1) / a);
1116
+ r.pendingRows.push({ start: c, count: l - c + 1 }), this.contentRevision++;
1108
1117
  }
1109
1118
  /**
1110
1119
  * Effect hooks, folded into the vertex stage in array order - each
@@ -1117,10 +1126,10 @@ const Yt = 4, v = class v extends d.Mesh {
1117
1126
  get modifiers() {
1118
1127
  return this.modifierList;
1119
1128
  }
1120
- set modifiers(e) {
1121
- if (e.length === this.modifierList.length && e.every((s, r) => s === this.modifierList[r])) return;
1129
+ set modifiers(t) {
1130
+ if (t.length === this.modifierList.length && t.every((s, r) => s === this.modifierList[r])) return;
1122
1131
  const i = this.modifierList;
1123
- this.modifierList = [...e];
1132
+ this.modifierList = [...t];
1124
1133
  try {
1125
1134
  this.rebuildGraph();
1126
1135
  } catch (s) {
@@ -1147,9 +1156,9 @@ const Yt = 4, v = class v extends d.Mesh {
1147
1156
  * after EWA projection (not the stylized M13 scale modifier). Live uniforms
1148
1157
  * - no material rebuild. Pass `aperture: 0` to disable.
1149
1158
  */
1150
- setDepthOfField(e) {
1151
- const t = It(e, this.getDepthOfField());
1152
- this.dofFocusDistance.value = t.focusDistance, this.dofAperture.value = t.aperture;
1159
+ setDepthOfField(t) {
1160
+ const e = It(t, this.getDepthOfField());
1161
+ this.dofFocusDistance.value = e.focusDistance, this.dofAperture.value = e.aperture;
1153
1162
  }
1154
1163
  /**
1155
1164
  * PlayCanvas-style proxy-mesh relighting. Multiplies baked splat color in the
@@ -1160,13 +1169,13 @@ const Yt = 4, v = class v extends d.Mesh {
1160
1169
  * the map texture identity rebuilds the material once. Does not affect the
1161
1170
  * pick pass. Does not invalidate a unified gather cache.
1162
1171
  */
1163
- setRelighting(e) {
1164
- if (e === null) {
1172
+ setRelighting(t) {
1173
+ if (t === null) {
1165
1174
  this.relightBlend.value = 0, this.relightMap !== this.relightPlaceholder && (this.relightMap = this.relightPlaceholder, this.rebuildGraph());
1166
1175
  return;
1167
1176
  }
1168
- const t = kt(e, this.getRelighting());
1169
- this.relightBlend.value = t.blend, this.relightBrightness.value = t.brightness, this.relightBackground.value = t.background, this.relightSoftness.value = t.softness, e.map !== this.relightMap && (this.relightMap = e.map, this.rebuildGraph());
1177
+ const e = kt(t, this.getRelighting());
1178
+ this.relightBlend.value = e.blend, this.relightBrightness.value = e.brightness, this.relightBackground.value = e.background, this.relightSoftness.value = e.softness, t.map !== this.relightMap && (this.relightMap = t.map, this.rebuildGraph());
1170
1179
  }
1171
1180
  /** Current relight numeric uniforms (`blend === 0` means off). */
1172
1181
  getRelighting() {
@@ -1189,8 +1198,8 @@ const Yt = 4, v = class v extends d.Mesh {
1189
1198
  * selects smaller splats, and a band left where it was would cull precisely
1190
1199
  * the detail that refinement bought.
1191
1200
  */
1192
- setScreenRadiusBand(e, t) {
1193
- this.screenBandMin.value = Math.max(0, e), this.screenBandMax.value = Math.max(0, t);
1201
+ setScreenRadiusBand(t, e) {
1202
+ this.screenBandMin.value = Math.max(0, t), this.screenBandMax.value = Math.max(0, e);
1194
1203
  }
1195
1204
  /** Current core DoF uniforms (`aperture === 0` means off). */
1196
1205
  getDepthOfField() {
@@ -1219,13 +1228,13 @@ const Yt = 4, v = class v extends d.Mesh {
1219
1228
  * {@link SplatPoolTenant}: follow one range to its new rows. The pool has
1220
1229
  * already moved the splat data; this moves what the mesh keys by pool row.
1221
1230
  */
1222
- relocatePoolRange(e, t) {
1223
- const i = e, s = v.DATA_TEXTURE_WIDTH;
1231
+ relocatePoolRange(t, e) {
1232
+ const i = t, s = v.DATA_TEXTURE_WIDTH;
1224
1233
  for (const r of this.channels.values()) {
1225
- const n = i.startRow * s, a = t * s, c = i.rowCount * s;
1226
- r.backing.copyWithin(a, n, n + c), r.pendingRows.push({ start: t, count: i.rowCount });
1234
+ const n = i.startRow * s, a = e * s, h = i.rowCount * s;
1235
+ r.backing.copyWithin(a, n, n + h), r.pendingRows.push({ start: e, count: i.rowCount });
1227
1236
  }
1228
- i.startRow = t, i.start = t * s, this.markRowsWritten(t, i.rowCount);
1237
+ i.startRow = e, i.start = e * s, this.markRowsWritten(e, i.rowCount);
1229
1238
  }
1230
1239
  /** {@link SplatPoolTenant}: rebuild everything keyed by pool index. */
1231
1240
  onPoolCompacted() {
@@ -1236,16 +1245,16 @@ const Yt = 4, v = class v extends d.Mesh {
1236
1245
  * uniforms and requests a depth re-sort when the camera or the content
1237
1246
  * has changed. Call this every frame, before `renderer.render`.
1238
1247
  */
1239
- update(e, t, i = {}) {
1248
+ update(t, e, i = {}) {
1240
1249
  if (this.disposed) return;
1241
- this.lastRenderer = t, this.assertPoolFitsDevice(t), e.updateMatrixWorld(), this.updateWorldMatrix(!0, !1), this.updateTimings.activeListMs = 0, this.updateTimings.uploadMs = 0, this.updateTimings.sortSubmitMs = 0, this.updateTimings.stagingTextureAllocations = 0, this.updateTimings.activeListUpdateRanges = 0;
1250
+ this.lastRenderer = e, this.assertPoolFitsDevice(e), t.updateMatrixWorld(), this.updateWorldMatrix(!0, !1), this.updateTimings.activeListMs = 0, this.updateTimings.uploadMs = 0, this.updateTimings.sortSubmitMs = 0, this.updateTimings.stagingTextureAllocations = 0, this.updateTimings.activeListUpdateRanges = 0;
1242
1251
  const s = performance.now();
1243
- this.flushPendingUploads(t), this.updateTimings.uploadMs = performance.now() - s;
1244
- const r = Pt(e, t);
1245
- let n = e, a = e, c, h;
1246
- if (r ? (n = r.eye, a = r.head, c = r.width, h = r.height) : (t.getDrawingBufferSize(P), c = P.x, h = P.y), this.adaptFoveationLimit(n, h), this.writeViewUniforms(n, c, h, a), this.updateTimings.activeListUpdateRanges = this.sourceIndexAttribute.updateRanges.length, i.sort !== !1) {
1252
+ this.flushPendingUploads(e), this.updateTimings.uploadMs = performance.now() - s;
1253
+ const r = Pt(t, e);
1254
+ let n = t, a = t, h, c;
1255
+ if (r ? (n = r.eye, a = r.head, h = r.width, c = r.height) : (e.getDrawingBufferSize(P), h = P.x, c = P.y), this.adaptFoveationLimit(n, c), this.writeViewUniforms(n, h, c, a), this.updateTimings.activeListUpdateRanges = this.sourceIndexAttribute.updateRanges.length, i.sort !== !1) {
1247
1256
  const l = performance.now();
1248
- this.requestSortIfNeeded(a, t), this.updateTimings.sortSubmitMs = performance.now() - l;
1257
+ this.requestSortIfNeeded(a, e), this.updateTimings.sortSubmitMs = performance.now() - l;
1249
1258
  }
1250
1259
  }
1251
1260
  /** Returns the render-preparation CPU timings for the current update. */
@@ -1271,14 +1280,14 @@ const Yt = 4, v = class v extends d.Mesh {
1271
1280
  * 16.7 M splats). If the limit can't be read, the check is skipped rather
1272
1281
  * than risk a false rejection.
1273
1282
  */
1274
- assertPoolFitsDevice(e) {
1283
+ assertPoolFitsDevice(t) {
1275
1284
  if (this.textureLimitChecked) return;
1276
1285
  this.textureLimitChecked = !0;
1277
- const t = Ct(e);
1278
- if (t > 0 && this.poolRows > t) {
1286
+ const e = Ct(t);
1287
+ if (e > 0 && this.poolRows > e) {
1279
1288
  const i = v.DATA_TEXTURE_WIDTH;
1280
1289
  throw new Error(
1281
- `SplatMesh: this scene needs a ${i}×${this.poolRows} data texture, but this device caps texture dimensions at ${t} (about ${(t * i).toLocaleString("en-US")} splats). Stream it with StreamedSplatMesh, or reduce the splat count.`
1290
+ `SplatMesh: this scene needs a ${i}×${this.poolRows} data texture, but this device caps texture dimensions at ${e} (about ${(e * i).toLocaleString("en-US")} splats). Stream it with StreamedSplatMesh, or reduce the splat count.`
1282
1291
  );
1283
1292
  }
1284
1293
  }
@@ -1298,8 +1307,8 @@ const Yt = 4, v = class v extends d.Mesh {
1298
1307
  * Does not return a persistent splat id - LOD streaming and pool reuse make
1299
1308
  * identity unstable across frames.
1300
1309
  */
1301
- pick(e, t, i, s) {
1302
- return this.picker.pick(e, t, i, s);
1310
+ pick(t, e, i, s) {
1311
+ return this.picker.pick(t, e, i, s);
1303
1312
  }
1304
1313
  /**
1305
1314
  * The resident splat center nearest a world point, within `radius` (world
@@ -1320,15 +1329,15 @@ const Yt = 4, v = class v extends d.Mesh {
1320
1329
  * in an ancestor transform is not supported. Splats displaced by GPU
1321
1330
  * modifiers are queried at their undisplaced CPU positions.
1322
1331
  */
1323
- queryNearest(e, t) {
1324
- if (this.activeCount === 0 || !(t >= 0)) return null;
1325
- this.updateWorldMatrix(!0, !1), T.copy(e), this.worldToLocal(T);
1326
- const i = this.ensureQueryGrid(), s = t / this.queryWorldMinScale(), r = t * t;
1332
+ queryNearest(t, e) {
1333
+ if (this.activeCount === 0 || !(e >= 0)) return null;
1334
+ this.updateWorldMatrix(!0, !1), T.copy(t), this.worldToLocal(T);
1335
+ const i = this.ensureQueryGrid(), s = e / this.queryWorldMinScale(), r = e * e;
1327
1336
  let n = -1, a = 1 / 0;
1328
- return i.forEachWithin(T.x, T.y, T.z, s, (h) => {
1329
- this.splatWorldPosition(h, k);
1330
- const l = k.distanceToSquared(e);
1331
- l <= r && l < a && (a = l, n = h);
1337
+ return i.forEachWithin(T.x, T.y, T.z, s, (c) => {
1338
+ this.splatWorldPosition(c, k);
1339
+ const l = k.distanceToSquared(t);
1340
+ l <= r && l < a && (a = l, n = c);
1332
1341
  }), n < 0 ? null : { point: this.splatWorldPosition(n, new d.Vector3()), distance: Math.sqrt(a) };
1333
1342
  }
1334
1343
  /**
@@ -1340,19 +1349,19 @@ const Yt = 4, v = class v extends d.Mesh {
1340
1349
  *
1341
1350
  * Like {@link queryNearest}, this searches resident, undisplaced CPU centers.
1342
1351
  */
1343
- queryRay(e, t = 0.025, i = 0.05) {
1344
- if (this.activeCount === 0 || !(t >= 0) || !(i >= 0) || e.direction.lengthSq() === 0)
1352
+ queryRay(t, e = 0.025, i = 0.05) {
1353
+ if (this.activeCount === 0 || !(e >= 0) || !(i >= 0) || t.direction.lengthSq() === 0)
1345
1354
  return null;
1346
1355
  this.updateWorldMatrix(!0, !1);
1347
1356
  const s = this.sourceIndexAttribute.array.subarray(0, this.activeCount);
1348
1357
  let r = -1, n = 1 / 0;
1349
1358
  for (const a of s) {
1350
- this.splatWorldPosition(a, k), T.subVectors(k, e.origin);
1351
- const c = T.dot(e.direction);
1352
- if (c < 0 || c >= n) continue;
1353
- T.addScaledVector(e.direction, -c);
1354
- const h = Math.max(i, c * t);
1355
- T.lengthSq() <= h * h && (r = a, n = c);
1359
+ this.splatWorldPosition(a, k), T.subVectors(k, t.origin);
1360
+ const h = T.dot(t.direction);
1361
+ if (h < 0 || h >= n) continue;
1362
+ T.addScaledVector(t.direction, -h);
1363
+ const c = Math.max(i, h * e);
1364
+ T.lengthSq() <= c * c && (r = a, n = h);
1356
1365
  }
1357
1366
  return r < 0 ? null : {
1358
1367
  point: this.splatWorldPosition(r, new d.Vector3()),
@@ -1374,20 +1383,20 @@ const Yt = 4, v = class v extends d.Mesh {
1374
1383
  * every candidate is judged in world space, where the −Y probe direction is
1375
1384
  * defined, so the vertical test never assumes local axis alignment.
1376
1385
  */
1377
- queryHeight(e, t, i = t / 2) {
1378
- if (this.activeCount === 0 || !(t >= 0) || !(i >= 0)) return null;
1379
- this.updateWorldMatrix(!0, !1), T.copy(e), this.worldToLocal(T);
1380
- const s = this.ensureQueryGrid(), r = (t + i) / this.queryWorldMinScale(), n = i * i;
1381
- let a = -1 / 0, c = -1;
1386
+ queryHeight(t, e, i = e / 2) {
1387
+ if (this.activeCount === 0 || !(e >= 0) || !(i >= 0)) return null;
1388
+ this.updateWorldMatrix(!0, !1), T.copy(t), this.worldToLocal(T);
1389
+ const s = this.ensureQueryGrid(), r = (e + i) / this.queryWorldMinScale(), n = i * i;
1390
+ let a = -1 / 0, h = -1;
1382
1391
  if (s.forEachWithin(T.x, T.y, T.z, r, (l) => {
1383
1392
  this.splatWorldPosition(l, k);
1384
- const f = e.y - k.y;
1385
- if (f < 0 || f > t) return;
1386
- const x = k.x - e.x, p = k.z - e.z;
1387
- x * x + p * p > n || k.y > a && (a = k.y, c = l);
1388
- }), c < 0) return null;
1389
- const h = this.splatWorldPosition(c, new d.Vector3());
1390
- return { point: h, drop: e.y - h.y };
1393
+ const f = t.y - k.y;
1394
+ if (f < 0 || f > e) return;
1395
+ const x = k.x - t.x, p = k.z - t.z;
1396
+ x * x + p * p > n || k.y > a && (a = k.y, h = l);
1397
+ }), h < 0) return null;
1398
+ const c = this.splatWorldPosition(h, new d.Vector3());
1399
+ return { point: c, drop: t.y - c.y };
1391
1400
  }
1392
1401
  /**
1393
1402
  * Renders this mesh from a second camera - into `target`, or the canvas when
@@ -1411,39 +1420,39 @@ const Yt = 4, v = class v extends d.Mesh {
1411
1420
  *
1412
1421
  * @param target - Destination render target, or `null`/omitted for the canvas.
1413
1422
  */
1414
- renderView(e, t, i = null) {
1423
+ renderView(t, e, i = null) {
1415
1424
  if (this.disposed) return;
1416
- this.lastRenderer = t, e.updateMatrixWorld(), this.updateWorldMatrix(!0, !1), this.flushPendingUploads(t), i ? P.set(i.width, i.height) : t.getDrawingBufferSize(P), this.writeViewUniforms(e, P.x, P.y);
1417
- const s = this.sortForView(e, t), r = t.getRenderTarget();
1425
+ this.lastRenderer = e, t.updateMatrixWorld(), this.updateWorldMatrix(!0, !1), this.flushPendingUploads(e), i ? P.set(i.width, i.height) : e.getDrawingBufferSize(P), this.writeViewUniforms(t, P.x, P.y);
1426
+ const s = this.sortForView(t, e), r = e.getRenderTarget();
1418
1427
  try {
1419
- t.setRenderTarget(i), t.render(this, e);
1428
+ e.setRenderTarget(i), e.render(this, t);
1420
1429
  } finally {
1421
- t.setRenderTarget(r), s && (this.orderIsForeign = !0);
1430
+ e.setRenderTarget(r), s && (this.orderIsForeign = !0);
1422
1431
  }
1423
1432
  }
1424
1433
  /**
1425
1434
  * Sorts the shared order buffer for a secondary view's camera, bypassing the
1426
- * primary view's sort scheduler and its `lastSortedModelView` record (that
1435
+ * primary view's sort scheduler and its last-sorted pose record (that
1427
1436
  * state belongs to `update()`'s camera). WebGPU dispatches synchronously into
1428
1437
  * the render queue, so the following draw reads this order.
1429
1438
  */
1430
- sortForView(e, t) {
1431
- return this.activeCount === 0 || !(t.backend.isWebGPUBackend === !0) || (this.currentModelView.multiplyMatrices(e.matrixWorldInverse, this.matrixWorld), this.refreshSortBounds(), this.sorter ?? (this.sorter = this.createSorter(t)), !this.sorter) ? !1 : (this.sorter.sort(this.currentModelView, this.activeCount, this.boundingSphereLocal), !0);
1439
+ sortForView(t, e) {
1440
+ return this.activeCount === 0 || !(e.backend.isWebGPUBackend === !0) || (this.currentModelView.multiplyMatrices(t.matrixWorldInverse, this.matrixWorld), this.refreshSortBounds(), this.sorter ?? (this.sorter = this.createSorter(e)), !this.sorter) ? !1 : (this.sorter.sort(this.currentModelView, this.activeCount, this.boundingSphereLocal), !0);
1432
1441
  }
1433
1442
  /** Rebuilds the query grid if the resident set changed since it was built. */
1434
1443
  ensureQueryGrid() {
1435
1444
  if (this.queryGrid && this.queryGridEpoch === this.queryEpoch) return this.queryGrid;
1436
- const e = this.sourceIndexAttribute.array.subarray(0, this.activeCount);
1437
- return this.queryGrid = new $t(this.backing.centers, e, this.activeCount), this.queryGridEpoch = this.queryEpoch, this.queryGrid;
1445
+ const t = this.sourceIndexAttribute.array.subarray(0, this.activeCount);
1446
+ return this.queryGrid = new Yt(this.backing.centers, t, this.activeCount), this.queryGridEpoch = this.queryEpoch, this.queryGrid;
1438
1447
  }
1439
1448
  /** World-space position of pool splat `poolIndex`, written into `out`. */
1440
- splatWorldPosition(e, t) {
1441
- const i = e * 4;
1442
- return t.set(
1449
+ splatWorldPosition(t, e) {
1450
+ const i = t * 4;
1451
+ return e.set(
1443
1452
  this.backing.centers[i],
1444
1453
  this.backing.centers[i + 1],
1445
1454
  this.backing.centers[i + 2]
1446
- ), t.applyMatrix4(this.matrixWorld);
1455
+ ), e.applyMatrix4(this.matrixWorld);
1447
1456
  }
1448
1457
  /**
1449
1458
  * The smallest world axis scale, for conservatively mapping a world radius
@@ -1451,7 +1460,7 @@ const Yt = 4, v = class v extends d.Mesh {
1451
1460
  * of `r / minAxisScale`, for any per-axis (non-uniform) scale.
1452
1461
  */
1453
1462
  queryWorldMinScale() {
1454
- return this.getWorldScale(q), Math.min(Math.abs(q.x), Math.abs(q.y), Math.abs(q.z)) || 1;
1463
+ return this.getWorldScale(z), Math.min(Math.abs(z.x), Math.abs(z.y), Math.abs(z.z)) || 1;
1455
1464
  }
1456
1465
  /**
1457
1466
  * Releases every GPU resource and worker this mesh owns. Idempotent: a
@@ -1460,24 +1469,24 @@ const Yt = 4, v = class v extends d.Mesh {
1460
1469
  * become no-ops after dispose.
1461
1470
  */
1462
1471
  dispose() {
1463
- var e;
1472
+ var t;
1464
1473
  if (!this.disposed) {
1465
- this.disposed = !0, (e = this.sorter) == null || e.dispose(), this.sorter = null, this.geometry.dispose(), this.material.dispose(), this.picker.dispose(), this.relightPlaceholder.dispose();
1466
- for (const t of this.ranges.values())
1467
- this.pool.releaseRows(t.startRow, t.rowCount);
1474
+ this.disposed = !0, (t = this.sorter) == null || t.dispose(), this.sorter = null, this.geometry.dispose(), this.material.dispose(), this.picker.dispose(), this.relightPlaceholder.dispose();
1475
+ for (const e of this.ranges.values())
1476
+ this.pool.releaseRows(e.startRow, e.rowCount);
1468
1477
  this.pool.unregister(this), this.ownsPool && this.pool.dispose();
1469
- for (const t of this.dataTextures)
1470
- !this.ownsPool && this.pool.isPoolTexture(t) || t.dispose();
1471
- for (const t of this.channels.values()) t.texture.dispose();
1478
+ for (const e of this.dataTextures)
1479
+ !this.ownsPool && this.pool.isPoolTexture(e) || e.dispose();
1480
+ for (const e of this.channels.values()) e.texture.dispose();
1472
1481
  this.channels.clear();
1473
- for (const t of this.uploadStaging.values())
1474
- for (const i of t.values()) i.dispose();
1482
+ for (const e of this.uploadStaging.values())
1483
+ for (const i of e.values()) i.dispose();
1475
1484
  this.uploadStaging.clear(), this.halfEncodeBuffers.clear(), this.lastRenderer && (Ut(this.lastRenderer, [this.sourceIndexAttribute]), this.lastRenderer = null), this.pendingUploadRows = [], this.workerDirtyRows = [], this.queryGrid = null, this.ranges.clear();
1476
1485
  }
1477
1486
  }
1478
1487
  /** Matches the viewport / focal / local-camera uniforms written by {@link update}. */
1479
- refreshProjectionUniforms(e, t) {
1480
- t.getDrawingBufferSize(P), this.writeViewUniforms(e, P.x, P.y);
1488
+ refreshProjectionUniforms(t, e) {
1489
+ e.getDrawingBufferSize(P), this.writeViewUniforms(t, P.x, P.y);
1481
1490
  }
1482
1491
  /**
1483
1492
  * Writes the three view-dependent uniforms - viewport, focal (splat screen
@@ -1492,10 +1501,10 @@ const Yt = 4, v = class v extends d.Mesh {
1492
1501
  * head, so both eyes shade from one cyclopean point while each still
1493
1502
  * projects through its own eye.
1494
1503
  */
1495
- writeViewUniforms(e, t, i, s = e) {
1496
- this.viewport.value.set(t, i);
1497
- const r = e.projectionMatrix.elements, n = r[5] * i / 2;
1498
- this.focal.value.set(r[0] * t / 2, n), s.getWorldPosition(this.localCameraPosition.value), this.worldToLocal(this.localCameraPosition.value), this.foveationMode === "frontier" && n > 0 && (this.pixelScaleLimit.value = this.foveationLimitPx / n);
1504
+ writeViewUniforms(t, e, i, s = t) {
1505
+ this.viewport.value.set(e, i);
1506
+ const r = t.projectionMatrix.elements, n = r[5] * i / 2;
1507
+ this.focal.value.set(r[0] * e / 2, n), s.getWorldPosition(this.localCameraPosition.value), this.worldToLocal(this.localCameraPosition.value), this.foveationMode === "frontier" && n > 0 && (this.pixelScaleLimit.value = this.foveationLimitPx / n);
1499
1508
  }
1500
1509
  /**
1501
1510
  * Self-adjusts {@link foveationLimitPx} so the frontier cut's drawn-splat count
@@ -1511,84 +1520,84 @@ const Yt = 4, v = class v extends d.Mesh {
1511
1520
  * here against a per-eye viewport there) makes the estimator judge a cut the
1512
1521
  * shader is not applying, and the ratchet runs away toward the maximum.
1513
1522
  */
1514
- adaptFoveationLimit(e, t) {
1523
+ adaptFoveationLimit(t, e) {
1515
1524
  if (this.foveationMode !== "frontier") return;
1516
1525
  const i = performance.now();
1517
- if (i - this.lastFoveationAdaptAt < Kt) return;
1526
+ if (i - this.lastFoveationAdaptAt < Qt) return;
1518
1527
  this.lastFoveationAdaptAt = i;
1519
- const s = e.projectionMatrix.elements[5] * t / 2;
1528
+ const s = t.projectionMatrix.elements[5] * e / 2;
1520
1529
  if (!(s > 0)) return;
1521
1530
  const r = this.foveationLimitPx / s;
1522
- e.getWorldPosition(_), this.worldToLocal(_), ot.copy(e.matrixWorld).invert(), at.multiplyMatrices(ot, this.matrixWorld).premultiply(e.projectionMatrix);
1523
- const n = at.elements, { covarianceA: a, covarianceB: c, centers: h } = this.backing, l = c.length / 4;
1531
+ t.getWorldPosition(_), this.worldToLocal(_), ot.copy(t.matrixWorld).invert(), at.multiplyMatrices(ot, this.matrixWorld).premultiply(t.projectionMatrix);
1532
+ const n = at.elements, { covarianceA: a, covarianceB: h, centers: c } = this.backing, l = h.length / 4;
1524
1533
  let f = 0, x = 0;
1525
- for (let m = 0; m < l; m += ht) {
1526
- const S = m * 4, A = c[S + 3];
1534
+ for (let m = 0; m < l; m += ct) {
1535
+ const S = m * 4, A = h[S + 3];
1527
1536
  if (A === 0) continue;
1528
1537
  f++;
1529
- const R = h[S], y = h[S + 1], M = h[S + 2], I = (n[3] * R + n[7] * y + n[11] * M + n[15]) * 1.2;
1538
+ const R = c[S], y = c[S + 1], M = c[S + 2], I = (n[3] * R + n[7] * y + n[11] * M + n[15]) * 1.2;
1530
1539
  if (n[2] * R + n[6] * y + n[10] * M + n[14] <= -I) continue;
1531
1540
  const B = n[0] * R + n[4] * y + n[8] * M + n[12];
1532
1541
  if (B > I || B < -I) continue;
1533
1542
  const E = n[1] * R + n[5] * y + n[9] * M + n[13];
1534
1543
  if (E > I || E < -I) continue;
1535
- const W = a[S] + a[S + 3] + c[S + 1], L = 2 * Math.sqrt(Math.max(W, 0) / 3), C = A < 0, ut = Math.abs(A), N = R - _.x, X = y - _.y, j = M - _.z, $ = r * Math.sqrt(N * N + X * X + j * j), dt = C ? 0 : L;
1544
+ const W = a[S] + a[S + 3] + h[S + 1], L = 2 * Math.sqrt(Math.max(W, 0) / 3), C = A < 0, ut = Math.abs(A), N = R - _.x, X = y - _.y, j = M - _.z, $ = r * Math.sqrt(N * N + X * X + j * j), dt = C ? 0 : L;
1536
1545
  ut > $ && dt <= $ && x++;
1537
1546
  }
1538
1547
  if (f === 0) return;
1539
- const p = x * ht, w = this.foveationDrawBudget;
1540
- p > w * 1.1 ? this.foveationLimitPx = Math.min(this.foveationLimitPx * 1.15, Qt) : p < w * 0.7 && (this.foveationLimitPx = Math.max(this.foveationLimitPx / 1.12, this.foveationTargetPx));
1548
+ const p = x * ct, w = this.foveationDrawBudget;
1549
+ p > w * 1.1 ? this.foveationLimitPx = Math.min(this.foveationLimitPx * 1.15, Jt) : p < w * 0.7 && (this.foveationLimitPx = Math.max(this.foveationLimitPx / 1.12, this.foveationTargetPx));
1541
1550
  }
1542
1551
  /** Records a written row span for GPU upload and the sort-worker mirror. */
1543
- markRowsWritten(e, t) {
1552
+ markRowsWritten(t, e) {
1544
1553
  var i;
1545
- this.pendingUploadRows.push({ start: e, count: t }), ((i = this.sorter) == null ? void 0 : i.kind) === "worker" && this.workerDirtyRows.push({ start: e, count: t });
1554
+ this.pendingUploadRows.push({ start: t, count: e }), ((i = this.sorter) == null ? void 0 : i.kind) === "worker" && this.workerDirtyRows.push({ start: t, count: e });
1546
1555
  }
1547
1556
  /** Appends one newly active pool range to the packed source-index list. */
1548
- activateRecord(e) {
1549
- const t = e.activePrefix ?? e.count;
1550
- if (t === 0) return;
1557
+ activateRecord(t) {
1558
+ const e = t.activePrefix ?? t.count;
1559
+ if (e === 0) return;
1551
1560
  this.queryEpoch++;
1552
1561
  const i = this.sourceIndexAttribute.array, s = this.getPoolIndexTemplate(), r = this.activeCount;
1553
- i.set(s.subarray(e.start, e.start + t), r), this.activeSlotByPoolIndex.set(
1554
- s.subarray(r, r + t),
1555
- e.start
1556
- ), this.activeCount += t, this.commitActiveListMutation(r, t);
1562
+ i.set(s.subarray(t.start, t.start + e), r), this.activeSlotByPoolIndex.set(
1563
+ s.subarray(r, r + e),
1564
+ t.start
1565
+ ), this.activeCount += e, this.commitActiveListMutation(r, e);
1557
1566
  }
1558
1567
  /**
1559
1568
  * Removes one active range and backfills its holes from the packed tail.
1560
1569
  * The common contiguous case uses one native block copy; the fallback
1561
1570
  * handles a range split by earlier tail backfills in O(record.count).
1562
1571
  */
1563
- deactivateRecord(e) {
1564
- const t = e.activePrefix ?? e.count;
1565
- if (t === 0) return;
1572
+ deactivateRecord(t) {
1573
+ const e = t.activePrefix ?? t.count;
1574
+ if (e === 0) return;
1566
1575
  this.queryEpoch++;
1567
- const i = this.sourceIndexAttribute.array, s = this.activeSlotByPoolIndex[e.start];
1576
+ const i = this.sourceIndexAttribute.array, s = this.activeSlotByPoolIndex[t.start];
1568
1577
  let r = !0;
1569
- for (let c = 1; c < t; c++)
1570
- if (this.activeSlotByPoolIndex[e.start + c] !== s + c) {
1578
+ for (let h = 1; h < e; h++)
1579
+ if (this.activeSlotByPoolIndex[t.start + h] !== s + h) {
1571
1580
  r = !1;
1572
1581
  break;
1573
1582
  }
1574
1583
  let n = this.activeCount, a = 0;
1575
1584
  if (r) {
1576
- const c = this.activeCount - t, h = Math.min(t, Math.max(0, c - s));
1577
- if (h > 0) {
1578
- i.copyWithin(s, this.activeCount - h, this.activeCount);
1579
- for (let l = 0; l < h; l++) {
1585
+ const h = this.activeCount - e, c = Math.min(e, Math.max(0, h - s));
1586
+ if (c > 0) {
1587
+ i.copyWithin(s, this.activeCount - c, this.activeCount);
1588
+ for (let l = 0; l < c; l++) {
1580
1589
  const f = i[s + l];
1581
1590
  this.activeSlotByPoolIndex[f] = s + l;
1582
1591
  }
1583
- n = s, a = s + h;
1592
+ n = s, a = s + c;
1584
1593
  }
1585
- this.activeCount = c;
1594
+ this.activeCount = h;
1586
1595
  } else {
1587
- for (let c = e.start; c < e.start + t; c++) {
1588
- const h = this.activeSlotByPoolIndex[c], l = this.activeCount - 1;
1589
- if (h !== l) {
1596
+ for (let h = t.start; h < t.start + e; h++) {
1597
+ const c = this.activeSlotByPoolIndex[h], l = this.activeCount - 1;
1598
+ if (c !== l) {
1590
1599
  const f = i[l];
1591
- i[h] = f, this.activeSlotByPoolIndex[f] = h, n = Math.min(n, h), a = Math.max(a, h + 1);
1600
+ i[c] = f, this.activeSlotByPoolIndex[f] = c, n = Math.min(n, c), a = Math.max(a, c + 1);
1592
1601
  }
1593
1602
  this.activeCount--;
1594
1603
  }
@@ -1597,25 +1606,25 @@ const Yt = 4, v = class v extends d.Mesh {
1597
1606
  this.commitActiveListMutation(n, Math.max(0, a - n));
1598
1607
  }
1599
1608
  /** Uploads only the changed packed slots and invalidates the current depth order. */
1600
- commitActiveListMutation(e, t) {
1609
+ commitActiveListMutation(t, e) {
1601
1610
  var i;
1602
- if (t > 0 && (z(this.sourceIndexAttribute, e, t), this.sourceIndexAttribute.needsUpdate = !0), ((i = this.sorter) == null ? void 0 : i.kind) === "worker" || this.sorter === null) {
1611
+ if (e > 0 && (q(this.sourceIndexAttribute, t, e), this.sourceIndexAttribute.needsUpdate = !0), ((i = this.sorter) == null ? void 0 : i.kind) === "worker" || this.sorter === null) {
1603
1612
  const s = this.sourceIndexAttribute.array, r = this.splatIndexAttribute.array;
1604
- this.drawListSorted ? (r.set(s.subarray(0, this.activeCount)), this.activeCount > 0 && z(this.splatIndexAttribute, 0, this.activeCount), this.splatIndexAttribute.needsUpdate = !0, this.drawListSorted = !1) : t > 0 && (r.set(s.subarray(e, e + t), e), z(this.splatIndexAttribute, e, t), this.splatIndexAttribute.needsUpdate = !0);
1613
+ this.drawListSorted ? (r.set(s.subarray(0, this.activeCount)), this.activeCount > 0 && q(this.splatIndexAttribute, 0, this.activeCount), this.splatIndexAttribute.needsUpdate = !0, this.drawListSorted = !1) : e > 0 && (r.set(s.subarray(t, t + e), t), q(this.splatIndexAttribute, t, e), this.splatIndexAttribute.needsUpdate = !0);
1605
1614
  }
1606
1615
  this.geometry.instanceCount = this.activeCount, this.activeListVersion++, this.sortScheduler.invalidateContent();
1607
1616
  }
1608
1617
  /** Rewrites the active-splat list (pool indices, range by range). */
1609
1618
  rebuildActiveList() {
1610
1619
  var s;
1611
- const e = this.sourceIndexAttribute.array, t = this.getPoolIndexTemplate();
1620
+ const t = this.sourceIndexAttribute.array, e = this.getPoolIndexTemplate();
1612
1621
  let i = 0;
1613
1622
  for (const r of this.ranges.values()) {
1614
1623
  if (!r.active) continue;
1615
1624
  const n = r.activePrefix ?? r.count;
1616
- e.set(t.subarray(r.start, r.start + n), i), this.activeSlotByPoolIndex.set(t.subarray(i, i + n), r.start), i += n;
1625
+ t.set(e.subarray(r.start, r.start + n), i), this.activeSlotByPoolIndex.set(e.subarray(i, i + n), r.start), i += n;
1617
1626
  }
1618
- this.activeCount = i, this.sourceIndexAttribute.clearUpdateRanges(), i > 0 && this.sourceIndexAttribute.addUpdateRange(0, i), this.sourceIndexAttribute.needsUpdate = !0, (((s = this.sorter) == null ? void 0 : s.kind) === "worker" || this.sorter === null) && (this.splatIndexAttribute.array.set(e.subarray(0, i)), this.splatIndexAttribute.clearUpdateRanges(), i > 0 && this.splatIndexAttribute.addUpdateRange(0, i), this.splatIndexAttribute.needsUpdate = !0, this.drawListSorted = !1), this.geometry.instanceCount = i, this.activeListVersion++, this.sortScheduler.invalidateContent();
1627
+ this.activeCount = i, this.sourceIndexAttribute.clearUpdateRanges(), i > 0 && this.sourceIndexAttribute.addUpdateRange(0, i), this.sourceIndexAttribute.needsUpdate = !0, (((s = this.sorter) == null ? void 0 : s.kind) === "worker" || this.sorter === null) && (this.splatIndexAttribute.array.set(t.subarray(0, i)), this.splatIndexAttribute.clearUpdateRanges(), i > 0 && this.splatIndexAttribute.addUpdateRange(0, i), this.splatIndexAttribute.needsUpdate = !0, this.drawListSorted = !1), this.geometry.instanceCount = i, this.activeListVersion++, this.sortScheduler.invalidateContent();
1619
1628
  }
1620
1629
  /** The pool's reusable index ramp; shared by every mesh drawing from it. */
1621
1630
  getPoolIndexTemplate() {
@@ -1626,15 +1635,15 @@ const Yt = 4, v = class v extends d.Mesh {
1626
1635
  * through a staging texture. (Constructor-time writes never appear here;
1627
1636
  * they ride the textures' initial full upload instead.)
1628
1637
  */
1629
- flushPendingUploads(e) {
1638
+ flushPendingUploads(t) {
1630
1639
  if (this.pendingUploadRows.length > 0) {
1631
- const t = this.poolFloatTextures === "float16" ? d.HalfFloatType : d.FloatType;
1632
- this.uploadRows(e, this.pendingUploadRows, d.RGBAFormat, 4, [
1640
+ const e = this.poolFloatTextures === "float16" ? d.HalfFloatType : d.FloatType;
1641
+ this.uploadRows(t, this.pendingUploadRows, d.RGBAFormat, 4, [
1633
1642
  {
1634
1643
  key: "centers",
1635
1644
  texture: this.dataTextures[0],
1636
1645
  data: this.backing.centers,
1637
- type: t,
1646
+ type: e,
1638
1647
  encodeHalf: this.poolFloatTextures === "float16"
1639
1648
  },
1640
1649
  {
@@ -1647,7 +1656,7 @@ const Yt = 4, v = class v extends d.Mesh {
1647
1656
  key: "covarianceA",
1648
1657
  texture: this.dataTextures[2],
1649
1658
  data: this.backing.covarianceA,
1650
- type: t,
1659
+ type: e,
1651
1660
  encodeHalf: this.poolFloatTextures === "float16"
1652
1661
  },
1653
1662
  {
@@ -1657,7 +1666,7 @@ const Yt = 4, v = class v extends d.Mesh {
1657
1666
  type: d.FloatType
1658
1667
  }
1659
1668
  ]), this.shPackedTextures.length > 0 && this.uploadRows(
1660
- e,
1669
+ t,
1661
1670
  this.pendingUploadRows,
1662
1671
  d.RGBAIntegerFormat,
1663
1672
  4,
@@ -1669,10 +1678,10 @@ const Yt = 4, v = class v extends d.Mesh {
1669
1678
  }))
1670
1679
  ), this.pendingUploadRows = [];
1671
1680
  }
1672
- for (const [t, i] of this.channels.entries())
1673
- i.pendingRows.length !== 0 && (this.uploadRows(e, i.pendingRows, d.RedFormat, 1, [
1681
+ for (const [e, i] of this.channels.entries())
1682
+ i.pendingRows.length !== 0 && (this.uploadRows(t, i.pendingRows, d.RedFormat, 1, [
1674
1683
  {
1675
- key: `channel:${t}`,
1684
+ key: `channel:${e}`,
1676
1685
  texture: i.texture,
1677
1686
  data: i.backing,
1678
1687
  type: i.textureType
@@ -1685,8 +1694,8 @@ const Yt = 4, v = class v extends d.Mesh {
1685
1694
  * upload carries half bits (staging is skipped for that path).
1686
1695
  */
1687
1696
  syncHalfFloatPoolImages() {
1688
- const e = this.dataTextures[0], t = this.dataTextures[2], i = e.image.data, s = t.image.data;
1689
- G(this.backing.centers, i), G(this.backing.covarianceA, s), e.needsUpdate = !0, t.needsUpdate = !0;
1697
+ const t = this.dataTextures[0], e = this.dataTextures[2], i = t.image.data, s = e.image.data;
1698
+ G(this.backing.centers, i), G(this.backing.covarianceA, s), t.needsUpdate = !0, e.needsUpdate = !0;
1690
1699
  }
1691
1700
  /**
1692
1701
  * Uploads the given row spans of one or more same-layout pool textures via
@@ -1694,17 +1703,17 @@ const Yt = 4, v = class v extends d.Mesh {
1694
1703
  * upload as one rectangle each - the copyTextureToTexture call count, not
1695
1704
  * the pixel volume, dominates.
1696
1705
  */
1697
- uploadRows(e, t, i, s, r) {
1698
- const n = v.DATA_TEXTURE_WIDTH, a = t.sort((h, l) => h.start - l.start), c = [];
1699
- for (const h of a) {
1700
- const l = c[c.length - 1];
1701
- l && h.start <= l.start + l.count ? l.count = Math.max(l.count, h.start + h.count - l.start) : c.push({ start: h.start, count: h.count });
1706
+ uploadRows(t, e, i, s, r) {
1707
+ const n = v.DATA_TEXTURE_WIDTH, a = e.sort((c, l) => c.start - l.start), h = [];
1708
+ for (const c of a) {
1709
+ const l = h[h.length - 1];
1710
+ l && c.start <= l.start + l.count ? l.count = Math.max(l.count, c.start + c.count - l.start) : h.push({ start: c.start, count: c.count });
1702
1711
  }
1703
- for (const h of c)
1712
+ for (const c of h)
1704
1713
  for (const { key: l, texture: f, data: x, type: p, encodeHalf: w } of r) {
1705
1714
  const m = x.subarray(
1706
- h.start * n * s,
1707
- (h.start + h.count) * n * s
1715
+ c.start * n * s,
1716
+ (c.start + c.count) * n * s
1708
1717
  );
1709
1718
  let S = m;
1710
1719
  if (w) {
@@ -1715,19 +1724,19 @@ const Yt = 4, v = class v extends d.Mesh {
1715
1724
  l,
1716
1725
  S,
1717
1726
  n,
1718
- h.count,
1727
+ c.count,
1719
1728
  i,
1720
1729
  p
1721
1730
  );
1722
- e.copyTextureToTexture(A, f, null, Zt.set(0, h.start));
1731
+ t.copyTextureToTexture(A, f, null, Kt.set(0, c.start));
1723
1732
  }
1724
1733
  }
1725
1734
  /** Reuses a same-length half encode buffer for one staging key. */
1726
- acquireHalfEncodeBuffer(e, t) {
1727
- const i = this.halfEncodeBuffers.get(e);
1728
- if (i && i.length === t) return i;
1729
- const s = new Uint16Array(t);
1730
- return this.halfEncodeBuffers.set(e, s), s;
1735
+ acquireHalfEncodeBuffer(t, e) {
1736
+ const i = this.halfEncodeBuffers.get(t);
1737
+ if (i && i.length === e) return i;
1738
+ const s = new Uint16Array(e);
1739
+ return this.halfEncodeBuffers.set(t, s), s;
1731
1740
  }
1732
1741
  /**
1733
1742
  * Reuses one of the recent same-sized staging textures for this upload. WebGPU
@@ -1735,25 +1744,25 @@ const Yt = 4, v = class v extends d.Mesh {
1735
1744
  * a small LRU per channel avoids recreating all core/SH staging resources when
1736
1745
  * a stream alternates among a few chunk heights, while bounding GPU memory.
1737
1746
  */
1738
- acquireUploadStaging(e, t, i, s, r, n) {
1747
+ acquireUploadStaging(t, e, i, s, r, n) {
1739
1748
  var l;
1740
- let a = this.uploadStaging.get(e);
1741
- a || (a = /* @__PURE__ */ new Map(), this.uploadStaging.set(e, a));
1742
- const c = a.get(s);
1743
- if (c)
1744
- return c.image = { data: t, width: i, height: s }, c.needsUpdate = !0, a.delete(s), a.set(s, c), c;
1745
- const h = new d.DataTexture(t, i, s, r, n);
1746
- if (r === d.RGBAIntegerFormat && (h.magFilter = d.NearestFilter, h.minFilter = d.NearestFilter), h.needsUpdate = !0, a.set(s, h), a.size > Yt) {
1749
+ let a = this.uploadStaging.get(t);
1750
+ a || (a = /* @__PURE__ */ new Map(), this.uploadStaging.set(t, a));
1751
+ const h = a.get(s);
1752
+ if (h)
1753
+ return h.image = { data: e, width: i, height: s }, h.needsUpdate = !0, a.delete(s), a.set(s, h), h;
1754
+ const c = new d.DataTexture(e, i, s, r, n);
1755
+ if (r === d.RGBAIntegerFormat && (c.magFilter = d.NearestFilter, c.minFilter = d.NearestFilter), c.needsUpdate = !0, a.set(s, c), a.size > Zt) {
1747
1756
  const f = a.keys().next().value;
1748
1757
  (l = a.get(f)) == null || l.dispose(), a.delete(f);
1749
1758
  }
1750
- return this.updateTimings.stagingTextureAllocations++, h;
1759
+ return this.updateTimings.stagingTextureAllocations++, c;
1751
1760
  }
1752
1761
  /** Gathers everything the material graph reads. See `splat-mesh-material.ts`. */
1753
- graphInputs(e, t) {
1762
+ graphInputs(t, e) {
1754
1763
  return {
1755
- textures: e,
1756
- sh: t,
1764
+ textures: t,
1765
+ sh: e,
1757
1766
  sourcePlacement: this.perSourceSort,
1758
1767
  // The uniform node instances, shared with the pick graph on purpose: one
1759
1768
  // per-frame write then reaches both.
@@ -1791,22 +1800,22 @@ const Yt = 4, v = class v extends d.Mesh {
1791
1800
  modifiers: this.modifierList
1792
1801
  };
1793
1802
  }
1794
- buildMaterial(e, t) {
1803
+ buildMaterial(t, e) {
1795
1804
  Z(
1796
1805
  this.material,
1797
1806
  "display",
1798
- this.graphInputs(e, t)
1807
+ this.graphInputs(t, e)
1799
1808
  ), this.picker.rebuildMaterial();
1800
1809
  }
1801
- requestSortIfNeeded(e, t) {
1810
+ requestSortIfNeeded(t, e) {
1802
1811
  if (this.deferSortRequestOnce && (this.deferSortRequestOnce = !1, this.activeListVersion === this.sortedActiveListVersion && !this.orderIsForeign) || this.activeCount === 0) return;
1803
- this.currentModelView.multiplyMatrices(e.matrixWorldInverse, this.matrixWorld);
1804
- const i = t.backend.isWebGPUBackend === !0, s = i ? performance.now() : 0;
1812
+ this.currentModelView.multiplyMatrices(t.matrixWorldInverse, this.matrixWorld), this.writeSortState(t);
1813
+ const i = e.backend.isWebGPUBackend === !0, s = i ? performance.now() : 0;
1805
1814
  if (!this.orderIsForeign) {
1806
1815
  if (i) {
1807
1816
  if (!this.sortScheduler.shouldSubmit(
1808
- this.currentModelView,
1809
- this.lastSortedModelView,
1817
+ this.currentSortState,
1818
+ this.lastSortedState,
1810
1819
  this.activeCount,
1811
1820
  s
1812
1821
  ))
@@ -1816,11 +1825,11 @@ const Yt = 4, v = class v extends d.Mesh {
1816
1825
  // still invalidated the draw order (the swap reset it to unsorted
1817
1826
  // active order) - skipping here would leave the scene blend-order
1818
1827
  // broken until the camera next moved.
1819
- !this.sortScheduler.hasPendingForce() && this.currentModelView.equals(this.lastSortedModelView)
1828
+ !this.sortScheduler.hasPendingForce() && this.currentSortState.equals(this.lastSortedState)
1820
1829
  )
1821
1830
  return;
1822
1831
  }
1823
- this.refreshSortBounds(), this.sorter ?? (this.sorter = this.createSorter(t)), this.sorter && this.sorter.sort(this.currentModelView, this.activeCount, this.boundingSphereLocal) && (this.lastSortedModelView.copy(this.currentModelView), this.sortedActiveListVersion = this.activeListVersion, this.orderIsForeign = !1, this.sortScheduler.markAccepted(s));
1832
+ this.refreshSortBounds(), this.sorter ?? (this.sorter = this.createSorter(e)), this.sorter && this.sorter.sort(this.currentModelView, this.activeCount, this.boundingSphereLocal) && (this.lastSortedState.copy(this.currentSortState), this.sortedActiveListVersion = this.activeListVersion, this.orderIsForeign = !1, this.sortScheduler.markAccepted(s));
1824
1833
  }
1825
1834
  /**
1826
1835
  * Refreshes {@link boundingSphereLocal} - the sphere the sorter quantizes
@@ -1832,16 +1841,16 @@ const Yt = 4, v = class v extends d.Mesh {
1832
1841
  this.boundsDirty && (this.localBounds.getBoundingSphere(this.boundingSphereLocal), this.boundsDirty = !1);
1833
1842
  }
1834
1843
  /** The data texture backing a channel defined with {@link defineChannel}. */
1835
- channelTexture(e) {
1836
- var t;
1837
- return (t = this.channels.get(e)) == null ? void 0 : t.texture;
1844
+ channelTexture(t) {
1845
+ var e;
1846
+ return (e = this.channels.get(t)) == null ? void 0 : e.texture;
1838
1847
  }
1839
1848
  /** CPU backing storage of a float channel, for internal CPU-side consumers. */
1840
- channelBacking(e) {
1841
- const t = this.channels.get(e);
1842
- if (!t || !(t.backing instanceof Float32Array))
1843
- throw new Error(`SplatMesh: float channel "${e}" is missing.`);
1844
- return t.backing;
1849
+ channelBacking(t) {
1850
+ const e = this.channels.get(t);
1851
+ if (!e || !(e.backing instanceof Float32Array))
1852
+ throw new Error(`SplatMesh: float channel "${t}" is missing.`);
1853
+ return e.backing;
1845
1854
  }
1846
1855
  /**
1847
1856
  * Forces the next {@link update} to re-sort even if the camera has not moved
@@ -1851,49 +1860,72 @@ const Yt = 4, v = class v extends d.Mesh {
1851
1860
  invalidateSort() {
1852
1861
  this.sortScheduler.invalidate(), this.boundsDirty = !0;
1853
1862
  }
1854
- createSorter(e) {
1855
- if (!(e.backend.isWebGPUBackend === !0))
1856
- return new qt({
1857
- capacity: this.capacity,
1858
- rowWidth: v.DATA_TEXTURE_WIDTH,
1859
- centers: this.backing.centers,
1860
- perSource: this.perSourceSort ? {
1861
- sourceIds: this.perSourceSort.sourceIds,
1862
- matrices: this.perSourceSort.matrices
1863
- } : void 0,
1864
- splatIndexAttribute: this.splatIndexAttribute,
1865
- takeDirtyRows: () => {
1866
- const s = this.workerDirtyRows;
1867
- return this.workerDirtyRows = [], s;
1868
- },
1869
- getActiveSpans: () => {
1870
- const s = new Uint32Array(this.ranges.size * 2);
1871
- let r = 0;
1872
- for (const n of this.ranges.values()) {
1873
- if (!n.active) continue;
1874
- const a = n.activePrefix ?? n.count;
1875
- a !== 0 && (s[r++] = n.start, s[r++] = a);
1863
+ /**
1864
+ * Writes the camera/mesh state that can change the selected ordering key.
1865
+ * Radial distance is invariant under camera rotation, so its state contains
1866
+ * the mesh's world linear transform and camera-relative translation only.
1867
+ */
1868
+ writeSortState(t) {
1869
+ if (this.sortMetric === "depth") {
1870
+ this.currentSortState.copy(this.currentModelView);
1871
+ return;
1872
+ }
1873
+ Dt(this.matrixWorld, t.matrixWorld, this.currentSortState);
1874
+ }
1875
+ createSorter(t) {
1876
+ if (!(t.backend.isWebGPUBackend === !0) || this.sortStrategy === "worker")
1877
+ return new qt(
1878
+ {
1879
+ capacity: this.capacity,
1880
+ rowWidth: v.DATA_TEXTURE_WIDTH,
1881
+ centers: this.backing.centers,
1882
+ perSource: this.perSourceSort ? {
1883
+ sourceIds: this.perSourceSort.sourceIds,
1884
+ matrices: this.perSourceSort.matrices
1885
+ } : void 0,
1886
+ splatIndexAttribute: this.splatIndexAttribute,
1887
+ takeDirtyRows: () => {
1888
+ const s = this.workerDirtyRows;
1889
+ return this.workerDirtyRows = [], s;
1890
+ },
1891
+ getActiveSpans: () => {
1892
+ const s = new Uint32Array(this.ranges.size * 2);
1893
+ let r = 0;
1894
+ for (const n of this.ranges.values()) {
1895
+ if (!n.active) continue;
1896
+ const a = n.activePrefix ?? n.count;
1897
+ a !== 0 && (s[r++] = n.start, s[r++] = a);
1898
+ }
1899
+ return s.subarray(0, r);
1900
+ },
1901
+ onOrderApplied: () => {
1902
+ this.drawListSorted = !0;
1876
1903
  }
1877
- return s.subarray(0, r);
1878
1904
  },
1879
- onOrderApplied: () => {
1880
- this.drawListSorted = !0;
1881
- }
1882
- });
1905
+ this.sortMetric
1906
+ );
1883
1907
  const i = {
1884
- renderer: e,
1908
+ renderer: t,
1885
1909
  capacity: this.poolRows * v.DATA_TEXTURE_WIDTH,
1886
1910
  centersTexture: this.centersTexture,
1887
1911
  dataTextureWidth: v.DATA_TEXTURE_WIDTH,
1888
1912
  splatIndexAttribute: this.splatIndexAttribute,
1889
1913
  sourceIndexAttribute: this.sourceIndexAttribute
1890
1914
  };
1891
- return this.perSourceSort ? new tt({ ...i, perSource: this.perSourceSort }) : this.sortStrategy === "radix" || this.sortStrategy === "exact" ? (this.ensureRadixSorter(), this.RadixSorterCtor ? new this.RadixSorterCtor({ ...i, exactDepth: this.sortStrategy === "exact" }) : null) : new tt(i);
1915
+ return this.perSourceSort ? new tt({
1916
+ ...i,
1917
+ perSource: this.perSourceSort,
1918
+ sortMetric: this.sortMetric
1919
+ }) : this.sortStrategy === "radix" || this.sortStrategy === "exact" ? (this.ensureRadixSorter(), this.RadixSorterCtor ? new this.RadixSorterCtor({
1920
+ ...i,
1921
+ exactDepth: this.sortStrategy === "exact",
1922
+ sortMetric: this.sortMetric
1923
+ }) : null) : new tt({ ...i, sortMetric: this.sortMetric });
1892
1924
  }
1893
1925
  /** Prefetches the experimental radix sorter; safe to call repeatedly. */
1894
1926
  ensureRadixSorter() {
1895
- this.RadixSorterCtor || this.radixSorterLoad || (this.radixSorterLoad = import("./radix-sorter-BrbUg_CV.js").then((e) => {
1896
- this.RadixSorterCtor = e.RadixSorter;
1927
+ this.RadixSorterCtor || this.radixSorterLoad || (this.radixSorterLoad = import("./radix-sorter-tSffmerk.js").then((t) => {
1928
+ this.RadixSorterCtor = t.RadixSorter;
1897
1929
  }).finally(() => {
1898
1930
  this.radixSorterLoad = null;
1899
1931
  }));
@@ -1901,13 +1933,13 @@ const Yt = 4, v = class v extends d.Mesh {
1901
1933
  };
1902
1934
  o(v, "DATA_TEXTURE_WIDTH", xt);
1903
1935
  let nt = v;
1904
- const F = new d.Box3(), Zt = new d.Vector2(), T = new d.Vector3(), k = new d.Vector3(), q = new d.Vector3(), P = new d.Vector2(), _ = new d.Vector3(), ot = new d.Matrix4(), at = new d.Matrix4(), Kt = 180, ht = 31, Qt = 64;
1905
- function ct(g) {
1936
+ const F = new d.Box3(), Kt = new d.Vector2(), T = new d.Vector3(), k = new d.Vector3(), z = new d.Vector3(), P = new d.Vector2(), _ = new d.Vector3(), ot = new d.Matrix4(), at = new d.Matrix4(), Qt = 180, ct = 31, Jt = 64;
1937
+ function ht(g) {
1906
1938
  if (g !== void 0 && (!Number.isFinite(g) || g <= 0))
1907
1939
  throw new RangeError("SplatMesh maxStdDev must be a finite number greater than 0.");
1908
1940
  return g;
1909
1941
  }
1910
- function Jt(g) {
1942
+ function te(g) {
1911
1943
  if (g !== void 0 && (!Number.isFinite(g) || g < 0))
1912
1944
  throw new RangeError("SplatMesh minSplatSizePx must be a finite number >= 0.");
1913
1945
  return g;
@@ -1918,25 +1950,25 @@ function H(g) {
1918
1950
  throw new RangeError("SplatMesh screen-radius cull must be a finite number ≥ 0.");
1919
1951
  return g;
1920
1952
  }
1921
- const te = 1;
1922
- function ee(g) {
1923
- if (g === void 0) return te;
1953
+ const ee = 1;
1954
+ function ie(g) {
1955
+ if (g === void 0) return ee;
1924
1956
  if (!Number.isFinite(g) || g <= 0)
1925
1957
  throw new RangeError("SplatMesh foveationTargetPx must be a finite number > 0.");
1926
1958
  return g;
1927
1959
  }
1928
- const ie = 9e5;
1929
- function se(g) {
1930
- if (g === void 0) return ie;
1960
+ const se = 9e5;
1961
+ function re(g) {
1962
+ if (g === void 0) return se;
1931
1963
  if (!Number.isFinite(g) || g <= 0)
1932
1964
  throw new RangeError("SplatMesh foveationDrawBudget must be a finite number > 0.");
1933
1965
  return g;
1934
1966
  }
1935
1967
  export {
1936
- ie as D,
1968
+ se as D,
1937
1969
  nt as S,
1938
- te as a,
1939
- Ft as c,
1940
- Vt as y
1970
+ ee as a,
1971
+ Vt as c,
1972
+ _t as y
1941
1973
  };
1942
- //# sourceMappingURL=splat-mesh-CsLOQb08.js.map
1974
+ //# sourceMappingURL=splat-mesh-B1KlWHvx.js.map