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