@voluma/vlam 0.2.4 → 0.3.2

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 (138) hide show
  1. package/README.md +3 -4
  2. package/dist/chunk-loader-DlNwggfG.js +1859 -0
  3. package/dist/chunk-loader-DlNwggfG.js.map +1 -0
  4. package/dist/{compute-sorter.d.ts → core/compute-sorter.d.ts} +1 -1
  5. package/dist/core/index.d.ts +45 -0
  6. package/dist/{splat-scene.d.ts → core/merged-splat-mesh.d.ts} +14 -15
  7. package/dist/{orientation.d.ts → core/orientation.d.ts} +7 -7
  8. package/dist/{relighting.d.ts → core/relighting.d.ts} +1 -1
  9. package/dist/{source-transform.d.ts → core/source-transform.d.ts} +4 -4
  10. package/dist/{splat-budget.d.ts → core/splat-budget.d.ts} +2 -2
  11. package/dist/{splat-data.d.ts → core/splat-data.d.ts} +4 -4
  12. package/dist/{splat-mesh-material.d.ts → core/splat-mesh-material.d.ts} +2 -2
  13. package/dist/{splat-mesh-types.d.ts → core/splat-mesh-types.d.ts} +19 -10
  14. package/dist/{splat-mesh.d.ts → core/splat-mesh.d.ts} +4 -4
  15. package/dist/{splat-modifier.d.ts → core/splat-modifier.d.ts} +5 -5
  16. package/dist/{webgpu-limits.d.ts → core/webgpu-limits.d.ts} +0 -59
  17. package/dist/{effects.d.ts → effects/index.d.ts} +14 -13
  18. package/dist/effects.js.map +1 -1
  19. package/dist/formats/ksplat/index.d.ts +1 -1
  20. package/dist/formats/ksplat/parse-ksplat.d.ts +1 -1
  21. package/dist/formats/ksplat.js.map +1 -1
  22. package/dist/formats/lcc/collision-mesh.d.ts +3 -3
  23. package/dist/formats/lcc/collision-partition.d.ts +1 -1
  24. package/dist/formats/lcc/lcc.d.ts +3 -3
  25. package/dist/formats/lcc/lcc2.d.ts +2 -2
  26. package/dist/formats/lcc/parse-lcc.d.ts +1 -1
  27. package/dist/formats/lcc.js +17 -16
  28. package/dist/formats/lcc.js.map +1 -1
  29. package/dist/formats/ply/index.d.ts +1 -1
  30. package/dist/formats/ply/parse-compressed-ply.d.ts +2 -2
  31. package/dist/formats/ply/parse-splat-ply.d.ts +4 -4
  32. package/dist/formats/ply.js +1 -1
  33. package/dist/formats/ply.js.map +1 -1
  34. package/dist/formats/rad/frontier-worker-protocol.d.ts +8 -1
  35. package/dist/formats/rad/index.d.ts +2 -2
  36. package/dist/formats/rad/parse-rad.d.ts +2 -2
  37. package/dist/formats/rad/rad-foveated-source.d.ts +3 -3
  38. package/dist/formats/rad/rad.d.ts +7 -7
  39. package/dist/formats/rad.js +3 -3
  40. package/dist/formats/rad.js.map +1 -1
  41. package/dist/formats/sog/index.d.ts +1 -1
  42. package/dist/formats/sog/parse-sog.d.ts +6 -6
  43. package/dist/formats/sog.js.map +1 -1
  44. package/dist/formats/splat/index.d.ts +1 -1
  45. package/dist/formats/splat/parse-splat.d.ts +1 -1
  46. package/dist/formats/splat.js.map +1 -1
  47. package/dist/formats/spz/index.d.ts +1 -1
  48. package/dist/formats/spz/parse-spz.d.ts +1 -1
  49. package/dist/formats/spz.js.map +1 -1
  50. package/dist/half-float-Cs4FDq8Q.js.map +1 -1
  51. package/dist/index.js +253 -9047
  52. package/dist/index.js.map +1 -1
  53. package/dist/{chunk-loader.d.ts → loaders/chunk-loader.d.ts} +4 -4
  54. package/dist/loaders/index.d.ts +15 -0
  55. package/dist/{load-scene.d.ts → loaders/load-splat-data.d.ts} +16 -14
  56. package/dist/{load-worker-protocol.d.ts → loaders/load-worker-protocol.d.ts} +2 -2
  57. package/dist/{loading.d.ts → loaders/loading.d.ts} +8 -8
  58. package/dist/loaders.js +26 -0
  59. package/dist/loaders.js.map +1 -0
  60. package/dist/loading-wLo8vRbA.js.map +1 -1
  61. package/dist/{splat-mesh-types-CTN_duw2.js → lod-scheduler-B0a_uBlv.js} +133 -140
  62. package/dist/lod-scheduler-B0a_uBlv.js.map +1 -0
  63. package/dist/logging-BfPdd7NJ.js.map +1 -1
  64. package/dist/{ply-header-BwgExCn-.js → ply-header-B9WllbPg.js} +3 -3
  65. package/dist/ply-header-B9WllbPg.js.map +1 -0
  66. package/dist/radix-sorter-BrbUg_CV.js +178 -0
  67. package/dist/radix-sorter-BrbUg_CV.js.map +1 -0
  68. package/dist/relighting-Tiwep8yd.js +977 -0
  69. package/dist/relighting-Tiwep8yd.js.map +1 -0
  70. package/dist/selection/index.d.ts +13 -0
  71. package/dist/{selection-volume.d.ts → selection/selection-volume.d.ts} +1 -1
  72. package/dist/{splat-partition.d.ts → selection/splat-partition.d.ts} +2 -2
  73. package/dist/selection.js +137 -0
  74. package/dist/selection.js.map +1 -0
  75. package/dist/sh-pack-D5wAe5gg.js.map +1 -1
  76. package/dist/{splat-budget-DXew_86c.js → splat-budget-DuVZspPQ.js} +7 -7
  77. package/dist/splat-budget-DuVZspPQ.js.map +1 -0
  78. package/dist/splat-data-BZM5dhhx.js.map +1 -1
  79. package/dist/splat-mesh-CsLOQb08.js +1942 -0
  80. package/dist/splat-mesh-CsLOQb08.js.map +1 -0
  81. package/dist/splat-mesh-types-BZIko-_9.js +18 -0
  82. package/dist/splat-mesh-types-BZIko-_9.js.map +1 -0
  83. package/dist/static-lod/index.d.ts +12 -0
  84. package/dist/{static-lod-splat-mesh.d.ts → static-lod/static-lod-splat-mesh.d.ts} +3 -3
  85. package/dist/{static-lod-worker-protocol.d.ts → static-lod/static-lod-worker-protocol.d.ts} +1 -1
  86. package/dist/{static-lod.d.ts → static-lod/static-lod.d.ts} +1 -1
  87. package/dist/{static-lod-worker-D2fyqQZO.js → static-lod-worker-DktKnJkR.js} +46 -46
  88. package/dist/{static-lod-worker-D2fyqQZO.js.map → static-lod-worker-DktKnJkR.js.map} +1 -1
  89. package/dist/static-lod.js +148 -0
  90. package/dist/static-lod.js.map +1 -0
  91. package/dist/{budget-governor.d.ts → streaming/budget-governor.d.ts} +4 -4
  92. package/dist/{camera-budget-governor.d.ts → streaming/camera-budget-governor.d.ts} +11 -11
  93. package/dist/{chunk-cache-budget.d.ts → streaming/chunk-cache-budget.d.ts} +5 -5
  94. package/dist/{chunk-fetch-scheduler.d.ts → streaming/chunk-fetch-scheduler.d.ts} +4 -4
  95. package/dist/{dataset-source.d.ts → streaming/dataset-source.d.ts} +1 -1
  96. package/dist/streaming/index.d.ts +23 -0
  97. package/dist/{lod-scheduler.d.ts → streaming/lod-scheduler.d.ts} +1 -1
  98. package/dist/{lod-source.d.ts → streaming/lod-source.d.ts} +9 -9
  99. package/dist/{streamed-splat-mesh-utils.d.ts → streaming/streamed-splat-mesh-utils.d.ts} +2 -2
  100. package/dist/{streamed-splat-mesh.d.ts → streaming/streamed-splat-mesh.d.ts} +66 -32
  101. package/dist/streaming.js +2911 -0
  102. package/dist/streaming.js.map +1 -0
  103. package/dist/unified/index.d.ts +11 -0
  104. package/dist/{unified-splat-renderer.d.ts → unified/unified-splat-mesh.d.ts} +23 -16
  105. package/dist/unified/unified-work-buffer.d.ts +66 -0
  106. package/dist/{work-buffer-gather.d.ts → unified/work-buffer-gather.d.ts} +6 -6
  107. package/dist/{work-buffer-material.d.ts → unified/work-buffer-material.d.ts} +1 -1
  108. package/dist/unified.js +746 -0
  109. package/dist/unified.js.map +1 -0
  110. package/dist/webgpu-limits-Y3CI_6_6.js +43 -0
  111. package/dist/webgpu-limits-Y3CI_6_6.js.map +1 -0
  112. package/package.json +27 -7
  113. package/dist/index.d.ts +0 -54
  114. package/dist/ply-header-BwgExCn-.js.map +0 -1
  115. package/dist/splat-budget-DXew_86c.js.map +0 -1
  116. package/dist/splat-mesh-types-CTN_duw2.js.map +0 -1
  117. /package/dist/{create-splat-renderer.d.ts → core/create-splat-renderer.d.ts} +0 -0
  118. /package/dist/{depth-of-field.d.ts → core/depth-of-field.d.ts} +0 -0
  119. /package/dist/{half-float.d.ts → core/half-float.d.ts} +0 -0
  120. /package/dist/{logging.d.ts → core/logging.d.ts} +0 -0
  121. /package/dist/{radix-sort.d.ts → core/radix-sort.d.ts} +0 -0
  122. /package/dist/{radix-sorter.d.ts → core/radix-sorter.d.ts} +0 -0
  123. /package/dist/{relighting-pass.d.ts → core/relighting-pass.d.ts} +0 -0
  124. /package/dist/{sh-pack.d.ts → core/sh-pack.d.ts} +0 -0
  125. /package/dist/{sort-scheduler.d.ts → core/sort-scheduler.d.ts} +0 -0
  126. /package/dist/{sort-worker-protocol.d.ts → core/sort-worker-protocol.d.ts} +0 -0
  127. /package/dist/{sorter.d.ts → core/sorter.d.ts} +0 -0
  128. /package/dist/{splat-depth-pack.d.ts → core/splat-depth-pack.d.ts} +0 -0
  129. /package/dist/{splat-mesh-picking.d.ts → core/splat-mesh-picking.d.ts} +0 -0
  130. /package/dist/{splat-mesh-pool.d.ts → core/splat-mesh-pool.d.ts} +0 -0
  131. /package/dist/{splat-modifier-stack.d.ts → core/splat-modifier-stack.d.ts} +0 -0
  132. /package/dist/{splat-query.d.ts → core/splat-query.d.ts} +0 -0
  133. /package/dist/{splat-sort-bounds.d.ts → core/splat-sort-bounds.d.ts} +0 -0
  134. /package/dist/{storage-attribute-mirror.d.ts → core/storage-attribute-mirror.d.ts} +0 -0
  135. /package/dist/{worker-sorter.d.ts → core/worker-sorter.d.ts} +0 -0
  136. /package/dist/{xr-view.d.ts → core/xr-view.d.ts} +0 -0
  137. /package/dist/{ply-header.d.ts → loaders/ply-header.d.ts} +0 -0
  138. /package/dist/{lod-manifest.d.ts → streaming/lod-manifest.d.ts} +0 -0
