@voluma/vlam 0.3.2 → 0.3.4
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.
- package/README.md +2 -2
- package/dist/core/index.d.ts +1 -1
- package/dist/formats/lcc.js +276 -277
- package/dist/formats/lcc.js.map +1 -1
- package/dist/formats/rad/index.d.ts +1 -1
- package/dist/formats/rad/parse-rad.d.ts +1 -1
- package/dist/formats/rad.js.map +1 -1
- package/dist/lod-scheduler-ChoZyEeq.js +466 -0
- package/dist/lod-scheduler-ChoZyEeq.js.map +1 -0
- package/dist/streaming/lod-scheduler.d.ts +32 -0
- package/dist/streaming/lod-source.d.ts +15 -9
- package/dist/streaming/streamed-splat-mesh.d.ts +38 -22
- package/dist/streaming.js +950 -918
- package/dist/streaming.js.map +1 -1
- package/package.json +1 -1
- package/dist/lod-scheduler-B0a_uBlv.js +0 -383
- package/dist/lod-scheduler-B0a_uBlv.js.map +0 -1
package/dist/streaming.js
CHANGED
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
1
|
+
var Fe = Object.defineProperty;
|
|
2
|
+
var Me = (l, i, e) => i in l ? Fe(l, i, { enumerable: !0, configurable: !0, writable: !0, value: e }) : l[i] = e;
|
|
3
|
+
var d = (l, i, e) => Me(l, typeof i != "symbol" ? i + "" : i, e);
|
|
4
4
|
import { h as Be, f as W, a as Pe, l as ke } from "./splat-budget-DuVZspPQ.js";
|
|
5
5
|
import * as w from "three/webgpu";
|
|
6
6
|
import { S as Ee, a as ie, y as xe } from "./splat-mesh-CsLOQb08.js";
|
|
7
|
-
import { L as We, r as C } from "./lod-scheduler-
|
|
8
|
-
import { S as q, t as ee, r as Ae, i as
|
|
7
|
+
import { L as We, r as C } from "./lod-scheduler-ChoZyEeq.js";
|
|
8
|
+
import { S as q, t as ee, r as Ae, i as D, a as _ } from "./loading-wLo8vRbA.js";
|
|
9
9
|
import { y as Le } from "./relighting-Tiwep8yd.js";
|
|
10
10
|
import { C as Ve } from "./chunk-loader-DlNwggfG.js";
|
|
11
|
-
import { s as
|
|
11
|
+
import { s as Te } from "./sh-pack-D5wAe5gg.js";
|
|
12
12
|
import { w as E } from "./logging-BfPdd7NJ.js";
|
|
13
|
-
import { r as
|
|
14
|
-
const
|
|
15
|
-
function _e(
|
|
16
|
-
return
|
|
17
|
-
adds: [
|
|
13
|
+
import { r as Ge, M as Ne, a as ne, i as j } from "./splat-mesh-types-BZIko-_9.js";
|
|
14
|
+
const De = 32e3;
|
|
15
|
+
function _e(l) {
|
|
16
|
+
return l.map((i) => ({
|
|
17
|
+
adds: [i],
|
|
18
18
|
removes: [],
|
|
19
|
-
leafStart:
|
|
20
|
-
leafEnd:
|
|
21
|
-
addCount:
|
|
22
|
-
})).sort((
|
|
19
|
+
leafStart: i.leafStart,
|
|
20
|
+
leafEnd: i.leafEnd,
|
|
21
|
+
addCount: i.count
|
|
22
|
+
})).sort((i, e) => i.leafStart - e.leafStart);
|
|
23
23
|
}
|
|
24
|
-
function Oe(
|
|
25
|
-
const e = [...
|
|
24
|
+
function Oe(l, i) {
|
|
25
|
+
const e = [...l, ...i.map(([, n]) => n.run)];
|
|
26
26
|
if (e.length > 0 && e.every((n) => n.coverageGroup !== void 0)) {
|
|
27
|
-
const n = /* @__PURE__ */ new Map(), a = (
|
|
28
|
-
let c = n.get(
|
|
29
|
-
return c || (c = { adds: [], removes: [] }, n.set(
|
|
27
|
+
const n = /* @__PURE__ */ new Map(), a = (r) => {
|
|
28
|
+
let c = n.get(r);
|
|
29
|
+
return c || (c = { adds: [], removes: [] }, n.set(r, c)), c;
|
|
30
30
|
};
|
|
31
|
-
for (const
|
|
32
|
-
a(
|
|
33
|
-
for (const
|
|
34
|
-
a(
|
|
35
|
-
const
|
|
36
|
-
for (const
|
|
37
|
-
const c = /* @__PURE__ */ new Map(),
|
|
38
|
-
const v = h
|
|
31
|
+
for (const r of l)
|
|
32
|
+
a(r.coverageGroup).adds.push(r);
|
|
33
|
+
for (const r of i)
|
|
34
|
+
a(r[1].run.coverageGroup).removes.push(r);
|
|
35
|
+
const o = [];
|
|
36
|
+
for (const r of n.values()) {
|
|
37
|
+
const c = /* @__PURE__ */ new Map(), u = (h, g) => `${h}:${g}`, f = (h, g) => {
|
|
38
|
+
const v = u(h, g);
|
|
39
39
|
let m = c.get(v);
|
|
40
|
-
return m || (m = { adds: [], removes: [], leafStart:
|
|
40
|
+
return m || (m = { adds: [], removes: [], leafStart: h, leafEnd: g, addCount: 0 }, c.set(v, m)), m;
|
|
41
41
|
};
|
|
42
|
-
for (const
|
|
43
|
-
const g = f(
|
|
44
|
-
g.adds.push(
|
|
42
|
+
for (const h of r.adds) {
|
|
43
|
+
const g = f(h.leafStart, h.leafEnd);
|
|
44
|
+
g.adds.push(h), g.addCount += h.count;
|
|
45
45
|
}
|
|
46
|
-
for (const
|
|
47
|
-
const g =
|
|
48
|
-
v.removes.push(
|
|
46
|
+
for (const h of r.removes) {
|
|
47
|
+
const g = h[1].run, v = f(g.leafStart, g.leafEnd);
|
|
48
|
+
v.removes.push(h), v.leafStart = Math.min(v.leafStart, g.leafStart), v.leafEnd = Math.max(v.leafEnd, g.leafEnd);
|
|
49
49
|
}
|
|
50
|
-
|
|
50
|
+
o.push(...c.values());
|
|
51
51
|
}
|
|
52
|
-
return
|
|
52
|
+
return o.sort((r, c) => r.leafStart - c.leafStart);
|
|
53
53
|
}
|
|
54
54
|
const t = [
|
|
55
|
-
...
|
|
55
|
+
...l.map((n) => ({
|
|
56
56
|
start: n.leafStart,
|
|
57
57
|
end: n.leafEnd,
|
|
58
58
|
add: n,
|
|
59
59
|
remove: void 0
|
|
60
60
|
})),
|
|
61
|
-
...
|
|
61
|
+
...i.map((n) => ({
|
|
62
62
|
start: n[1].run.leafStart,
|
|
63
63
|
end: n[1].run.leafEnd,
|
|
64
64
|
add: void 0,
|
|
65
65
|
remove: n
|
|
66
66
|
}))
|
|
67
|
-
].sort((n, a) => n.start - a.start || a.end - n.end),
|
|
67
|
+
].sort((n, a) => n.start - a.start || a.end - n.end), s = [];
|
|
68
68
|
for (const n of t) {
|
|
69
|
-
const a =
|
|
70
|
-
(!a || n.start >= a.leafEnd) &&
|
|
69
|
+
const a = s[s.length - 1];
|
|
70
|
+
(!a || n.start >= a.leafEnd) && s.push({
|
|
71
71
|
adds: [],
|
|
72
72
|
removes: [],
|
|
73
73
|
leafStart: n.start,
|
|
74
74
|
leafEnd: n.end,
|
|
75
75
|
addCount: 0
|
|
76
76
|
});
|
|
77
|
-
const
|
|
78
|
-
|
|
77
|
+
const o = s[s.length - 1];
|
|
78
|
+
o.leafEnd = Math.max(o.leafEnd, n.end), n.add && (o.adds.push(n.add), o.addCount += n.add.count), n.remove && o.removes.push(n.remove);
|
|
79
79
|
}
|
|
80
|
-
return
|
|
80
|
+
return s;
|
|
81
81
|
}
|
|
82
|
-
function ae(
|
|
83
|
-
if (
|
|
84
|
-
const
|
|
85
|
-
return
|
|
82
|
+
function ae(l) {
|
|
83
|
+
if (l.adds.length === 0) return 1e3;
|
|
84
|
+
const i = -Math.max(...l.adds.map((e) => e.level));
|
|
85
|
+
return l.removes.length === 0 ? -1e3 + i : i;
|
|
86
86
|
}
|
|
87
|
-
function ze(
|
|
88
|
-
return
|
|
89
|
-
(
|
|
87
|
+
function ze(l) {
|
|
88
|
+
return l.length > 0 && l.every(
|
|
89
|
+
(i) => [...i.adds, ...i.removes.map(([, e]) => e.run)].every(
|
|
90
90
|
(e) => e.coverageGroup !== void 0
|
|
91
91
|
)
|
|
92
92
|
);
|
|
93
93
|
}
|
|
94
|
-
function Ue(
|
|
94
|
+
function Ue(l, i) {
|
|
95
95
|
const e = (n) => {
|
|
96
|
-
const a = [...n.adds, ...n.removes.map(([,
|
|
96
|
+
const a = [...n.adds, ...n.removes.map(([, o]) => o.run)];
|
|
97
97
|
return {
|
|
98
98
|
removeOnly: n.adds.length === 0 ? 1 : 0,
|
|
99
|
-
view: a.some((
|
|
100
|
-
finest: n.adds.some((
|
|
101
|
-
screen: Math.min(...a.map((
|
|
102
|
-
distance: Math.min(...a.map((
|
|
99
|
+
view: a.some((o) => o.inView !== !1) ? 0 : 1,
|
|
100
|
+
finest: n.adds.some((o) => o.level === 0) ? 0 : 1,
|
|
101
|
+
screen: Math.min(...a.map((o) => o.screenImportance ?? Number.POSITIVE_INFINITY)),
|
|
102
|
+
distance: Math.min(...a.map((o) => o.distance ?? Number.POSITIVE_INFINITY))
|
|
103
103
|
};
|
|
104
|
-
}, t = e(
|
|
105
|
-
return t.removeOnly -
|
|
104
|
+
}, t = e(l), s = e(i);
|
|
105
|
+
return t.removeOnly - s.removeOnly || t.view - s.view || t.finest - s.finest || t.screen - s.screen || t.distance - s.distance || l.leafStart - i.leafStart;
|
|
106
106
|
}
|
|
107
|
-
function re(
|
|
108
|
-
switch (
|
|
107
|
+
function re(l) {
|
|
108
|
+
switch (l) {
|
|
109
109
|
case "environment":
|
|
110
110
|
return -1;
|
|
111
111
|
case "finest-target":
|
|
@@ -118,19 +118,19 @@ function re(o) {
|
|
|
118
118
|
return 3;
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
function He(
|
|
122
|
-
return
|
|
121
|
+
function He(l) {
|
|
122
|
+
return l === "background" ? "base" : "priority";
|
|
123
123
|
}
|
|
124
|
-
function
|
|
125
|
-
return
|
|
124
|
+
function N(l, i) {
|
|
125
|
+
return l.coverageGroup < 0 ? `file:${i}` : l.phase === "finest-target" ? `cell:${l.coverageGroup}` : `slice:${l.coverageGroup}:${l.leafStart}:${l.leafEnd}`;
|
|
126
126
|
}
|
|
127
|
-
function $e(
|
|
128
|
-
const t = te(
|
|
129
|
-
for (const [n, a] of
|
|
127
|
+
function $e(l, i = 10, e = !1) {
|
|
128
|
+
const t = te(i), s = /* @__PURE__ */ new Map();
|
|
129
|
+
for (const [n, a] of l) {
|
|
130
130
|
if (a.phase === "environment") continue;
|
|
131
|
-
const
|
|
132
|
-
if (!
|
|
133
|
-
|
|
131
|
+
const o = N(a, n), r = s.get(o);
|
|
132
|
+
if (!r) {
|
|
133
|
+
s.set(o, {
|
|
134
134
|
distance: a.distance,
|
|
135
135
|
count: 1,
|
|
136
136
|
inView: a.inView,
|
|
@@ -139,55 +139,55 @@ function $e(o, s = 10, e = !1) {
|
|
|
139
139
|
});
|
|
140
140
|
continue;
|
|
141
141
|
}
|
|
142
|
-
a.distance <
|
|
142
|
+
a.distance < r.distance && (r.distance = a.distance), a.inView && (r.inView = !0), a.screenImportance < r.screenImportance && (r.screenImportance = a.screenImportance), a.phase === "finest-target" && (r.finest = !0), r.count++;
|
|
143
143
|
}
|
|
144
|
-
for (const [n, a] of
|
|
144
|
+
for (const [n, a] of l) {
|
|
145
145
|
if (a.phase === "environment") {
|
|
146
146
|
a.kind = "priority", a.groupDistance = 0, a.groupPending = 1, a.groupInView = !0, a.groupScreenImportance = Number.NEGATIVE_INFINITY, a.groupFinest = !0, a.groupId = "environment", a.groupClass = 0;
|
|
147
147
|
continue;
|
|
148
148
|
}
|
|
149
|
-
const
|
|
150
|
-
if (!
|
|
151
|
-
const c =
|
|
152
|
-
a.groupDistance =
|
|
149
|
+
const o = N(a, n), r = s.get(o);
|
|
150
|
+
if (!r) continue;
|
|
151
|
+
const c = r.inView ? 0 : r.distance <= t ? 1 : 2, u = c === 0 || c === 1 && e ? "priority" : "base";
|
|
152
|
+
a.groupDistance = r.distance, a.groupPending = r.count, a.groupInView = r.inView, a.groupScreenImportance = r.screenImportance, a.groupFinest = r.finest, a.groupId = o, a.groupClass = c, a.kind = u;
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
-
function te(
|
|
156
|
-
return
|
|
155
|
+
function te(l, i = 2) {
|
|
156
|
+
return l;
|
|
157
157
|
}
|
|
158
|
-
function Ye(
|
|
159
|
-
return
|
|
158
|
+
function Ye(l) {
|
|
159
|
+
return l.adds.some((i) => i.level === 0);
|
|
160
160
|
}
|
|
161
|
-
function qe(
|
|
162
|
-
if (
|
|
163
|
-
const t =
|
|
164
|
-
return
|
|
161
|
+
function qe(l, i, e = 2) {
|
|
162
|
+
if (l.level === 0) return "finest-target";
|
|
163
|
+
const t = l.distance ?? Number.POSITIVE_INFINITY;
|
|
164
|
+
return l.inView === !1 && t > te(i) ? "background" : "target";
|
|
165
165
|
}
|
|
166
|
-
function je(
|
|
167
|
-
const t =
|
|
168
|
-
return
|
|
166
|
+
function je(l, i, e = 2) {
|
|
167
|
+
const t = l.distance ?? Number.POSITIVE_INFINITY;
|
|
168
|
+
return l.inView === !1 && t > te(i) ? "background" : "coverage";
|
|
169
169
|
}
|
|
170
|
-
function oe(
|
|
171
|
-
const
|
|
172
|
-
if (!
|
|
173
|
-
const v =
|
|
174
|
-
{ phase: e, coverageGroup:
|
|
175
|
-
|
|
170
|
+
function oe(l, i, e, t) {
|
|
171
|
+
const s = t.distance ?? Number.POSITIVE_INFINITY, n = t.level, a = t.inView !== !1, o = t.coverageGroup ?? -1, r = t.screenImportance ?? Number.POSITIVE_INFINITY, c = He(e), u = l.get(i);
|
|
172
|
+
if (!u) {
|
|
173
|
+
const v = N(
|
|
174
|
+
{ phase: e, coverageGroup: o, leafStart: t.leafStart, leafEnd: t.leafEnd },
|
|
175
|
+
i
|
|
176
176
|
);
|
|
177
|
-
|
|
177
|
+
l.set(i, {
|
|
178
178
|
kind: c,
|
|
179
179
|
phase: e,
|
|
180
|
-
distance:
|
|
180
|
+
distance: s,
|
|
181
181
|
level: n,
|
|
182
182
|
inView: a,
|
|
183
|
-
coverageGroup:
|
|
183
|
+
coverageGroup: o,
|
|
184
184
|
leafStart: t.leafStart,
|
|
185
185
|
leafEnd: t.leafEnd,
|
|
186
|
-
screenImportance:
|
|
187
|
-
groupDistance:
|
|
186
|
+
screenImportance: r,
|
|
187
|
+
groupDistance: s,
|
|
188
188
|
groupPending: 1,
|
|
189
189
|
groupInView: a,
|
|
190
|
-
groupScreenImportance:
|
|
190
|
+
groupScreenImportance: r,
|
|
191
191
|
groupFinest: e === "finest-target",
|
|
192
192
|
groupId: v,
|
|
193
193
|
// Provisional; finalized in stampClassicFetchGroups().
|
|
@@ -195,41 +195,41 @@ function oe(o, s, e, t) {
|
|
|
195
195
|
});
|
|
196
196
|
return;
|
|
197
197
|
}
|
|
198
|
-
const f = re(e) < re(
|
|
199
|
-
(f ||
|
|
198
|
+
const f = re(e) < re(u.phase), h = e === u.phase && (s < u.distance || s === u.distance && n < u.level), g = e === u.phase && s === u.distance && n === u.level && a && !u.inView;
|
|
199
|
+
(f || h || g) && l.set(i, {
|
|
200
200
|
kind: c,
|
|
201
201
|
phase: e,
|
|
202
|
-
distance:
|
|
202
|
+
distance: s,
|
|
203
203
|
level: n,
|
|
204
|
-
inView: a ||
|
|
205
|
-
coverageGroup:
|
|
204
|
+
inView: a || u.inView,
|
|
205
|
+
coverageGroup: o >= 0 ? o : u.coverageGroup,
|
|
206
206
|
leafStart: t.leafStart,
|
|
207
207
|
leafEnd: t.leafEnd,
|
|
208
|
-
screenImportance:
|
|
209
|
-
groupDistance: Math.min(
|
|
210
|
-
groupPending:
|
|
211
|
-
groupInView: a ||
|
|
212
|
-
groupScreenImportance: Math.min(
|
|
213
|
-
groupFinest: e === "finest-target" ||
|
|
214
|
-
groupId:
|
|
215
|
-
groupClass:
|
|
208
|
+
screenImportance: r,
|
|
209
|
+
groupDistance: Math.min(s, u.groupDistance),
|
|
210
|
+
groupPending: u.groupPending,
|
|
211
|
+
groupInView: a || u.groupInView,
|
|
212
|
+
groupScreenImportance: Math.min(r, u.groupScreenImportance),
|
|
213
|
+
groupFinest: e === "finest-target" || u.groupFinest,
|
|
214
|
+
groupId: u.groupId,
|
|
215
|
+
groupClass: u.groupClass
|
|
216
216
|
});
|
|
217
217
|
}
|
|
218
|
-
function X(
|
|
219
|
-
const
|
|
220
|
-
return
|
|
218
|
+
function X(l, i, e, t) {
|
|
219
|
+
const s = l.groupDistance ?? l.distance, n = i.groupDistance ?? i.distance, a = l.groupPending ?? 1, o = i.groupPending ?? 1, r = l.groupId ?? N(l, e), c = i.groupId ?? N(i, t), u = l.groupClass ?? (l.inView ? 0 : 2), f = i.groupClass ?? (i.inView ? 0 : 2), h = l.groupScreenImportance ?? l.screenImportance, g = i.groupScreenImportance ?? i.screenImportance, v = l.groupFinest ? 0 : 1, m = i.groupFinest ? 0 : 1, b = (y) => y === "coverage" ? 0 : y === "background" ? 2 : 1, I = l.phase === "environment" ? 0 : 1, T = i.phase === "environment" ? 0 : 1;
|
|
220
|
+
return I - T || u - f || v - m || h - g || s - n || o - a || (r < c ? -1 : r > c ? 1 : 0) || b(l.phase) - b(i.phase) || l.level - i.level || e - t;
|
|
221
221
|
}
|
|
222
|
-
function K(
|
|
223
|
-
if (
|
|
222
|
+
function K(l, i, e) {
|
|
223
|
+
if (i < 0 || e < 0 || i + e > l.count)
|
|
224
224
|
throw new Error(
|
|
225
|
-
`Splat range [${
|
|
225
|
+
`Splat range [${i}, ${i + e}) exceeds its chunk's ${l.count} splats; the manifest and chunk data disagree.`
|
|
226
226
|
);
|
|
227
|
-
const t =
|
|
227
|
+
const t = l.shPacked;
|
|
228
228
|
return {
|
|
229
229
|
count: e,
|
|
230
|
-
positions:
|
|
231
|
-
colors:
|
|
232
|
-
covariances:
|
|
230
|
+
positions: l.positions.subarray(i * 3, (i + e) * 3),
|
|
231
|
+
colors: l.colors.subarray(i * 4, (i + e) * 4),
|
|
232
|
+
covariances: l.covariances.subarray(i * 6, (i + e) * 6),
|
|
233
233
|
// Per-splat SH is splat-major, so it slices like everything else. Palette
|
|
234
234
|
// shN (`chunk.sh`) is deliberately not carried: its labels index a
|
|
235
235
|
// per-file codebook the shared pool has no way to hold.
|
|
@@ -237,259 +237,259 @@ function K(o, s, e) {
|
|
|
237
237
|
shPacked: {
|
|
238
238
|
...t,
|
|
239
239
|
packed: t.packed.subarray(
|
|
240
|
-
|
|
241
|
-
(
|
|
240
|
+
i * le(t.bands),
|
|
241
|
+
(i + e) * le(t.bands)
|
|
242
242
|
)
|
|
243
243
|
}
|
|
244
244
|
} : {},
|
|
245
245
|
// Per-splat frontier `parent_size` (foveated `.rad`) slices splat-major like
|
|
246
246
|
// the rest; uploaded into `covarianceB.w` by the pool.
|
|
247
|
-
...
|
|
247
|
+
...l.frontierParent ? { frontierParent: l.frontierParent.subarray(i, i + e) } : {}
|
|
248
248
|
};
|
|
249
249
|
}
|
|
250
|
-
function le(
|
|
251
|
-
return
|
|
250
|
+
function le(l) {
|
|
251
|
+
return l === 1 ? 3 : l === 2 ? 8 : 15;
|
|
252
252
|
}
|
|
253
|
-
function Xe(
|
|
254
|
-
var
|
|
255
|
-
return
|
|
253
|
+
function Xe(l) {
|
|
254
|
+
var i;
|
|
255
|
+
return l.positions.byteLength + l.colors.byteLength + l.covariances.byteLength + // SH is the largest part of an LCC Quality chunk (64 B/splat against the
|
|
256
256
|
// base 32); omitting it would let the CPU cache run ~3x over its cap.
|
|
257
|
-
(((
|
|
257
|
+
(((i = l.shPacked) == null ? void 0 : i.packed.byteLength) ?? 0);
|
|
258
258
|
}
|
|
259
|
-
function Ke(
|
|
260
|
-
const
|
|
261
|
-
return
|
|
259
|
+
function Ke(l) {
|
|
260
|
+
const i = l.reason;
|
|
261
|
+
return i instanceof Error ? i : new DOMException("Aborted", "AbortError");
|
|
262
262
|
}
|
|
263
|
-
function Qe(
|
|
264
|
-
const
|
|
265
|
-
if (!Number.isInteger(
|
|
263
|
+
function Qe(l) {
|
|
264
|
+
const i = l ?? De;
|
|
265
|
+
if (!Number.isInteger(i) || i <= 0)
|
|
266
266
|
throw new RangeError("StreamedSplatMesh maxSplatsPerSwap must be a positive integer.");
|
|
267
|
-
return
|
|
267
|
+
return i;
|
|
268
268
|
}
|
|
269
|
-
function ce(
|
|
270
|
-
const
|
|
271
|
-
if (!Number.isFinite(
|
|
269
|
+
function ce(l) {
|
|
270
|
+
const i = l ?? 1;
|
|
271
|
+
if (!Number.isFinite(i) || i <= 0)
|
|
272
272
|
throw new RangeError("StreamedSplatMesh lodScale must be a positive finite number.");
|
|
273
|
-
return
|
|
273
|
+
return i;
|
|
274
274
|
}
|
|
275
275
|
function Je() {
|
|
276
276
|
return Be();
|
|
277
277
|
}
|
|
278
|
-
function Ze(
|
|
279
|
-
const e =
|
|
278
|
+
function Ze(l, i) {
|
|
279
|
+
const e = l;
|
|
280
280
|
if (typeof e != "object" || e === null)
|
|
281
281
|
throw new Error("Streamed SOG manifest is not a JSON object.");
|
|
282
282
|
if (e.version !== 1)
|
|
283
283
|
throw new Error(`Unsupported Streamed SOG manifest version: ${e.version} (expected 1).`);
|
|
284
|
-
if (!Array.isArray(e.filenames) || e.filenames.some((
|
|
284
|
+
if (!Array.isArray(e.filenames) || e.filenames.some((r) => typeof r != "string"))
|
|
285
285
|
throw new Error('Streamed SOG manifest "filenames" must be an array of strings.');
|
|
286
|
-
if (!Array.isArray(e.counts) || e.counts.some((
|
|
286
|
+
if (!Array.isArray(e.counts) || e.counts.some((r) => !Number.isSafeInteger(r) || r < 0))
|
|
287
287
|
throw new Error('Streamed SOG manifest "counts" must be an array of non-negative integers.');
|
|
288
288
|
if (!Number.isSafeInteger(e.lodLevels) || e.lodLevels < 1 || e.lodLevels > 64)
|
|
289
289
|
throw new Error(`Streamed SOG manifest declares an invalid lodLevels: ${e.lodLevels}.`);
|
|
290
|
-
const t = e.filenames.map((
|
|
291
|
-
(
|
|
292
|
-
), n = [], a = e.lodLevels,
|
|
293
|
-
for (;
|
|
294
|
-
const
|
|
295
|
-
if (typeof
|
|
290
|
+
const t = e.filenames.map((r) => r.replace(/\/?meta\.json$/, "/")), s = t.map(
|
|
291
|
+
(r) => i.resolve(r) ?? `${i.manifestUrl}#${r}`
|
|
292
|
+
), n = [], a = e.lodLevels, o = [e.tree];
|
|
293
|
+
for (; o.length > 0; ) {
|
|
294
|
+
const r = o.pop();
|
|
295
|
+
if (typeof r != "object" || r === null)
|
|
296
296
|
throw new Error("Streamed SOG manifest tree contains a malformed node.");
|
|
297
|
-
if (
|
|
298
|
-
if (!Array.isArray(
|
|
297
|
+
if (r.children) {
|
|
298
|
+
if (!Array.isArray(r.children) || r.children.length !== 2)
|
|
299
299
|
throw new Error("Streamed SOG manifest tree node must have exactly two children.");
|
|
300
|
-
|
|
300
|
+
o.push(r.children[1], r.children[0]);
|
|
301
301
|
continue;
|
|
302
302
|
}
|
|
303
303
|
const c = new Array(a).fill(
|
|
304
304
|
void 0
|
|
305
305
|
);
|
|
306
|
-
for (const [
|
|
307
|
-
const
|
|
308
|
-
|
|
306
|
+
for (const [u, f] of Object.entries(r.lods ?? {})) {
|
|
307
|
+
const h = Number(u);
|
|
308
|
+
h >= 0 && h < a && (et(f, e.filenames.length), c[h] = f);
|
|
309
309
|
}
|
|
310
|
-
n.push({ bounds: he(
|
|
310
|
+
n.push({ bounds: he(r.bound), lods: c });
|
|
311
311
|
}
|
|
312
312
|
return {
|
|
313
313
|
leaves: n,
|
|
314
|
-
chunkUrls:
|
|
314
|
+
chunkUrls: s,
|
|
315
315
|
chunkDirectories: t,
|
|
316
316
|
counts: e.counts,
|
|
317
317
|
lodLevels: a,
|
|
318
318
|
bounds: he(e.tree.bound)
|
|
319
319
|
};
|
|
320
320
|
}
|
|
321
|
-
function et(
|
|
322
|
-
if (typeof
|
|
321
|
+
function et(l, i) {
|
|
322
|
+
if (typeof l != "object" || l === null || !Number.isSafeInteger(l.file) || l.file < 0 || l.file >= i || !Number.isSafeInteger(l.offset) || l.offset < 0 || !Number.isSafeInteger(l.count) || l.count < 0)
|
|
323
323
|
throw new Error(
|
|
324
|
-
`Streamed SOG manifest leaf declares an invalid LOD range (file ${
|
|
324
|
+
`Streamed SOG manifest leaf declares an invalid LOD range (file ${l == null ? void 0 : l.file}, offset ${l == null ? void 0 : l.offset}, count ${l == null ? void 0 : l.count}).`
|
|
325
325
|
);
|
|
326
326
|
}
|
|
327
|
-
function he(
|
|
327
|
+
function he(l) {
|
|
328
328
|
return new w.Box3(
|
|
329
|
-
new w.Vector3(
|
|
330
|
-
new w.Vector3(
|
|
329
|
+
new w.Vector3(l.min[0], l.min[1], l.min[2]),
|
|
330
|
+
new w.Vector3(l.max[0], l.max[1], l.max[2])
|
|
331
331
|
);
|
|
332
332
|
}
|
|
333
|
-
function tt(
|
|
334
|
-
const
|
|
333
|
+
function tt(l, i, e, t = 0) {
|
|
334
|
+
const s = Ze(l, i), n = t >= 1 ? t : void 0, a = s.chunkUrls.map((o, r) => {
|
|
335
335
|
var f;
|
|
336
|
-
const c = (f =
|
|
337
|
-
if (!(!
|
|
336
|
+
const c = (f = s.chunkDirectories) == null ? void 0 : f[r], u = c ? i.directoryFiles(c) : null;
|
|
337
|
+
if (!(!u && !n))
|
|
338
338
|
return {
|
|
339
339
|
format: "sog",
|
|
340
|
-
...
|
|
340
|
+
...u ? { files: u } : {},
|
|
341
341
|
...n ? { sog: { packShBands: n } } : {}
|
|
342
342
|
};
|
|
343
343
|
});
|
|
344
344
|
return {
|
|
345
|
-
source: new We(
|
|
346
|
-
chunkUrls:
|
|
345
|
+
source: new We(s, e),
|
|
346
|
+
chunkUrls: s.chunkUrls,
|
|
347
347
|
...a.some(Boolean) ? { chunkOptions: a } : {},
|
|
348
348
|
...n ? { shBands: n } : {},
|
|
349
349
|
chunkKind: "directory",
|
|
350
350
|
// Streamed SOG chunks are unbundled directories
|
|
351
|
-
bounds:
|
|
352
|
-
pinnedFiles: it(
|
|
353
|
-
maxResidentSplats:
|
|
354
|
-
minimumCoverageSplats: st(
|
|
351
|
+
bounds: s.bounds,
|
|
352
|
+
pinnedFiles: it(s),
|
|
353
|
+
maxResidentSplats: s.counts[0] ?? e.budget,
|
|
354
|
+
minimumCoverageSplats: st(s)
|
|
355
355
|
};
|
|
356
356
|
}
|
|
357
|
-
function st(
|
|
358
|
-
let
|
|
359
|
-
for (const e of
|
|
357
|
+
function st(l) {
|
|
358
|
+
let i = 0;
|
|
359
|
+
for (const e of l.leaves)
|
|
360
360
|
for (let t = e.lods.length - 1; t >= 0; t--) {
|
|
361
|
-
const
|
|
362
|
-
if (
|
|
363
|
-
|
|
361
|
+
const s = e.lods[t];
|
|
362
|
+
if (s) {
|
|
363
|
+
i += s.count;
|
|
364
364
|
break;
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
|
-
return Math.max(1,
|
|
367
|
+
return Math.max(1, i);
|
|
368
368
|
}
|
|
369
|
-
function it(
|
|
370
|
-
const
|
|
371
|
-
for (const e of
|
|
369
|
+
function it(l) {
|
|
370
|
+
const i = /* @__PURE__ */ new Set();
|
|
371
|
+
for (const e of l.leaves)
|
|
372
372
|
for (let t = e.lods.length - 1; t >= 0; t--) {
|
|
373
|
-
const
|
|
374
|
-
if (
|
|
375
|
-
|
|
373
|
+
const s = e.lods[t];
|
|
374
|
+
if (s) {
|
|
375
|
+
i.add(s.file);
|
|
376
376
|
break;
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
|
-
return
|
|
379
|
+
return i;
|
|
380
380
|
}
|
|
381
|
-
function nt(
|
|
381
|
+
function nt(l, i) {
|
|
382
382
|
return {
|
|
383
|
-
manifestUrl:
|
|
384
|
-
resolve: (e) => new URL(e,
|
|
385
|
-
size: (e) => at(new URL(e,
|
|
383
|
+
manifestUrl: l,
|
|
384
|
+
resolve: (e) => new URL(e, l).href,
|
|
385
|
+
size: (e) => at(new URL(e, l).href, i),
|
|
386
386
|
directoryFiles: () => null,
|
|
387
387
|
dispose: () => {
|
|
388
388
|
}
|
|
389
389
|
};
|
|
390
390
|
}
|
|
391
|
-
async function at(
|
|
391
|
+
async function at(l, i) {
|
|
392
392
|
var e;
|
|
393
393
|
try {
|
|
394
|
-
const t = await fetch(
|
|
395
|
-
if (await
|
|
396
|
-
const
|
|
397
|
-
if (
|
|
394
|
+
const t = await fetch(l, { ...ee(i), method: "HEAD" });
|
|
395
|
+
if (await ue(t), t.ok) {
|
|
396
|
+
const s = t.headers.get("content-length");
|
|
397
|
+
if (s !== null) return de(Number(s));
|
|
398
398
|
} else if (t.status === 404)
|
|
399
399
|
return null;
|
|
400
400
|
} catch {
|
|
401
401
|
}
|
|
402
402
|
try {
|
|
403
|
-
const t = await fetch(
|
|
404
|
-
...ee(
|
|
405
|
-
headers: { ...(
|
|
403
|
+
const t = await fetch(l, {
|
|
404
|
+
...ee(i),
|
|
405
|
+
headers: { ...(i == null ? void 0 : i.headers) ?? {}, Range: "bytes=0-0" }
|
|
406
406
|
});
|
|
407
|
-
if (await
|
|
408
|
-
const
|
|
409
|
-
return
|
|
407
|
+
if (await ue(t), t.status !== 206) return null;
|
|
408
|
+
const s = (e = t.headers.get("content-range")) == null ? void 0 : e.split("/")[1];
|
|
409
|
+
return s === void 0 || s === "*" ? null : de(Number(s));
|
|
410
410
|
} catch {
|
|
411
411
|
return null;
|
|
412
412
|
}
|
|
413
413
|
}
|
|
414
|
-
async function
|
|
415
|
-
var
|
|
414
|
+
async function ue(l) {
|
|
415
|
+
var i;
|
|
416
416
|
try {
|
|
417
|
-
await ((
|
|
417
|
+
await ((i = l.body) == null ? void 0 : i.cancel());
|
|
418
418
|
} catch {
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
|
-
function
|
|
422
|
-
return Number.isSafeInteger(
|
|
421
|
+
function de(l) {
|
|
422
|
+
return Number.isSafeInteger(l) && l >= 0 ? l : null;
|
|
423
423
|
}
|
|
424
424
|
const rt = [
|
|
425
|
-
{ test: (
|
|
426
|
-
{ test: (
|
|
425
|
+
{ test: (l) => l.endsWith(".lcc2"), format: "lcc2" },
|
|
426
|
+
{ test: (l) => l.endsWith(".lcc"), format: "lcc" },
|
|
427
427
|
// The `.rad` header of a `--rad-chunked` set; `.radc` chunk files are not
|
|
428
428
|
// manifests (they end in `.radc`, so `endsWith('.rad')` excludes them).
|
|
429
|
-
{ test: (
|
|
430
|
-
{ test: (
|
|
429
|
+
{ test: (l) => l.endsWith(".rad"), format: "rad" },
|
|
430
|
+
{ test: (l) => l === "lod-meta.json", format: "streamed-sog" }
|
|
431
431
|
];
|
|
432
|
-
function ot(
|
|
433
|
-
const
|
|
434
|
-
for (const
|
|
435
|
-
const
|
|
436
|
-
c && Re(
|
|
432
|
+
function ot(l) {
|
|
433
|
+
const i = [];
|
|
434
|
+
for (const o of l.keys()) {
|
|
435
|
+
const r = $(o).toLowerCase(), c = rt.find((u) => u.test(r));
|
|
436
|
+
c && Re(o) === lt(l, c) && i.push({ path: o, format: c.format });
|
|
437
437
|
}
|
|
438
|
-
if (
|
|
438
|
+
if (i.length === 0)
|
|
439
439
|
throw new q(
|
|
440
440
|
"That folder has no streamed-scene manifest in it (expected a .lcc, .lcc2 or lod-meta.json file).",
|
|
441
441
|
{ phase: "manifest", url: "local-folder", retryable: !1 }
|
|
442
442
|
);
|
|
443
|
-
if (
|
|
444
|
-
const
|
|
443
|
+
if (i.length > 1) {
|
|
444
|
+
const o = i.map((r) => $(r.path)).join(", ");
|
|
445
445
|
throw new q(
|
|
446
|
-
`That folder holds more than one scene manifest (${
|
|
446
|
+
`That folder holds more than one scene manifest (${o}) - drop one scene at a time.`,
|
|
447
447
|
{ phase: "manifest", url: "local-folder", retryable: !1 }
|
|
448
448
|
);
|
|
449
449
|
}
|
|
450
|
-
const e =
|
|
451
|
-
const
|
|
452
|
-
if (
|
|
453
|
-
const c =
|
|
450
|
+
const e = i[0], t = e.path.includes("/") ? e.path.slice(0, e.path.lastIndexOf("/") + 1) : "", s = /* @__PURE__ */ new Map(), n = (o) => {
|
|
451
|
+
const r = s.get(o);
|
|
452
|
+
if (r !== void 0) return r;
|
|
453
|
+
const c = l.get(o);
|
|
454
454
|
if (!c) return null;
|
|
455
|
-
const
|
|
456
|
-
return
|
|
455
|
+
const u = URL.createObjectURL(c);
|
|
456
|
+
return s.set(o, u), u;
|
|
457
457
|
};
|
|
458
458
|
return { source: {
|
|
459
459
|
manifestUrl: n(e.path),
|
|
460
|
-
resolve: (
|
|
461
|
-
size: (
|
|
462
|
-
var
|
|
463
|
-
return Promise.resolve(((
|
|
460
|
+
resolve: (o) => n(t + Q(o)),
|
|
461
|
+
size: (o) => {
|
|
462
|
+
var r;
|
|
463
|
+
return Promise.resolve(((r = l.get(t + Q(o))) == null ? void 0 : r.size) ?? null);
|
|
464
464
|
},
|
|
465
|
-
directoryFiles: (
|
|
466
|
-
const
|
|
467
|
-
for (const
|
|
468
|
-
if (!
|
|
469
|
-
const f = n(
|
|
470
|
-
f && (c[
|
|
465
|
+
directoryFiles: (o) => {
|
|
466
|
+
const r = t + Q(o).replace(/\/?$/, "/"), c = {};
|
|
467
|
+
for (const u of l.keys()) {
|
|
468
|
+
if (!u.startsWith(r)) continue;
|
|
469
|
+
const f = n(u);
|
|
470
|
+
f && (c[u.slice(r.length)] = f);
|
|
471
471
|
}
|
|
472
472
|
return Object.keys(c).length > 0 ? c : null;
|
|
473
473
|
},
|
|
474
474
|
dispose: () => {
|
|
475
|
-
for (const
|
|
476
|
-
|
|
475
|
+
for (const o of s.values()) URL.revokeObjectURL(o);
|
|
476
|
+
s.clear();
|
|
477
477
|
}
|
|
478
478
|
}, format: e.format, name: $(e.path) };
|
|
479
479
|
}
|
|
480
|
-
function Q(
|
|
481
|
-
return
|
|
480
|
+
function Q(l) {
|
|
481
|
+
return l.replace(/^\.?\//, "");
|
|
482
482
|
}
|
|
483
|
-
function $(
|
|
484
|
-
return
|
|
483
|
+
function $(l) {
|
|
484
|
+
return l.slice(l.lastIndexOf("/") + 1);
|
|
485
485
|
}
|
|
486
|
-
function Re(
|
|
487
|
-
return
|
|
486
|
+
function Re(l) {
|
|
487
|
+
return l.split("/").length - 1;
|
|
488
488
|
}
|
|
489
|
-
function lt(
|
|
489
|
+
function lt(l, i) {
|
|
490
490
|
let e = 1 / 0;
|
|
491
|
-
for (const t of
|
|
492
|
-
|
|
491
|
+
for (const t of l.keys())
|
|
492
|
+
i.test($(t).toLowerCase()) && (e = Math.min(e, Re(t)));
|
|
493
493
|
return e;
|
|
494
494
|
}
|
|
495
495
|
const fe = {
|
|
@@ -497,17 +497,17 @@ const fe = {
|
|
|
497
497
|
coneFov: 120,
|
|
498
498
|
coneFoveate: 0.4,
|
|
499
499
|
behindFoveate: 0.2
|
|
500
|
-
},
|
|
501
|
-
function bt(
|
|
502
|
-
const
|
|
503
|
-
return Math.max(1, t) *
|
|
500
|
+
}, B = 2048, ct = 6e4, ht = 0.25, ut = 8, dt = 600, ft = 250, gt = 4, pt = 500, mt = 3, vt = 4e6, ge = 65536, St = 2 * 1024 * 1024 * 1024;
|
|
501
|
+
function bt(l) {
|
|
502
|
+
const i = 52 + (l.shBands ? 16 * Math.ceil(Te(l.shBands) / 4) : 0), t = (l.chunkSize === void 0 ? void 0 : l.chunkSize * l.chunkUrls.length) ?? l.contentSplatCount ?? l.maxResidentSplats;
|
|
503
|
+
return Math.max(1, t) * i;
|
|
504
504
|
}
|
|
505
505
|
class Y extends Ee {
|
|
506
|
-
constructor(e, t,
|
|
507
|
-
var
|
|
508
|
-
super({ capacity:
|
|
509
|
-
|
|
510
|
-
|
|
506
|
+
constructor(e, t, s, n, a, o = !1) {
|
|
507
|
+
var h, g, v;
|
|
508
|
+
super({ capacity: s }, n);
|
|
509
|
+
d(this, "scene");
|
|
510
|
+
d(this, "loader", new Ve());
|
|
511
511
|
/**
|
|
512
512
|
* Cap the *classic* (non-page-table) chunk cache evicts against.
|
|
513
513
|
*
|
|
@@ -515,67 +515,67 @@ class Y extends Ee {
|
|
|
515
515
|
* moves; without a budget it stays at the value `options.cpuCacheBytes` or the
|
|
516
516
|
* device default set at construction.
|
|
517
517
|
*/
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
518
|
+
d(this, "cpuCacheBytes");
|
|
519
|
+
d(this, "budgetValue");
|
|
520
|
+
d(this, "maximumBudget");
|
|
521
521
|
/** Spark's per-mesh `lodScale`; divides the page-table cut limit. */
|
|
522
|
-
|
|
522
|
+
d(this, "lodScaleValue");
|
|
523
523
|
/** Set once the governed budget has been reported as exceeding an explicit
|
|
524
524
|
* `foveationDrawBudget`, so the warning is issued at most once. */
|
|
525
|
-
|
|
526
|
-
|
|
525
|
+
d(this, "warnedDrawTargetCap", !1);
|
|
526
|
+
d(this, "stagedSwapsEnabled");
|
|
527
527
|
/** Classic LCC must keep old cell coverage while a replacement is pending. */
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
528
|
+
d(this, "neverRetireCoverageEarly");
|
|
529
|
+
d(this, "appendCap");
|
|
530
|
+
d(this, "onPerformanceEvent");
|
|
531
|
+
d(this, "compactionCount", 0);
|
|
532
|
+
d(this, "cache", /* @__PURE__ */ new Map());
|
|
533
533
|
/** Running byte total of {@link cache}; maintained by {@link cacheChunk}, eviction and dispose. */
|
|
534
|
-
|
|
534
|
+
d(this, "cacheBytesTotal", 0);
|
|
535
535
|
/** In-flight chunk fetches. The kind is kept so a weight change can shed the
|
|
536
536
|
* speculative ones without touching the detail that is actually on screen. */
|
|
537
|
-
|
|
537
|
+
d(this, "fetching", /* @__PURE__ */ new Map());
|
|
538
538
|
/** This mesh's camera-projected share of the scene's fetch bandwidth. */
|
|
539
|
-
|
|
539
|
+
d(this, "fetchWeight");
|
|
540
540
|
/** Scene-wide fetch arbitration, when the host shares one; see `requestChunk`. */
|
|
541
|
-
|
|
542
|
-
|
|
541
|
+
d(this, "fetchScheduler");
|
|
542
|
+
d(this, "fetchHandle");
|
|
543
543
|
/**
|
|
544
544
|
* Blob-URL dataset from {@link loadLocal}, owned by this mesh so its object
|
|
545
545
|
* URLs are revoked on {@link dispose} rather than leaking for the document's
|
|
546
546
|
* lifetime. Undefined for every network-loaded mesh.
|
|
547
547
|
*/
|
|
548
|
-
|
|
548
|
+
d(this, "localSource");
|
|
549
549
|
/** Scene-wide chunk-cache ceiling, when the host shares one. */
|
|
550
|
-
|
|
551
|
-
|
|
550
|
+
d(this, "cacheBudget");
|
|
551
|
+
d(this, "cacheBudgetHandle");
|
|
552
552
|
/**
|
|
553
553
|
* The cap this mesh's frontier worker is currently evicting against.
|
|
554
554
|
*
|
|
555
555
|
* Mirrored on the main thread so `applyCacheAllowance` can skip no-op posts
|
|
556
556
|
* and so `fetchCounts.cacheLimitBytes` stays truthful between plans.
|
|
557
557
|
*/
|
|
558
|
-
|
|
559
|
-
|
|
558
|
+
d(this, "cacheLimitBytes", 0);
|
|
559
|
+
d(this, "resident", /* @__PURE__ */ new Map());
|
|
560
560
|
/** Replacement runs hidden while their pool data is uploaded in bounded segments. */
|
|
561
|
-
|
|
561
|
+
d(this, "staged", /* @__PURE__ */ new Map());
|
|
562
562
|
/** Files awaiting a backoff retry after a transient fetch/decode error. */
|
|
563
|
-
|
|
563
|
+
d(this, "retrying", /* @__PURE__ */ new Map());
|
|
564
564
|
/** Files given up on after {@link MAX_CHUNK_ATTEMPTS} failures. */
|
|
565
|
-
|
|
565
|
+
d(this, "failedFiles", /* @__PURE__ */ new Set());
|
|
566
566
|
/**
|
|
567
567
|
* When true, each resident run writes its LOD `level` into the `lodLevel`
|
|
568
568
|
* float channel for false-color debug modifiers.
|
|
569
569
|
*/
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
570
|
+
d(this, "lodLevelDebug", !1);
|
|
571
|
+
d(this, "lodLevelChannelReady", !1);
|
|
572
|
+
d(this, "lodLevelScratch");
|
|
573
573
|
/** Desired-but-not-resident files this tick; protected from cache eviction. */
|
|
574
|
-
|
|
574
|
+
d(this, "neededFiles", /* @__PURE__ */ new Set());
|
|
575
575
|
/** Non-null in `foveationMode: 'page-table'`: the worker that owns the chunk
|
|
576
576
|
* cache + traversal + pager off the main thread, and the always-active slab it
|
|
577
577
|
* pages the returned frontier into. */
|
|
578
|
-
|
|
578
|
+
d(this, "frontierWorker");
|
|
579
579
|
/**
|
|
580
580
|
* The frontier's slots, as a list of equally sized pages rather than one
|
|
581
581
|
* contiguous run.
|
|
@@ -588,15 +588,15 @@ class Y extends Ee {
|
|
|
588
588
|
* (Spark's pager does the same thing one level down, binding fixed pages to
|
|
589
589
|
* `(source, chunk)` pairs.)
|
|
590
590
|
*/
|
|
591
|
-
|
|
591
|
+
d(this, "slabPages", []);
|
|
592
592
|
/** Most slots the slab may ever hold - the construction capacity. */
|
|
593
|
-
|
|
593
|
+
d(this, "slabCeiling", 0);
|
|
594
594
|
/** Slot count the worker's pager was last told about. */
|
|
595
|
-
|
|
595
|
+
d(this, "pagerSlots", 0);
|
|
596
596
|
/** Consecutive ticks the wave gate has held retirements back. */
|
|
597
|
-
|
|
597
|
+
d(this, "retireHeldTicks", 0);
|
|
598
598
|
/** Backing store for {@link planTimings}. */
|
|
599
|
-
|
|
599
|
+
d(this, "planTimingsValue", {
|
|
600
600
|
applyMs: 0,
|
|
601
601
|
worstApplyMs: 0,
|
|
602
602
|
writeMs: 0,
|
|
@@ -610,7 +610,7 @@ class Y extends Ee {
|
|
|
610
610
|
* they answer is about a *steady state* - "this keeps streaming after the view
|
|
611
611
|
* settled" - which a per-frame or windowed number cannot express.
|
|
612
612
|
*/
|
|
613
|
-
|
|
613
|
+
d(this, "fetchCountsValue", {
|
|
614
614
|
priority: 0,
|
|
615
615
|
base: 0,
|
|
616
616
|
sweep: 0,
|
|
@@ -626,55 +626,55 @@ class Y extends Ee {
|
|
|
626
626
|
* with the solved frontier cut and always relative to the original - scaling
|
|
627
627
|
* the live values repeatedly would drift. Null when the scene has no band.
|
|
628
628
|
*/
|
|
629
|
-
|
|
629
|
+
d(this, "frontierBandBase", null);
|
|
630
630
|
/**
|
|
631
631
|
* Splats per slab page for this mesh: {@link SLAB_PAGE_SPLATS}, or the whole
|
|
632
632
|
* capacity when that is smaller. Spark can use one fixed page size because
|
|
633
633
|
* its pool is a single large arena; here a mesh may be smaller than a page,
|
|
634
634
|
* and rounding it up to one would waste most of the reservation.
|
|
635
635
|
*/
|
|
636
|
-
|
|
636
|
+
d(this, "slabPageSplats", ge);
|
|
637
637
|
/** Target drawn-splat count for the page-table frontier; see the constructor. */
|
|
638
|
-
|
|
638
|
+
d(this, "pageTableDrawBudget", 0);
|
|
639
639
|
/** The unclamped draw target (`foveationDrawBudget` or the default), kept so
|
|
640
640
|
* `setBudget` can re-derive the effective draw budget when the pool budget
|
|
641
641
|
* moves (e.g. under a `BudgetGovernor`). */
|
|
642
|
-
|
|
642
|
+
d(this, "pageTableDrawTarget", 0);
|
|
643
643
|
/** Whether {@link pageTableDrawTarget} came from an explicit
|
|
644
644
|
* `foveationDrawBudget` - a caller-chosen hard cap worth warning about when a
|
|
645
645
|
* governed budget outgrows it, rather than the library's own default. */
|
|
646
|
-
|
|
646
|
+
d(this, "pageTableDrawTargetExplicit", !1);
|
|
647
647
|
/** Last frontier's drawn (non-degenerate) splat count - the true on-screen size
|
|
648
648
|
* in `page-table` mode, where the slab is fully "active" but mostly degenerate. */
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
649
|
+
d(this, "pageTableDrawn", 0);
|
|
650
|
+
d(this, "frontierConverged", !0);
|
|
651
|
+
d(this, "pendingFrontierSplats", 0);
|
|
652
|
+
d(this, "staleResidentSplats", 0);
|
|
653
|
+
d(this, "lastPlanAppends", 0);
|
|
654
|
+
d(this, "lastPlanMoves", 0);
|
|
655
|
+
d(this, "lastPlanGeneration", 0);
|
|
656
|
+
d(this, "lastPlanBudget", 0);
|
|
657
|
+
d(this, "lastPlanCamera", null);
|
|
658
|
+
d(this, "firstFrontierCamera", null);
|
|
659
659
|
/** Monotonic reschedule id; a stale plan (superseded by a newer request) is
|
|
660
660
|
* dropped. `pageTableInFlight` coalesces to one outstanding traversal. */
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
661
|
+
d(this, "pageTableSeq", 0);
|
|
662
|
+
d(this, "pageTableInFlight", !1);
|
|
663
|
+
d(this, "pageTableDisposed", !1);
|
|
664
664
|
/** Files whose data has been forwarded to the worker (so we don't refetch). */
|
|
665
|
-
|
|
665
|
+
d(this, "pageTableCachedFiles", /* @__PURE__ */ new Set());
|
|
666
666
|
/** Chunks the last frontier wanted but did not have, biggest-on-screen first.
|
|
667
667
|
* These outrank the background sweep - they are the detail actually on screen. */
|
|
668
|
-
|
|
668
|
+
d(this, "pageTableFetchPriority", []);
|
|
669
669
|
/** Frontier-cut target node size (px) and foveation ramp; see `frontierView`. */
|
|
670
|
-
|
|
671
|
-
|
|
670
|
+
d(this, "pageTableTargetPx", ie);
|
|
671
|
+
d(this, "pageTableFoveation", fe);
|
|
672
672
|
/** Drawing-buffer height, sampled in `update` so `reschedule` can derive the
|
|
673
673
|
* cut limit the same way the material does (`targetPx / focalY`). */
|
|
674
|
-
|
|
674
|
+
d(this, "pageTableViewportY", 0);
|
|
675
675
|
/** Frontier cut on foveated `size / distance`. Re-derived each reschedule once
|
|
676
676
|
* the drawing buffer is known; the initial value only covers the first frame. */
|
|
677
|
-
|
|
677
|
+
d(this, "pageTableLimit", 0.02);
|
|
678
678
|
/**
|
|
679
679
|
* Whether the worker's cache is sitting at its cap: sweeping past that point
|
|
680
680
|
* only evicts what the frontier is using.
|
|
@@ -686,51 +686,51 @@ class Y extends Ee {
|
|
|
686
686
|
* and is trimmed - and latching would kill its sweep for the session, so a
|
|
687
687
|
* mesh that went cold could never re-warm when the camera returned.
|
|
688
688
|
*/
|
|
689
|
-
|
|
689
|
+
d(this, "pageTableCacheAtLimit", !1);
|
|
690
690
|
/** Per-splat channels whose edits survive chunk eviction/reload (M7.6). */
|
|
691
|
-
|
|
691
|
+
d(this, "persistentChannels", /* @__PURE__ */ new Map());
|
|
692
692
|
/** Chunk-file index of the always-resident environment tile, if the scene ships one. */
|
|
693
|
-
|
|
693
|
+
d(this, "envFile");
|
|
694
694
|
/** Whether the environment tile should be visible; toggled live. */
|
|
695
|
-
|
|
695
|
+
d(this, "envEnabled");
|
|
696
696
|
/** Pool handle of the environment tile once it has loaded (kept for toggling). */
|
|
697
|
-
|
|
697
|
+
d(this, "envHandle");
|
|
698
698
|
/** Env splat count, measured when the tile decodes; 0 until then. */
|
|
699
|
-
|
|
699
|
+
d(this, "envSplatCount", 0);
|
|
700
700
|
/** Set when the env tile is larger than the whole pool - terminal, warned once. */
|
|
701
|
-
|
|
701
|
+
d(this, "envUnfit", !1);
|
|
702
702
|
/**
|
|
703
703
|
* Startup hold. `'capture'` waits for the first schedule after the host
|
|
704
704
|
* applies the final camera; `'holding'` freezes that coverage set.
|
|
705
705
|
*/
|
|
706
|
-
|
|
706
|
+
d(this, "initialRevealPhase", "off");
|
|
707
707
|
/** Which hold, if any, was armed at construction. Survives release for recapture. */
|
|
708
|
-
|
|
708
|
+
d(this, "initialRevealHold", "off");
|
|
709
709
|
/** Frozen nearby-detail / in-view coverage runs for {@link initialRevealPhase} `'holding'`. */
|
|
710
|
-
|
|
710
|
+
d(this, "frozenCriticalRuns", null);
|
|
711
711
|
/** Timestamp of the final-camera capture that began the current hold. */
|
|
712
|
-
|
|
713
|
-
|
|
712
|
+
d(this, "initialRevealStartedAt");
|
|
713
|
+
d(this, "initialRevealStateValue", { status: "disabled" });
|
|
714
714
|
/** Fetch settings this mesh was loaded with, reused for collision meshes. */
|
|
715
|
-
|
|
715
|
+
d(this, "requestOptions");
|
|
716
716
|
/** In-flight or settled collision load; see {@link loadCollisionMeshes}. */
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
717
|
+
d(this, "collisionTiles");
|
|
718
|
+
d(this, "collisionAbort");
|
|
719
|
+
d(this, "pendingWork", !0);
|
|
720
|
+
d(this, "lastScheduleTime", -1 / 0);
|
|
721
721
|
/** Reused leaf-coverage bitmap for {@link substituteCoverage}; grows only. */
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
this.scene = e, this.budgetValue = t, this.maximumBudget = n.maxBudget === void 0 ? t : Math.max(t, W(n.maxBudget)), this.lodScaleValue = ce(n.lodScale), this.stagedSwapsEnabled = n.experimentalStagedSwaps !== !1, this.neverRetireCoverageEarly =
|
|
726
|
-
const
|
|
727
|
-
|
|
722
|
+
d(this, "coverageScratch");
|
|
723
|
+
d(this, "lastCameraPos", new w.Vector3(1 / 0, 1 / 0, 1 / 0));
|
|
724
|
+
d(this, "lastCameraQuat", new w.Quaternion());
|
|
725
|
+
this.scene = e, this.budgetValue = t, this.maximumBudget = n.maxBudget === void 0 ? t : Math.max(t, W(n.maxBudget)), this.lodScaleValue = ce(n.lodScale), this.stagedSwapsEnabled = n.experimentalStagedSwaps !== !1, this.neverRetireCoverageEarly = o, this.appendCap = Qe(n.maxSplatsPerSwap);
|
|
726
|
+
const r = n.initialReveal === "hold-coverage" && this.scene.source.coverageRunsFor !== void 0, c = n.initialReveal === "hold-near-l0" && o;
|
|
727
|
+
r || c ? (this.initialRevealHold = r ? "hold-coverage" : "hold-near-l0", this.initialRevealPhase = "capture", this.initialRevealStateValue = {
|
|
728
728
|
status: "pending",
|
|
729
729
|
stagedSplats: 0,
|
|
730
730
|
totalSplats: 0,
|
|
731
731
|
readyGroups: 0,
|
|
732
732
|
totalGroups: 0
|
|
733
|
-
}) : (this.initialRevealHold = "off", this.initialRevealPhase = "off", this.initialRevealStateValue = { status: "disabled" }), this.onPerformanceEvent = n.onPerformanceEvent, this.cpuCacheBytes = n.cpuCacheBytes ?? Je(), this.requestOptions = n.request, this.envFile = (
|
|
733
|
+
}) : (this.initialRevealHold = "off", this.initialRevealPhase = "off", this.initialRevealStateValue = { status: "disabled" }), this.onPerformanceEvent = n.onPerformanceEvent, this.cpuCacheBytes = n.cpuCacheBytes ?? Je(), this.requestOptions = n.request, this.envFile = (h = e.environment) == null ? void 0 : h.file, this.envEnabled = n.environmentEnabled !== !1, this.fetchWeight = n.fetchWeight, this.fetchScheduler = n.fetchScheduler, this.cacheBudget = n.cacheBudget, this.fetchHandle = (g = this.fetchScheduler) == null ? void 0 : g.register({
|
|
734
734
|
// No weight supplied: claim an equal share rather than none, so a partly
|
|
735
735
|
// wired host degrades to round-robin instead of silently starving.
|
|
736
736
|
weight: () => {
|
|
@@ -742,7 +742,7 @@ class Y extends Ee {
|
|
|
742
742
|
},
|
|
743
743
|
shedFetches: (m) => this.abortFetches(m)
|
|
744
744
|
});
|
|
745
|
-
const
|
|
745
|
+
const u = j(n.foveationMode), f = u ? Math.max(
|
|
746
746
|
this.cpuCacheBytes,
|
|
747
747
|
Math.min(St, bt(e))
|
|
748
748
|
) : this.cpuCacheBytes;
|
|
@@ -757,13 +757,13 @@ class Y extends Ee {
|
|
|
757
757
|
},
|
|
758
758
|
ceilingBytes: f,
|
|
759
759
|
onAllowanceChanged: (m) => this.applyCacheAllowance(m)
|
|
760
|
-
}), this.cacheLimitBytes = this.cacheBudget && this.cacheBudgetHandle ? this.cacheBudget.allowanceFor(this.cacheBudgetHandle) : f,
|
|
760
|
+
}), this.cacheLimitBytes = this.cacheBudget && this.cacheBudgetHandle ? this.cacheBudget.allowanceFor(this.cacheBudgetHandle) : f, u || (this.cpuCacheBytes = this.cacheLimitBytes), this.fetchCountsValue.cacheLimitBytes = this.cacheLimitBytes, j(n.foveationMode)) {
|
|
761
761
|
if (!a)
|
|
762
762
|
throw new Error("StreamedSplatMesh: page-table foveation requires the frontier worker.");
|
|
763
763
|
this.pageTableDrawTarget = n.foveationDrawBudget ?? vt, this.pageTableDrawTargetExplicit = n.foveationDrawBudget !== void 0, this.pageTableDrawBudget = Math.min(t, this.pageTableDrawTarget), this.pageTableTargetPx = n.foveationTargetPx ?? ie, this.pageTableFoveation = { ...fe, ...n.frontierFoveation }, (n.minSplatScreenRadius !== void 0 || n.maxSplatScreenRadius !== void 0) && (this.frontierBandBase = {
|
|
764
764
|
min: n.minSplatScreenRadius ?? 0,
|
|
765
765
|
max: n.maxSplatScreenRadius ?? 0
|
|
766
|
-
}), this.slabPageSplats = Math.min(ge,
|
|
766
|
+
}), this.slabPageSplats = Math.min(ge, s), this.slabCeiling = s, this.syncSlabPages(this.pageTableDrawBudget), this.frontierWorker = new a(), this.frontierWorker.onmessage = (b) => this.applyFrontierPlan(b.data), this.pagerSlots = this.slabSlots, this.postToWorker({
|
|
767
767
|
type: "init",
|
|
768
768
|
capacity: this.pagerSlots,
|
|
769
769
|
chunkSize: e.chunkSize ?? 65536,
|
|
@@ -790,9 +790,9 @@ class Y extends Ee {
|
|
|
790
790
|
* failure, or a `DOMException` named `AbortError` when `options.signal` fires.
|
|
791
791
|
*/
|
|
792
792
|
static async load(e, t = {}) {
|
|
793
|
-
const
|
|
793
|
+
const s = Ae(e, t.baseUrl).href, n = s.toLowerCase(), a = t.format !== void 0 && t.format !== "auto" ? t.format : n.endsWith(".lcc2") ? "lcc2" : n.endsWith(".lcc") ? "lcc" : n.endsWith(".rad") ? "rad" : "streamed-sog";
|
|
794
794
|
return Y.fromSource(
|
|
795
|
-
nt(
|
|
795
|
+
nt(s, t.request),
|
|
796
796
|
a,
|
|
797
797
|
t
|
|
798
798
|
);
|
|
@@ -812,9 +812,9 @@ class Y extends Ee {
|
|
|
812
812
|
* `DOMException` named `AbortError` when `options.signal` fires.
|
|
813
813
|
*/
|
|
814
814
|
static async loadLocal(e, t = {}) {
|
|
815
|
-
let
|
|
815
|
+
let s;
|
|
816
816
|
try {
|
|
817
|
-
|
|
817
|
+
s = ot(e);
|
|
818
818
|
} catch (n) {
|
|
819
819
|
throw n instanceof q ? n : new q(n instanceof Error ? n.message : String(n), {
|
|
820
820
|
phase: "manifest",
|
|
@@ -824,42 +824,42 @@ class Y extends Ee {
|
|
|
824
824
|
});
|
|
825
825
|
}
|
|
826
826
|
try {
|
|
827
|
-
const n = await Y.fromSource(
|
|
828
|
-
return n.localSource =
|
|
827
|
+
const n = await Y.fromSource(s.source, s.format, t);
|
|
828
|
+
return n.localSource = s.source, n;
|
|
829
829
|
} catch (n) {
|
|
830
|
-
throw
|
|
830
|
+
throw s.source.dispose(), n;
|
|
831
831
|
}
|
|
832
832
|
}
|
|
833
833
|
/** Shared load path: fetch the manifest from a source, then build the scene. */
|
|
834
|
-
static async fromSource(e, t,
|
|
835
|
-
const n =
|
|
834
|
+
static async fromSource(e, t, s) {
|
|
835
|
+
const n = s.deviceProfile, a = W(s.budget, n, {
|
|
836
836
|
format: t,
|
|
837
|
-
...
|
|
838
|
-
}),
|
|
839
|
-
if (
|
|
837
|
+
...s.budgetCap === void 0 ? {} : { cap: s.budgetCap }
|
|
838
|
+
}), o = s.maxBudget === void 0 ? a : W(s.maxBudget, n);
|
|
839
|
+
if (o < a)
|
|
840
840
|
throw new RangeError(
|
|
841
|
-
`StreamedSplatMesh: maxBudget (${
|
|
841
|
+
`StreamedSplatMesh: maxBudget (${o}) must be >= budget (${a}).`
|
|
842
842
|
);
|
|
843
|
-
const
|
|
844
|
-
budget:
|
|
845
|
-
lodBaseDistance:
|
|
846
|
-
lodMultiplier:
|
|
847
|
-
}, c =
|
|
848
|
-
|
|
843
|
+
const r = {
|
|
844
|
+
budget: o,
|
|
845
|
+
lodBaseDistance: s.lodBaseDistance ?? 10,
|
|
846
|
+
lodMultiplier: s.lodMultiplier ?? 2
|
|
847
|
+
}, c = s.shBands ?? (Ge(s.performanceProfile, n) === "smooth" ? 0 : Ne), u = Pe(n), f = (s.allowFinestLevelLift === !0 || s.budget === void 0 && s.maxBudget === void 0) && s.budgetCap === void 0, h = s.signal;
|
|
848
|
+
h == null || h.throwIfAborted();
|
|
849
849
|
let g;
|
|
850
850
|
if (t === "rad")
|
|
851
851
|
try {
|
|
852
852
|
const { buildRadScene: p } = await import("./formats/rad.js");
|
|
853
|
-
g = await p(e,
|
|
853
|
+
g = await p(e, r, s.request, c, f);
|
|
854
854
|
} catch (p) {
|
|
855
|
-
throw
|
|
855
|
+
throw D(p) ? p : _(p, { phase: "manifest", url: e.manifestUrl });
|
|
856
856
|
}
|
|
857
857
|
else {
|
|
858
858
|
let p;
|
|
859
859
|
try {
|
|
860
|
-
p = await fetch(e.manifestUrl, ee(
|
|
860
|
+
p = await fetch(e.manifestUrl, ee(s.request, h));
|
|
861
861
|
} catch (S) {
|
|
862
|
-
throw
|
|
862
|
+
throw D(S) ? S : _(S, { phase: "fetch", url: e.manifestUrl });
|
|
863
863
|
}
|
|
864
864
|
if (!p.ok)
|
|
865
865
|
throw _(
|
|
@@ -869,45 +869,44 @@ class Y extends Ee {
|
|
|
869
869
|
try {
|
|
870
870
|
const S = await p.json();
|
|
871
871
|
if (t === "lcc2") {
|
|
872
|
-
const { buildLcc2Scene:
|
|
873
|
-
g =
|
|
872
|
+
const { buildLcc2Scene: F } = await import("./formats/lcc.js");
|
|
873
|
+
g = F(S, e, r, s.shBands ?? 0);
|
|
874
874
|
} else if (t === "lcc") {
|
|
875
|
-
const { buildLccScene:
|
|
876
|
-
g = await
|
|
875
|
+
const { buildLccScene: F } = await import("./formats/lcc.js");
|
|
876
|
+
g = await F(S, e, { ...r, shBands: c });
|
|
877
877
|
} else
|
|
878
|
-
g = tt(S, e,
|
|
878
|
+
g = tt(S, e, r, s.shBands ?? 0);
|
|
879
879
|
} catch (S) {
|
|
880
|
-
throw
|
|
880
|
+
throw D(S) ? S : _(S, { phase: "manifest", url: e.manifestUrl });
|
|
881
881
|
}
|
|
882
882
|
}
|
|
883
|
-
|
|
884
|
-
const v = (t === "lcc" || t === "rad") && f ? ke(
|
|
883
|
+
h == null || h.throwIfAborted();
|
|
884
|
+
const v = (t === "lcc" || t === "rad") && f ? ke(o, g.maxResidentSplats, n) : o, m = s.maxBudget === void 0 ? v : Math.min(a, v);
|
|
885
885
|
g.source.budget = m;
|
|
886
|
-
const b = Math.min(v, g.maxResidentSplats),
|
|
886
|
+
const b = Math.min(v, g.maxResidentSplats), I = s.experimentalStagedSwaps !== !1 ? 1.5 : 1.4, T = Math.max(
|
|
887
887
|
1,
|
|
888
|
-
Math.ceil(b *
|
|
888
|
+
Math.ceil(b * I / B)
|
|
889
889
|
), y = g.foveation ? ne(
|
|
890
|
-
|
|
890
|
+
s.foveationMode,
|
|
891
891
|
t === "rad" ? "page-table" : "frontier"
|
|
892
|
-
) :
|
|
892
|
+
) : s.foveationMode === void 0 ? void 0 : ne(s.foveationMode);
|
|
893
893
|
let A;
|
|
894
894
|
if (j(y)) {
|
|
895
|
-
A = (await import("./frontier-worker-CAnK_Cmu.js")).default,
|
|
895
|
+
A = (await import("./frontier-worker-CAnK_Cmu.js")).default, h == null || h.throwIfAborted();
|
|
896
896
|
const S = g.source;
|
|
897
897
|
S.needsParentSizes !== void 0 && (S.needsParentSizes = !1);
|
|
898
898
|
}
|
|
899
899
|
const R = new Y(
|
|
900
900
|
g,
|
|
901
901
|
m,
|
|
902
|
-
|
|
902
|
+
T * B,
|
|
903
903
|
{
|
|
904
|
-
...
|
|
905
|
-
// Classic
|
|
906
|
-
//
|
|
907
|
-
//
|
|
908
|
-
//
|
|
909
|
-
...t === "lcc" &&
|
|
910
|
-
...t === "lcc2" && i.initialReveal === void 0 ? { initialReveal: "hold-coverage" } : {},
|
|
904
|
+
...s,
|
|
905
|
+
// Classic `.lcc` and `.lcc2` wait for in-view coverage so first paint
|
|
906
|
+
// has no empty cells (classic nearby cells at L1, farther at coarsest).
|
|
907
|
+
// Keep every other format progressive, and let a caller explicitly
|
|
908
|
+
// request progressive or hold-near-l0.
|
|
909
|
+
...(t === "lcc" || t === "lcc2") && s.initialReveal === void 0 ? { initialReveal: "hold-coverage" } : {},
|
|
911
910
|
// The resolved ceiling, not the caller's raw option: it may have been
|
|
912
911
|
// lifted to a moderate capture's leaf count above.
|
|
913
912
|
maxBudget: v,
|
|
@@ -923,7 +922,7 @@ class Y extends Ee {
|
|
|
923
922
|
// compensation `α·√(detRaw/detBlur)`). Match that default for `.rad`: the
|
|
924
923
|
// 0.3 low-pass without the compensation makes splats too opaque (uniform
|
|
925
924
|
// blur) and leaves anisotropic splats bright (needle spikes).
|
|
926
|
-
antialias:
|
|
925
|
+
antialias: s.antialias ?? (t === "rad" ? !0 : void 0),
|
|
927
926
|
// Older XGRIDS LCC uses a smaller, compensated projected low-pass.
|
|
928
927
|
...t === "lcc" ? { projectedFilterProfile: "lcc" } : {},
|
|
929
928
|
// Match Spark's `.rad` render exactly: the LOD alpha encoding + merged-node
|
|
@@ -935,8 +934,8 @@ class Y extends Ee {
|
|
|
935
934
|
// same 4 ceiling `.rad` was the only format escaping. An explicit
|
|
936
935
|
// `maxStdDev` still wins, through `...options` above.
|
|
937
936
|
...t === "rad" ? {
|
|
938
|
-
lodAlpha:
|
|
939
|
-
...
|
|
937
|
+
lodAlpha: s.lodAlpha ?? !0,
|
|
938
|
+
...s.maxStdDev === void 0 && u !== void 0 ? { maxStdDev: u } : {}
|
|
940
939
|
} : {},
|
|
941
940
|
// A foveated scene renders whole chunks and picks the LOD cut per splat.
|
|
942
941
|
// `.rad` defaults to Spark's selected-index page table (only the frontier is
|
|
@@ -952,7 +951,7 @@ class Y extends Ee {
|
|
|
952
951
|
A,
|
|
953
952
|
t === "lcc"
|
|
954
953
|
), L = g.formatTransform ?? (R.orientation === "y-up" ? xe(t) : null);
|
|
955
|
-
return L && (R.matrix.copy(L), R.matrix.decompose(R.position, R.quaternion, R.scale), R.matrixWorldNeedsUpdate = !0),
|
|
954
|
+
return L && (R.matrix.copy(L), R.matrix.decompose(R.position, R.quaternion, R.scale), R.matrixWorldNeedsUpdate = !0), h != null && h.aborted && (R.dispose(), h.throwIfAborted()), R;
|
|
956
955
|
}
|
|
957
956
|
/** Slots the currently reserved pages can hold. */
|
|
958
957
|
get slabSlots() {
|
|
@@ -974,47 +973,47 @@ class Y extends Ee {
|
|
|
974
973
|
syncSlabPages(e) {
|
|
975
974
|
if (this.slabCeiling === 0) return;
|
|
976
975
|
const t = Math.max(this.slabPageSplats, Math.min(this.slabCeiling, e));
|
|
977
|
-
let
|
|
978
|
-
for (;
|
|
979
|
-
const n = Math.min(this.slabPageSplats, this.slabCeiling -
|
|
976
|
+
let s = this.slabSlots;
|
|
977
|
+
for (; s < t; ) {
|
|
978
|
+
const n = Math.min(this.slabPageSplats, this.slabCeiling - s);
|
|
980
979
|
if (n <= 0) break;
|
|
981
980
|
try {
|
|
982
981
|
this.slabPages.push(this.reserveInactiveRange(n));
|
|
983
982
|
} catch {
|
|
984
983
|
break;
|
|
985
984
|
}
|
|
986
|
-
|
|
985
|
+
s += n;
|
|
987
986
|
}
|
|
988
987
|
for (; this.slabPages.length > 1; ) {
|
|
989
988
|
const n = this.slabPages[this.slabPages.length - 1];
|
|
990
|
-
if (
|
|
991
|
-
this.slabPages.pop(),
|
|
989
|
+
if (s - n.count < t) break;
|
|
990
|
+
this.slabPages.pop(), s -= n.count, this.removeRange(n);
|
|
992
991
|
}
|
|
993
|
-
|
|
992
|
+
s !== this.pagerSlots && (this.pagerSlots = s, this.postToWorker({ type: "resize", capacity: s }), this.pageTableDrawn > s && this.setSlabResident(s), this.pendingWork = !0, this.lastScheduleTime = -1 / 0);
|
|
994
993
|
}
|
|
995
994
|
/**
|
|
996
995
|
* Writes `data` at slot `slot`, splitting the write where it crosses a page
|
|
997
996
|
* boundary. The pager's runs are contiguous in *slot* space, which page
|
|
998
997
|
* storage no longer guarantees is contiguous in the pool.
|
|
999
998
|
*/
|
|
1000
|
-
writeSlabSlots(e, t,
|
|
999
|
+
writeSlabSlots(e, t, s) {
|
|
1001
1000
|
let n = 0;
|
|
1002
|
-
for (; n <
|
|
1003
|
-
const a = t + n,
|
|
1004
|
-
if (!
|
|
1005
|
-
const
|
|
1006
|
-
this.overwriteRangeData(
|
|
1001
|
+
for (; n < s; ) {
|
|
1002
|
+
const a = t + n, o = this.slabPages[Math.floor(a / this.slabPageSplats)];
|
|
1003
|
+
if (!o) return;
|
|
1004
|
+
const r = a % this.slabPageSplats, c = Math.min(s - n, this.slabPageSplats - r);
|
|
1005
|
+
this.overwriteRangeData(o, K(e, n, c), r), n += c;
|
|
1007
1006
|
}
|
|
1008
1007
|
}
|
|
1009
1008
|
/** Zeros slots `[slot, slot + count)`, splitting at page boundaries like
|
|
1010
1009
|
* {@link writeSlabSlots}, so freed slots hold nothing drawable. */
|
|
1011
1010
|
degenerateSlabSlots(e, t) {
|
|
1012
|
-
let
|
|
1013
|
-
for (;
|
|
1014
|
-
const n = e +
|
|
1011
|
+
let s = 0;
|
|
1012
|
+
for (; s < t; ) {
|
|
1013
|
+
const n = e + s, a = this.slabPages[Math.floor(n / this.slabPageSplats)];
|
|
1015
1014
|
if (!a) return;
|
|
1016
|
-
const
|
|
1017
|
-
this.degenerateRange(a,
|
|
1015
|
+
const o = n % this.slabPageSplats, r = Math.min(t - s, this.slabPageSplats - o);
|
|
1016
|
+
this.degenerateRange(a, o, r), s += r;
|
|
1018
1017
|
}
|
|
1019
1018
|
}
|
|
1020
1019
|
/**
|
|
@@ -1026,17 +1025,17 @@ class Y extends Ee {
|
|
|
1026
1025
|
*/
|
|
1027
1026
|
setSlabResident(e) {
|
|
1028
1027
|
for (let t = 0; t < this.slabPages.length; t++) {
|
|
1029
|
-
const
|
|
1028
|
+
const s = Math.min(
|
|
1030
1029
|
this.slabPageSplats,
|
|
1031
1030
|
Math.max(0, e - t * this.slabPageSplats)
|
|
1032
1031
|
);
|
|
1033
|
-
this.setRangeActivePrefix(this.slabPages[t],
|
|
1032
|
+
this.setRangeActivePrefix(this.slabPages[t], s);
|
|
1034
1033
|
}
|
|
1035
1034
|
}
|
|
1036
1035
|
/** Typed post to the frontier worker. */
|
|
1037
1036
|
postToWorker(e, t = []) {
|
|
1038
|
-
var
|
|
1039
|
-
(
|
|
1037
|
+
var s;
|
|
1038
|
+
(s = this.frontierWorker) == null || s.postMessage(e, t);
|
|
1040
1039
|
}
|
|
1041
1040
|
/**
|
|
1042
1041
|
* Applies a new decoded-chunk allowance from the scene's shared
|
|
@@ -1087,28 +1086,28 @@ class Y extends Ee {
|
|
|
1087
1086
|
const t = this.scene.collision;
|
|
1088
1087
|
if (!t || t.meshes.length === 0) return [];
|
|
1089
1088
|
if (!this.collisionTiles) {
|
|
1090
|
-
const
|
|
1091
|
-
this.collisionAbort =
|
|
1092
|
-
({ loadCollisionMeshTiles:
|
|
1089
|
+
const o = new AbortController();
|
|
1090
|
+
this.collisionAbort = o, this.collisionTiles = import("./formats/lcc.js").then(
|
|
1091
|
+
({ loadCollisionMeshTiles: r }) => r(t, {
|
|
1093
1092
|
...this.requestOptions ? { request: this.requestOptions } : {},
|
|
1094
|
-
signal:
|
|
1093
|
+
signal: o.signal
|
|
1095
1094
|
})
|
|
1096
|
-
).catch((
|
|
1097
|
-
throw this.collisionTiles = void 0,
|
|
1095
|
+
).catch((r) => {
|
|
1096
|
+
throw this.collisionTiles = void 0, r;
|
|
1098
1097
|
});
|
|
1099
1098
|
}
|
|
1100
|
-
const { signal:
|
|
1101
|
-
if (!
|
|
1099
|
+
const { signal: s } = e;
|
|
1100
|
+
if (!s) return this.collisionTiles;
|
|
1102
1101
|
let n;
|
|
1103
1102
|
try {
|
|
1104
1103
|
return await Promise.race([
|
|
1105
1104
|
this.collisionTiles,
|
|
1106
|
-
new Promise((
|
|
1107
|
-
n = () =>
|
|
1105
|
+
new Promise((o, r) => {
|
|
1106
|
+
n = () => r(Ke(s)), s.addEventListener("abort", n, { once: !0 });
|
|
1108
1107
|
})
|
|
1109
1108
|
]);
|
|
1110
1109
|
} finally {
|
|
1111
|
-
n &&
|
|
1110
|
+
n && s.removeEventListener("abort", n);
|
|
1112
1111
|
}
|
|
1113
1112
|
}
|
|
1114
1113
|
/**
|
|
@@ -1344,15 +1343,15 @@ class Y extends Ee {
|
|
|
1344
1343
|
set lodBaseDistance(e) {
|
|
1345
1344
|
this.scene.source.lodBaseDistance = e, this.pendingWork = !0;
|
|
1346
1345
|
}
|
|
1347
|
-
update(e, t,
|
|
1346
|
+
update(e, t, s = {}) {
|
|
1348
1347
|
const n = performance.now();
|
|
1349
1348
|
e.updateMatrixWorld(), this.updateWorldMatrix(!0, !1);
|
|
1350
1349
|
const a = Le(e, t);
|
|
1351
1350
|
this.frontierWorker && (a ? this.pageTableViewportY = a.height : (t.getDrawingBufferSize(Se), this.pageTableViewportY = Se.y));
|
|
1352
|
-
const
|
|
1353
|
-
if (super.update(e, t,
|
|
1351
|
+
const o = (a == null ? void 0 : a.head) ?? e, r = this.shouldReschedule(o, n) ? this.reschedule(o, n) : null;
|
|
1352
|
+
if (super.update(e, t, s), r && this.onPerformanceEvent) {
|
|
1354
1353
|
const c = this.getUpdateTimings();
|
|
1355
|
-
|
|
1354
|
+
r.cpuMs += performance.now() - r.timestamp, r.activeListMs = c.activeListMs, r.uploadMs = c.uploadMs, r.sortSubmitMs = c.sortSubmitMs, r.stagingTextureAllocations = c.stagingTextureAllocations, r.activeListUpdateRanges = c.activeListUpdateRanges, this.onPerformanceEvent(r);
|
|
1356
1355
|
}
|
|
1357
1356
|
}
|
|
1358
1357
|
/** Root bounds of the whole scene, valid before any chunk has loaded. */
|
|
@@ -1368,10 +1367,10 @@ class Y extends Ee {
|
|
|
1368
1367
|
setLodLevelDebug(e) {
|
|
1369
1368
|
if (e) {
|
|
1370
1369
|
this.lodLevelChannelReady || (this.defineChannel("lodLevel", { type: "float", fill: -1 }), this.lodLevelChannelReady = !0), this.lodLevelDebug = !0;
|
|
1371
|
-
for (const { run: t, handle:
|
|
1372
|
-
this.writeLodLevelChannel(
|
|
1373
|
-
for (const { run: t, handle:
|
|
1374
|
-
n === t.count && this.writeLodLevelChannel(
|
|
1370
|
+
for (const { run: t, handle: s } of this.resident.values())
|
|
1371
|
+
this.writeLodLevelChannel(s, t.level);
|
|
1372
|
+
for (const { run: t, handle: s, uploadedCount: n } of this.staged.values())
|
|
1373
|
+
n === t.count && this.writeLodLevelChannel(s, t.level);
|
|
1375
1374
|
return;
|
|
1376
1375
|
}
|
|
1377
1376
|
this.lodLevelDebug = !1;
|
|
@@ -1445,39 +1444,39 @@ class Y extends Ee {
|
|
|
1445
1444
|
* @throws {Error} if the channel was not declared with
|
|
1446
1445
|
* {@link definePersistentChannel}.
|
|
1447
1446
|
*/
|
|
1448
|
-
paintPersistent(e, t,
|
|
1447
|
+
paintPersistent(e, t, s, n) {
|
|
1449
1448
|
const a = this.persistentChannels.get(e);
|
|
1450
1449
|
if (!a)
|
|
1451
1450
|
throw new Error(
|
|
1452
1451
|
`StreamedSplatMesh.paintPersistent: channel "${e}" is not a persistent channel. Call definePersistentChannel("${e}") first.`
|
|
1453
1452
|
);
|
|
1454
1453
|
V.copy(t), this.worldToLocal(V);
|
|
1455
|
-
const
|
|
1456
|
-
let
|
|
1454
|
+
const o = s * s;
|
|
1455
|
+
let r = 0;
|
|
1457
1456
|
const c = /* @__PURE__ */ new Set();
|
|
1458
|
-
for (const { run:
|
|
1459
|
-
const f = this.cache.get(
|
|
1457
|
+
for (const { run: u } of this.resident.values()) {
|
|
1458
|
+
const f = this.cache.get(u.file);
|
|
1460
1459
|
if (!f) continue;
|
|
1461
|
-
const
|
|
1460
|
+
const h = f.data.positions, g = a.edits.get(u.file) ?? /* @__PURE__ */ new Map();
|
|
1462
1461
|
let v = !1;
|
|
1463
|
-
for (let m = 0; m <
|
|
1464
|
-
const b =
|
|
1465
|
-
if (!(
|
|
1462
|
+
for (let m = 0; m < u.count; m++) {
|
|
1463
|
+
const b = u.offset + m, I = h[b * 3 + 0] - V.x, T = h[b * 3 + 1] - V.y, y = h[b * 3 + 2] - V.z;
|
|
1464
|
+
if (!(I * I + T * T + y * y > o) && !g.has(b)) {
|
|
1466
1465
|
if (a.total >= a.maxEdits) {
|
|
1467
1466
|
a.warned || (a.warned = !0, E(
|
|
1468
1467
|
`StreamedSplatMesh.paintPersistent: channel "${e}" hit its maxEdits cap (${a.maxEdits}); further new edits are dropped.`
|
|
1469
1468
|
));
|
|
1470
1469
|
continue;
|
|
1471
1470
|
}
|
|
1472
|
-
a.total++, g.set(b, n), v = !0,
|
|
1471
|
+
a.total++, g.set(b, n), v = !0, r++;
|
|
1473
1472
|
}
|
|
1474
1473
|
}
|
|
1475
|
-
v && (a.edits.set(
|
|
1474
|
+
v && (a.edits.set(u.file, g), c.add(u.file));
|
|
1476
1475
|
}
|
|
1477
1476
|
if (c.size > 0)
|
|
1478
|
-
for (const { run:
|
|
1479
|
-
c.has(
|
|
1480
|
-
return
|
|
1477
|
+
for (const { run: u, handle: f } of this.resident.values())
|
|
1478
|
+
c.has(u.file) && this.applyPersistentRun(e, a, u, f);
|
|
1479
|
+
return r;
|
|
1481
1480
|
}
|
|
1482
1481
|
/**
|
|
1483
1482
|
* Clears every stored edit for a persistent channel and zeroes the value on
|
|
@@ -1493,20 +1492,20 @@ class Y extends Ee {
|
|
|
1493
1492
|
`StreamedSplatMesh.clearPersistentChannel: channel "${e}" is not a persistent channel.`
|
|
1494
1493
|
);
|
|
1495
1494
|
t.edits.clear(), t.total = 0;
|
|
1496
|
-
for (const { run:
|
|
1497
|
-
const a = t.type === "byte" ? new Uint8Array(
|
|
1495
|
+
for (const { run: s, handle: n } of this.resident.values()) {
|
|
1496
|
+
const a = t.type === "byte" ? new Uint8Array(s.count) : new Float32Array(s.count);
|
|
1498
1497
|
this.writeChannel(n, e, a);
|
|
1499
1498
|
}
|
|
1500
1499
|
}
|
|
1501
1500
|
dispose() {
|
|
1502
|
-
var e, t,
|
|
1501
|
+
var e, t, s, n, a;
|
|
1503
1502
|
if (!this.disposed) {
|
|
1504
1503
|
this.loader.dispose(), this.frontierWorker && (this.frontierWorker.onmessage = null, this.frontierWorker.terminate()), this.pageTableDisposed = !0, (e = this.collisionAbort) == null || e.abort(), (t = this.collisionTiles) == null || t.catch(() => {
|
|
1505
1504
|
}), this.collisionTiles = void 0;
|
|
1506
|
-
for (const { controller:
|
|
1507
|
-
if (this.fetching.clear(), this.fetchHandle && ((
|
|
1508
|
-
const
|
|
1509
|
-
this.cacheBudgetHandle = void 0, (n = this.cacheBudget) == null || n.unregister(
|
|
1505
|
+
for (const { controller: o } of this.fetching.values()) o.abort();
|
|
1506
|
+
if (this.fetching.clear(), this.fetchHandle && ((s = this.fetchScheduler) == null || s.unregister(this.fetchHandle)), this.cacheBudgetHandle) {
|
|
1507
|
+
const o = this.cacheBudgetHandle;
|
|
1508
|
+
this.cacheBudgetHandle = void 0, (n = this.cacheBudget) == null || n.unregister(o);
|
|
1510
1509
|
}
|
|
1511
1510
|
(a = this.localSource) == null || a.dispose(), this.localSource = void 0, this.cache.clear(), this.cacheBytesTotal = 0, this.retrying.clear(), this.failedFiles.clear(), this.neededFiles.clear(), this.persistentChannels.clear(), this.resident.clear(), this.staged.clear(), this.pageTableCachedFiles.clear(), this.envHandle = void 0, this.envSplatCount = 0, super.dispose();
|
|
1512
1511
|
}
|
|
@@ -1514,12 +1513,12 @@ class Y extends Ee {
|
|
|
1514
1513
|
shouldReschedule(e, t) {
|
|
1515
1514
|
if (this.pendingWork || t - this.lastScheduleTime > ft) return !0;
|
|
1516
1515
|
e.getWorldPosition(pe);
|
|
1517
|
-
const
|
|
1518
|
-
return pe.distanceTo(this.lastCameraPos) >
|
|
1516
|
+
const s = this.scene.bounds.getBoundingSphere(wt).radius || 1;
|
|
1517
|
+
return pe.distanceTo(this.lastCameraPos) > s * 25e-4 ? !0 : (e.getWorldQuaternion(me), me.angleTo(this.lastCameraQuat) > 87e-4);
|
|
1519
1518
|
}
|
|
1520
1519
|
reschedule(e, t) {
|
|
1521
1520
|
var L;
|
|
1522
|
-
const
|
|
1521
|
+
const s = performance.now();
|
|
1523
1522
|
let n = null;
|
|
1524
1523
|
if (this.onPerformanceEvent !== void 0) {
|
|
1525
1524
|
n = { resident: /* @__PURE__ */ new Map(), staged: /* @__PURE__ */ new Map() };
|
|
@@ -1528,13 +1527,13 @@ class Y extends Ee {
|
|
|
1528
1527
|
}
|
|
1529
1528
|
const a = this.compactionCount;
|
|
1530
1529
|
if (this.pendingWork = !1, this.lastScheduleTime = t, e.getWorldPosition(this.lastCameraPos), e.getWorldQuaternion(this.lastCameraQuat), x.copy(this.lastCameraPos), this.worldToLocal(x), ve.multiplyMatrices(e.projectionMatrix, e.matrixWorldInverse).multiply(this.matrixWorld), O.setFromProjectionMatrix(ve), this.frontierWorker) {
|
|
1531
|
-
e.getWorldDirection(
|
|
1530
|
+
e.getWorldDirection(M).add(this.lastCameraPos), this.worldToLocal(M), M.sub(x).normalize();
|
|
1532
1531
|
const p = e.projectionMatrix.elements[5] * this.pageTableViewportY / 2;
|
|
1533
|
-
if (p > 0 && (this.pageTableLimit = this.pageTableTargetPx / p), this.reschedulePageTable(x,
|
|
1532
|
+
if (p > 0 && (this.pageTableLimit = this.pageTableTargetPx / p), this.reschedulePageTable(x, M, O, t), this.onPerformanceEvent === void 0) return null;
|
|
1534
1533
|
const S = performance.now();
|
|
1535
1534
|
return {
|
|
1536
1535
|
timestamp: S,
|
|
1537
|
-
cpuMs: S -
|
|
1536
|
+
cpuMs: S - s,
|
|
1538
1537
|
activeListMs: 0,
|
|
1539
1538
|
uploadMs: 0,
|
|
1540
1539
|
sortSubmitMs: 0,
|
|
@@ -1549,35 +1548,36 @@ class Y extends Ee {
|
|
|
1549
1548
|
compacted: !1
|
|
1550
1549
|
};
|
|
1551
1550
|
}
|
|
1552
|
-
e.getWorldDirection(
|
|
1553
|
-
const
|
|
1551
|
+
e.getWorldDirection(M).add(this.lastCameraPos), this.worldToLocal(M), M.sub(x).normalize();
|
|
1552
|
+
const o = this.scene.source.computeDesiredRuns(
|
|
1554
1553
|
x,
|
|
1555
1554
|
O,
|
|
1556
1555
|
t,
|
|
1557
|
-
|
|
1558
|
-
),
|
|
1559
|
-
|
|
1556
|
+
M
|
|
1557
|
+
), r = this.captureOrContinueInitialReveal(
|
|
1558
|
+
o,
|
|
1560
1559
|
t,
|
|
1561
1560
|
x,
|
|
1562
|
-
O
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1561
|
+
O,
|
|
1562
|
+
M
|
|
1563
|
+
), c = r !== null, u = r ?? o, f = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new Set();
|
|
1564
|
+
for (const p of u)
|
|
1565
|
+
f.set(C(p), p), h.add(p.file);
|
|
1566
1566
|
for (const [p, S] of this.staged)
|
|
1567
|
-
f.has(p) || c && ((L = this.frozenCriticalRuns) != null && L.some((
|
|
1567
|
+
f.has(p) || c && ((L = this.frozenCriticalRuns) != null && L.some((F) => C(F) === p)) || (this.removeRange(S.handle), this.staged.delete(p));
|
|
1568
1568
|
for (const [p, { controller: S }] of this.fetching)
|
|
1569
|
-
!
|
|
1569
|
+
!h.has(p) && !this.scene.pinnedFiles.has(p) && S.abort();
|
|
1570
1570
|
for (const p of this.retrying.keys())
|
|
1571
|
-
!
|
|
1571
|
+
!h.has(p) && !this.scene.pinnedFiles.has(p) && this.retrying.delete(p);
|
|
1572
1572
|
this.neededFiles.clear();
|
|
1573
|
-
for (const p of
|
|
1573
|
+
for (const p of u) {
|
|
1574
1574
|
const S = C(p);
|
|
1575
1575
|
if (this.resident.has(S)) continue;
|
|
1576
|
-
const
|
|
1577
|
-
|
|
1576
|
+
const F = this.staged.get(S);
|
|
1577
|
+
F && F.uploadedCount === p.count || this.neededFiles.add(p.file);
|
|
1578
1578
|
}
|
|
1579
1579
|
this.envFile !== void 0 && this.envEnabled && this.envHandle === void 0 && !this.envUnfit && !this.failedFiles.has(this.envFile) && this.neededFiles.add(this.envFile);
|
|
1580
|
-
const g =
|
|
1580
|
+
const g = u.filter((p) => !this.resident.has(C(p))), v = c ? [] : [...this.resident.entries()].filter(([p]) => !f.has(p)), m = c ? (
|
|
1581
1581
|
// Mesh is invisible during the hold, so L0 cell-atomicity (no holes) is
|
|
1582
1582
|
// irrelevant - commit each frozen slice as it lands so a partial home
|
|
1583
1583
|
// cell cannot block reveal behind sibling subchunks still fetching.
|
|
@@ -1586,12 +1586,12 @@ class Y extends Ee {
|
|
|
1586
1586
|
m.sort(
|
|
1587
1587
|
(p, S) => b ? Ue(p, S) : ae(p) - ae(S)
|
|
1588
1588
|
);
|
|
1589
|
-
const
|
|
1590
|
-
this.updateEnvironment(t,
|
|
1591
|
-
let
|
|
1589
|
+
const I = /* @__PURE__ */ new Map();
|
|
1590
|
+
this.updateEnvironment(t, I);
|
|
1591
|
+
let T = 0, y = !1, A = !1, R = !1;
|
|
1592
1592
|
for (const p of m) {
|
|
1593
1593
|
if (!b && p.removes.length > 0 && y) {
|
|
1594
|
-
if (this.neverRetireCoverageEarly || !A && this.retireHeldTicks <
|
|
1594
|
+
if (this.neverRetireCoverageEarly || !A && this.retireHeldTicks < dt) {
|
|
1595
1595
|
this.pendingWork = !0, R = !0;
|
|
1596
1596
|
continue;
|
|
1597
1597
|
}
|
|
@@ -1601,25 +1601,25 @@ class Y extends Ee {
|
|
|
1601
1601
|
this.applyGroup(p, t);
|
|
1602
1602
|
continue;
|
|
1603
1603
|
}
|
|
1604
|
-
const S = p.adds.filter((P) => !this.cache.has(P.file)),
|
|
1604
|
+
const S = p.adds.filter((P) => !this.cache.has(P.file)), F = c || Ye(p) && this.initialRevealHold !== "hold-coverage";
|
|
1605
1605
|
if (S.length > 0) {
|
|
1606
1606
|
let P = !1;
|
|
1607
1607
|
for (const k of S)
|
|
1608
1608
|
this.failedFiles.has(k.file) || (oe(
|
|
1609
|
-
|
|
1609
|
+
I,
|
|
1610
1610
|
k.file,
|
|
1611
1611
|
qe(k, this.scene.source.lodBaseDistance),
|
|
1612
1612
|
k
|
|
1613
1613
|
), P = !0);
|
|
1614
|
-
if (c || this.substituteCoverage(p, t,
|
|
1614
|
+
if (c || this.substituteCoverage(p, t, I, F), P && (this.pendingWork = !0, y = !0), !c) continue;
|
|
1615
1615
|
}
|
|
1616
1616
|
if (c && this.environmentPendingForReveal()) {
|
|
1617
1617
|
this.pendingWork = !0, y = !0;
|
|
1618
1618
|
continue;
|
|
1619
1619
|
}
|
|
1620
1620
|
if ((c || this.stagedSwapsEnabled && p.addCount > this.appendCap) && this.canStageGroup(p)) {
|
|
1621
|
-
const P = this.stageGroup(p, t, Math.max(0, this.appendCap -
|
|
1622
|
-
if (
|
|
1621
|
+
const P = this.stageGroup(p, t, Math.max(0, this.appendCap - T));
|
|
1622
|
+
if (T += P, !p.adds.every((k) => {
|
|
1623
1623
|
var se;
|
|
1624
1624
|
return ((se = this.staged.get(C(k))) == null ? void 0 : se.uploadedCount) === k.count;
|
|
1625
1625
|
})) {
|
|
@@ -1633,7 +1633,7 @@ class Y extends Ee {
|
|
|
1633
1633
|
this.commitStagedGroup(p);
|
|
1634
1634
|
continue;
|
|
1635
1635
|
}
|
|
1636
|
-
if (!c &&
|
|
1636
|
+
if (!c && T > 0 && T + p.addCount > this.appendCap) {
|
|
1637
1637
|
this.pendingWork = !0, y = !0;
|
|
1638
1638
|
continue;
|
|
1639
1639
|
}
|
|
@@ -1645,17 +1645,17 @@ class Y extends Ee {
|
|
|
1645
1645
|
this.pendingWork = !0, A = !0;
|
|
1646
1646
|
continue;
|
|
1647
1647
|
}
|
|
1648
|
-
|
|
1648
|
+
T += p.addCount;
|
|
1649
1649
|
}
|
|
1650
|
-
return this.flushClassicFetches(
|
|
1650
|
+
return this.flushClassicFetches(I, this.scene.source.lodBaseDistance, c), this.retireHeldTicks = R ? this.retireHeldTicks + 1 : 0, c && (this.finishInitialRevealIfComplete(), this.initialRevealPhase === "holding" && (this.pendingWork = !0)), this.fetchCountsValue.cacheBytes = this.cacheBytesTotal, this.fetchCountsValue.cacheLimitBytes = this.cpuCacheBytes, this.cacheBytesTotal > this.cpuCacheBytes && (this.fetchCountsValue.cacheFull = !0), this.evictChunks(t), n === null ? null : this.createPerformanceEvent(
|
|
1651
1651
|
n.resident,
|
|
1652
1652
|
n.staged,
|
|
1653
1653
|
a,
|
|
1654
|
-
|
|
1654
|
+
s
|
|
1655
1655
|
);
|
|
1656
1656
|
}
|
|
1657
1657
|
rowAlignedSplats(e) {
|
|
1658
|
-
return Math.ceil(e /
|
|
1658
|
+
return Math.ceil(e / B) * B;
|
|
1659
1659
|
}
|
|
1660
1660
|
/**
|
|
1661
1661
|
* Startup hold seeds: the coverage group containing (or nearest to) the
|
|
@@ -1666,68 +1666,68 @@ class Y extends Ee {
|
|
|
1666
1666
|
*/
|
|
1667
1667
|
selectHomeSeedRuns(e) {
|
|
1668
1668
|
var a;
|
|
1669
|
-
const t = this.scene.source.lodBaseDistance,
|
|
1670
|
-
(
|
|
1669
|
+
const t = this.scene.source.lodBaseDistance, s = e.filter(
|
|
1670
|
+
(o) => o.coverageGroup !== void 0 && (o.distance ?? Number.POSITIVE_INFINITY) <= t
|
|
1671
1671
|
).sort(
|
|
1672
|
-
(
|
|
1673
|
-
(
|
|
1674
|
-
), n = (a =
|
|
1675
|
-
return n === void 0 ? [] :
|
|
1672
|
+
(o, r) => (o.distance ?? Number.POSITIVE_INFINITY) - (r.distance ?? Number.POSITIVE_INFINITY) || // Same distance: prefer in-view, then finer.
|
|
1673
|
+
(o.inView === !0 ? 0 : 1) - (r.inView === !0 ? 0 : 1) || o.level - r.level || o.leafStart - r.leafStart
|
|
1674
|
+
), n = (a = s[0]) == null ? void 0 : a.coverageGroup;
|
|
1675
|
+
return n === void 0 ? [] : s.filter((o) => o.coverageGroup === n);
|
|
1676
1676
|
}
|
|
1677
1677
|
coarsenHomeRuns(e, t) {
|
|
1678
1678
|
var a;
|
|
1679
|
-
const
|
|
1680
|
-
for (const
|
|
1681
|
-
if (
|
|
1682
|
-
|
|
1679
|
+
const s = [], n = this.scene.source;
|
|
1680
|
+
for (const o of e) {
|
|
1681
|
+
if (o.level === t) {
|
|
1682
|
+
s.push(o);
|
|
1683
1683
|
continue;
|
|
1684
1684
|
}
|
|
1685
|
-
const
|
|
1686
|
-
if (
|
|
1687
|
-
for (const c of
|
|
1688
|
-
|
|
1685
|
+
const r = ((a = n.runsAtLevelFor) == null ? void 0 : a.call(n, o.leafStart, o.leafEnd, t)) ?? [];
|
|
1686
|
+
if (r.length !== 0)
|
|
1687
|
+
for (const c of r)
|
|
1688
|
+
s.push({
|
|
1689
1689
|
...c,
|
|
1690
|
-
distance:
|
|
1691
|
-
inView:
|
|
1692
|
-
...
|
|
1693
|
-
...
|
|
1690
|
+
distance: o.distance,
|
|
1691
|
+
inView: o.inView,
|
|
1692
|
+
...o.coverageGroup === void 0 ? {} : { coverageGroup: o.coverageGroup },
|
|
1693
|
+
...o.screenImportance === void 0 ? {} : { screenImportance: o.screenImportance }
|
|
1694
1694
|
});
|
|
1695
1695
|
}
|
|
1696
|
-
return
|
|
1696
|
+
return s;
|
|
1697
1697
|
}
|
|
1698
1698
|
criticalRunsFitCapacity(e) {
|
|
1699
1699
|
let t = 0;
|
|
1700
|
-
for (const
|
|
1700
|
+
for (const s of e) t += this.rowAlignedSplats(s.count);
|
|
1701
1701
|
return t <= this.freeSplatCapacity;
|
|
1702
1702
|
}
|
|
1703
1703
|
publishInitialRevealProgress(e) {
|
|
1704
1704
|
const t = /* @__PURE__ */ new Map();
|
|
1705
|
-
for (const
|
|
1706
|
-
const c =
|
|
1707
|
-
let
|
|
1708
|
-
|
|
1705
|
+
for (const r of e) {
|
|
1706
|
+
const c = r.coverageGroup !== void 0 ? `g:${r.coverageGroup}` : C(r);
|
|
1707
|
+
let u = t.get(c);
|
|
1708
|
+
u || (u = [], t.set(c, u)), u.push(r);
|
|
1709
1709
|
}
|
|
1710
|
-
let
|
|
1711
|
-
for (const
|
|
1710
|
+
let s = 0, n = 0, a = 0;
|
|
1711
|
+
for (const r of t.values()) {
|
|
1712
1712
|
let c = !0;
|
|
1713
|
-
for (const
|
|
1714
|
-
n +=
|
|
1715
|
-
const f = C(
|
|
1713
|
+
for (const u of r) {
|
|
1714
|
+
n += u.count;
|
|
1715
|
+
const f = C(u);
|
|
1716
1716
|
if (this.resident.has(f)) {
|
|
1717
|
-
|
|
1717
|
+
s += u.count;
|
|
1718
1718
|
continue;
|
|
1719
1719
|
}
|
|
1720
|
-
const
|
|
1721
|
-
|
|
1720
|
+
const h = this.staged.get(f);
|
|
1721
|
+
s += (h == null ? void 0 : h.uploadedCount) ?? 0, (!h || h.uploadedCount !== u.count) && (c = !1);
|
|
1722
1722
|
}
|
|
1723
1723
|
c && a++;
|
|
1724
1724
|
}
|
|
1725
|
-
const
|
|
1726
|
-
if (
|
|
1725
|
+
const o = this.initialRevealStateValue;
|
|
1726
|
+
if (o.status === "degraded") {
|
|
1727
1727
|
this.initialRevealStateValue = {
|
|
1728
1728
|
status: "degraded",
|
|
1729
|
-
reason:
|
|
1730
|
-
stagedSplats:
|
|
1729
|
+
reason: o.reason,
|
|
1730
|
+
stagedSplats: s,
|
|
1731
1731
|
totalSplats: n,
|
|
1732
1732
|
readyGroups: a,
|
|
1733
1733
|
totalGroups: t.size
|
|
@@ -1736,77 +1736,109 @@ class Y extends Ee {
|
|
|
1736
1736
|
}
|
|
1737
1737
|
this.initialRevealStateValue = {
|
|
1738
1738
|
status: "pending",
|
|
1739
|
-
stagedSplats:
|
|
1739
|
+
stagedSplats: s,
|
|
1740
1740
|
totalSplats: n,
|
|
1741
1741
|
readyGroups: a,
|
|
1742
1742
|
totalGroups: t.size
|
|
1743
1743
|
};
|
|
1744
1744
|
}
|
|
1745
1745
|
releaseInitialReveal(e, t) {
|
|
1746
|
-
const
|
|
1747
|
-
this.publishInitialRevealProgress(
|
|
1748
|
-
const n = this.initialRevealStateValue, a = n.status === "pending" || n.status === "degraded" ? n.stagedSplats : 0,
|
|
1746
|
+
const s = this.frozenCriticalRuns ?? [];
|
|
1747
|
+
this.publishInitialRevealProgress(s);
|
|
1748
|
+
const n = this.initialRevealStateValue, a = n.status === "pending" || n.status === "degraded" ? n.stagedSplats : 0, o = n.status === "pending" || n.status === "degraded" ? n.totalSplats : 0, r = n.status === "pending" || n.status === "degraded" ? n.readyGroups : 0, c = n.status === "pending" || n.status === "degraded" ? n.totalGroups : 0;
|
|
1749
1749
|
e === "ready" ? this.initialRevealStateValue = { status: "ready" } : this.initialRevealStateValue = {
|
|
1750
1750
|
status: "degraded",
|
|
1751
1751
|
reason: t ?? "fetch-failed",
|
|
1752
1752
|
stagedSplats: a,
|
|
1753
|
-
totalSplats:
|
|
1754
|
-
readyGroups:
|
|
1753
|
+
totalSplats: o,
|
|
1754
|
+
readyGroups: r,
|
|
1755
1755
|
totalGroups: c
|
|
1756
1756
|
}, this.frozenCriticalRuns = null, this.initialRevealPhase = "released", this.pendingWork = !0;
|
|
1757
1757
|
}
|
|
1758
1758
|
/**
|
|
1759
|
-
*
|
|
1759
|
+
* Coverage hold: freeze covering runs for in-view cells (classic `.lcc`
|
|
1760
|
+
* physical cells at L1 near / coarsest far, `.lcc2` octree root-children).
|
|
1760
1761
|
* Missing `coverageRunsFor` (or an empty result after fallback) releases
|
|
1761
1762
|
* immediately so the mesh does not stay hidden with nothing to fetch.
|
|
1763
|
+
* If the mixed set overflows the pool, coarsen only the near (non-coarsest)
|
|
1764
|
+
* groups one more rung before degrading to progressive.
|
|
1762
1765
|
*/
|
|
1763
|
-
captureCoverageHold(e, t,
|
|
1764
|
-
var
|
|
1765
|
-
|
|
1766
|
-
if (
|
|
1766
|
+
captureCoverageHold(e, t, s, n) {
|
|
1767
|
+
var o, r;
|
|
1768
|
+
let a = ((r = (o = this.scene.source).coverageRunsFor) == null ? void 0 : r.call(o, e, t, n)) ?? [];
|
|
1769
|
+
if (a.length === 0) {
|
|
1767
1770
|
if (this.environmentPendingForReveal()) {
|
|
1768
|
-
this.frozenCriticalRuns = [], this.initialRevealStartedAt =
|
|
1771
|
+
this.frozenCriticalRuns = [], this.initialRevealStartedAt = s, this.initialRevealPhase = "holding", this.publishInitialRevealProgress([]);
|
|
1769
1772
|
return;
|
|
1770
1773
|
}
|
|
1771
1774
|
this.initialRevealStateValue = { status: "ready" }, this.initialRevealPhase = "released";
|
|
1772
1775
|
return;
|
|
1773
1776
|
}
|
|
1774
|
-
if (!this.criticalRunsFitCapacity(
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
+
if (!this.criticalRunsFitCapacity(a)) {
|
|
1778
|
+
const c = this.coarsenCoverageNearRuns(a);
|
|
1779
|
+
if (this.criticalRunsFitCapacity(c))
|
|
1780
|
+
a = c;
|
|
1781
|
+
else {
|
|
1782
|
+
this.frozenCriticalRuns = a, this.releaseInitialReveal("degraded", "capacity");
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
this.frozenCriticalRuns = a, this.initialRevealStartedAt = s, this.initialRevealPhase = "holding", this.publishInitialRevealProgress(a);
|
|
1787
|
+
}
|
|
1788
|
+
/**
|
|
1789
|
+
* Bump each coverage run one coarser rung when the source has one. Already-
|
|
1790
|
+
* coarsest (far) runs stay put so a tight pool only drops near L1 → L2.
|
|
1791
|
+
*/
|
|
1792
|
+
coarsenCoverageNearRuns(e) {
|
|
1793
|
+
var n;
|
|
1794
|
+
const t = [], s = this.scene.source;
|
|
1795
|
+
for (const a of e) {
|
|
1796
|
+
const o = ((n = s.runsAtLevelFor) == null ? void 0 : n.call(s, a.leafStart, a.leafEnd, a.level + 1)) ?? [];
|
|
1797
|
+
if (o.length === 0 || o.every((r) => r.level <= a.level)) {
|
|
1798
|
+
t.push(a);
|
|
1799
|
+
continue;
|
|
1800
|
+
}
|
|
1801
|
+
for (const r of o)
|
|
1802
|
+
t.push({
|
|
1803
|
+
...r,
|
|
1804
|
+
distance: a.distance,
|
|
1805
|
+
inView: a.inView,
|
|
1806
|
+
...a.coverageGroup === void 0 ? {} : { coverageGroup: a.coverageGroup },
|
|
1807
|
+
...a.screenImportance === void 0 ? {} : { screenImportance: a.screenImportance }
|
|
1808
|
+
});
|
|
1777
1809
|
}
|
|
1778
|
-
|
|
1810
|
+
return t;
|
|
1779
1811
|
}
|
|
1780
|
-
captureOrContinueInitialReveal(e, t,
|
|
1812
|
+
captureOrContinueInitialReveal(e, t, s, n, a) {
|
|
1781
1813
|
if (this.initialRevealPhase === "off" || this.initialRevealPhase === "released") return null;
|
|
1782
1814
|
if (this.initialRevealPhase === "capture")
|
|
1783
1815
|
if (this.initialRevealHold === "hold-coverage")
|
|
1784
|
-
this.captureCoverageHold(
|
|
1816
|
+
this.captureCoverageHold(s, n, t, a);
|
|
1785
1817
|
else {
|
|
1786
|
-
const
|
|
1818
|
+
const o = this.selectHomeSeedRuns(e);
|
|
1787
1819
|
let r = [];
|
|
1788
|
-
if (
|
|
1789
|
-
const
|
|
1790
|
-
(
|
|
1791
|
-
),
|
|
1792
|
-
(
|
|
1820
|
+
if (o.length === 0) {
|
|
1821
|
+
const c = this.scene.source.lodBaseDistance * this.scene.source.lodMultiplier * this.scene.source.lodMultiplier, u = e.filter(
|
|
1822
|
+
(h) => h.level <= 2 && h.coverageGroup !== void 0 && (h.distance ?? Number.POSITIVE_INFINITY) <= c
|
|
1823
|
+
), f = [...u].sort(
|
|
1824
|
+
(h, g) => (h.distance ?? Number.POSITIVE_INFINITY) - (g.distance ?? Number.POSITIVE_INFINITY) || (h.inView === !0 ? 0 : 1) - (g.inView === !0 ? 0 : 1) || (h.screenImportance ?? Number.POSITIVE_INFINITY) - (g.screenImportance ?? Number.POSITIVE_INFINITY) || h.leafStart - g.leafStart
|
|
1793
1825
|
)[0];
|
|
1794
|
-
if (!
|
|
1826
|
+
if (!f)
|
|
1795
1827
|
return this.initialRevealStateValue = { status: "ready" }, this.initialRevealPhase = "released", null;
|
|
1796
|
-
if (r =
|
|
1797
|
-
(
|
|
1798
|
-
).slice(0, 1) :
|
|
1799
|
-
return this.frozenCriticalRuns = r.length > 0 ? r : [
|
|
1828
|
+
if (r = f.coverageGroup !== void 0 ? u.filter((h) => h.coverageGroup === f.coverageGroup) : [f], this.criticalRunsFitCapacity(r) || (r = f.coverageGroup !== void 0 ? u.filter(
|
|
1829
|
+
(h) => h.coverageGroup === f.coverageGroup && this.criticalRunsFitCapacity([h])
|
|
1830
|
+
).slice(0, 1) : u.filter((h) => this.criticalRunsFitCapacity([h])).slice(0, 1)), r.length === 0 || !this.criticalRunsFitCapacity(r))
|
|
1831
|
+
return this.frozenCriticalRuns = r.length > 0 ? r : [f], this.releaseInitialReveal("degraded", "capacity"), null;
|
|
1800
1832
|
this.frozenCriticalRuns = r, this.initialRevealStartedAt = t, this.initialRevealPhase = "holding", this.publishInitialRevealProgress(r);
|
|
1801
1833
|
} else {
|
|
1802
|
-
for (const
|
|
1803
|
-
const
|
|
1804
|
-
if (
|
|
1805
|
-
if (this.criticalRunsFitCapacity(
|
|
1806
|
-
r =
|
|
1834
|
+
for (const c of [0, 1, 2]) {
|
|
1835
|
+
const u = this.coarsenHomeRuns(o, c);
|
|
1836
|
+
if (u.length !== 0) {
|
|
1837
|
+
if (this.criticalRunsFitCapacity(u)) {
|
|
1838
|
+
r = u;
|
|
1807
1839
|
break;
|
|
1808
1840
|
}
|
|
1809
|
-
r =
|
|
1841
|
+
r = u;
|
|
1810
1842
|
}
|
|
1811
1843
|
}
|
|
1812
1844
|
if (r.length === 0)
|
|
@@ -1819,10 +1851,10 @@ class Y extends Ee {
|
|
|
1819
1851
|
if (this.initialRevealPhase !== "holding" || !this.frozenCriticalRuns) return null;
|
|
1820
1852
|
if (this.initialRevealStartedAt !== void 0 && t - this.initialRevealStartedAt >= ct)
|
|
1821
1853
|
return this.releaseInitialReveal("degraded", "timeout"), null;
|
|
1822
|
-
for (const
|
|
1823
|
-
if (this.failedFiles.has(
|
|
1824
|
-
const r = this.staged.get(C(
|
|
1825
|
-
if (!r || r.uploadedCount !==
|
|
1854
|
+
for (const o of this.frozenCriticalRuns)
|
|
1855
|
+
if (this.failedFiles.has(o.file) && !this.resident.has(C(o))) {
|
|
1856
|
+
const r = this.staged.get(C(o));
|
|
1857
|
+
if (!r || r.uploadedCount !== o.count)
|
|
1826
1858
|
return this.releaseInitialReveal("degraded", "fetch-failed"), null;
|
|
1827
1859
|
}
|
|
1828
1860
|
return this.publishInitialRevealProgress(this.frozenCriticalRuns), this.frozenCriticalRuns;
|
|
@@ -1839,18 +1871,18 @@ class Y extends Ee {
|
|
|
1839
1871
|
return this.envFile !== void 0 && this.envEnabled && !this.envUnfit && this.envHandle === void 0 && !this.failedFiles.has(this.envFile);
|
|
1840
1872
|
}
|
|
1841
1873
|
/** Creates a performance event for a changed streamed-LOD tick, if any. */
|
|
1842
|
-
createPerformanceEvent(e, t,
|
|
1843
|
-
let a = 0,
|
|
1844
|
-
for (const [
|
|
1845
|
-
|
|
1846
|
-
let
|
|
1847
|
-
for (const [
|
|
1848
|
-
this.resident.has(
|
|
1874
|
+
createPerformanceEvent(e, t, s, n) {
|
|
1875
|
+
let a = 0, o = 0;
|
|
1876
|
+
for (const [h, g] of this.resident)
|
|
1877
|
+
o += g.run.count, e.has(h) || (a += g.run.count);
|
|
1878
|
+
let r = 0;
|
|
1879
|
+
for (const [h, g] of e)
|
|
1880
|
+
this.resident.has(h) || (r += g);
|
|
1849
1881
|
let c = 0;
|
|
1850
|
-
for (const [
|
|
1851
|
-
c += Math.max(0, g.uploadedCount - (t.get(
|
|
1852
|
-
const
|
|
1853
|
-
if (a === 0 &&
|
|
1882
|
+
for (const [h, g] of this.staged)
|
|
1883
|
+
c += Math.max(0, g.uploadedCount - (t.get(h) ?? 0));
|
|
1884
|
+
const u = this.compactionCount !== s;
|
|
1885
|
+
if (a === 0 && r === 0 && c === 0 && !u) return null;
|
|
1854
1886
|
const f = performance.now();
|
|
1855
1887
|
return {
|
|
1856
1888
|
timestamp: f,
|
|
@@ -1861,29 +1893,29 @@ class Y extends Ee {
|
|
|
1861
1893
|
stagingTextureAllocations: 0,
|
|
1862
1894
|
activeListUpdateRanges: 0,
|
|
1863
1895
|
appendedCount: a,
|
|
1864
|
-
removedCount:
|
|
1896
|
+
removedCount: r,
|
|
1865
1897
|
stagedCount: c,
|
|
1866
1898
|
uploadCount: a + c,
|
|
1867
|
-
activeCount:
|
|
1868
|
-
forcedSort:
|
|
1869
|
-
compacted:
|
|
1899
|
+
activeCount: o,
|
|
1900
|
+
forcedSort: o === 0 || a + r >= o * ht,
|
|
1901
|
+
compacted: u
|
|
1870
1902
|
};
|
|
1871
1903
|
}
|
|
1872
1904
|
/** Returns whether all new rows can coexist with the currently visible region. */
|
|
1873
1905
|
canStageGroup(e) {
|
|
1874
|
-
return e.adds.filter((
|
|
1906
|
+
return e.adds.filter((s) => !this.staged.has(C(s))).reduce((s, n) => s + this.rowAlignedSplats(n.count), 0) <= this.freeSplatCapacity;
|
|
1875
1907
|
}
|
|
1876
1908
|
/**
|
|
1877
1909
|
* Uploads a bounded part of a replacement without rendering it.
|
|
1878
1910
|
* Skips runs whose chunks are not yet cached so siblings can stage out of order.
|
|
1879
1911
|
*/
|
|
1880
|
-
stageGroup(e, t,
|
|
1881
|
-
if (
|
|
1912
|
+
stageGroup(e, t, s) {
|
|
1913
|
+
if (s <= 0) return 0;
|
|
1882
1914
|
let n = 0;
|
|
1883
1915
|
for (const a of e.adds) {
|
|
1884
|
-
const
|
|
1885
|
-
if (!
|
|
1886
|
-
let c = this.staged.get(
|
|
1916
|
+
const o = C(a), r = this.cache.get(a.file);
|
|
1917
|
+
if (!r) continue;
|
|
1918
|
+
let c = this.staged.get(o);
|
|
1887
1919
|
if (!c) {
|
|
1888
1920
|
let f;
|
|
1889
1921
|
try {
|
|
@@ -1897,36 +1929,36 @@ class Y extends Ee {
|
|
|
1897
1929
|
break;
|
|
1898
1930
|
}
|
|
1899
1931
|
}
|
|
1900
|
-
c = { run: a, handle: f, uploadedCount: 0 }, this.staged.set(
|
|
1932
|
+
c = { run: a, handle: f, uploadedCount: 0 }, this.staged.set(o, c);
|
|
1901
1933
|
}
|
|
1902
1934
|
if (c.uploadedCount === a.count) continue;
|
|
1903
|
-
const
|
|
1904
|
-
if (
|
|
1935
|
+
const u = Math.min(a.count - c.uploadedCount, s - n);
|
|
1936
|
+
if (u <= 0) break;
|
|
1905
1937
|
if (this.writeInactiveRange(
|
|
1906
1938
|
c.handle,
|
|
1907
|
-
K(
|
|
1939
|
+
K(r.data, a.offset + c.uploadedCount, u),
|
|
1908
1940
|
c.uploadedCount
|
|
1909
|
-
), c.uploadedCount +=
|
|
1941
|
+
), c.uploadedCount += u, r.lastUsed = t, n += u, c.uploadedCount === a.count) {
|
|
1910
1942
|
this.writeLodLevelChannel(c.handle, a.level);
|
|
1911
|
-
for (const [f,
|
|
1912
|
-
this.applyPersistentRun(f,
|
|
1943
|
+
for (const [f, h] of this.persistentChannels)
|
|
1944
|
+
this.applyPersistentRun(f, h, a, c.handle);
|
|
1913
1945
|
}
|
|
1914
|
-
if (n >=
|
|
1946
|
+
if (n >= s) break;
|
|
1915
1947
|
}
|
|
1916
1948
|
return n;
|
|
1917
1949
|
}
|
|
1918
1950
|
/** Switches a fully staged region from old to new visibility in one tick. */
|
|
1919
1951
|
commitStagedGroup(e) {
|
|
1920
1952
|
for (const t of e.adds) {
|
|
1921
|
-
const
|
|
1922
|
-
if (!
|
|
1953
|
+
const s = this.staged.get(C(t));
|
|
1954
|
+
if (!s || s.uploadedCount !== t.count)
|
|
1923
1955
|
throw new Error("StreamedSplatMesh: incomplete staged group commit.");
|
|
1924
1956
|
}
|
|
1925
|
-
for (const [t,
|
|
1926
|
-
this.resident.has(t) && (this.removeRange(
|
|
1957
|
+
for (const [t, s] of e.removes)
|
|
1958
|
+
this.resident.has(t) && (this.removeRange(s.handle), this.resident.delete(t));
|
|
1927
1959
|
for (const t of e.adds) {
|
|
1928
|
-
const
|
|
1929
|
-
this.setRangeActive(n.handle, !0), this.resident.set(
|
|
1960
|
+
const s = C(t), n = this.staged.get(s);
|
|
1961
|
+
this.setRangeActive(n.handle, !0), this.resident.set(s, n), this.staged.delete(s);
|
|
1930
1962
|
}
|
|
1931
1963
|
}
|
|
1932
1964
|
/**
|
|
@@ -1936,19 +1968,19 @@ class Y extends Ee {
|
|
|
1936
1968
|
* removals - the caller defers it and the old runs keep rendering.
|
|
1937
1969
|
*/
|
|
1938
1970
|
applyGroup(e, t) {
|
|
1939
|
-
const
|
|
1971
|
+
const s = (o) => Math.ceil(o / B) * B, n = e.adds.reduce((o, r) => o + s(r.count), 0), a = e.removes.reduce((o, [, r]) => o + s(r.run.count), 0);
|
|
1940
1972
|
if (n > this.freeSplatCapacity + a) return !1;
|
|
1941
|
-
for (const [
|
|
1942
|
-
this.resident.has(
|
|
1943
|
-
for (const
|
|
1944
|
-
this.appendRun(
|
|
1973
|
+
for (const [o, r] of e.removes)
|
|
1974
|
+
this.resident.has(o) && (this.removeRange(r.handle), this.resident.delete(o));
|
|
1975
|
+
for (const o of e.adds)
|
|
1976
|
+
this.appendRun(o, t);
|
|
1945
1977
|
return !0;
|
|
1946
1978
|
}
|
|
1947
1979
|
/** Appends one run from the cache, compacting the pool on fragmentation. */
|
|
1948
1980
|
appendRun(e, t) {
|
|
1949
|
-
const
|
|
1950
|
-
if (!
|
|
1951
|
-
const n = K(
|
|
1981
|
+
const s = this.cache.get(e.file);
|
|
1982
|
+
if (!s) return;
|
|
1983
|
+
const n = K(s.data, e.offset, e.count);
|
|
1952
1984
|
let a;
|
|
1953
1985
|
try {
|
|
1954
1986
|
a = this.appendRange(n);
|
|
@@ -1961,25 +1993,25 @@ class Y extends Ee {
|
|
|
1961
1993
|
return;
|
|
1962
1994
|
}
|
|
1963
1995
|
}
|
|
1964
|
-
this.resident.set(C(e), { run: e, handle: a }),
|
|
1965
|
-
for (const [
|
|
1966
|
-
this.applyPersistentRun(
|
|
1996
|
+
this.resident.set(C(e), { run: e, handle: a }), s.lastUsed = t, this.writeLodLevelChannel(a, e.level);
|
|
1997
|
+
for (const [o, r] of this.persistentChannels)
|
|
1998
|
+
this.applyPersistentRun(o, r, e, a);
|
|
1967
1999
|
}
|
|
1968
2000
|
/**
|
|
1969
2001
|
* Writes the stored edits for one run's `[offset, offset + count)` splats
|
|
1970
2002
|
* into its freshly appended pool range. No-op when the file has no edits.
|
|
1971
2003
|
*/
|
|
1972
|
-
applyPersistentRun(e, t,
|
|
1973
|
-
const a = t.edits.get(
|
|
2004
|
+
applyPersistentRun(e, t, s, n) {
|
|
2005
|
+
const a = t.edits.get(s.file);
|
|
1974
2006
|
if (!a || a.size === 0) return;
|
|
1975
|
-
const
|
|
1976
|
-
t.fill &&
|
|
1977
|
-
let
|
|
1978
|
-
for (let c = 0; c <
|
|
1979
|
-
const
|
|
1980
|
-
|
|
2007
|
+
const o = t.type === "byte" ? new Uint8Array(s.count) : new Float32Array(s.count);
|
|
2008
|
+
t.fill && o.fill(t.fill);
|
|
2009
|
+
let r = !1;
|
|
2010
|
+
for (let c = 0; c < s.count; c++) {
|
|
2011
|
+
const u = a.get(s.offset + c);
|
|
2012
|
+
u !== void 0 && (o[c] = u, r = !0);
|
|
1981
2013
|
}
|
|
1982
|
-
|
|
2014
|
+
r && this.writeChannel(n, e, o);
|
|
1983
2015
|
}
|
|
1984
2016
|
/**
|
|
1985
2017
|
* Covers a deferred group's leaves that no resident run covers with each
|
|
@@ -1992,21 +2024,21 @@ class Y extends Ee {
|
|
|
1992
2024
|
* paint and its pin fetch entirely - cold load requests only the target cut
|
|
1993
2025
|
* for that cell. Far gaps keep the shell.
|
|
1994
2026
|
*/
|
|
1995
|
-
substituteCoverage(e, t,
|
|
2027
|
+
substituteCoverage(e, t, s, n) {
|
|
1996
2028
|
const a = e.leafEnd - e.leafStart;
|
|
1997
2029
|
(this.coverageScratch === void 0 || this.coverageScratch.length < a) && (this.coverageScratch = new Uint8Array(a));
|
|
1998
|
-
const
|
|
1999
|
-
|
|
2000
|
-
for (const { run:
|
|
2001
|
-
const f = Math.max(
|
|
2002
|
-
|
|
2030
|
+
const o = this.coverageScratch;
|
|
2031
|
+
o.fill(0, 0, a);
|
|
2032
|
+
for (const { run: u } of this.resident.values()) {
|
|
2033
|
+
const f = Math.max(u.leafStart, e.leafStart), h = Math.min(u.leafEnd, e.leafEnd);
|
|
2034
|
+
h > f && o.fill(1, f - e.leafStart, h - e.leafStart);
|
|
2003
2035
|
}
|
|
2004
|
-
const
|
|
2036
|
+
const r = o.subarray(0, a);
|
|
2005
2037
|
let c = 0;
|
|
2006
2038
|
for (; c < a; ) {
|
|
2007
|
-
const
|
|
2008
|
-
if (
|
|
2009
|
-
const f =
|
|
2039
|
+
const u = r.indexOf(0, c);
|
|
2040
|
+
if (u < 0) break;
|
|
2041
|
+
const f = r.indexOf(1, u), h = f < 0 ? a : f, g = e.leafStart + u, v = e.leafStart + h;
|
|
2010
2042
|
for (const m of this.scene.source.coarsestRunsFor(g, v))
|
|
2011
2043
|
if (!this.resident.has(C(m))) {
|
|
2012
2044
|
if (n) {
|
|
@@ -2015,29 +2047,29 @@ class Y extends Ee {
|
|
|
2015
2047
|
}
|
|
2016
2048
|
if (!this.cache.has(m.file)) {
|
|
2017
2049
|
oe(
|
|
2018
|
-
|
|
2050
|
+
s,
|
|
2019
2051
|
m.file,
|
|
2020
2052
|
je(m, this.scene.source.lodBaseDistance),
|
|
2021
2053
|
m
|
|
2022
2054
|
), this.fetchCountsValue.uncovered += Math.min(m.leafEnd, v) - Math.max(m.leafStart, g);
|
|
2023
2055
|
continue;
|
|
2024
2056
|
}
|
|
2025
|
-
for (const [b,
|
|
2026
|
-
|
|
2057
|
+
for (const [b, I] of this.resident)
|
|
2058
|
+
I.run.leafStart < m.leafEnd && I.run.leafEnd > m.leafStart && (this.removeRange(I.handle), this.resident.delete(b));
|
|
2027
2059
|
this.appendRun(m, t);
|
|
2028
2060
|
}
|
|
2029
|
-
c =
|
|
2061
|
+
c = h;
|
|
2030
2062
|
}
|
|
2031
2063
|
}
|
|
2032
2064
|
/** Issues pending classic-path chunk wants in group-priority order. */
|
|
2033
|
-
flushClassicFetches(e, t,
|
|
2065
|
+
flushClassicFetches(e, t, s = !1) {
|
|
2034
2066
|
if (e.size === 0) return;
|
|
2035
|
-
$e(e, t,
|
|
2067
|
+
$e(e, t, s);
|
|
2036
2068
|
const n = [...e.entries()].sort(
|
|
2037
|
-
(a,
|
|
2069
|
+
(a, o) => X(a[1], o[1], a[0], o[0])
|
|
2038
2070
|
);
|
|
2039
2071
|
this.preemptClassicFetches(n);
|
|
2040
|
-
for (const [a,
|
|
2072
|
+
for (const [a, o] of n) this.requestChunk(a, o.kind, o);
|
|
2041
2073
|
}
|
|
2042
2074
|
/**
|
|
2043
2075
|
* A camera turn must not wait for all eight old visible requests to finish.
|
|
@@ -2046,12 +2078,12 @@ class Y extends Ee {
|
|
|
2046
2078
|
*/
|
|
2047
2079
|
preemptClassicFetches(e) {
|
|
2048
2080
|
var t;
|
|
2049
|
-
for (const [
|
|
2050
|
-
if (this.cache.has(
|
|
2051
|
-
let a,
|
|
2052
|
-
for (const [
|
|
2053
|
-
c.classicWant && (!
|
|
2054
|
-
if (
|
|
2081
|
+
for (const [s, n] of e) {
|
|
2082
|
+
if (this.cache.has(s) || this.fetching.has(s)) continue;
|
|
2083
|
+
let a, o;
|
|
2084
|
+
for (const [r, c] of this.fetching)
|
|
2085
|
+
c.classicWant && (!o || X(c.classicWant, o, r, a) > 0) && (a = r, o = c.classicWant);
|
|
2086
|
+
if (o && a !== void 0 && X(n, o, s, a) < 0 && ((t = this.fetching.get(a)) == null || t.controller.abort()), this.fetching.size >= this.maxInflight) return;
|
|
2055
2087
|
}
|
|
2056
2088
|
}
|
|
2057
2089
|
/**
|
|
@@ -2063,15 +2095,15 @@ class Y extends Ee {
|
|
|
2063
2095
|
* it issues ahead of LOD coverage.
|
|
2064
2096
|
*/
|
|
2065
2097
|
updateEnvironment(e, t) {
|
|
2066
|
-
const
|
|
2067
|
-
if (
|
|
2098
|
+
const s = this.envFile;
|
|
2099
|
+
if (s === void 0 || this.envHandle !== void 0 || !this.envEnabled || this.envUnfit)
|
|
2068
2100
|
return;
|
|
2069
|
-
const n = this.cache.get(
|
|
2101
|
+
const n = this.cache.get(s);
|
|
2070
2102
|
if (!n) {
|
|
2071
|
-
this.failedFiles.has(
|
|
2103
|
+
this.failedFiles.has(s) || (t ? this.enqueueEnvironmentFetch(t, s) : this.requestChunk(s, "priority"), this.pendingWork = !0);
|
|
2072
2104
|
return;
|
|
2073
2105
|
}
|
|
2074
|
-
const a = Math.ceil(n.data.count /
|
|
2106
|
+
const a = Math.ceil(n.data.count / B) * B;
|
|
2075
2107
|
if (a > this.capacity) {
|
|
2076
2108
|
this.envUnfit = !0, E(
|
|
2077
2109
|
`the environment tile (${n.data.count} splats) exceeds the pool capacity (${this.capacity}); it will not be shown. Raise the splat budget to fit it.`
|
|
@@ -2082,19 +2114,19 @@ class Y extends Ee {
|
|
|
2082
2114
|
this.pendingWork = !0;
|
|
2083
2115
|
return;
|
|
2084
2116
|
}
|
|
2085
|
-
let
|
|
2117
|
+
let o;
|
|
2086
2118
|
try {
|
|
2087
|
-
|
|
2119
|
+
o = this.appendRange(n.data);
|
|
2088
2120
|
} catch {
|
|
2089
2121
|
this.compactionCount++, this.compact();
|
|
2090
2122
|
try {
|
|
2091
|
-
|
|
2123
|
+
o = this.appendRange(n.data);
|
|
2092
2124
|
} catch {
|
|
2093
2125
|
this.pendingWork = !0;
|
|
2094
2126
|
return;
|
|
2095
2127
|
}
|
|
2096
2128
|
}
|
|
2097
|
-
this.envHandle =
|
|
2129
|
+
this.envHandle = o, this.envSplatCount = n.data.count, n.lastUsed = e;
|
|
2098
2130
|
}
|
|
2099
2131
|
/** Ranks the env tile ahead of every LOD want in {@link flushClassicFetches}. */
|
|
2100
2132
|
enqueueEnvironmentFetch(e, t) {
|
|
@@ -2123,16 +2155,16 @@ class Y extends Ee {
|
|
|
2123
2155
|
* with a paging plan. Coalesced to one outstanding request so the main thread
|
|
2124
2156
|
* never blocks. Also drives chunk fetching, in priority order.
|
|
2125
2157
|
*/
|
|
2126
|
-
reschedulePageTable(e, t,
|
|
2127
|
-
for (const
|
|
2158
|
+
reschedulePageTable(e, t, s, n) {
|
|
2159
|
+
for (const o of this.pageTableFetchPriority) this.requestChunk(o, "priority");
|
|
2128
2160
|
const a = new Set(this.pageTableFetchPriority);
|
|
2129
|
-
for (const
|
|
2130
|
-
a.add(
|
|
2131
|
-
for (const [
|
|
2132
|
-
|
|
2161
|
+
for (const o of this.scene.source.computeDesiredRuns(e, s, n))
|
|
2162
|
+
a.add(o.file), this.requestChunk(o.file, "base");
|
|
2163
|
+
for (const [o, r] of this.fetching)
|
|
2164
|
+
r.kind !== "sweep" && !a.has(o) && !this.scene.pinnedFiles.has(o) && r.controller.abort();
|
|
2133
2165
|
if (!this.pageTableCacheAtLimit && this.sweepAllowed()) {
|
|
2134
|
-
const
|
|
2135
|
-
for (let c = 0; c <
|
|
2166
|
+
const o = Math.max(1, this.maxInflight - mt), r = this.scene.chunkUrls.length;
|
|
2167
|
+
for (let c = 0; c < r && this.fetching.size < o; c++)
|
|
2136
2168
|
this.pageTableCachedFiles.has(c) || this.requestChunk(c, "sweep");
|
|
2137
2169
|
}
|
|
2138
2170
|
this.pageTableInFlight || (this.pageTableInFlight = !0, this.postToWorker({
|
|
@@ -2157,48 +2189,48 @@ class Y extends Ee {
|
|
|
2157
2189
|
if (this.pageTableInFlight = !1, this.pageTableDisposed || this.slabPages.length === 0) return;
|
|
2158
2190
|
const t = this.pagerSlots;
|
|
2159
2191
|
e.capacity !== t && (this.pendingWork = !0, this.lastScheduleTime = -1 / 0);
|
|
2160
|
-
const
|
|
2161
|
-
for (let
|
|
2192
|
+
const s = performance.now(), n = e.moveSlots;
|
|
2193
|
+
for (let h = 0; h < n.length; ) {
|
|
2162
2194
|
let g = 1;
|
|
2163
|
-
for (;
|
|
2195
|
+
for (; h + g < n.length && n[h + g] === n[h] + g; )
|
|
2164
2196
|
g++;
|
|
2165
|
-
const v = n[
|
|
2166
|
-
m > 0 && this.writeSlabSlots(yt(e.moves,
|
|
2197
|
+
const v = n[h], m = Math.min(g, t - v);
|
|
2198
|
+
m > 0 && this.writeSlabSlots(yt(e.moves, h, m), v, m), h += g;
|
|
2167
2199
|
}
|
|
2168
2200
|
if (e.appends.count > 0) {
|
|
2169
|
-
const
|
|
2170
|
-
|
|
2201
|
+
const h = Math.min(e.appends.count, t - e.appendStart);
|
|
2202
|
+
h > 0 && this.writeSlabSlots(e.appends, e.appendStart, h);
|
|
2171
2203
|
}
|
|
2172
|
-
const a = performance.now(),
|
|
2173
|
-
this.setSlabResident(
|
|
2174
|
-
const
|
|
2175
|
-
c > 0 && this.degenerateSlabSlots(
|
|
2176
|
-
const
|
|
2177
|
-
this.pageTableDrawn =
|
|
2204
|
+
const a = performance.now(), o = Math.min(e.residentCount, t);
|
|
2205
|
+
this.setSlabResident(o);
|
|
2206
|
+
const r = Math.min(e.degenerateStart, t), c = Math.min(e.degenerateCount, t - r);
|
|
2207
|
+
c > 0 && this.degenerateSlabSlots(r, c);
|
|
2208
|
+
const u = performance.now();
|
|
2209
|
+
this.pageTableDrawn = o, this.frontierConverged = e.converged, this.pendingFrontierSplats = e.pendingFrontierSplats ?? 0, this.staleResidentSplats = e.staleResidentSplats ?? 0, this.lastPlanAppends = e.lastPlanAppends ?? e.appends.count, this.lastPlanMoves = e.lastPlanMoves ?? e.moveSlots.length, this.lastPlanGeneration = e.planGeneration ?? this.lastPlanGeneration + 1, this.lastPlanBudget = e.planBudget ?? this.pageTableDrawBudget, e.cameraLocal && (this.lastPlanCamera = e.cameraLocal, this.firstFrontierCamera ?? (this.firstFrontierCamera = e.cameraLocal)), e.gatherMissing > 0 && E(
|
|
2178
2210
|
`StreamedSplatMesh: page-table plan gathered ${e.gatherMissing} splats from evicted chunks; they render as holes.`
|
|
2179
2211
|
);
|
|
2180
2212
|
const f = this.planTimingsValue;
|
|
2181
|
-
if (f.applyMs =
|
|
2182
|
-
const
|
|
2213
|
+
if (f.applyMs = u - s, f.writeMs = a - s, f.residentMs = u - a, f.moves = e.moveSlots.length, f.appends = e.appends.count, f.applyMs > f.worstApplyMs && (f.worstApplyMs = f.applyMs, f.worstSplats = f.moves + f.appends), this.frontierBandBase !== null && e.solvedLimit > 0 && this.pageTableLimit > 0) {
|
|
2214
|
+
const h = Math.min(1, e.solvedLimit / this.pageTableLimit);
|
|
2183
2215
|
this.setScreenRadiusBand(
|
|
2184
|
-
this.frontierBandBase.min *
|
|
2185
|
-
this.frontierBandBase.max *
|
|
2216
|
+
this.frontierBandBase.min * h,
|
|
2217
|
+
this.frontierBandBase.max * h
|
|
2186
2218
|
);
|
|
2187
2219
|
}
|
|
2188
2220
|
this.invalidateSort(), e.dropped > 0 && E(
|
|
2189
2221
|
`StreamedSplatMesh: page-table slab full, dropped ${e.dropped} frontier splats (draw budget ${this.pageTableDrawBudget} exceeds the pool).`
|
|
2190
2222
|
);
|
|
2191
|
-
for (let
|
|
2192
|
-
this.pageTableCachedFiles.delete(e.evicted[
|
|
2223
|
+
for (let h = 0; h < e.evicted.length; h++)
|
|
2224
|
+
this.pageTableCachedFiles.delete(e.evicted[h]);
|
|
2193
2225
|
this.fetchCountsValue.cacheBytes = e.cacheBytes, this.fetchCountsValue.cacheLimitBytes = e.cacheLimitBytes, this.pageTableCacheAtLimit = e.cacheBytes >= e.cacheLimitBytes, e.evicted.length > 0 && (this.fetchCountsValue.cacheFull = !0, this.fetchCountsValue.evicted += e.evicted.length), this.pageTableFetchPriority = Array.from(e.touched);
|
|
2194
|
-
for (const
|
|
2226
|
+
for (const h of this.pageTableFetchPriority) this.requestChunk(h, "priority");
|
|
2195
2227
|
(this.fetching.size > 0 || !e.converged) && (this.pendingWork = !0, e.converged || (this.lastScheduleTime = -1 / 0));
|
|
2196
2228
|
}
|
|
2197
2229
|
/** Forwards a decoded chunk's arrays to the worker (buffers transferred) so the
|
|
2198
2230
|
* worker's cache/traversal/gather can use it. */
|
|
2199
2231
|
forwardChunkToWorker(e, t) {
|
|
2200
|
-
const
|
|
2201
|
-
if (!
|
|
2232
|
+
const s = t.radTree;
|
|
2233
|
+
if (!s) return;
|
|
2202
2234
|
this.pageTableCachedFiles.add(e);
|
|
2203
2235
|
const n = this.shBands > 0 ? t.shPacked : void 0;
|
|
2204
2236
|
this.postToWorker(
|
|
@@ -2209,9 +2241,9 @@ class Y extends Ee {
|
|
|
2209
2241
|
positions: t.positions,
|
|
2210
2242
|
colors: t.colors,
|
|
2211
2243
|
covariances: t.covariances,
|
|
2212
|
-
childCount:
|
|
2213
|
-
childStart:
|
|
2214
|
-
size:
|
|
2244
|
+
childCount: s.childCount,
|
|
2245
|
+
childStart: s.childStart,
|
|
2246
|
+
size: s.size,
|
|
2215
2247
|
shBands: (n == null ? void 0 : n.bands) ?? 0,
|
|
2216
2248
|
...n ? { shPacked: n.packed, shRange: n.range } : {}
|
|
2217
2249
|
},
|
|
@@ -2219,9 +2251,9 @@ class Y extends Ee {
|
|
|
2219
2251
|
t.positions.buffer,
|
|
2220
2252
|
t.colors.buffer,
|
|
2221
2253
|
t.covariances.buffer,
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2254
|
+
s.childCount.buffer,
|
|
2255
|
+
s.childStart.buffer,
|
|
2256
|
+
s.size.buffer,
|
|
2225
2257
|
...n ? [n.packed.buffer] : []
|
|
2226
2258
|
]
|
|
2227
2259
|
);
|
|
@@ -2230,7 +2262,7 @@ class Y extends Ee {
|
|
|
2230
2262
|
* per-host cap simply queues. Same cap for classic and page-table so near
|
|
2231
2263
|
* detail is not structurally starved on the non-page-table path. */
|
|
2232
2264
|
get maxInflight() {
|
|
2233
|
-
return
|
|
2265
|
+
return ut;
|
|
2234
2266
|
}
|
|
2235
2267
|
/**
|
|
2236
2268
|
* Whether this mesh may run its speculative background sweep. A mesh with no
|
|
@@ -2260,8 +2292,8 @@ class Y extends Ee {
|
|
|
2260
2292
|
for (const t of this.fetching.values())
|
|
2261
2293
|
t.kind === e && t.controller.abort();
|
|
2262
2294
|
}
|
|
2263
|
-
requestChunk(e, t,
|
|
2264
|
-
var
|
|
2295
|
+
requestChunk(e, t, s) {
|
|
2296
|
+
var r, c;
|
|
2265
2297
|
if (this.cache.has(e) || this.pageTableCachedFiles.has(e) || this.fetching.has(e) || this.fetching.size >= this.maxInflight || this.failedFiles.has(e)) return;
|
|
2266
2298
|
const n = this.retrying.get(e);
|
|
2267
2299
|
if (n && performance.now() < n.readyAt) return;
|
|
@@ -2271,31 +2303,31 @@ class Y extends Ee {
|
|
|
2271
2303
|
E(`StreamedSplatMesh: manifest references unknown chunk file #${e}.`), this.failedFiles.add(e);
|
|
2272
2304
|
return;
|
|
2273
2305
|
}
|
|
2274
|
-
if (this.fetchHandle && !((
|
|
2275
|
-
const
|
|
2276
|
-
this.fetching.set(e, { controller:
|
|
2306
|
+
if (this.fetchHandle && !((r = this.fetchScheduler) != null && r.tryAcquire(this.fetchHandle, t))) return;
|
|
2307
|
+
const o = new AbortController();
|
|
2308
|
+
this.fetching.set(e, { controller: o, kind: t, classicWant: s }), this.loader.load(a, {
|
|
2277
2309
|
kind: this.scene.chunkKind,
|
|
2278
|
-
signal:
|
|
2310
|
+
signal: o.signal,
|
|
2279
2311
|
...(c = this.scene.chunkOptions) == null ? void 0 : c[e]
|
|
2280
|
-
}).then((
|
|
2281
|
-
var f,
|
|
2282
|
-
this.disposed || (this.retrying.delete(e), (
|
|
2283
|
-
}).catch((
|
|
2284
|
-
var
|
|
2285
|
-
if (
|
|
2286
|
-
const f = (((
|
|
2312
|
+
}).then((u) => {
|
|
2313
|
+
var f, h;
|
|
2314
|
+
this.disposed || (this.retrying.delete(e), (h = (f = this.scene.source).onChunkDecoded) == null || h.call(f, e, u), this.frontierWorker ? (this.forwardChunkToWorker(e, u), this.pendingWork = !0) : this.cacheChunk(e, u));
|
|
2315
|
+
}).catch((u) => {
|
|
2316
|
+
var h;
|
|
2317
|
+
if (D(u)) return;
|
|
2318
|
+
const f = (((h = this.retrying.get(e)) == null ? void 0 : h.attempts) ?? 0) + 1;
|
|
2287
2319
|
if (f >= gt)
|
|
2288
2320
|
this.retrying.delete(e), this.failedFiles.add(e), E(
|
|
2289
2321
|
`StreamedSplatMesh: gave up on chunk #${e} (${a}) after ${f} attempts.`,
|
|
2290
|
-
|
|
2322
|
+
u
|
|
2291
2323
|
);
|
|
2292
2324
|
else {
|
|
2293
2325
|
const g = pt * 2 ** (f - 1);
|
|
2294
2326
|
this.retrying.set(e, { attempts: f, readyAt: performance.now() + g });
|
|
2295
2327
|
}
|
|
2296
2328
|
}).finally(() => {
|
|
2297
|
-
var
|
|
2298
|
-
this.fetching.delete(e), this.fetchHandle && ((
|
|
2329
|
+
var u;
|
|
2330
|
+
this.fetching.delete(e), this.fetchHandle && ((u = this.fetchScheduler) == null || u.release(this.fetchHandle)), this.pendingWork = !0;
|
|
2299
2331
|
});
|
|
2300
2332
|
}
|
|
2301
2333
|
/**
|
|
@@ -2304,53 +2336,53 @@ class Y extends Ee {
|
|
|
2304
2336
|
* of {@link cache} (this method, eviction, dispose's clear) maintains it.
|
|
2305
2337
|
*/
|
|
2306
2338
|
cacheChunk(e, t) {
|
|
2307
|
-
const
|
|
2308
|
-
|
|
2339
|
+
const s = this.cache.get(e);
|
|
2340
|
+
s !== void 0 && (this.cacheBytesTotal -= s.bytes);
|
|
2309
2341
|
const n = Xe(t);
|
|
2310
2342
|
this.cache.set(e, { data: t, bytes: n, lastUsed: performance.now() }), this.cacheBytesTotal += n;
|
|
2311
2343
|
}
|
|
2312
2344
|
evictChunks(e) {
|
|
2313
2345
|
let t = this.cacheBytesTotal;
|
|
2314
2346
|
if (t <= this.cpuCacheBytes) return;
|
|
2315
|
-
const
|
|
2347
|
+
const s = [...this.cache.entries()].filter(
|
|
2316
2348
|
([n, a]) => a.lastUsed !== e && !this.scene.pinnedFiles.has(n) && !this.neededFiles.has(n)
|
|
2317
2349
|
).sort((n, a) => n[1].lastUsed - a[1].lastUsed);
|
|
2318
|
-
for (const [n, a] of
|
|
2350
|
+
for (const [n, a] of s) {
|
|
2319
2351
|
if (t <= this.cpuCacheBytes) break;
|
|
2320
2352
|
this.cache.delete(n), this.cacheBytesTotal -= a.bytes, t -= a.bytes, this.fetchCountsValue.evicted++;
|
|
2321
2353
|
}
|
|
2322
2354
|
}
|
|
2323
2355
|
}
|
|
2324
|
-
const V = new w.Vector3(), pe = new w.Vector3(), me = new w.Quaternion(), x = new w.Vector3(), ve = new w.Matrix4(), O = new w.Frustum(), wt = new w.Sphere(),
|
|
2325
|
-
function be(
|
|
2326
|
-
return Math.ceil(3 *
|
|
2356
|
+
const V = new w.Vector3(), pe = new w.Vector3(), me = new w.Quaternion(), x = new w.Vector3(), ve = new w.Matrix4(), O = new w.Frustum(), wt = new w.Sphere(), M = new w.Vector3(), Se = new w.Vector2();
|
|
2357
|
+
function be(l) {
|
|
2358
|
+
return Math.ceil(3 * Te(l) / 4);
|
|
2327
2359
|
}
|
|
2328
|
-
function yt(
|
|
2329
|
-
const t =
|
|
2360
|
+
function yt(l, i, e) {
|
|
2361
|
+
const t = l.shPacked;
|
|
2330
2362
|
return {
|
|
2331
2363
|
count: e,
|
|
2332
|
-
positions:
|
|
2333
|
-
colors:
|
|
2334
|
-
covariances:
|
|
2364
|
+
positions: l.positions.subarray(i * 3, (i + e) * 3),
|
|
2365
|
+
colors: l.colors.subarray(i * 4, (i + e) * 4),
|
|
2366
|
+
covariances: l.covariances.subarray(i * 6, (i + e) * 6),
|
|
2335
2367
|
...t ? {
|
|
2336
2368
|
shPacked: {
|
|
2337
2369
|
...t,
|
|
2338
2370
|
packed: t.packed.subarray(
|
|
2339
|
-
|
|
2340
|
-
(
|
|
2371
|
+
i * be(t.bands),
|
|
2372
|
+
(i + e) * be(t.bands)
|
|
2341
2373
|
)
|
|
2342
2374
|
}
|
|
2343
2375
|
} : {}
|
|
2344
2376
|
};
|
|
2345
2377
|
}
|
|
2346
2378
|
const Ct = 1;
|
|
2347
|
-
class
|
|
2348
|
-
constructor(
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
this.total = W(
|
|
2353
|
-
const e =
|
|
2379
|
+
class It {
|
|
2380
|
+
constructor(i = {}) {
|
|
2381
|
+
d(this, "entries", /* @__PURE__ */ new Map());
|
|
2382
|
+
d(this, "total");
|
|
2383
|
+
d(this, "hysteresis");
|
|
2384
|
+
this.total = W(i.totalBudget);
|
|
2385
|
+
const e = i.hysteresis ?? 0.1;
|
|
2354
2386
|
if (!Number.isFinite(e) || e < 0)
|
|
2355
2387
|
throw new RangeError("BudgetGovernor hysteresis must be a non-negative finite number.");
|
|
2356
2388
|
this.hysteresis = e;
|
|
@@ -2360,8 +2392,8 @@ class Tt {
|
|
|
2360
2392
|
return this.total;
|
|
2361
2393
|
}
|
|
2362
2394
|
/** Replaces the shared total and reallocates. */
|
|
2363
|
-
setTotalBudget(
|
|
2364
|
-
const e = W(
|
|
2395
|
+
setTotalBudget(i) {
|
|
2396
|
+
const e = W(i);
|
|
2365
2397
|
e !== this.total && (this.total = e, this.reallocate());
|
|
2366
2398
|
}
|
|
2367
2399
|
/** Number of registered members. */
|
|
@@ -2377,15 +2409,15 @@ class Tt {
|
|
|
2377
2409
|
* proportional to its weight - e.g. main mesh `7`, additional mesh `3` reproduces
|
|
2378
2410
|
* the old 0.7 host split. `0` registers the member suspended.
|
|
2379
2411
|
*/
|
|
2380
|
-
register(
|
|
2381
|
-
if (this.entries.has(
|
|
2412
|
+
register(i, e = {}) {
|
|
2413
|
+
if (this.entries.has(i))
|
|
2382
2414
|
throw new Error("BudgetGovernor: member is already registered.");
|
|
2383
2415
|
const t = J(e.weight ?? 1);
|
|
2384
|
-
this.entries.set(
|
|
2385
|
-
member:
|
|
2416
|
+
this.entries.set(i, {
|
|
2417
|
+
member: i,
|
|
2386
2418
|
weight: t,
|
|
2387
|
-
applied:
|
|
2388
|
-
restoreBudget:
|
|
2419
|
+
applied: i.budget,
|
|
2420
|
+
restoreBudget: i.budget
|
|
2389
2421
|
}), this.reallocate();
|
|
2390
2422
|
}
|
|
2391
2423
|
/**
|
|
@@ -2393,17 +2425,17 @@ class Tt {
|
|
|
2393
2425
|
* reallocates the total across the remaining members. No-op for a member
|
|
2394
2426
|
* that is not registered (so disposing hosts need not track membership).
|
|
2395
2427
|
*/
|
|
2396
|
-
unregister(
|
|
2397
|
-
const e = this.entries.get(
|
|
2398
|
-
e !== void 0 && (this.entries.delete(
|
|
2428
|
+
unregister(i) {
|
|
2429
|
+
const e = this.entries.get(i);
|
|
2430
|
+
e !== void 0 && (this.entries.delete(i), e.member.setBudget(e.restoreBudget), this.reallocate());
|
|
2399
2431
|
}
|
|
2400
2432
|
/**
|
|
2401
2433
|
* Changes a member's priority weight and reallocates. `0` suspends the
|
|
2402
2434
|
* member (see the class doc); any positive weight resumes it.
|
|
2403
2435
|
*/
|
|
2404
|
-
setWeight(
|
|
2405
|
-
const t = this.entryOf(
|
|
2406
|
-
|
|
2436
|
+
setWeight(i, e) {
|
|
2437
|
+
const t = this.entryOf(i), s = J(e);
|
|
2438
|
+
s !== t.weight && (t.weight = s, this.reallocate());
|
|
2407
2439
|
}
|
|
2408
2440
|
/**
|
|
2409
2441
|
* Writes several weights, then reallocates **once**.
|
|
@@ -2420,19 +2452,19 @@ class Tt {
|
|
|
2420
2452
|
* is written, so a bad pair leaves every weight untouched.
|
|
2421
2453
|
* @throws {RangeError} if any weight is not a non-negative finite number.
|
|
2422
2454
|
*/
|
|
2423
|
-
setWeights(
|
|
2424
|
-
const e = [...
|
|
2425
|
-
([
|
|
2455
|
+
setWeights(i) {
|
|
2456
|
+
const e = [...i].map(
|
|
2457
|
+
([s, n]) => [this.entryOf(s), J(n)]
|
|
2426
2458
|
);
|
|
2427
2459
|
let t = !1;
|
|
2428
|
-
for (const [
|
|
2429
|
-
|
|
2460
|
+
for (const [s, n] of e)
|
|
2461
|
+
s.weight !== n && (s.weight = n, t = !0);
|
|
2430
2462
|
t && this.reallocate();
|
|
2431
2463
|
}
|
|
2432
2464
|
/** The budget the governor last applied to a member, if registered. */
|
|
2433
|
-
budgetOf(
|
|
2465
|
+
budgetOf(i) {
|
|
2434
2466
|
var e;
|
|
2435
|
-
return (e = this.entries.get(
|
|
2467
|
+
return (e = this.entries.get(i)) == null ? void 0 : e.applied;
|
|
2436
2468
|
}
|
|
2437
2469
|
/**
|
|
2438
2470
|
* Recomputes and applies every member's share. Called automatically by all
|
|
@@ -2440,19 +2472,19 @@ class Tt {
|
|
|
2440
2472
|
* outside the governor's view.
|
|
2441
2473
|
*/
|
|
2442
2474
|
reallocate() {
|
|
2443
|
-
let
|
|
2475
|
+
let i = [];
|
|
2444
2476
|
for (const t of this.entries.values())
|
|
2445
|
-
t.weight === 0 ? this.applyTarget(t, Ct) :
|
|
2477
|
+
t.weight === 0 ? this.applyTarget(t, Ct) : i.push(t);
|
|
2446
2478
|
let e = this.total;
|
|
2447
|
-
for (;
|
|
2448
|
-
const t =
|
|
2479
|
+
for (; i.length > 0; ) {
|
|
2480
|
+
const t = i.reduce((a, o) => a + o.weight, 0), s = [];
|
|
2449
2481
|
let n = 0;
|
|
2450
|
-
for (const a of
|
|
2451
|
-
const
|
|
2452
|
-
this.applyTarget(a,
|
|
2482
|
+
for (const a of i) {
|
|
2483
|
+
const o = Math.max(1, Math.floor(e * a.weight / t));
|
|
2484
|
+
this.applyTarget(a, o) && (s.push(a), n += a.applied);
|
|
2453
2485
|
}
|
|
2454
|
-
if (
|
|
2455
|
-
e = Math.max(0, e - n),
|
|
2486
|
+
if (s.length === 0) break;
|
|
2487
|
+
e = Math.max(0, e - n), i = i.filter((a) => !s.includes(a));
|
|
2456
2488
|
}
|
|
2457
2489
|
}
|
|
2458
2490
|
/**
|
|
@@ -2460,13 +2492,13 @@ class Tt {
|
|
|
2460
2492
|
* The governor itself stays usable (dispose is just "unregister everyone").
|
|
2461
2493
|
*/
|
|
2462
2494
|
dispose() {
|
|
2463
|
-
for (const
|
|
2464
|
-
|
|
2495
|
+
for (const i of this.entries.values())
|
|
2496
|
+
i.member.setBudget(i.restoreBudget);
|
|
2465
2497
|
this.entries.clear();
|
|
2466
2498
|
}
|
|
2467
2499
|
/** The entry for a registered member, or a thrown error naming the problem. */
|
|
2468
|
-
entryOf(
|
|
2469
|
-
const e = this.entries.get(
|
|
2500
|
+
entryOf(i) {
|
|
2501
|
+
const e = this.entries.get(i);
|
|
2470
2502
|
if (e === void 0)
|
|
2471
2503
|
throw new Error("BudgetGovernor: member is not registered.");
|
|
2472
2504
|
return e;
|
|
@@ -2475,36 +2507,36 @@ class Tt {
|
|
|
2475
2507
|
* Pushes `target` to a member, with the grow dead-band. Returns true when
|
|
2476
2508
|
* the member clamped below its target (it is capped and cannot absorb more).
|
|
2477
2509
|
*/
|
|
2478
|
-
applyTarget(
|
|
2479
|
-
if (e >
|
|
2480
|
-
if (e -
|
|
2481
|
-
} else if (e ===
|
|
2510
|
+
applyTarget(i, e) {
|
|
2511
|
+
if (e > i.applied) {
|
|
2512
|
+
if (e - i.applied <= this.hysteresis * i.applied) return !1;
|
|
2513
|
+
} else if (e === i.applied)
|
|
2482
2514
|
return !1;
|
|
2483
|
-
return
|
|
2515
|
+
return i.applied = i.member.setBudget(e), i.applied < e;
|
|
2484
2516
|
}
|
|
2485
2517
|
}
|
|
2486
|
-
function J(
|
|
2487
|
-
if (!Number.isFinite(
|
|
2518
|
+
function J(l) {
|
|
2519
|
+
if (!Number.isFinite(l) || l < 0)
|
|
2488
2520
|
throw new RangeError(
|
|
2489
2521
|
"BudgetGovernor member weight must be a non-negative finite number (0 suspends the member)."
|
|
2490
2522
|
);
|
|
2491
|
-
return
|
|
2523
|
+
return l;
|
|
2492
2524
|
}
|
|
2493
2525
|
const we = new w.Vector3(), ye = new w.Matrix4(), Ce = new w.Frustum(), Z = new w.Box3(), z = new w.Sphere();
|
|
2494
2526
|
class zt {
|
|
2495
|
-
constructor(
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2527
|
+
constructor(i = {}) {
|
|
2528
|
+
d(this, "entries", /* @__PURE__ */ new Map());
|
|
2529
|
+
d(this, "budgetGovernor");
|
|
2530
|
+
d(this, "minIntervalMs");
|
|
2531
|
+
d(this, "weightDeadband");
|
|
2532
|
+
d(this, "falloff");
|
|
2533
|
+
d(this, "offScreenWeight");
|
|
2534
|
+
d(this, "minWeight");
|
|
2535
|
+
d(this, "maxWeight");
|
|
2536
|
+
d(this, "lastUpdateAt", -1 / 0);
|
|
2505
2537
|
/** Set by membership/priority changes: the next update ignores both damps. */
|
|
2506
|
-
|
|
2507
|
-
if (this.budgetGovernor =
|
|
2538
|
+
d(this, "forceNext", !0);
|
|
2539
|
+
if (this.budgetGovernor = i.governor ?? new It(i), this.minIntervalMs = G(i.minIntervalMs ?? 250, "minIntervalMs"), this.weightDeadband = G(i.weightDeadband ?? 0.15, "weightDeadband"), this.falloff = U(i.falloff ?? 1, "falloff"), this.offScreenWeight = U(i.offScreenWeight ?? 0.25, "offScreenWeight"), this.minWeight = U(i.minWeight ?? 0.05, "minWeight"), this.maxWeight = U(i.maxWeight ?? 8, "maxWeight"), this.maxWeight < this.minWeight)
|
|
2508
2540
|
throw new RangeError("CameraBudgetGovernor maxWeight must be >= minWeight.");
|
|
2509
2541
|
}
|
|
2510
2542
|
/** The governor this drives; use it for fixed-weight members and diagnostics. */
|
|
@@ -2516,8 +2548,8 @@ class zt {
|
|
|
2516
2548
|
return this.budgetGovernor.totalBudget;
|
|
2517
2549
|
}
|
|
2518
2550
|
/** Replaces the shared total (e.g. the presenting budget on `sessionstart`). */
|
|
2519
|
-
setTotalBudget(
|
|
2520
|
-
this.budgetGovernor.setTotalBudget(
|
|
2551
|
+
setTotalBudget(i) {
|
|
2552
|
+
this.budgetGovernor.setTotalBudget(i);
|
|
2521
2553
|
}
|
|
2522
2554
|
/** Number of camera-weighted members. */
|
|
2523
2555
|
get size() {
|
|
@@ -2530,18 +2562,18 @@ class zt {
|
|
|
2530
2562
|
* @throws {Error} if the member is already registered here.
|
|
2531
2563
|
* @throws {RangeError} if `priority` or `fixedWeight` is invalid.
|
|
2532
2564
|
*/
|
|
2533
|
-
register(
|
|
2534
|
-
if (this.entries.has(
|
|
2565
|
+
register(i, e = {}) {
|
|
2566
|
+
if (this.entries.has(i))
|
|
2535
2567
|
throw new Error("CameraBudgetGovernor: member is already registered.");
|
|
2536
|
-
const t =
|
|
2537
|
-
this.budgetGovernor.register(
|
|
2568
|
+
const t = G(e.priority ?? 1, "priority"), s = e.fixedWeight === void 0 ? void 0 : G(e.fixedWeight, "fixedWeight"), n = s ?? t;
|
|
2569
|
+
this.budgetGovernor.register(i, { weight: n }), this.entries.set(i, { member: i, priority: t, fixedWeight: s, applied: n }), this.forceNext = !0;
|
|
2538
2570
|
}
|
|
2539
2571
|
/**
|
|
2540
2572
|
* Removes a member from this helper and the underlying governor, restoring
|
|
2541
2573
|
* the budget it had when it joined. No-op for an unknown member.
|
|
2542
2574
|
*/
|
|
2543
|
-
unregister(
|
|
2544
|
-
this.entries.delete(
|
|
2575
|
+
unregister(i) {
|
|
2576
|
+
this.entries.delete(i) && (this.budgetGovernor.unregister(i), this.forceNext = !0);
|
|
2545
2577
|
}
|
|
2546
2578
|
/**
|
|
2547
2579
|
* Changes a member's priority tier. Takes effect on the next {@link update},
|
|
@@ -2551,12 +2583,12 @@ class zt {
|
|
|
2551
2583
|
* @throws {Error} if the member is not registered here.
|
|
2552
2584
|
* @throws {RangeError} if `priority` is negative or not finite.
|
|
2553
2585
|
*/
|
|
2554
|
-
setPriority(
|
|
2555
|
-
const t = this.entries.get(
|
|
2586
|
+
setPriority(i, e) {
|
|
2587
|
+
const t = this.entries.get(i);
|
|
2556
2588
|
if (t === void 0)
|
|
2557
2589
|
throw new Error("CameraBudgetGovernor: member is not registered.");
|
|
2558
|
-
const
|
|
2559
|
-
|
|
2590
|
+
const s = G(e, "priority");
|
|
2591
|
+
s !== t.priority && (t.priority = s, this.forceNext = !0);
|
|
2560
2592
|
}
|
|
2561
2593
|
/**
|
|
2562
2594
|
* Recomputes every member's weight from the camera and applies them in one
|
|
@@ -2573,33 +2605,33 @@ class zt {
|
|
|
2573
2605
|
* @param now - Timestamp in ms on the `performance.now` clock; defaults to it.
|
|
2574
2606
|
* @returns whether weights were reapplied.
|
|
2575
2607
|
*/
|
|
2576
|
-
update(
|
|
2608
|
+
update(i, e = performance.now()) {
|
|
2577
2609
|
if (this.entries.size === 0) return !1;
|
|
2578
2610
|
const t = this.forceNext;
|
|
2579
2611
|
if (!t && e - this.lastUpdateAt < this.minIntervalMs) return !1;
|
|
2580
|
-
|
|
2581
|
-
const
|
|
2612
|
+
i.updateMatrixWorld(), i.getWorldPosition(we), ye.multiplyMatrices(i.projectionMatrix, i.matrixWorldInverse), Ce.setFromProjectionMatrix(ye);
|
|
2613
|
+
const s = [];
|
|
2582
2614
|
let n = !1;
|
|
2583
2615
|
for (const a of this.entries.values()) {
|
|
2584
|
-
const
|
|
2585
|
-
|
|
2616
|
+
const o = this.weightFor(a);
|
|
2617
|
+
s.push([a.member, o]), !n && this.isSignificant(a.applied, o) && (n = !0);
|
|
2586
2618
|
}
|
|
2587
2619
|
if (!t && !n) return !1;
|
|
2588
|
-
this.budgetGovernor.setWeights(
|
|
2589
|
-
for (const [a,
|
|
2590
|
-
const
|
|
2591
|
-
|
|
2620
|
+
this.budgetGovernor.setWeights(s);
|
|
2621
|
+
for (const [a, o] of s) {
|
|
2622
|
+
const r = this.entries.get(a);
|
|
2623
|
+
r !== void 0 && (r.applied = o);
|
|
2592
2624
|
}
|
|
2593
2625
|
return this.lastUpdateAt = e, this.forceNext = !1, !0;
|
|
2594
2626
|
}
|
|
2595
2627
|
/** The weight currently written for a member, if registered here. */
|
|
2596
|
-
weightOf(
|
|
2628
|
+
weightOf(i) {
|
|
2597
2629
|
var e;
|
|
2598
|
-
return (e = this.entries.get(
|
|
2630
|
+
return (e = this.entries.get(i)) == null ? void 0 : e.applied;
|
|
2599
2631
|
}
|
|
2600
2632
|
/** The budget the underlying governor last applied to a member. */
|
|
2601
|
-
budgetOf(
|
|
2602
|
-
return this.budgetGovernor.budgetOf(
|
|
2633
|
+
budgetOf(i) {
|
|
2634
|
+
return this.budgetGovernor.budgetOf(i);
|
|
2603
2635
|
}
|
|
2604
2636
|
/**
|
|
2605
2637
|
* Unregisters every member, restoring the budget each had when it joined.
|
|
@@ -2607,7 +2639,7 @@ class zt {
|
|
|
2607
2639
|
* any members the host registered on it directly.
|
|
2608
2640
|
*/
|
|
2609
2641
|
dispose() {
|
|
2610
|
-
for (const
|
|
2642
|
+
for (const i of [...this.entries.keys()]) this.budgetGovernor.unregister(i);
|
|
2611
2643
|
this.entries.clear(), this.lastUpdateAt = -1 / 0, this.forceNext = !0;
|
|
2612
2644
|
}
|
|
2613
2645
|
/**
|
|
@@ -2621,49 +2653,49 @@ class zt {
|
|
|
2621
2653
|
* distant center, and is floored so a camera inside the bounds saturates at
|
|
2622
2654
|
* `maxWeight` rather than dividing by zero.
|
|
2623
2655
|
*/
|
|
2624
|
-
weightFor(
|
|
2625
|
-
if (
|
|
2626
|
-
const { member: e, priority: t } =
|
|
2656
|
+
weightFor(i) {
|
|
2657
|
+
if (i.fixedWeight !== void 0) return i.fixedWeight;
|
|
2658
|
+
const { member: e, priority: t } = i;
|
|
2627
2659
|
if (t === 0 || !(e.effectiveVisibility ?? e.visible)) return 0;
|
|
2628
2660
|
if (e.updateWorldMatrix(!0, !1), Z.copy(e.computeSplatBounds()), Z.isEmpty()) return t * this.minWeight;
|
|
2629
2661
|
Z.applyMatrix4(e.matrixWorld).getBoundingSphere(z);
|
|
2630
|
-
const
|
|
2631
|
-
if (!(
|
|
2632
|
-
const n = z.center.distanceTo(we) -
|
|
2633
|
-
if (!Number.isFinite(
|
|
2634
|
-
const
|
|
2635
|
-
return t *
|
|
2662
|
+
const s = z.radius;
|
|
2663
|
+
if (!(s > 0)) return t * this.minWeight;
|
|
2664
|
+
const n = z.center.distanceTo(we) - s, a = Math.max(n, s * 1e-3, 1e-6), o = Tt((s / a) ** this.falloff, this.minWeight, this.maxWeight);
|
|
2665
|
+
if (!Number.isFinite(o)) return t * this.minWeight;
|
|
2666
|
+
const r = Ce.intersectsSphere(z) ? 1 : this.offScreenWeight;
|
|
2667
|
+
return t * o * r;
|
|
2636
2668
|
}
|
|
2637
2669
|
/** Whether a weight moved enough to be worth a reallocation. */
|
|
2638
|
-
isSignificant(
|
|
2639
|
-
return
|
|
2670
|
+
isSignificant(i, e) {
|
|
2671
|
+
return i === 0 || e === 0 ? i !== e : Math.abs(e - i) > this.weightDeadband * i;
|
|
2640
2672
|
}
|
|
2641
2673
|
}
|
|
2642
|
-
function
|
|
2643
|
-
return Math.min(e, Math.max(
|
|
2674
|
+
function Tt(l, i, e) {
|
|
2675
|
+
return Math.min(e, Math.max(i, l));
|
|
2644
2676
|
}
|
|
2645
|
-
function
|
|
2646
|
-
if (!Number.isFinite(
|
|
2647
|
-
throw new RangeError(`CameraBudgetGovernor ${
|
|
2648
|
-
return
|
|
2677
|
+
function G(l, i) {
|
|
2678
|
+
if (!Number.isFinite(l) || l < 0)
|
|
2679
|
+
throw new RangeError(`CameraBudgetGovernor ${i} must be a non-negative finite number.`);
|
|
2680
|
+
return l;
|
|
2649
2681
|
}
|
|
2650
|
-
function U(
|
|
2651
|
-
if (!Number.isFinite(
|
|
2652
|
-
throw new RangeError(`CameraBudgetGovernor ${
|
|
2653
|
-
return
|
|
2682
|
+
function U(l, i) {
|
|
2683
|
+
if (!Number.isFinite(l) || l <= 0)
|
|
2684
|
+
throw new RangeError(`CameraBudgetGovernor ${i} must be a positive finite number.`);
|
|
2685
|
+
return l;
|
|
2654
2686
|
}
|
|
2655
|
-
const Rt = 16,
|
|
2687
|
+
const Rt = 16, Ft = 1;
|
|
2656
2688
|
class Ut {
|
|
2657
|
-
constructor(
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2689
|
+
constructor(i = {}) {
|
|
2690
|
+
d(this, "entries", /* @__PURE__ */ new Set());
|
|
2691
|
+
d(this, "maxGlobalInflight");
|
|
2692
|
+
d(this, "perMeshFloor");
|
|
2693
|
+
d(this, "inflightCount", 0);
|
|
2694
|
+
d(this, "disposed", !1);
|
|
2663
2695
|
this.maxGlobalInflight = Math.max(
|
|
2664
2696
|
1,
|
|
2665
|
-
Math.floor(
|
|
2666
|
-
), this.perMeshFloor = Math.max(0, Math.floor(
|
|
2697
|
+
Math.floor(i.maxGlobalInflight ?? Rt)
|
|
2698
|
+
), this.perMeshFloor = Math.max(0, Math.floor(i.perMeshFloor ?? Ft));
|
|
2667
2699
|
}
|
|
2668
2700
|
/** Total slots granted and not yet released. */
|
|
2669
2701
|
get inflight() {
|
|
@@ -2673,16 +2705,16 @@ class Ut {
|
|
|
2673
2705
|
get clientCount() {
|
|
2674
2706
|
return this.entries.size;
|
|
2675
2707
|
}
|
|
2676
|
-
register(
|
|
2677
|
-
const e = { client:
|
|
2708
|
+
register(i) {
|
|
2709
|
+
const e = { client: i, held: 0, demanding: !1, live: !0 };
|
|
2678
2710
|
return this.entries.add(e), e;
|
|
2679
2711
|
}
|
|
2680
2712
|
/**
|
|
2681
2713
|
* Drops a mesh. Slots it still holds are released here: a disposing mesh
|
|
2682
2714
|
* aborts its fetches, and those aborts land after the handle is gone.
|
|
2683
2715
|
*/
|
|
2684
|
-
unregister(
|
|
2685
|
-
const e =
|
|
2716
|
+
unregister(i) {
|
|
2717
|
+
const e = i;
|
|
2686
2718
|
this.entries.delete(e) && (e.live = !1, e.held > 0 && (this.inflightCount -= e.held, e.held = 0, this.wake()));
|
|
2687
2719
|
}
|
|
2688
2720
|
/**
|
|
@@ -2692,19 +2724,19 @@ class Ut {
|
|
|
2692
2724
|
* mesh simply did not fetch this tick, and will be woken (or reschedule on
|
|
2693
2725
|
* its own within the idle interval) to ask again.
|
|
2694
2726
|
*/
|
|
2695
|
-
tryAcquire(
|
|
2696
|
-
const t =
|
|
2727
|
+
tryAcquire(i, e) {
|
|
2728
|
+
const t = i;
|
|
2697
2729
|
if (this.disposed || !t.live) return !1;
|
|
2698
|
-
const
|
|
2699
|
-
return e === "sweep" &&
|
|
2730
|
+
const s = H(t.client.weight());
|
|
2731
|
+
return e === "sweep" && s <= 0 ? (t.demanding = !1, !1) : this.inflightCount >= this.maxGlobalInflight || t.held >= this.shareFor(t, s) ? (t.demanding = !0, !1) : (t.held++, t.demanding = !1, this.inflightCount++, !0);
|
|
2700
2732
|
}
|
|
2701
2733
|
/**
|
|
2702
2734
|
* Returns a slot. Must be called exactly once for every granted acquire -
|
|
2703
2735
|
* on success, on failure **and** on abort - or the pipe leaks capacity until
|
|
2704
2736
|
* the scene is torn down.
|
|
2705
2737
|
*/
|
|
2706
|
-
release(
|
|
2707
|
-
const e =
|
|
2738
|
+
release(i) {
|
|
2739
|
+
const e = i;
|
|
2708
2740
|
e.held <= 0 || (e.held--, this.inflightCount--, this.wake());
|
|
2709
2741
|
}
|
|
2710
2742
|
/**
|
|
@@ -2717,8 +2749,8 @@ class Ut {
|
|
|
2717
2749
|
*/
|
|
2718
2750
|
weightsChanged() {
|
|
2719
2751
|
if (!this.disposed) {
|
|
2720
|
-
for (const
|
|
2721
|
-
|
|
2752
|
+
for (const i of this.entries)
|
|
2753
|
+
i.held > 0 && H(i.client.weight()) <= 0 && i.client.shedFetches("sweep");
|
|
2722
2754
|
this.wake();
|
|
2723
2755
|
}
|
|
2724
2756
|
}
|
|
@@ -2729,8 +2761,8 @@ class Ut {
|
|
|
2729
2761
|
*/
|
|
2730
2762
|
dispose() {
|
|
2731
2763
|
this.disposed = !0;
|
|
2732
|
-
for (const
|
|
2733
|
-
|
|
2764
|
+
for (const i of this.entries)
|
|
2765
|
+
i.live = !1, i.held = 0, i.demanding = !1;
|
|
2734
2766
|
this.entries.clear(), this.inflightCount = 0;
|
|
2735
2767
|
}
|
|
2736
2768
|
/**
|
|
@@ -2750,47 +2782,47 @@ class Ut {
|
|
|
2750
2782
|
* The denominator counts every mesh that plausibly wants the pipe - all
|
|
2751
2783
|
* registered meshes except those both weightless and idle, plus the caller.
|
|
2752
2784
|
*/
|
|
2753
|
-
shareFor(
|
|
2754
|
-
let t = 0,
|
|
2755
|
-
for (const
|
|
2756
|
-
const c =
|
|
2757
|
-
|
|
2785
|
+
shareFor(i, e) {
|
|
2786
|
+
let t = 0, s = 0;
|
|
2787
|
+
for (const r of this.entries) {
|
|
2788
|
+
const c = r === i ? e : H(r.client.weight());
|
|
2789
|
+
r !== i && c <= 0 && r.held === 0 && !r.demanding || (t++, s += c);
|
|
2758
2790
|
}
|
|
2759
2791
|
if (t <= 1) return this.maxGlobalInflight;
|
|
2760
|
-
const n =
|
|
2761
|
-
return Math.max(1, Math.min(a, this.maxGlobalInflight -
|
|
2792
|
+
const n = s > 0 ? this.maxGlobalInflight * e / s : this.maxGlobalInflight / t, a = Math.max(1, this.perMeshFloor, Math.round(n)), o = Math.max(1, this.perMeshFloor) * (t - 1);
|
|
2793
|
+
return Math.max(1, Math.min(a, this.maxGlobalInflight - o));
|
|
2762
2794
|
}
|
|
2763
2795
|
/** Pokes the heaviest mesh that was denied since its last grant. */
|
|
2764
2796
|
wake() {
|
|
2765
2797
|
if (this.disposed || this.inflightCount >= this.maxGlobalInflight) return;
|
|
2766
|
-
let
|
|
2798
|
+
let i = null, e = -1 / 0;
|
|
2767
2799
|
for (const t of this.entries) {
|
|
2768
2800
|
if (!t.demanding) continue;
|
|
2769
|
-
const
|
|
2770
|
-
|
|
2801
|
+
const s = H(t.client.weight());
|
|
2802
|
+
s > e && (i = t, e = s);
|
|
2771
2803
|
}
|
|
2772
|
-
|
|
2804
|
+
i && (i.demanding = !1, i.client.onSlotAvailable());
|
|
2773
2805
|
}
|
|
2774
2806
|
}
|
|
2775
|
-
function H(
|
|
2776
|
-
return Number.isFinite(
|
|
2807
|
+
function H(l) {
|
|
2808
|
+
return Number.isFinite(l) && l > 0 ? l : 0;
|
|
2777
2809
|
}
|
|
2778
|
-
const
|
|
2810
|
+
const Mt = 32 * 1024 * 1024, Bt = 250, Pt = 0.15;
|
|
2779
2811
|
class Ht {
|
|
2780
|
-
constructor(
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
if (!Number.isFinite(
|
|
2812
|
+
constructor(i) {
|
|
2813
|
+
d(this, "entries", /* @__PURE__ */ new Set());
|
|
2814
|
+
d(this, "perMeshFloorBytes");
|
|
2815
|
+
d(this, "minIntervalMs");
|
|
2816
|
+
d(this, "deadband");
|
|
2817
|
+
d(this, "totalBytesValue");
|
|
2818
|
+
d(this, "lastAllocationMs", Number.NEGATIVE_INFINITY);
|
|
2819
|
+
d(this, "disposed", !1);
|
|
2820
|
+
if (!Number.isFinite(i.totalBytes) || i.totalBytes <= 0)
|
|
2789
2821
|
throw new RangeError("Chunk cache totalBytes must be a positive finite number.");
|
|
2790
|
-
this.totalBytesValue = Math.floor(
|
|
2822
|
+
this.totalBytesValue = Math.floor(i.totalBytes), this.perMeshFloorBytes = Math.max(
|
|
2791
2823
|
0,
|
|
2792
|
-
Math.floor(
|
|
2793
|
-
), this.minIntervalMs = Math.max(0,
|
|
2824
|
+
Math.floor(i.perMeshFloorBytes ?? Mt)
|
|
2825
|
+
), this.minIntervalMs = Math.max(0, i.minIntervalMs ?? Bt), this.deadband = Math.max(0, i.deadband ?? Pt);
|
|
2794
2826
|
}
|
|
2795
2827
|
/** Bytes shared across every registered mesh. */
|
|
2796
2828
|
get totalBytes() {
|
|
@@ -2800,10 +2832,10 @@ class Ht {
|
|
|
2800
2832
|
* Resizes the scene envelope and re-splits immediately. For a host reacting
|
|
2801
2833
|
* to a quality change or a device-memory signal.
|
|
2802
2834
|
*/
|
|
2803
|
-
setTotalBytes(
|
|
2804
|
-
if (!Number.isFinite(
|
|
2835
|
+
setTotalBytes(i) {
|
|
2836
|
+
if (!Number.isFinite(i) || i <= 0)
|
|
2805
2837
|
throw new RangeError("Chunk cache totalBytes must be a positive finite number.");
|
|
2806
|
-
const e = Math.floor(
|
|
2838
|
+
const e = Math.floor(i);
|
|
2807
2839
|
e !== this.totalBytesValue && (this.totalBytesValue = e, this.allocate());
|
|
2808
2840
|
}
|
|
2809
2841
|
/** Meshes currently registered. */
|
|
@@ -2814,18 +2846,18 @@ class Ht {
|
|
|
2814
2846
|
* Adds a mesh and re-splits at once, so the caller can read its opening
|
|
2815
2847
|
* allowance out of {@link allowanceFor} before posting worker init.
|
|
2816
2848
|
*/
|
|
2817
|
-
register(
|
|
2818
|
-
const e = { client:
|
|
2849
|
+
register(i) {
|
|
2850
|
+
const e = { client: i, allowance: 0, live: !0 };
|
|
2819
2851
|
return this.entries.add(e), this.allocate({ force: !0, silentFor: e }), e;
|
|
2820
2852
|
}
|
|
2821
2853
|
/** Drops a mesh and hands its bytes back to the siblings. */
|
|
2822
|
-
unregister(
|
|
2823
|
-
const e =
|
|
2854
|
+
unregister(i) {
|
|
2855
|
+
const e = i;
|
|
2824
2856
|
this.entries.delete(e) && (e.live = !1, e.allowance = 0, this.allocate({ force: !0 }));
|
|
2825
2857
|
}
|
|
2826
2858
|
/** This mesh's current allowance in bytes, or 0 once unregistered. */
|
|
2827
|
-
allowanceFor(
|
|
2828
|
-
const e =
|
|
2859
|
+
allowanceFor(i) {
|
|
2860
|
+
const e = i;
|
|
2829
2861
|
return e.live ? e.allowance : 0;
|
|
2830
2862
|
}
|
|
2831
2863
|
/**
|
|
@@ -2835,8 +2867,8 @@ class Ht {
|
|
|
2835
2867
|
*
|
|
2836
2868
|
* Rate-limited and dead-banded; calling it every frame is the intended use.
|
|
2837
2869
|
*/
|
|
2838
|
-
weightsChanged(
|
|
2839
|
-
this.disposed ||
|
|
2870
|
+
weightsChanged(i = Date.now()) {
|
|
2871
|
+
this.disposed || i - this.lastAllocationMs < this.minIntervalMs || (this.lastAllocationMs = i, this.allocate());
|
|
2840
2872
|
}
|
|
2841
2873
|
/**
|
|
2842
2874
|
* Releases every registration. Meshes are not disposed - the budget is shared
|
|
@@ -2845,8 +2877,8 @@ class Ht {
|
|
|
2845
2877
|
*/
|
|
2846
2878
|
dispose() {
|
|
2847
2879
|
this.disposed = !0;
|
|
2848
|
-
for (const
|
|
2849
|
-
|
|
2880
|
+
for (const i of this.entries)
|
|
2881
|
+
i.live = !1, i.allowance = 0;
|
|
2850
2882
|
this.entries.clear();
|
|
2851
2883
|
}
|
|
2852
2884
|
/**
|
|
@@ -2860,44 +2892,44 @@ class Ht {
|
|
|
2860
2892
|
* silently overcommitting, because a budget that can be exceeded by
|
|
2861
2893
|
* registering more meshes is the bug this class exists to fix.
|
|
2862
2894
|
*/
|
|
2863
|
-
allocate(
|
|
2895
|
+
allocate(i = {}) {
|
|
2864
2896
|
if (this.disposed) return;
|
|
2865
2897
|
const e = [...this.entries];
|
|
2866
2898
|
if (e.length === 0) return;
|
|
2867
|
-
const t = this.totalBytesValue,
|
|
2868
|
-
let
|
|
2869
|
-
for (let
|
|
2870
|
-
const c = Math.max(0,
|
|
2871
|
-
let
|
|
2872
|
-
for (const
|
|
2899
|
+
const t = this.totalBytesValue, s = Math.min(this.perMeshFloorBytes, Math.floor(t / e.length)), n = /* @__PURE__ */ new Map(), a = new Set(e);
|
|
2900
|
+
let o = t;
|
|
2901
|
+
for (let r = 0; r <= e.length && a.size > 0; r++) {
|
|
2902
|
+
const c = Math.max(0, o - s * a.size);
|
|
2903
|
+
let u = 0;
|
|
2904
|
+
for (const h of a) u += Ie(h.client.weight());
|
|
2873
2905
|
const f = [];
|
|
2874
|
-
for (const
|
|
2875
|
-
const g =
|
|
2876
|
-
b >= m ? (n.set(
|
|
2906
|
+
for (const h of a) {
|
|
2907
|
+
const g = Ie(h.client.weight()), v = u > 0 ? c * g / u : c / a.size, m = kt(h.client.ceilingBytes), b = Math.floor(s + v);
|
|
2908
|
+
b >= m ? (n.set(h, m), f.push(h)) : n.set(h, b);
|
|
2877
2909
|
}
|
|
2878
2910
|
if (f.length === 0) break;
|
|
2879
|
-
for (const
|
|
2880
|
-
a.delete(
|
|
2881
|
-
|
|
2911
|
+
for (const h of f)
|
|
2912
|
+
a.delete(h), o -= n.get(h) ?? 0;
|
|
2913
|
+
o = Math.max(0, o);
|
|
2882
2914
|
}
|
|
2883
|
-
for (const
|
|
2884
|
-
const c = n.get(
|
|
2885
|
-
|
|
2915
|
+
for (const r of e) {
|
|
2916
|
+
const c = n.get(r) ?? 0, u = r.allowance;
|
|
2917
|
+
r.allowance = c, r !== i.silentFor && (!i.force && !this.movedEnough(u, c) || u !== c && r.client.onAllowanceChanged(c));
|
|
2886
2918
|
}
|
|
2887
2919
|
}
|
|
2888
2920
|
/** Suppresses reposts for changes too small to alter any mesh's behaviour. */
|
|
2889
|
-
movedEnough(
|
|
2890
|
-
return
|
|
2921
|
+
movedEnough(i, e) {
|
|
2922
|
+
return i === e ? !1 : i === 0 || e === 0 ? !0 : Math.abs(e - i) / i >= this.deadband;
|
|
2891
2923
|
}
|
|
2892
2924
|
}
|
|
2893
|
-
function
|
|
2894
|
-
return Number.isFinite(
|
|
2925
|
+
function Ie(l) {
|
|
2926
|
+
return Number.isFinite(l) && l > 0 ? l : 0;
|
|
2895
2927
|
}
|
|
2896
|
-
function kt(
|
|
2897
|
-
return Number.isFinite(
|
|
2928
|
+
function kt(l) {
|
|
2929
|
+
return Number.isFinite(l) && l > 0 ? Math.floor(l) : Number.MAX_SAFE_INTEGER;
|
|
2898
2930
|
}
|
|
2899
2931
|
export {
|
|
2900
|
-
|
|
2932
|
+
It as BudgetGovernor,
|
|
2901
2933
|
zt as CameraBudgetGovernor,
|
|
2902
2934
|
Ht as ChunkCacheBudget,
|
|
2903
2935
|
Ut as ChunkFetchScheduler,
|
|
@@ -2905,7 +2937,7 @@ export {
|
|
|
2905
2937
|
Y as StreamedSplatMesh,
|
|
2906
2938
|
ot as createLocalDataset,
|
|
2907
2939
|
nt as httpDatasetSource,
|
|
2908
|
-
|
|
2940
|
+
D as isAbortError,
|
|
2909
2941
|
Be as resolveCpuCacheBytes
|
|
2910
2942
|
};
|
|
2911
2943
|
//# sourceMappingURL=streaming.js.map
|