@@ -0,0 +1,977 @@
1
+ var Tt = Object.defineProperty;
2
+ var yt = (s, e, t) => e in s ? Tt(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
+ var l = (s, e, t) => yt(s, typeof e != "symbol" ? e + "" : e, t);
4
+ import * as h from "three/webgpu";
5
+ import { bool as At, mat3 as ye, vec3 as S, float as w, modelViewMatrix as je, vec4 as Q, modelWorldMatrix as Mt, int as N, attribute as Ct, ivec2 as He, textureLoad as _, varying as re, colorSpaceToWorking as Pt, positionGeometry as Ne, Fn as $, cameraProjectionMatrix as kt, If as be, mix as ce, vec2 as te, Discard as qe, texture as Se, screenUV as Te, uniform as xe, uint as P, storage as ie, atomicStore as We, instanceIndex as I, atomicAdd as it, Loop as Ge, atomicLoad as ct } from "three/tsl";
6
+ import { w as Rt } from "./logging-BfPdd7NJ.js";
7
+ function Bt(s, e, t) {
8
+ if (s.length === 0)
9
+ return {
10
+ color: t.color,
11
+ offset: null,
12
+ scaleSquared: null,
13
+ rotation: null,
14
+ visible: null,
15
+ isotropicCovarianceMix: null,
16
+ isotropicVarianceScale: null,
17
+ isotropicScreenRadiusPx: null
18
+ };
19
+ const o = e, a = {
20
+ color: t.color,
21
+ offset: S(0, 0, 0),
22
+ scale: w(1),
23
+ rotation: ye(S(1, 0, 0), S(0, 1, 0), S(0, 0, 1)),
24
+ visible: At(!0)
25
+ }, n = { offset: !1, scale: !1, rotation: !1, visible: !1 };
26
+ let r = null, i = null, d = null, c = null, T = null, D = null;
27
+ const y = /* @__PURE__ */ new Map(), q = {
28
+ index: t.index,
29
+ localCenter: t.localCenter,
30
+ sourceCenter: t.sourceCenter ?? t.localCenter,
31
+ sourceToLocal: t.sourceToLocal ?? a.rotation,
32
+ cameraLocal: o,
33
+ baseColor: t.color,
34
+ get worldCenter() {
35
+ return c ?? (c = t.makeWorldCenter ? t.makeWorldCenter() : Mt.mul(Q(t.localCenter, 1)).xyz);
36
+ },
37
+ get viewCenter() {
38
+ return T ?? (T = t.makeViewCenter ? t.makeViewCenter() : je.mul(Q(t.localCenter, 1)).xyz);
39
+ },
40
+ get normal() {
41
+ return D ?? (D = t.makeNormal());
42
+ },
43
+ channel(C) {
44
+ let m = y.get(C);
45
+ return m || (m = t.makeChannel(C), y.set(C, m)), m;
46
+ },
47
+ get color() {
48
+ return a.color;
49
+ },
50
+ get offset() {
51
+ return a.offset;
52
+ },
53
+ get scale() {
54
+ return a.scale;
55
+ },
56
+ get rotation() {
57
+ return a.rotation;
58
+ },
59
+ get visible() {
60
+ return a.visible;
61
+ }
62
+ };
63
+ for (const C of s) {
64
+ const m = C(q);
65
+ m.color && (a.color = m.color), m.offset && (a.offset = m.offset, n.offset = !0), m.scale && (a.scale = m.scale, n.scale = !0), m.rotation && (a.rotation = m.rotation, n.rotation = !0), m.visible && (a.visible = m.visible, n.visible = !0), m.isotropicCovarianceMix !== void 0 && (r = m.isotropicCovarianceMix), m.isotropicVarianceScale !== void 0 && (i = m.isotropicVarianceScale), m.isotropicScreenRadiusPx !== void 0 && (d = m.isotropicScreenRadiusPx);
66
+ }
67
+ return {
68
+ color: a.color,
69
+ offset: n.offset ? a.offset : null,
70
+ scaleSquared: n.scale ? a.scale.mul(a.scale) : null,
71
+ rotation: n.rotation ? a.rotation : null,
72
+ visible: n.visible ? a.visible : null,
73
+ isotropicCovarianceMix: r,
74
+ isotropicVarianceScale: i,
75
+ isotropicScreenRadiusPx: d
76
+ };
77
+ }
78
+ const Fe = 2048;
79
+ function Et(s, e, t) {
80
+ let o = -1;
81
+ for (let a = 0; a < s.length; a++) {
82
+ const n = s[a];
83
+ if (!(n.count < e) && ((o === -1 || n.count < s[o].count) && (o = a), n.count === e))
84
+ break;
85
+ }
86
+ if (o !== -1) {
87
+ const a = s[o], n = a.start;
88
+ return a.start += e, a.count -= e, a.count === 0 && s.splice(o, 1), n;
89
+ }
90
+ throw new Error(
91
+ `SplatMesh capacity exceeded: no contiguous space for ${e} rows (${Fe} splats each) in a ${t}-row pool.`
92
+ );
93
+ }
94
+ function It(s, e, t) {
95
+ s.push({ start: e, count: t }), s.sort((a, n) => a.start - n.start);
96
+ const o = [];
97
+ for (const a of s) {
98
+ const n = o[o.length - 1];
99
+ if (n && n.start + n.count > a.start)
100
+ throw new Error(
101
+ `SplatMesh pool released rows [${e}, ${e + t}) overlap an already-free span.`
102
+ );
103
+ n && n.start + n.count === a.start ? n.count += a.count : o.push(a);
104
+ }
105
+ return o;
106
+ }
107
+ class cs {
108
+ constructor(e) {
109
+ l(this, "width", Fe);
110
+ l(this, "rows");
111
+ l(this, "floatTextures");
112
+ l(this, "packedShBands");
113
+ l(this, "backing");
114
+ l(this, "centersTexture");
115
+ l(this, "colorsTexture");
116
+ l(this, "covarianceATexture");
117
+ l(this, "covarianceBTexture");
118
+ l(this, "shPackedTextures");
119
+ /** Free row spans, sorted by start row. Mutated in place by the allocator. */
120
+ l(this, "freeRowSpans");
121
+ l(this, "tenants", /* @__PURE__ */ new Set());
122
+ /**
123
+ * Pool index → its owner's packed active-list slot, valid only while that
124
+ * pool index is active.
125
+ *
126
+ * Pool-owned rather than per-mesh because it is keyed by *pool* index: a
127
+ * per-mesh copy would have to span the whole pool, so N meshes sharing one
128
+ * pool would each pay 4 B per pool splat (a 4 M-splat pool shared by 13
129
+ * meshes = ~200 MB of reverse maps). One array is safe because a row belongs
130
+ * to exactly one tenant at a time, so no two tenants ever write the same
131
+ * entry - the slot numbers in it are simply read back by whoever owns
132
+ * the row.
133
+ */
134
+ l(this, "activeSlotByPoolIndex");
135
+ l(this, "poolIndexTemplate", null);
136
+ if (!(e.capacity > 0)) throw new Error("SplatPool capacity must be positive.");
137
+ this.rows = Math.ceil(e.capacity / this.width), Ft(this.rows, e.maxTextureSize ?? 0, this.width);
138
+ const t = this.width * this.rows;
139
+ this.floatTextures = e.floatTextures === "float16" ? "float16" : "float32", this.packedShBands = e.packedShBands ?? 0;
140
+ const o = this.floatTextures === "float16" ? h.HalfFloatType : h.FloatType;
141
+ this.backing = {
142
+ centers: new Float32Array(t * 4),
143
+ colors: new Uint8Array(t * 4),
144
+ covarianceA: new Float32Array(t * 4),
145
+ covarianceB: new Float32Array(t * 4),
146
+ // One RGBA32UI texel per splat per texture; sharing the pool's row
147
+ // geometry lets the whole partial-upload/compaction path reuse the
148
+ // existing row arithmetic unchanged.
149
+ shPacked: Array.from(
150
+ { length: e.packedShTextureCount ?? 0 },
151
+ () => new Uint32Array(t * 4)
152
+ )
153
+ };
154
+ const a = this.floatTextures === "float16" ? new Uint16Array(t * 4) : this.backing.centers, n = this.floatTextures === "float16" ? new Uint16Array(t * 4) : this.backing.covarianceA;
155
+ this.centersTexture = De(a, this.width, this.rows, o), this.colorsTexture = De(
156
+ this.backing.colors,
157
+ this.width,
158
+ this.rows,
159
+ h.UnsignedByteType
160
+ ), this.covarianceATexture = De(n, this.width, this.rows, o), this.covarianceBTexture = De(
161
+ this.backing.covarianceB,
162
+ this.width,
163
+ this.rows,
164
+ h.FloatType
165
+ ), this.shPackedTextures = this.backing.shPacked.map(
166
+ (r) => Dt(r, this.width, this.rows)
167
+ ), this.freeRowSpans = [{ start: 0, count: this.rows }], this.activeSlotByPoolIndex = new Uint32Array(t);
168
+ }
169
+ /**
170
+ * A reusable `0, 1, 2, …` ramp over the pool, used to fill runs of pool
171
+ * indices and active-list slots without a per-element loop. Pool-owned so
172
+ * tenants sharing a pool share the one copy.
173
+ */
174
+ indexTemplate() {
175
+ if (this.poolIndexTemplate) return this.poolIndexTemplate;
176
+ const e = new Uint32Array(this.capacity);
177
+ for (let t = 0; t < e.length; t++) e[t] = t;
178
+ return this.poolIndexTemplate = e, e;
179
+ }
180
+ /** Splats the pool holds, always a whole number of rows. */
181
+ get capacity() {
182
+ return this.rows * this.width;
183
+ }
184
+ /** Whether `texture` belongs to this pool (and so outlives any one tenant). */
185
+ isPoolTexture(e) {
186
+ return e === this.centersTexture || e === this.colorsTexture || e === this.covarianceATexture || e === this.covarianceBTexture || this.shPackedTextures.includes(e);
187
+ }
188
+ /** The four core textures, in the order the upload path indexes them. */
189
+ get coreTextures() {
190
+ return [
191
+ this.centersTexture,
192
+ this.colorsTexture,
193
+ this.covarianceATexture,
194
+ this.covarianceBTexture
195
+ ];
196
+ }
197
+ /** Rows still free, whether or not they are contiguous. */
198
+ get freeRows() {
199
+ let e = 0;
200
+ for (const t of this.freeRowSpans) e += t.count;
201
+ return e;
202
+ }
203
+ /** Takes `rowCount` contiguous rows; throws when none are left (compact cue). */
204
+ allocateRows(e) {
205
+ return Et(this.freeRowSpans, e, this.rows);
206
+ }
207
+ /** Returns rows to the free list, coalescing neighbours. */
208
+ releaseRows(e, t) {
209
+ this.freeRowSpans = It(this.freeRowSpans, e, t);
210
+ }
211
+ /** Resets the free list to one span covering the whole pool. */
212
+ resetFreeRows(e = 0) {
213
+ this.freeRowSpans = e < this.rows ? [{ start: e, count: this.rows - e }] : [];
214
+ }
215
+ /**
216
+ * Adds a mesh that draws from this pool. Registration exists for
217
+ * {@link compact}: packing the pool moves rows that belong to *every*
218
+ * tenant, so each has to be told where its ranges went.
219
+ */
220
+ register(e) {
221
+ this.tenants.add(e);
222
+ }
223
+ /**
224
+ * Drops a tenant. Release its ranges first: an unregistered tenant is
225
+ * invisible to {@link compact}, which would then treat rows it still holds
226
+ * as free and hand them to someone else. `compact` throws rather than let
227
+ * that happen silently.
228
+ */
229
+ unregister(e) {
230
+ this.tenants.delete(e);
231
+ }
232
+ /** Number of meshes drawing from this pool. */
233
+ get tenantCount() {
234
+ return this.tenants.size;
235
+ }
236
+ /**
237
+ * Packs every tenant's ranges toward row 0, removing the gaps that add /
238
+ * remove churn leaves behind and restoring a single contiguous free span.
239
+ * Callers reach this when {@link allocateRows} throws despite enough total
240
+ * free rows - row-alignment fragmentation.
241
+ *
242
+ * The CPU backing arrays are authoritative, so nothing is re-fetched; moved
243
+ * rows are re-uploaded on the tenant's next update.
244
+ *
245
+ * Note this is a whole-pool stall: with several tenants, one mesh's
246
+ * fragmentation relocates the others' rows too, and every tenant rebuilds
247
+ * its draw state. (Spark sidesteps the equivalent by allocating fixed-size,
248
+ * interchangeable pages that never need packing; vlam's ranges are variable
249
+ * runs, so it packs instead.)
250
+ */
251
+ compact() {
252
+ const e = this.width, t = [];
253
+ let o = 0;
254
+ for (const n of this.tenants)
255
+ for (const r of n.poolRanges())
256
+ t.push({ tenant: n, range: r }), o += r.rowCount;
257
+ if (o + this.freeRows !== this.rows)
258
+ throw new Error(
259
+ `SplatPool compaction found ${this.rows - o - this.freeRows} unaccounted row(s): ${o} held by ${this.tenants.size} tenant(s), ${this.freeRows} free, ${this.rows} total. Release a tenant's ranges before unregistering it.`
260
+ );
261
+ t.sort((n, r) => n.range.startRow - r.range.startRow);
262
+ let a = 0;
263
+ for (const { tenant: n, range: r } of t) {
264
+ if (r.startRow !== a) {
265
+ const i = r.startRow * e * 4, d = a * e * 4, c = r.rowCount * e * 4;
266
+ this.backing.centers.copyWithin(d, i, i + c), this.backing.colors.copyWithin(d, i, i + c), this.backing.covarianceA.copyWithin(d, i, i + c), this.backing.covarianceB.copyWithin(d, i, i + c);
267
+ for (const T of this.backing.shPacked) T.copyWithin(d, i, i + c);
268
+ n.relocatePoolRange(r, a);
269
+ }
270
+ a += r.rowCount;
271
+ }
272
+ this.resetFreeRows(a);
273
+ for (const n of this.tenants) n.onPoolCompacted();
274
+ }
275
+ dispose() {
276
+ for (const e of this.coreTextures) e.dispose();
277
+ for (const e of this.shPackedTextures) e.dispose();
278
+ this.tenants.clear();
279
+ }
280
+ }
281
+ function De(s, e, t, o) {
282
+ const a = new h.DataTexture(s, e, t, h.RGBAFormat, o);
283
+ return a.needsUpdate = !0, a;
284
+ }
285
+ function Dt(s, e, t) {
286
+ const o = new h.DataTexture(
287
+ s,
288
+ e,
289
+ t,
290
+ h.RGBAIntegerFormat,
291
+ h.UnsignedIntType
292
+ );
293
+ return o.magFilter = h.NearestFilter, o.minFilter = h.NearestFilter, o.generateMipmaps = !1, o.needsUpdate = !0, o;
294
+ }
295
+ function ls(s) {
296
+ var a, n;
297
+ const e = s.backend, t = (n = (a = e == null ? void 0 : e.device) == null ? void 0 : a.limits) == null ? void 0 : n.maxTextureDimension2D;
298
+ if (typeof t == "number" && t > 0) return t;
299
+ const o = e == null ? void 0 : e.gl;
300
+ if (o) {
301
+ const r = o.getParameter(o.MAX_TEXTURE_SIZE);
302
+ if (typeof r == "number" && r > 0) return r;
303
+ }
304
+ return 0;
305
+ }
306
+ function Ft(s, e, t = Fe) {
307
+ if (!(!(e > 0) || s <= e))
308
+ throw new Error(
309
+ `SplatPool: this scene needs a ${t}×${s} data texture, but this device caps texture dimensions at ${e} (about ${(e * t).toLocaleString("en-US")} pool splats). Lower the splat budget, or raise maxTextureDimension2D in the renderer's requiredLimits if the adapter advertises more.`
310
+ );
311
+ }
312
+ function us(s, e, t) {
313
+ let o = e, a = e + t;
314
+ const n = [];
315
+ for (const r of s.updateRanges) {
316
+ const i = r.start + r.count;
317
+ if (i < o || r.start > a) {
318
+ n.push(r);
319
+ continue;
320
+ }
321
+ o = Math.min(o, r.start), a = Math.max(a, i);
322
+ }
323
+ n.push({ start: o, count: a - o }), n.sort((r, i) => r.start - i.start), s.clearUpdateRanges();
324
+ for (const r of n) s.addUpdateRange(r.start, r.count);
325
+ }
326
+ const lt = 24, mt = lt * lt;
327
+ function zt(s, e) {
328
+ const t = Math.max(0, s);
329
+ if (t <= 0) return 0;
330
+ const o = Math.max(1e-4, e);
331
+ return 2 * Math.atan(0.5 * t / o);
332
+ }
333
+ function ds(s) {
334
+ const e = Math.max(1e-4, s.depth), t = Math.max(1e-4, s.focusDistance), o = zt(s.aperture, t);
335
+ if (o <= 0 || !(s.focalPx > 0)) return 0;
336
+ const a = Math.abs(e - t) / e, n = s.focalPx * Math.tan(0.5 * o), r = a * n, i = r * r, d = s.maxVariance ?? mt;
337
+ return Math.min(i, d);
338
+ }
339
+ function ms(s, e) {
340
+ return Math.sqrt(Math.max(0, s) / Math.max(1e-9, e));
341
+ }
342
+ function hs(s, e = { focusDistance: 10, aperture: 0 }) {
343
+ const t = typeof s.focusDistance == "number" && Number.isFinite(s.focusDistance) ? Math.max(1e-4, s.focusDistance) : e.focusDistance, o = typeof s.aperture == "number" && Number.isFinite(s.aperture) ? Math.max(0, s.aperture) : e.aperture;
344
+ return { focusDistance: t, aperture: o };
345
+ }
346
+ const ut = 1024, Ut = 1e30, Vt = 0.35 * 0.35;
347
+ function Ot(s, e, t, o) {
348
+ const a = S(1, 0, 0), n = S(0, 1, 0), r = S(0, 0, 1), i = s.mul(a), d = s.mul(n), c = s.mul(r), T = i.x, D = d.y, y = c.z, q = i.cross(d), C = d.cross(c), m = c.cross(i), v = q.length(), L = C.length(), J = m.length(), le = v.greaterThanEqual(L).and(v.greaterThanEqual(J)), ue = L.greaterThan(v).and(L.greaterThanEqual(J)), de = le.select(q, ue.select(C, m)), u = de.div(de.length().max(1e-12)), x = u.dot(s.mul(u)), F = T.min(D).min(y).min(x).max(1e-12).mul(o), j = ye(S(F, 0, 0), S(0, F, 0), S(0, 0, F));
349
+ return s.mul(w(1).sub(t)).add(j.mul(t));
350
+ }
351
+ function Lt(s, e, t) {
352
+ const o = s.min(e);
353
+ return {
354
+ lambda1: ce(s, o, t),
355
+ lambda2: ce(e, o, t)
356
+ };
357
+ }
358
+ function _t(s, e, t, o, a) {
359
+ const n = o.div(a).pow(2), r = s.min(e).min(n), i = ce(s, r, t), d = ce(e, r, t), c = o.greaterThan(0);
360
+ return {
361
+ lambda1: c.select(i, s),
362
+ lambda2: c.select(d, e)
363
+ };
364
+ }
365
+ function fs(s) {
366
+ return s;
367
+ }
368
+ function ps() {
369
+ return xe(new h.Vector3());
370
+ }
371
+ function ht(s, e, t) {
372
+ const o = e.mul(N(4)), a = s.element(o), n = s.element(o.add(N(1))), r = s.element(o.add(N(2))), i = s.element(o.add(N(3))), d = a.xyz.mul(t.x).add(n.xyz.mul(t.y)).add(r.xyz.mul(t.z)).add(i.xyz), c = ye(a.xyz, n.xyz, r.xyz);
373
+ return { worldCenter: d, linear: c };
374
+ }
375
+ function Nt(s) {
376
+ return [0, 3, 8, 15][s] ?? 0;
377
+ }
378
+ function ft(s, e, t) {
379
+ if (s.mode === "palette") {
380
+ const n = _(e.covarianceBTexture, t).z.toInt(), r = n.mod(N(64)).mul(N(Nt(s.bands))), i = n.div(N(64));
381
+ return (d) => _(s.paletteTexture, He(r.add(N(d)), i)).xyz;
382
+ }
383
+ const o = s.textures.map(
384
+ (n) => _(n, t).toVar()
385
+ ), a = s.range.max.sub(s.range.min);
386
+ return (n) => {
387
+ const r = o[n >> 2], i = [r.x, r.y, r.z, r.w][n & 3], d = S(
388
+ i.bitAnd(P(2047)).toFloat().div(2047),
389
+ i.shiftRight(P(11)).bitAnd(P(1023)).toFloat().div(1023),
390
+ i.shiftRight(P(21)).bitAnd(P(2047)).toFloat().div(2047)
391
+ );
392
+ return s.range.min.add(a.mul(d));
393
+ };
394
+ }
395
+ const we = 0.4886025119029199, X = [
396
+ 1.0925484305920792,
397
+ -1.0925484305920792,
398
+ 0.31539156525252005,
399
+ -1.0925484305920792,
400
+ 0.5462742152960396
401
+ ], O = [
402
+ -0.5900435899266435,
403
+ 2.890611442640554,
404
+ -0.4570457994644658,
405
+ 0.3731763325901154,
406
+ -0.4570457994644658,
407
+ 1.445305721320277,
408
+ -0.5900435899266435
409
+ ];
410
+ function gs(s, e, t, o) {
411
+ const a = o.x, n = o.y, r = o.z, i = ft(s, e, t), d = i(0).mul(n.mul(-we)).add(i(1).mul(r.mul(we))).add(i(2).mul(a.mul(-we)));
412
+ if (s.bands === 1) return d;
413
+ const c = a.mul(a), T = n.mul(n), D = r.mul(r), y = d.add(i(3).mul(a.mul(n).mul(X[0]))).add(i(4).mul(n.mul(r).mul(X[1]))).add(i(5).mul(D.mul(2).sub(c).sub(T).mul(X[2]))).add(i(6).mul(a.mul(r).mul(X[3]))).add(i(7).mul(c.sub(T).mul(X[4])));
414
+ return s.bands === 2 ? y : y.add(i(8).mul(n.mul(c.mul(3).sub(T)).mul(O[0]))).add(i(9).mul(a.mul(n).mul(r).mul(O[1]))).add(i(10).mul(n.mul(D.mul(4).sub(c).sub(T)).mul(O[2]))).add(i(11).mul(r.mul(D.mul(2).sub(c.mul(3)).sub(T.mul(3))).mul(O[3]))).add(i(12).mul(a.mul(D.mul(4).sub(c).sub(T)).mul(O[4]))).add(i(13).mul(r.mul(c.sub(T)).mul(O[5]))).add(i(14).mul(a.mul(c.sub(T.mul(3))).mul(O[6])));
415
+ }
416
+ function xs(s, e, t) {
417
+ const { textures: o, sh: a, uniforms: n, settings: r, pick: i } = t, d = N(Fe), c = w(ut), T = -0.5 * r.maxStdDev * r.maxStdDev, D = Ct("splatIndex", "float").toInt(), y = He(D.mod(d), D.div(d)), q = _(o.colorsTexture, y), C = _(o.centersTexture, y).xyz, m = t.sourcePlacement, v = m ? ht(
418
+ m.columns,
419
+ _(m.sourceIdTexture, y).r.toInt(),
420
+ C
421
+ ) : null, L = v ? v.worldCenter : C, J = a === null ? null : (() => {
422
+ const b = v ? v.linear.inverse().mul(L.sub(n.localCameraPosition)).normalize() : L.sub(n.localCameraPosition).normalize(), f = b.x, g = b.y, B = b.z, p = ft(a, o, y), U = p(0).mul(g.mul(-we)).add(p(1).mul(B.mul(we))).add(p(2).mul(f.mul(-we)));
423
+ if (a.bands === 1) return U;
424
+ const A = f.mul(f), E = g.mul(g), M = B.mul(B), z = U.add(p(3).mul(f.mul(g).mul(X[0]))).add(p(4).mul(g.mul(B).mul(X[1]))).add(p(5).mul(M.mul(2).sub(A).sub(E).mul(X[2]))).add(p(6).mul(f.mul(B).mul(X[3]))).add(p(7).mul(A.sub(E).mul(X[4])));
425
+ return a.bands === 2 ? z : z.add(p(8).mul(g.mul(A.mul(3).sub(E)).mul(O[0]))).add(p(9).mul(f.mul(g).mul(B).mul(O[1]))).add(p(10).mul(g.mul(M.mul(4).sub(A).sub(E)).mul(O[2]))).add(
426
+ p(11).mul(
427
+ B.mul(M.mul(2).sub(A.mul(3)).sub(E.mul(3))).mul(O[3])
428
+ )
429
+ ).add(p(12).mul(f.mul(M.mul(4).sub(A).sub(E)).mul(O[4]))).add(p(13).mul(B.mul(A.sub(E)).mul(O[5]))).add(p(14).mul(f.mul(A.sub(E.mul(3))).mul(O[6])));
430
+ })(), le = J === null ? q : Q(q.rgb.add(J).clamp(0, 1), q.a), ue = () => {
431
+ const b = _(o.covarianceATexture, y), f = _(o.covarianceBTexture, y), g = ye(
432
+ S(b.x.add(1e-8), b.y, b.z),
433
+ S(b.y, b.w.add(1e-8), f.x),
434
+ S(b.z, f.x, f.y.add(1e-8))
435
+ ), p = (v ? v.linear.mul(g).mul(v.linear.transpose()) : g).inverse(), U = n.localCameraPosition.sub(L), A = p.mul(p.mul(U)).normalize();
436
+ return A.mul(A.dot(U).sign());
437
+ }, de = (b) => {
438
+ const f = t.channels.get(b);
439
+ if (!f)
440
+ throw new Error(
441
+ `SplatMesh: a modifier reads channel "${b}", which is not defined. Call defineChannel("${b}") before assigning the modifier.`
442
+ );
443
+ return _(f.texture, y).r;
444
+ }, u = Bt(t.modifiers, n.localCameraPosition, {
445
+ index: D,
446
+ localCenter: L,
447
+ sourceCenter: C,
448
+ sourceToLocal: v == null ? void 0 : v.linear,
449
+ color: le,
450
+ makeNormal: ue,
451
+ makeChannel: de
452
+ }), x = re(
453
+ r.srgbOutput ? u.color : Pt(u.color, h.SRGBColorSpace)
454
+ ), R = re(Ne.xy), F = e === "pick" ? re(w(0), "pickViewDepth") : null, j = re(w(1), "vOpacityCompensation"), W = r.lodAlpha ? re(w(r.maxStdDev), "vAdjustedStdDev") : null, H = r.lodAlpha ? re(w(1), "vAlpha2") : null, me = r.lodAlpha ? re(w(1), "vVisualOpacity") : null;
455
+ if (s.vertexNode = $(() => {
456
+ const b = u.offset === null ? L : L.add(u.offset), f = je.mul(Q(b, 1)).toVar(), g = kt.mul(f).toVar(), B = Q(0, 0, 2, 1).toVar(), p = e === "pick" ? 1.2 + 2 * ut : 1.2, U = g.w.mul(p), A = g.z.greaterThan(U.negate()).and(g.x.abs().lessThan(U)).and(g.y.abs().lessThan(U)), E = u.visible === null ? A : A.and(u.visible);
457
+ return be(E, () => {
458
+ F && F.assign(f.z.negate());
459
+ const M = _(o.covarianceATexture, y), z = _(o.covarianceBTexture, y), Y = ye(
460
+ S(M.x, M.y, M.z),
461
+ S(M.y, M.w, z.x),
462
+ S(M.z, z.x, z.y)
463
+ ), se = v ? v.linear.mul(Y).mul(v.linear.transpose()) : Y;
464
+ let ne = u.rotation === null ? se : u.rotation.mul(se).mul(u.rotation.transpose());
465
+ if (u.isotropicCovarianceMix !== null) {
466
+ const k = u.isotropicVarianceScale ?? w(Vt);
467
+ ne = Ot(
468
+ ne,
469
+ S(0, 0, 1),
470
+ u.isotropicCovarianceMix,
471
+ k
472
+ );
473
+ }
474
+ const he = w(1).div(f.z), Ae = he.mul(he), Me = S(
475
+ n.focal.x.mul(he),
476
+ 0,
477
+ n.focal.x.negate().mul(f.x).mul(Ae)
478
+ ), ze = S(
479
+ 0,
480
+ n.focal.y.mul(he),
481
+ n.focal.y.negate().mul(f.y).mul(Ae)
482
+ ), Ce = je.toMat3().transpose(), fe = Ce.mul(Me), pe = Ce.mul(ze), Pe = fe.dot(ne.mul(fe)), ke = pe.dot(ne.mul(pe)), Ke = fe.dot(ne.mul(pe)), Ue = u.scaleSquared === null ? Pe : Pe.mul(u.scaleSquared), Ve = u.scaleSquared === null ? ke : ke.mul(u.scaleSquared), ve = u.scaleSquared === null ? Ke : Ke.mul(u.scaleSquared), Xe = f.z.negate().max(1e-4), Ze = n.dofFocusDistance.max(1e-4), pt = n.dofAperture.max(0).mul(0.5).div(Ze).atan(), gt = Xe.sub(Ze).abs().div(Xe), xt = n.focal.x.mul(pt.tan()), Qe = gt.mul(xt), Je = Qe.mul(Qe).min(w(mt)), Re = r.projectedFilterProfile === "lcc" ? 0.1 : 0.3, Be = Ue.add(Re).add(Je), Oe = Ve.add(Re).add(Je), Ee = ve, bt = Be.mul(Oe).sub(Ee.mul(Ee)).max(1e-9), Ye = (r.antialias || r.projectedFilterProfile === "lcc" ? Ue.mul(Ve).sub(ve.mul(ve)).max(0) : Ue.add(Re).mul(Ve.add(Re)).sub(ve.mul(ve)).max(1e-9)).div(bt).sqrt();
483
+ j.assign(
484
+ u.isotropicCovarianceMix === null ? Ye : ce(Ye, w(1), u.isotropicCovarianceMix)
485
+ );
486
+ const et = Be.add(Oe).mul(0.5), tt = te(Be.sub(Oe).mul(0.5), Ee).length();
487
+ let ee = et.add(tt), ge = et.sub(tt).max(0);
488
+ if (u.isotropicCovarianceMix !== null) {
489
+ const k = Lt(
490
+ ee,
491
+ ge,
492
+ u.isotropicCovarianceMix
493
+ );
494
+ if (ee = k.lambda1, ge = k.lambda2, u.isotropicScreenRadiusPx !== null) {
495
+ const V = _t(
496
+ ee,
497
+ ge,
498
+ u.isotropicCovarianceMix,
499
+ u.isotropicScreenRadiusPx,
500
+ w(r.maxStdDev)
501
+ );
502
+ ee = V.lambda1, ge = V.lambda2;
503
+ }
504
+ }
505
+ const Le = te(Ee, ee.sub(Be)).add(te(1e-6, 0)).normalize();
506
+ let Ie = w(r.maxStdDev);
507
+ if (r.lodAlpha && W && H && me) {
508
+ const k = le.a, V = k.mul(2), Z = V.mul(4).sub(3).min(5);
509
+ Ie = V.greaterThan(1).select(
510
+ w(r.maxStdDev).add(Z.sub(1).mul(0.7)),
511
+ w(r.maxStdDev)
512
+ ), W.assign(Ie), H.assign(V), me.assign(
513
+ k.greaterThan(0).select(u.color.a.div(k.max(1e-8)), w(1))
514
+ );
515
+ }
516
+ const wt = r.maxAspect && r.maxAspect > 0 ? ee.min(ge.mul(r.maxAspect * r.maxAspect)) : ee, st = w(r.minSplatSizePx ?? 0), nt = Le.mul(
517
+ wt.sqrt().mul(Ie).min(c).max(st)
518
+ ), ot = te(Le.y, Le.x.negate()).mul(
519
+ ge.sqrt().mul(Ie).min(c).max(st)
520
+ ), _e = () => {
521
+ const k = nt.mul(Ne.x).add(ot.mul(Ne.y)), V = g.xy.div(g.w);
522
+ B.assign(
523
+ Q(
524
+ V.add(k.mul(2).div(n.viewport)),
525
+ g.z.div(g.w),
526
+ 1
527
+ )
528
+ );
529
+ };
530
+ let oe;
531
+ if (r.foveationMode === "page-table")
532
+ oe = null;
533
+ else if (r.foveationMode === "frontier") {
534
+ const k = f.z.negate(), Z = M.x.add(M.w).add(z.y).max(0).mul(1 / 3).sqrt().mul(2), G = z.w, ae = G.lessThan(0), at = G.abs(), vt = at.equal(0).select(w(Ut), at), rt = n.pixelScaleLimit.mul(k), St = ae.select(w(0), Z);
535
+ oe = vt.greaterThan(rt).and(St.lessThanEqual(rt));
536
+ } else {
537
+ const k = r.maxScreenRadiusPx ?? 0, V = r.minScreenRadiusPx ?? 0, Z = ee.sqrt().mul(r.maxStdDev);
538
+ let G = null;
539
+ if (k > 0 && (G = Z.lessThanEqual(n.screenBandMax)), V > 0) {
540
+ const ae = Z.greaterThan(n.screenBandMin);
541
+ G = G ? G.and(ae) : ae;
542
+ }
543
+ oe = G;
544
+ }
545
+ if (r.performanceProfile === "smooth") {
546
+ const k = nt.length(), V = ot.length(), Z = u.color.a, G = Z.greaterThanEqual(1 / 255).and(k.max(V).mul(2).greaterThanEqual(2)).and(Z.mul(k).mul(V).greaterThanEqual(3)), ae = u.isotropicCovarianceMix === null ? G : G.or(u.isotropicCovarianceMix.greaterThan(0));
547
+ be(oe ? ae.and(oe) : ae, _e);
548
+ } else oe ? be(oe, _e) : _e();
549
+ }), B;
550
+ })(), e === "display")
551
+ s.fragmentNode = $(() => {
552
+ const b = R.dot(R);
553
+ qe(b.greaterThan(1));
554
+ let f;
555
+ if (r.lodAlpha && W && H && me) {
556
+ const fe = b.mul(W.mul(W).mul(-0.5)).exp(), pe = H.mul(4).sub(3).min(5), Pe = pe.mul(pe).sub(1).mul(1 / Math.E).exp(), ke = fe.oneMinus().pow(Pe).oneMinus();
557
+ f = H.greaterThan(1).select(ke, fe.mul(H)).mul(me);
558
+ } else
559
+ f = b.mul(T).exp().mul(x.a);
560
+ const g = f.mul(j), B = Se(n.relightMap, Te), p = n.relightSoftness.div(n.viewport.x.max(1)), U = n.relightSoftness.div(n.viewport.y.max(1)), A = B, E = Se(n.relightMap, Te.add(te(p, 0))), M = Se(n.relightMap, Te.add(te(p.negate(), 0))), z = Se(n.relightMap, Te.add(te(0, U))), Y = Se(n.relightMap, Te.add(te(0, U.negate()))), se = A.a.add(E.a).add(M.a).add(z.a).add(Y.a).max(1e-4), ne = A.rgb.mul(A.a).add(E.rgb.mul(E.a)).add(M.rgb.mul(M.a)).add(z.rgb.mul(z.a)).add(Y.rgb.mul(Y.a)).div(se), he = se.mul(0.2), Ae = Q(ne, he), Me = n.relightSoftness.greaterThan(0.5).select(Ae, B), ze = ce(
561
+ S(n.relightBackground),
562
+ Me.rgb.mul(n.relightBrightness),
563
+ Me.a
564
+ ), Ce = ce(x.rgb, x.rgb.mul(ze), n.relightBlend);
565
+ return Q(Ce.mul(g), g);
566
+ })(), s.transparent = !0, s.depthTest = !0, s.depthWrite = !1, s.side = h.DoubleSide, s.blending = h.CustomBlending, s.blendSrc = h.OneFactor, s.blendDst = h.OneMinusSrcAlphaFactor, s.blendSrcAlpha = h.OneFactor, s.blendDstAlpha = h.OneMinusSrcAlphaFactor, s.toneMapped = !1;
567
+ else {
568
+ if (!i)
569
+ throw new Error("applySplatMaterialGraph in 'pick' mode requires pick uniforms.");
570
+ s.fragmentNode = $(() => {
571
+ const b = R.dot(R);
572
+ qe(b.greaterThan(1));
573
+ let f;
574
+ if (r.lodAlpha && W && H && me) {
575
+ const M = b.mul(W.mul(W).mul(-0.5)).exp(), z = H.mul(4).sub(3).min(5), Y = z.mul(z).sub(1).mul(1 / Math.E).exp(), se = M.oneMinus().pow(Y).oneMinus();
576
+ f = H.greaterThan(1).select(se, M.mul(H)).mul(me);
577
+ } else
578
+ f = b.mul(T).exp().mul(x.a);
579
+ const g = f.mul(j);
580
+ qe(g.lessThan(i.alphaThreshold));
581
+ const p = F.sub(i.near).div(i.far.sub(i.near)).clamp(0, 1).mul(16777215), U = p.div(65536).floor(), A = p.mod(65536).div(256).floor(), E = p.mod(256).floor();
582
+ return Q(U.div(255), A.div(255), E.div(255), 1);
583
+ })(), s.transparent = !1, s.depthTest = !0, s.depthWrite = !0, s.side = h.DoubleSide, s.blending = h.NoBlending, s.toneMapped = !1;
584
+ }
585
+ }
586
+ function qt(s, e) {
587
+ const t = s.elements;
588
+ return e * Math.hypot(t[2], t[6], t[10]);
589
+ }
590
+ function Wt(s, e) {
591
+ const t = s.backend;
592
+ return !t || t.isWebGPUBackend !== !0 || typeof t.has != "function" || typeof t.get != "function" || !t.has(e) ? !1 : t.get(e).buffer !== void 0;
593
+ }
594
+ function Gt(s) {
595
+ const e = s.array, t = e.byteLength;
596
+ if (t === 0) return 0;
597
+ const o = e.constructor;
598
+ return s.array = new o(0), t;
599
+ }
600
+ class $t {
601
+ constructor(e) {
602
+ l(this, "pending");
603
+ /** Released attributes and the `version` they carried when released. */
604
+ l(this, "released", /* @__PURE__ */ new Map());
605
+ l(this, "releasedBytesValue", 0);
606
+ l(this, "warnedDrift", !1);
607
+ this.pending = [...e];
608
+ }
609
+ /** Nothing left to release. */
610
+ get settled() {
611
+ return this.pending.length === 0;
612
+ }
613
+ /** Bytes still mirrored on the JS heap. */
614
+ get pendingBytes() {
615
+ let e = 0;
616
+ for (const t of this.pending) e += t.array.byteLength;
617
+ return e;
618
+ }
619
+ /** Bytes freed so far. Diagnostic. */
620
+ get releasedBytes() {
621
+ return this.releasedBytesValue;
622
+ }
623
+ /**
624
+ * Releases every pending mirror three has uploaded, and checks the ones
625
+ * already released for version drift. Idempotent and cheap once settled.
626
+ *
627
+ * @returns Bytes freed by this call.
628
+ */
629
+ release(e) {
630
+ if (this.checkDrift(), this.pending.length === 0) return 0;
631
+ let t = 0;
632
+ for (let o = this.pending.length - 1; o >= 0; o--) {
633
+ const a = this.pending[o];
634
+ Wt(e, a) && (t += Gt(a), this.released.set(a, a.version), this.pending.splice(o, 1));
635
+ }
636
+ return this.releasedBytesValue += t, t;
637
+ }
638
+ /**
639
+ * A released attribute whose `version` moved means someone added a CPU write
640
+ * to a buffer this class promised was GPU-only. Three would then upload the
641
+ * zero-length array - a legal no-op - and the data would simply never reach
642
+ * the GPU. Warn once, so that failure is visible rather than a silent wrong
643
+ * render.
644
+ */
645
+ checkDrift() {
646
+ if (!(this.warnedDrift || this.released.size === 0)) {
647
+ for (const [e, t] of this.released)
648
+ if (e.version !== t) {
649
+ this.warnedDrift = !0, Rt(
650
+ `StorageMirrorReleaser: storage attribute "${e.name || "unnamed"}" was written from the CPU after its mirror was released; that write will not reach the GPU. Remove it from the releaser's attribute list.`
651
+ );
652
+ return;
653
+ }
654
+ }
655
+ }
656
+ }
657
+ const K = class K {
658
+ constructor(e) {
659
+ l(this, "kind", "counting");
660
+ l(this, "renderer");
661
+ l(this, "clearPass");
662
+ l(this, "histogramPass");
663
+ l(this, "scanBlocksPass");
664
+ l(this, "scanBlockSumsPass");
665
+ l(this, "addBlockSumOffsetsPass");
666
+ l(this, "addOffsetsPass");
667
+ l(this, "scatterPass");
668
+ /** All stages in dependency order, submitted as one WebGPU compute pass. */
669
+ l(this, "sortPasses");
670
+ /** Sorter-owned working buffers, released on {@link dispose}. */
671
+ l(this, "workingAttributes");
672
+ /** Frees the JS mirrors three keeps behind the GPU-only working buffers. */
673
+ l(this, "mirrors");
674
+ /** Set by {@link dispose}; makes a second dispose a no-op. */
675
+ l(this, "disposed", !1);
676
+ /** Row 2 of the model-view matrix; view-space z = row2 · (position, 1). */
677
+ l(this, "viewRow2", xe(new h.Vector4()));
678
+ l(this, "depthMin", xe(0));
679
+ l(this, "depthScale", xe(0));
680
+ /** Active splat count; a float compares exactly for counts < 2²⁴. */
681
+ l(this, "activeCount", xe(0));
682
+ /** Highest bucket index this sort uses; see {@link effectiveBucketCount}. */
683
+ l(this, "bucketMax", xe(0));
684
+ l(this, "viewCenter", new h.Vector3());
685
+ const { renderer: t, capacity: o, centersTexture: a, dataTextureWidth: n, centersBuffer: r, perSource: i } = e, { BUCKET_COUNT: d, BLOCK_SIZE: c } = K;
686
+ if (!a && !r)
687
+ throw new Error("ComputeSorter: provide centersTexture or centersBuffer.");
688
+ if (a && n === void 0)
689
+ throw new Error("ComputeSorter: dataTextureWidth is required with centersTexture.");
690
+ if (r && i)
691
+ throw new Error("ComputeSorter: work-buffer centers are already in world space.");
692
+ this.renderer = t;
693
+ const T = new h.StorageBufferAttribute(new Uint32Array(d), 1), D = new h.StorageBufferAttribute(
694
+ new Uint32Array(d / c),
695
+ 1
696
+ ), y = new h.StorageBufferAttribute(
697
+ new Uint32Array(d / c / c),
698
+ 1
699
+ ), q = new h.StorageBufferAttribute(new Uint32Array(o), 1);
700
+ this.workingAttributes = [
701
+ T,
702
+ D,
703
+ y,
704
+ q
705
+ ], this.mirrors = new $t(this.workingAttributes);
706
+ const C = ie(T, "uint", d).toAtomic(), m = ie(D, "uint", d / c), v = ie(
707
+ y,
708
+ "uint",
709
+ d / c / c
710
+ ), L = ie(q, "uint", o), J = ie(e.sourceIndexAttribute, "uint", o), le = ie(e.splatIndexAttribute, "float", o), ue = r ? ie(r, "vec4", o) : null;
711
+ this.clearPass = $(() => {
712
+ We(C.element(I), P(0));
713
+ })().compute(d, [c]), this.histogramPass = $(() => {
714
+ be(w(I).lessThan(this.activeCount), () => {
715
+ const u = N(J.element(I)), x = a ? He(
716
+ u.mod(N(n)),
717
+ u.div(N(n))
718
+ ) : null, R = ue ? ue.element(u).xyz : _(a, x).xyz, F = i ? ht(
719
+ i.columns,
720
+ N(_(i.sourceIdTexture, x).r),
721
+ R
722
+ ).worldCenter : R, W = this.viewRow2.xyz.dot(F).add(this.viewRow2.w).sub(this.depthMin).mul(this.depthScale).clamp(0, this.bucketMax).toUint();
723
+ L.element(I).assign(W), it(C.element(W), P(1));
724
+ });
725
+ })().compute(o, [c]), this.scanBlocksPass = $(() => {
726
+ const u = I.mul(P(c)).toVar(), x = P(0).toVar();
727
+ Ge(c, ({ i: R }) => {
728
+ const F = C.element(u.add(P(R))), j = ct(F).toVar();
729
+ We(F, x), x.addAssign(j);
730
+ }), m.element(I).assign(x);
731
+ })().compute(d / c, [64]), this.scanBlockSumsPass = $(() => {
732
+ const u = I.mul(P(c)).toVar(), x = P(0).toVar();
733
+ Ge(c, ({ i: R }) => {
734
+ const F = m.element(u.add(P(R))), j = F.toVar();
735
+ F.assign(x), x.addAssign(j);
736
+ }), v.element(I).assign(x);
737
+ })().compute(d / c / c, [64]);
738
+ const de = $(() => {
739
+ be(I.equal(P(0)), () => {
740
+ const u = P(0).toVar();
741
+ Ge(d / c / c, ({ i: x }) => {
742
+ const R = v.element(x).toVar();
743
+ v.element(x).assign(u), u.addAssign(R);
744
+ });
745
+ });
746
+ })().compute(1, [64]);
747
+ this.addBlockSumOffsetsPass = $(() => {
748
+ m.element(I).addAssign(v.element(I.div(P(c))));
749
+ })().compute(d / c, [c]), this.addOffsetsPass = $(() => {
750
+ const u = C.element(I), x = m.element(I.shiftRight(P(Math.log2(c))));
751
+ We(u, ct(u).add(x));
752
+ })().compute(d, [c]), this.scatterPass = $(() => {
753
+ be(w(I).lessThan(this.activeCount), () => {
754
+ const u = J.element(I), x = L.element(I), R = it(C.element(x), P(1));
755
+ le.element(R).assign(w(u));
756
+ });
757
+ })().compute(o, [c]), this.sortPasses = [
758
+ this.clearPass,
759
+ this.histogramPass,
760
+ this.scanBlocksPass,
761
+ this.scanBlockSumsPass,
762
+ de,
763
+ this.addBlockSumOffsetsPass,
764
+ this.addOffsetsPass,
765
+ this.scatterPass
766
+ ];
767
+ }
768
+ /**
769
+ * Buckets to actually use for `activeCount` splats, rounded up to a power of
770
+ * two so block indexing stays exact.
771
+ *
772
+ * The histogram is allocated once for the pool's worst case, but clearing and
773
+ * scanning all 2²² buckets costs the same whether one splat is resident or
774
+ * four million - a fixed per-sort bill that dominates on a mobile GPU when
775
+ * the pool is only partly filled (a streaming scene ramping up, or any small
776
+ * scene). Sizing the dispatch to the live splat count keeps the design's
777
+ * ~1-bucket-per-splat depth resolution, so ordering is unaffected, while
778
+ * skipping work on buckets no splat can land in.
779
+ */
780
+ effectiveBucketCount(e) {
781
+ const o = 2 ** Math.ceil(Math.log2(Math.max(1, e)));
782
+ return Math.min(Math.max(o, K.MIN_BUCKET_COUNT), K.BUCKET_COUNT);
783
+ }
784
+ sort(e, t, o) {
785
+ if (t === 0) return !0;
786
+ const a = e.elements;
787
+ this.viewRow2.value.set(a[2], a[6], a[10], a[14]), this.activeCount.value = t;
788
+ const n = this.effectiveBucketCount(t);
789
+ this.viewCenter.copy(o.center).applyMatrix4(e);
790
+ const r = qt(e, o.radius), i = this.viewCenter.z - r, d = this.viewCenter.z + r;
791
+ this.depthMin.value = i, this.depthScale.value = (n - 1) / (d - i || 1), this.bucketMax.value = n - 1;
792
+ const c = n / K.BLOCK_SIZE;
793
+ return this.histogramPass.count = t, this.scatterPass.count = t, this.clearPass.count = n, this.scanBlocksPass.count = c, this.scanBlockSumsPass.count = c / K.BLOCK_SIZE, this.addBlockSumOffsetsPass.count = c, this.addOffsetsPass.count = n, this.renderer.compute(this.sortPasses), this.mirrors.settled || this.mirrors.release(this.renderer), !0;
794
+ }
795
+ dispose() {
796
+ if (!this.disposed) {
797
+ this.disposed = !0;
798
+ for (const e of this.sortPasses) e.dispose();
799
+ jt(this.renderer, this.workingAttributes);
800
+ }
801
+ }
802
+ };
803
+ l(K, "BUCKET_COUNT", 1 << 22), l(K, "BLOCK_SIZE", 256), /**
804
+ * Smallest bucket count a sort will dispatch. Below this the fixed passes
805
+ * are already cheap, and the floor keeps every block-scan index exact.
806
+ */
807
+ l(K, "MIN_BUCKET_COUNT", 65536);
808
+ let dt = K;
809
+ function jt(s, e) {
810
+ const t = s._attributes;
811
+ if (t)
812
+ for (const o of e) t.delete(o);
813
+ }
814
+ const Ht = 2e6, Kt = 5e6, Xt = 8e6, Zt = 1e-6;
815
+ function Qt(s) {
816
+ if (s !== void 0 && (!Number.isFinite(s) || s < 0))
817
+ throw new RangeError(
818
+ "SplatMesh sortIntervalMs must be a finite number greater than or equal to 0."
819
+ );
820
+ return s;
821
+ }
822
+ function Jt(s, e = !1) {
823
+ return s < Ht ? e ? 33 : 0 : s < Kt ? e ? 66 : 50 : s < Xt ? e ? 133 : 100 : 1e3 / 6;
824
+ }
825
+ class bs {
826
+ constructor(e, t = !1) {
827
+ l(this, "sortIntervalMs");
828
+ l(this, "isMobile");
829
+ l(this, "previousModelView", new h.Matrix4());
830
+ l(this, "hasPreviousModelView", !1);
831
+ l(this, "legacyWasMoving", !1);
832
+ l(this, "forcePending", !0);
833
+ l(this, "lastAcceptedAt", -1 / 0);
834
+ l(this, "acceptedCount", 0);
835
+ this.sortIntervalMs = Qt(e), this.isMobile = t;
836
+ }
837
+ /** Forces the next changed or content-invalidated pose to bypass throttling. */
838
+ invalidate() {
839
+ this.forcePending = !0;
840
+ }
841
+ /**
842
+ * Content changes replace pool indices underneath the current draw order.
843
+ * They must bypass cadence so a newly active range never renders through a
844
+ * stale sort while the camera is moving.
845
+ */
846
+ invalidateContent() {
847
+ this.forcePending = !0;
848
+ }
849
+ /**
850
+ * Whether an invalidation is still waiting for an accepted sort. The WebGL2
851
+ * worker path consults this directly: it has no cadence, but a content swap
852
+ * under a stationary camera must still trigger a re-sort - the swap reset
853
+ * the draw list to unsorted active order, and without this the scene would
854
+ * render in that unsorted order until the camera next moved (visible
855
+ * blend-order flicker on every streaming swap).
856
+ */
857
+ hasPendingForce() {
858
+ return this.forcePending;
859
+ }
860
+ /**
861
+ * Returns whether a sort should be submitted at this timestamp.
862
+ */
863
+ shouldSubmit(e, t, o, a) {
864
+ return this.shouldSubmitLegacy(e, t, o, a);
865
+ }
866
+ /**
867
+ * Commits timing state only after the sorter accepts a submission.
868
+ */
869
+ markAccepted(e) {
870
+ this.lastAcceptedAt = e, this.acceptedCount++, this.forcePending = !1;
871
+ }
872
+ /** Internal diagnostics for the demo HUD; it does not alter scheduling. */
873
+ snapshot() {
874
+ return { acceptedCount: this.acceptedCount, lastAcceptedAt: this.lastAcceptedAt };
875
+ }
876
+ shouldSubmitLegacy(e, t, o, a) {
877
+ let n = !1;
878
+ if (this.hasPreviousModelView) {
879
+ const i = Yt(e, this.previousModelView) > Zt;
880
+ n = this.legacyWasMoving && !i, this.legacyWasMoving = i;
881
+ } else
882
+ this.hasPreviousModelView = !0;
883
+ this.previousModelView.copy(e);
884
+ const r = this.sortIntervalMs ?? Jt(o, this.isMobile);
885
+ return this.forcePending ? !0 : e.equals(t) ? !1 : n ? !0 : r === 0 || a - this.lastAcceptedAt >= r;
886
+ }
887
+ }
888
+ function Yt(s, e) {
889
+ let t = 0;
890
+ for (let o = 0; o < 16; o++)
891
+ t = Math.max(t, Math.abs(s.elements[o] - e.elements[o]));
892
+ return t;
893
+ }
894
+ const $e = new h.Vector2();
895
+ function ws(s, e) {
896
+ var d;
897
+ const t = e.xr;
898
+ if ((t == null ? void 0 : t.isPresenting) !== !0 || typeof t.getCamera != "function") return null;
899
+ t.cameraAutoUpdate !== !1 && typeof t.updateCamera == "function" && t.updateCamera(s);
900
+ const o = t.getCamera(), a = (d = o.cameras) == null ? void 0 : d[0];
901
+ if (!a) return null;
902
+ const n = a.viewport;
903
+ let r = (n == null ? void 0 : n.z) ?? 0, i = (n == null ? void 0 : n.w) ?? 0;
904
+ return (!(r > 0) || !(i > 0)) && (e.getDrawingBufferSize($e), r = $e.x, i = $e.y), { head: o, eye: a, width: r, height: i };
905
+ }
906
+ function vs(s) {
907
+ return s.isArrayCamera === !0;
908
+ }
909
+ function Ss(s, e = {}) {
910
+ const t = s.backend.isWebGPUBackend === !0, o = [...e.requiredFeatures ?? [], ...t ? ["webgpu"] : []], a = e.optionalFeatures ?? [];
911
+ return {
912
+ ...e,
913
+ ...o.length > 0 ? { requiredFeatures: o } : {},
914
+ ...a.length > 0 ? { optionalFeatures: a } : {}
915
+ };
916
+ }
917
+ const es = 1, ts = 2, ss = 1, ns = 0;
918
+ function Ts(s, e = {
919
+ blend: es,
920
+ brightness: ts,
921
+ background: ss,
922
+ softness: ns
923
+ }) {
924
+ const t = s.blend !== void 0 ? s.blend : e.blend, o = s.brightness !== void 0 ? s.brightness : e.brightness, a = s.background !== void 0 ? s.background : e.background, n = s.softness !== void 0 ? s.softness : e.softness;
925
+ return {
926
+ blend: Number.isFinite(t) ? Math.min(1, Math.max(0, t)) : e.blend,
927
+ brightness: Number.isFinite(o) ? Math.max(0, o) : e.brightness,
928
+ background: Number.isFinite(a) ? Math.max(0, a) : e.background,
929
+ softness: Number.isFinite(n) ? Math.min(8, Math.max(0, n)) : e.softness
930
+ };
931
+ }
932
+ function ys() {
933
+ const s = new Uint8Array([255, 255, 255, 255]), e = new h.DataTexture(s, 1, 1);
934
+ return e.needsUpdate = !0, e.magFilter = h.NearestFilter, e.minFilter = h.NearestFilter, e.generateMipmaps = !1, e;
935
+ }
936
+ export {
937
+ xs as A,
938
+ Qt as B,
939
+ dt as C,
940
+ ss as D,
941
+ De as E,
942
+ ps as F,
943
+ Et as G,
944
+ Nt as H,
945
+ It as I,
946
+ us as J,
947
+ lt as M,
948
+ $t as S,
949
+ bs as W,
950
+ es as a,
951
+ ts as b,
952
+ ns as c,
953
+ mt as d,
954
+ Fe as e,
955
+ cs as f,
956
+ zt as g,
957
+ Ft as h,
958
+ hs as i,
959
+ Ts as j,
960
+ ds as k,
961
+ ms as l,
962
+ ys as m,
963
+ ls as n,
964
+ gs as o,
965
+ Bt as p,
966
+ fs as q,
967
+ jt as r,
968
+ Vt as s,
969
+ Ot as t,
970
+ Lt as u,
971
+ qt as v,
972
+ _t as w,
973
+ Ss as x,
974
+ ws as y,
975
+ vs as z
976
+ };
977
+ //# sourceMappingURL=relighting-Tiwep8yd.js.map