ldr 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -12
- package/dist/cdn.d.ts +8 -41
- package/dist/cli.js +201 -36
- package/dist/cull.d.ts +68 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.js +1325 -549
- package/dist/instructions.d.ts +80 -0
- package/dist/load-worker.d.ts +1 -0
- package/dist/load-worker.gen.d.ts +2 -0
- package/dist/model.d.ts +23 -1
- package/dist/node/index.js +1414 -545
- package/dist/pack-io.d.ts +9 -0
- package/dist/parts-cdn.d.ts +66 -0
- package/dist/render.d.ts +24 -44
- package/dist/scene.d.ts +13 -3
- package/dist/spec.d.ts +7 -0
- package/package.json +2 -2
package/dist/node/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/spec.ts
|
|
2
2
|
var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
3
3
|
function parseColor(tok) {
|
|
4
4
|
if (/^0x/i.test(tok))
|
|
@@ -86,6 +86,36 @@ var b64 = (s) => {
|
|
|
86
86
|
out[i] = bin.charCodeAt(i);
|
|
87
87
|
return out;
|
|
88
88
|
};
|
|
89
|
+
function type1Fast(line) {
|
|
90
|
+
const n = line.length;
|
|
91
|
+
let i = 1;
|
|
92
|
+
const ws = (c) => c === 32 || c === 9;
|
|
93
|
+
const next = () => {
|
|
94
|
+
while (i < n && ws(line.charCodeAt(i)))
|
|
95
|
+
i++;
|
|
96
|
+
const a = i;
|
|
97
|
+
while (i < n && !ws(line.charCodeAt(i)))
|
|
98
|
+
i++;
|
|
99
|
+
return a < i ? line.slice(a, i) : null;
|
|
100
|
+
};
|
|
101
|
+
const ct = next();
|
|
102
|
+
if (ct === null)
|
|
103
|
+
return null;
|
|
104
|
+
const m = new Array(12);
|
|
105
|
+
for (let k = 0;k < 12; k++) {
|
|
106
|
+
const t = next();
|
|
107
|
+
if (t === null)
|
|
108
|
+
return null;
|
|
109
|
+
m[k] = +t;
|
|
110
|
+
}
|
|
111
|
+
while (i < n && ws(line.charCodeAt(i)))
|
|
112
|
+
i++;
|
|
113
|
+
if (i >= n)
|
|
114
|
+
return null;
|
|
115
|
+
const rest = line.slice(i);
|
|
116
|
+
const file = /[ \t]{2,}|\t/.test(rest) ? rest.split(/\s+/).join(" ") : rest;
|
|
117
|
+
return { t: 1, color: parseColor(ct), m, file: norm(file) };
|
|
118
|
+
}
|
|
89
119
|
function geomLine(tk) {
|
|
90
120
|
const t = +tk[0];
|
|
91
121
|
if (!(t >= 1 && t <= 5) || tk.length < 2)
|
|
@@ -154,7 +184,8 @@ function parse(src, name = "main.ldr", popts = {}) {
|
|
|
154
184
|
} else
|
|
155
185
|
c.tex = top.map;
|
|
156
186
|
};
|
|
157
|
-
for (const raw of src.split(
|
|
187
|
+
for (const raw of src.split(`
|
|
188
|
+
`)) {
|
|
158
189
|
const line = raw.trim();
|
|
159
190
|
if (!line)
|
|
160
191
|
continue;
|
|
@@ -205,6 +236,17 @@ function parse(src, name = "main.ldr", popts = {}) {
|
|
|
205
236
|
continue;
|
|
206
237
|
}
|
|
207
238
|
}
|
|
239
|
+
if (line.charCodeAt(0) === 49 && (line.charCodeAt(1) === 32 || line.charCodeAt(1) === 9) && !dataCur && !skip) {
|
|
240
|
+
const g = type1Fast(line);
|
|
241
|
+
if (g) {
|
|
242
|
+
if (!cur)
|
|
243
|
+
start(name);
|
|
244
|
+
annotate(g, false);
|
|
245
|
+
cur.cmds.push(g);
|
|
246
|
+
inHeader = false;
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
208
250
|
const tk = line.split(/\s+/);
|
|
209
251
|
const t = +tk[0];
|
|
210
252
|
if (t === 0) {
|
|
@@ -413,6 +455,7 @@ function transformTexMap(map, m) {
|
|
|
413
455
|
const x = (q) => [m[3] * q[0] + m[4] * q[1] + m[5] * q[2] + m[0], m[6] * q[0] + m[7] * q[1] + m[8] * q[2] + m[1], m[9] * q[0] + m[10] * q[1] + m[11] * q[2] + m[2]];
|
|
414
456
|
return { ...map, p1: x(map.p1), p2: x(map.p2), p3: x(map.p3) };
|
|
415
457
|
}
|
|
458
|
+
var STUB_OVERRIDES = { "32531.dat": "32531a.dat" };
|
|
416
459
|
function mul(a, b) {
|
|
417
460
|
const [ax, ay, az, a0, a1, a2, a3, a4, a5, a6, a7, a8] = a, [bx, by, bz, b0, b1, b2, b3, b4, b5, b6, b7, b8] = b;
|
|
418
461
|
return [
|
|
@@ -647,12 +690,15 @@ function fileStepViews(f) {
|
|
|
647
690
|
viewMemo.set(f, out);
|
|
648
691
|
return out;
|
|
649
692
|
}
|
|
650
|
-
// ../../../../../../../tmp/ldr-build-
|
|
693
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/model.ts
|
|
694
|
+
var CALLOUT_END = 999999;
|
|
695
|
+
var stepKey = (steps) => steps.map((x) => String(x).padStart(6, "0")).join(".") + "~";
|
|
651
696
|
function flatten(doc, opts = {}) {
|
|
652
697
|
const out = [];
|
|
653
698
|
const maxDepth = opts.maxDepth ?? 64;
|
|
654
|
-
const loose = opts.looseGeometry !== false, tx = !!opts.textures;
|
|
699
|
+
const loose = opts.looseGeometry !== false, tx = !!opts.textures, co = !!opts.callouts;
|
|
655
700
|
const src = new Map;
|
|
701
|
+
let subs = 0;
|
|
656
702
|
const lazy = (f, k) => {
|
|
657
703
|
const key = f.name + "#" + k;
|
|
658
704
|
let fn = src.get(key);
|
|
@@ -663,16 +709,44 @@ function flatten(doc, opts = {}) {
|
|
|
663
709
|
}
|
|
664
710
|
return fn;
|
|
665
711
|
};
|
|
666
|
-
const walk = (d, fname, m, color, path, stepPath, depth, texIn) => {
|
|
712
|
+
const walk = (d, fname, m, color, path, stepPath, depth, texIn, fixed = null, subPath = [], subMats = []) => {
|
|
667
713
|
const f = d.files.get(fname);
|
|
668
714
|
if (!f || depth > maxDepth)
|
|
669
715
|
return;
|
|
670
716
|
let s = 0;
|
|
717
|
+
const subId = depth > 0 ? ++subs : 0;
|
|
718
|
+
const sp0 = co && subId ? [...subPath, subId] : subPath;
|
|
719
|
+
const sm0 = co && subId ? [...subMats, m] : subMats;
|
|
720
|
+
const groups = co && !fixed ? new Map : null;
|
|
721
|
+
let ordStep = -1, ord = 0;
|
|
722
|
+
const sub = (sd, file, mm, col, sp, lt) => {
|
|
723
|
+
if (ordStep !== s) {
|
|
724
|
+
ordStep = s;
|
|
725
|
+
ord = 0;
|
|
726
|
+
}
|
|
727
|
+
const g = groups?.get(s + "|" + file);
|
|
728
|
+
if (g) {
|
|
729
|
+
g.n++;
|
|
730
|
+
return walk(sd, sd === d ? file : sd.main, mm, col, path + "/" + file, [...sp, CALLOUT_END], depth + 1, lt, [...sp, CALLOUT_END], sp0, sm0);
|
|
731
|
+
}
|
|
732
|
+
const spo = [...sp, ord++], from = out.length;
|
|
733
|
+
walk(sd, sd === d ? file : sd.main, mm, col, path + "/" + file, spo, depth + 1, lt, fixed, sp0, sm0);
|
|
734
|
+
groups?.set(s + "|" + file, { n: 1, from, to: out.length });
|
|
735
|
+
};
|
|
671
736
|
const views = fileStepViews(f);
|
|
672
737
|
const ls = loose ? looseSteps(f) : [];
|
|
673
738
|
let li = 0;
|
|
674
739
|
const emit = (part, col, mm, sp, k, embedded, tex) => {
|
|
740
|
+
if (fixed)
|
|
741
|
+
sp = fixed;
|
|
675
742
|
const i = { part, color: col, m: mm, step: sp[0], steps: sp, localStep: k, path };
|
|
743
|
+
if (subId) {
|
|
744
|
+
i.sub = subId;
|
|
745
|
+
if (co) {
|
|
746
|
+
i.subPath = sp0;
|
|
747
|
+
i.subMats = sm0;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
676
750
|
if (embedded)
|
|
677
751
|
i.embedded = true;
|
|
678
752
|
if (tex) {
|
|
@@ -718,7 +792,7 @@ function flatten(doc, opts = {}) {
|
|
|
718
792
|
const lt = tex && local ? transformTexMap(tex, local) : null;
|
|
719
793
|
if (d.files.has(c.file)) {
|
|
720
794
|
if (fileKind(d, c.file) === "model") {
|
|
721
|
-
|
|
795
|
+
sub(d, c.file, mm, col, sp, lt);
|
|
722
796
|
continue;
|
|
723
797
|
}
|
|
724
798
|
emit(c.file, col, mm, sp, s, true, lt);
|
|
@@ -726,12 +800,18 @@ function flatten(doc, opts = {}) {
|
|
|
726
800
|
}
|
|
727
801
|
const ext = opts.resolveModel?.(c.file);
|
|
728
802
|
if (ext) {
|
|
729
|
-
|
|
803
|
+
sub(ext, c.file, mm, col, sp, lt);
|
|
730
804
|
continue;
|
|
731
805
|
}
|
|
732
806
|
emit(c.file, col, mm, sp, s, false, lt);
|
|
733
807
|
}
|
|
734
808
|
flushLoose(Infinity);
|
|
809
|
+
if (groups) {
|
|
810
|
+
for (const g of groups.values())
|
|
811
|
+
if (g.n > 1)
|
|
812
|
+
for (let j = g.from;j < g.to; j++)
|
|
813
|
+
out[j].mult ??= g.n;
|
|
814
|
+
}
|
|
735
815
|
};
|
|
736
816
|
if (fileKind(doc, doc.main) === "part") {
|
|
737
817
|
const f = doc.files.get(doc.main);
|
|
@@ -743,10 +823,10 @@ function flatten(doc, opts = {}) {
|
|
|
743
823
|
return out;
|
|
744
824
|
}
|
|
745
825
|
function parseModel(text, name = "main.ldr", opts) {
|
|
746
|
-
return flatten(parse(text, name), opts);
|
|
826
|
+
return flatten(parse(text, name, { geometryText: true }), opts);
|
|
747
827
|
}
|
|
748
828
|
function sequenceSteps(insts) {
|
|
749
|
-
const key = (i) => i.steps
|
|
829
|
+
const key = (i) => stepKey(i.steps);
|
|
750
830
|
const uniq = [...new Set(insts.map(key))].sort();
|
|
751
831
|
const rank = new Map(uniq.map((k, j) => [k, j]));
|
|
752
832
|
const stepOf = new Int32Array(insts.length);
|
|
@@ -768,326 +848,397 @@ function parseLDConfig(text) {
|
|
|
768
848
|
}
|
|
769
849
|
return out;
|
|
770
850
|
}
|
|
771
|
-
// ../../../../../../../tmp/ldr-build-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
buf = await new Response(res.body.pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();
|
|
779
|
-
else if (url.endsWith(".br"))
|
|
780
|
-
buf = await new Response(res.body.pipeThrough(new DecompressionStream("brotli"))).arrayBuffer();
|
|
781
|
-
else if (url.endsWith(".zst")) {
|
|
782
|
-
const raw = new Uint8Array(await res.arrayBuffer());
|
|
783
|
-
const t1 = performance.now();
|
|
784
|
-
const { decompress } = await import("fzstd");
|
|
785
|
-
const o = decompress(raw);
|
|
786
|
-
buf = o.buffer.slice(o.byteOffset, o.byteOffset + o.byteLength);
|
|
787
|
-
globalThis.__decodeMs = performance.now() - t1;
|
|
788
|
-
} else
|
|
789
|
-
buf = await res.arrayBuffer();
|
|
790
|
-
if (!url.endsWith(".zst"))
|
|
791
|
-
globalThis.__decodeMs = performance.now() - t0;
|
|
792
|
-
return decodePack(buf);
|
|
793
|
-
}
|
|
794
|
-
function decodePack(buf) {
|
|
795
|
-
const hl = new DataView(buf).getUint32(0, true);
|
|
796
|
-
const header = JSON.parse(new TextDecoder().decode(new Uint8Array(buf, 4, hl)));
|
|
797
|
-
const base = 4 + hl;
|
|
798
|
-
const arr = (r) => r && (r[2] === "f32" ? new Float32Array(buf, base + r[0], r[1]) : r[2] === "u16" ? new Uint16Array(buf, base + r[0], r[1]) : r[2] === "u8" ? new Uint8Array(buf, base + r[0], r[1]) : new Uint32Array(buf, base + r[0], r[1]));
|
|
799
|
-
return { header, arr, bytes: buf.byteLength, buffer: buf };
|
|
800
|
-
}
|
|
801
|
-
var toI8 = (a) => {
|
|
802
|
-
const o = new Int8Array(a.length);
|
|
803
|
-
for (let i = 0;i < a.length; i++)
|
|
804
|
-
o[i] = Math.round(Math.max(-1, Math.min(1, a[i])) * 127);
|
|
805
|
-
return o;
|
|
806
|
-
};
|
|
807
|
-
var toU8 = (a) => {
|
|
808
|
-
const o = new Uint8Array(a.length);
|
|
809
|
-
for (let i = 0;i < a.length; i++)
|
|
810
|
-
o[i] = Math.round(Math.max(0, Math.min(1, a[i])) * 255);
|
|
811
|
-
return o;
|
|
812
|
-
};
|
|
813
|
-
function flatNormals(pos, idx) {
|
|
814
|
-
const n = new Float32Array(pos.length);
|
|
815
|
-
for (let t = 0;t < idx.length; t += 3) {
|
|
816
|
-
const a = idx[t] * 3, b = idx[t + 1] * 3, c = idx[t + 2] * 3;
|
|
817
|
-
const ux = pos[b] - pos[a], uy = pos[b + 1] - pos[a + 1], uz = pos[b + 2] - pos[a + 2], vx = pos[c] - pos[a], vy = pos[c + 1] - pos[a + 1], vz = pos[c + 2] - pos[a + 2];
|
|
818
|
-
let nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;
|
|
819
|
-
const l = Math.hypot(nx, ny, nz) || 1;
|
|
820
|
-
nx /= l;
|
|
821
|
-
ny /= l;
|
|
822
|
-
nz /= l;
|
|
823
|
-
for (const o of [a, b, c]) {
|
|
824
|
-
n[o] = nx;
|
|
825
|
-
n[o + 1] = ny;
|
|
826
|
-
n[o + 2] = nz;
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
return n;
|
|
830
|
-
}
|
|
831
|
-
var geomCache = new WeakMap;
|
|
832
|
-
function geom(b, arr, quant = true) {
|
|
833
|
-
if (!b)
|
|
834
|
-
return null;
|
|
835
|
-
let c = geomCache.get(arr);
|
|
836
|
-
if (!c)
|
|
837
|
-
geomCache.set(arr, c = new Map);
|
|
838
|
-
const ck = quant ? b : b.pos;
|
|
839
|
-
let g = c.get(ck);
|
|
840
|
-
if (g)
|
|
841
|
-
return g;
|
|
842
|
-
g = new THREE.BufferGeometry;
|
|
843
|
-
g.setAttribute("position", new THREE.BufferAttribute(arr(b.pos), 3));
|
|
844
|
-
const nrm = b.nrm ? arr(b.nrm) : flatNormals(arr(b.pos), arr(b.idx));
|
|
845
|
-
const col = arr(b.col);
|
|
846
|
-
g.setAttribute("normal", quant ? new THREE.BufferAttribute(toI8(nrm), 3, true) : new THREE.BufferAttribute(nrm, 3));
|
|
847
|
-
g.setAttribute("ldrColor", col instanceof Uint8Array ? new THREE.BufferAttribute(col, 4, true) : quant ? new THREE.BufferAttribute(toU8(col), 4, true) : new THREE.BufferAttribute(col, 4));
|
|
848
|
-
if (b.idx)
|
|
849
|
-
g.setIndex(new THREE.BufferAttribute(arr(b.idx), 1));
|
|
850
|
-
if (b.uv)
|
|
851
|
-
g.setAttribute("ldrUV", new THREE.BufferAttribute(arr(b.uv), 2));
|
|
852
|
-
c.set(ck, g);
|
|
853
|
-
return g;
|
|
854
|
-
}
|
|
855
|
-
function makeMaterial(side) {
|
|
856
|
-
const m = new THREE.MeshStandardMaterial({ vertexColors: true, roughness: 0.45, side });
|
|
857
|
-
m.onBeforeCompile = (s) => {
|
|
858
|
-
s.vertexShader = `attribute vec4 ldrColor;
|
|
859
|
-
` + s.vertexShader.replace("#include <color_vertex>", `#include <color_vertex>
|
|
860
|
-
#ifdef USE_INSTANCING_COLOR
|
|
861
|
-
vColor.rgb = ldrColor.a > 0.5 ? pow(ldrColor.rgb, vec3(2.2)) : instanceColor.rgb; // baked LDConfig colours are sRGB
|
|
862
|
-
#else
|
|
863
|
-
vColor.rgb = pow(ldrColor.rgb, vec3(2.2));
|
|
864
|
-
#endif`);
|
|
865
|
-
};
|
|
866
|
-
m.customProgramCacheKey = () => "ldrColor";
|
|
867
|
-
return m;
|
|
851
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/instructions.ts
|
|
852
|
+
var MIN_VIS = 0.5;
|
|
853
|
+
var REORIENT = 0.35;
|
|
854
|
+
var deg = Math.PI / 180;
|
|
855
|
+
function viewDir(azimuthDeg, elevationDeg) {
|
|
856
|
+
const a = azimuthDeg * deg, e = elevationDeg * deg;
|
|
857
|
+
return [Math.sin(a) * Math.cos(e), -Math.sin(e), -Math.cos(a) * Math.cos(e)];
|
|
868
858
|
}
|
|
869
|
-
function
|
|
870
|
-
const m =
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
sh.uniforms.ldrWrapU = { value: wrapU ? 1 : 0 };
|
|
876
|
-
sh.vertexShader = `attribute vec2 ldrUV; varying vec2 vLdrUV;
|
|
877
|
-
` + sh.vertexShader.replace("#include <uv_vertex>", `#include <uv_vertex>
|
|
878
|
-
vLdrUV = ldrUV;`);
|
|
879
|
-
sh.fragmentShader = `uniform sampler2D ldrMap; uniform int ldrWrapU; varying vec2 vLdrUV;
|
|
880
|
-
` + sh.fragmentShader.replace("#include <color_fragment>", `#include <color_fragment>
|
|
881
|
-
{ vec2 uv = vec2(ldrWrapU == 1 ? fract(vLdrUV.x) : vLdrUV.x, vLdrUV.y); vec4 t = texture2D(ldrMap, uv);
|
|
882
|
-
float inside = step(0.0, uv.x) * step(uv.x, 1.0) * step(0.0, uv.y) * step(uv.y, 1.0);
|
|
883
|
-
diffuseColor.rgb = mix(diffuseColor.rgb, t.rgb, t.a * inside); }`);
|
|
884
|
-
};
|
|
885
|
-
m.customProgramCacheKey = () => "ldrColorTex";
|
|
886
|
-
m.userData.ldrMap = map;
|
|
859
|
+
function isolateMask(insts, sub) {
|
|
860
|
+
const m = new Uint8Array(insts.length);
|
|
861
|
+
insts.forEach((i, k) => {
|
|
862
|
+
if (i.subPath?.includes(sub))
|
|
863
|
+
m[k] = 1;
|
|
864
|
+
});
|
|
887
865
|
return m;
|
|
888
866
|
}
|
|
889
|
-
function
|
|
890
|
-
const
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
const
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
var lineMat = () => new THREE.ShaderMaterial({
|
|
905
|
-
vertexShader: `attribute vec4 im0; attribute vec4 im1; attribute vec4 im2; attribute vec4 im3;
|
|
906
|
-
void main(){ gl_Position = projectionMatrix * modelViewMatrix * mat4(im0,im1,im2,im3) * vec4(position,1.0); }`,
|
|
907
|
-
fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
|
|
908
|
-
});
|
|
909
|
-
var sharedLineMat = () => new THREE.ShaderMaterial({
|
|
910
|
-
vertexShader: `attribute mat4 instanceMatrix; void main(){ gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position,1.0); }`,
|
|
911
|
-
fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
|
|
912
|
-
});
|
|
913
|
-
var weldLines = (pos) => {
|
|
914
|
-
const map = new Map;
|
|
915
|
-
const P = [];
|
|
916
|
-
const I = [];
|
|
917
|
-
for (let i = 0;i < pos.length; i += 3) {
|
|
918
|
-
const k = pos[i].toFixed(2) + "," + pos[i + 1].toFixed(2) + "," + pos[i + 2].toFixed(2);
|
|
919
|
-
let j = map.get(k);
|
|
920
|
-
if (j === undefined) {
|
|
921
|
-
j = P.length / 3;
|
|
922
|
-
map.set(k, j);
|
|
923
|
-
P.push(pos[i], pos[i + 1], pos[i + 2]);
|
|
924
|
-
}
|
|
925
|
-
I.push(j);
|
|
867
|
+
function commonSub(insts, ids, whole) {
|
|
868
|
+
const path = insts[ids[0]]?.subPath;
|
|
869
|
+
if (!path)
|
|
870
|
+
return;
|
|
871
|
+
let n = path.length;
|
|
872
|
+
for (const id of ids) {
|
|
873
|
+
const p = insts[id].subPath;
|
|
874
|
+
if (!p)
|
|
875
|
+
return;
|
|
876
|
+
let j = 0;
|
|
877
|
+
while (j < n && j < p.length && p[j] === path[j])
|
|
878
|
+
j++;
|
|
879
|
+
n = j;
|
|
880
|
+
if (!n)
|
|
881
|
+
return;
|
|
926
882
|
}
|
|
927
|
-
return
|
|
928
|
-
};
|
|
929
|
-
function createInstancedEdges(pos, im, material = sharedLineMat()) {
|
|
930
|
-
return sharedLines(pos, im, material);
|
|
883
|
+
return whole(path[n - 1]) ? undefined : path[n - 1];
|
|
931
884
|
}
|
|
932
|
-
function
|
|
933
|
-
|
|
934
|
-
const
|
|
935
|
-
if (!
|
|
936
|
-
return
|
|
937
|
-
const
|
|
938
|
-
o
|
|
939
|
-
|
|
885
|
+
function instanceBoxes(insts, parts) {
|
|
886
|
+
return insts.map((i) => {
|
|
887
|
+
const b = parts[i.part]?.bbox;
|
|
888
|
+
if (!b)
|
|
889
|
+
return null;
|
|
890
|
+
const m = i.m;
|
|
891
|
+
const o = new Float64Array([Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity]);
|
|
892
|
+
for (let c = 0;c < 8; c++) {
|
|
893
|
+
const x = c & 1 ? b[3] : b[0], y = c & 2 ? b[4] : b[1], z = c & 4 ? b[5] : b[2];
|
|
894
|
+
const w = [m[0] + m[3] * x + m[4] * y + m[5] * z, m[1] + m[6] * x + m[7] * y + m[8] * z, m[2] + m[9] * x + m[10] * y + m[11] * z];
|
|
895
|
+
for (let k = 0;k < 3; k++) {
|
|
896
|
+
if (w[k] < o[k])
|
|
897
|
+
o[k] = w[k];
|
|
898
|
+
if (w[k] > o[k + 3])
|
|
899
|
+
o[k + 3] = w[k];
|
|
900
|
+
}
|
|
901
|
+
}
|
|
940
902
|
return o;
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
class BoxGrid {
|
|
907
|
+
cells = new Map;
|
|
908
|
+
boxes;
|
|
909
|
+
cell;
|
|
910
|
+
stamp;
|
|
911
|
+
q = 0;
|
|
912
|
+
lo;
|
|
913
|
+
hi;
|
|
914
|
+
constructor(boxes, cell) {
|
|
915
|
+
this.boxes = boxes;
|
|
916
|
+
this.cell = cell;
|
|
917
|
+
this.stamp = new Int32Array(boxes.length);
|
|
918
|
+
this.lo = [Infinity, Infinity, Infinity];
|
|
919
|
+
this.hi = [-Infinity, -Infinity, -Infinity];
|
|
920
|
+
for (const b of boxes)
|
|
921
|
+
if (b)
|
|
922
|
+
for (let k = 0;k < 3; k++) {
|
|
923
|
+
this.lo[k] = Math.min(this.lo[k], b[k]);
|
|
924
|
+
this.hi[k] = Math.max(this.hi[k], b[k + 3]);
|
|
925
|
+
}
|
|
941
926
|
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
return null;
|
|
945
|
-
const { arr } = pack;
|
|
946
|
-
if (c.raw)
|
|
947
|
-
return arr(c.raw);
|
|
948
|
-
const pools = [entry.body ? arr(entry.body.pos) : [], entry.under ? arr(entry.under.pos) : [], entry.edges ? arr(entry.edges) : [], c.x ? arr(c.x) : []];
|
|
949
|
-
const idx = arr(c.idx);
|
|
950
|
-
const out = new Float32Array(idx.length * 3);
|
|
951
|
-
const starts = [];
|
|
952
|
-
let base = 0;
|
|
953
|
-
for (const p of pools) {
|
|
954
|
-
starts.push(base);
|
|
955
|
-
base += p.length / 3;
|
|
927
|
+
key(i, j, k) {
|
|
928
|
+
return (i + 1024) * 4194304 + (j + 1024) * 2048 + (k + 1024);
|
|
956
929
|
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
let
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
930
|
+
add(id) {
|
|
931
|
+
const b = this.boxes[id];
|
|
932
|
+
if (!b)
|
|
933
|
+
return;
|
|
934
|
+
const c = this.cell;
|
|
935
|
+
for (let i = Math.floor(b[0] / c);i <= Math.floor(b[3] / c); i++)
|
|
936
|
+
for (let j = Math.floor(b[1] / c);j <= Math.floor(b[4] / c); j++)
|
|
937
|
+
for (let k = Math.floor(b[2] / c);k <= Math.floor(b[5] / c); k++) {
|
|
938
|
+
const key = this.key(i, j, k);
|
|
939
|
+
let l = this.cells.get(key);
|
|
940
|
+
if (!l)
|
|
941
|
+
this.cells.set(key, l = []);
|
|
942
|
+
l.push(id);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
inside(p, self) {
|
|
946
|
+
const c = this.cell;
|
|
947
|
+
const l = this.cells.get(this.key(Math.floor(p[0] / c), Math.floor(p[1] / c), Math.floor(p[2] / c)));
|
|
948
|
+
if (!l)
|
|
949
|
+
return false;
|
|
950
|
+
for (const id of l) {
|
|
951
|
+
if (id === self)
|
|
952
|
+
continue;
|
|
953
|
+
const b = this.boxes[id];
|
|
954
|
+
if (p[0] > b[0] && p[0] < b[3] && p[1] > b[1] && p[1] < b[4] && p[2] > b[2] && p[2] < b[5])
|
|
955
|
+
return true;
|
|
956
|
+
}
|
|
957
|
+
return false;
|
|
958
|
+
}
|
|
959
|
+
hits(p, d, self, eps = 0.5) {
|
|
960
|
+
const c = this.cell, q = ++this.q;
|
|
961
|
+
let i = Math.floor(p[0] / c), j = Math.floor(p[1] / c), k = Math.floor(p[2] / c);
|
|
962
|
+
const step = d.map((v) => v > 0 ? 1 : v < 0 ? -1 : 0);
|
|
963
|
+
const idx = [i, j, k];
|
|
964
|
+
const tMax = [0, 1, 2].map((a) => d[a] === 0 ? Infinity : ((idx[a] + (d[a] > 0 ? 1 : 0)) * c - p[a]) / d[a]);
|
|
965
|
+
const tDelta = [0, 1, 2].map((a) => d[a] === 0 ? Infinity : c / Math.abs(d[a]));
|
|
966
|
+
const bound = [0, 1, 2].map((a) => d[a] > 0 ? Math.floor(this.hi[a] / c) + 1 : d[a] < 0 ? Math.floor(this.lo[a] / c) - 1 : 0);
|
|
967
|
+
for (let n = 0;n < 4096; n++) {
|
|
968
|
+
const l = this.cells.get(this.key(idx[0], idx[1], idx[2]));
|
|
969
|
+
if (l)
|
|
970
|
+
for (const id of l) {
|
|
971
|
+
if (id === self || this.stamp[id] === q)
|
|
972
|
+
continue;
|
|
973
|
+
this.stamp[id] = q;
|
|
974
|
+
if (rayBox(p, d, this.boxes[id], eps))
|
|
975
|
+
return true;
|
|
976
|
+
}
|
|
977
|
+
const a = tMax[0] < tMax[1] ? tMax[0] < tMax[2] ? 0 : 2 : tMax[1] < tMax[2] ? 1 : 2;
|
|
978
|
+
idx[a] += step[a];
|
|
979
|
+
tMax[a] += tDelta[a];
|
|
980
|
+
if (step[a] === 0 || idx[a] === bound[a])
|
|
981
|
+
return false;
|
|
982
|
+
}
|
|
983
|
+
return false;
|
|
969
984
|
}
|
|
970
|
-
return out;
|
|
971
985
|
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
const A = pr(o), B = pr(o + 3), C0 = pr(o + 6), C1 = pr(o + 9);
|
|
993
|
-
const dx = B[0] - A[0], dy = B[1] - A[1];
|
|
994
|
-
const s0 = dx * (C0[1] - A[1]) - dy * (C0[0] - A[0]), s1 = dx * (C1[1] - A[1]) - dy * (C1[0] - A[0]);
|
|
995
|
-
return s0 * s1 >= 0;
|
|
986
|
+
function rayBox(p, d, b, eps) {
|
|
987
|
+
let t0 = 0.000001, t1 = Infinity;
|
|
988
|
+
for (let a = 0;a < 3; a++) {
|
|
989
|
+
const lo = b[a] + eps, hi = b[a + 3] - eps;
|
|
990
|
+
if (d[a] === 0) {
|
|
991
|
+
if (p[a] <= lo || p[a] >= hi)
|
|
992
|
+
return false;
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
let ta = (lo - p[a]) / d[a], tb = (hi - p[a]) / d[a];
|
|
996
|
+
if (ta > tb)
|
|
997
|
+
[ta, tb] = [tb, ta];
|
|
998
|
+
if (ta > t0)
|
|
999
|
+
t0 = ta;
|
|
1000
|
+
if (tb < t1)
|
|
1001
|
+
t1 = tb;
|
|
1002
|
+
if (t0 > t1)
|
|
1003
|
+
return false;
|
|
1004
|
+
}
|
|
1005
|
+
return true;
|
|
996
1006
|
}
|
|
997
|
-
function
|
|
998
|
-
|
|
1007
|
+
function boxVisibility(grid, id, d, n = 3) {
|
|
1008
|
+
const b = grid.boxes[id];
|
|
1009
|
+
let vis = 0, tot = 0;
|
|
1010
|
+
for (let a = 0;a < 3; a++)
|
|
1011
|
+
for (const side of [-1, 1]) {
|
|
1012
|
+
const cos = side * d[a];
|
|
1013
|
+
if (cos <= 0.02)
|
|
1014
|
+
continue;
|
|
1015
|
+
const u = (a + 1) % 3, v = (a + 2) % 3;
|
|
1016
|
+
const area = (b[u + 3] - b[u]) * (b[v + 3] - b[v]);
|
|
1017
|
+
if (area <= 0)
|
|
1018
|
+
continue;
|
|
1019
|
+
const w = area * cos / (n * n);
|
|
1020
|
+
const p = [0, 0, 0], q = [0, 0, 0];
|
|
1021
|
+
p[a] = side > 0 ? b[a + 3] + 0.25 : b[a] - 0.25;
|
|
1022
|
+
q[a] = side > 0 ? b[a + 3] + 1 : b[a] - 1;
|
|
1023
|
+
for (let s = 0;s < n; s++)
|
|
1024
|
+
for (let t = 0;t < n; t++) {
|
|
1025
|
+
p[u] = q[u] = b[u] + (s + 0.5) / n * (b[u + 3] - b[u]);
|
|
1026
|
+
p[v] = q[v] = b[v] + (t + 0.5) / n * (b[v + 3] - b[v]);
|
|
1027
|
+
if (grid.inside(q, id))
|
|
1028
|
+
continue;
|
|
1029
|
+
tot += w;
|
|
1030
|
+
if (!grid.hits(p, d, id))
|
|
1031
|
+
vis += w;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
return tot ? vis / tot : -1;
|
|
999
1035
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1036
|
+
var angle = (a, b) => Math.acos(Math.max(-1, Math.min(1, a[0] * b[0] + a[1] * b[1] + a[2] * b[2]))) / deg;
|
|
1037
|
+
var spread = (l, max) => l.length <= max ? l : Array.from({ length: max }, (_, i) => l[Math.floor((i + 0.5) * l.length / max)]);
|
|
1038
|
+
function planStepViews(insts, parts, stepOf, nSteps, o = {}) {
|
|
1039
|
+
const boxes = instanceBoxes(insts, parts);
|
|
1040
|
+
const byStep = Array.from({ length: nSteps }, () => []);
|
|
1041
|
+
for (let k = 0;k < insts.length; k++)
|
|
1042
|
+
if (boxes[k])
|
|
1043
|
+
byStep[stepOf[k]]?.push(k);
|
|
1044
|
+
let nBoxed = 0;
|
|
1045
|
+
for (const b of boxes)
|
|
1046
|
+
if (b)
|
|
1047
|
+
nBoxed++;
|
|
1048
|
+
const isoCache = new Map;
|
|
1049
|
+
const isoParts = (u) => {
|
|
1050
|
+
let l = isoCache.get(u);
|
|
1051
|
+
if (!l) {
|
|
1052
|
+
l = [];
|
|
1053
|
+
for (let k = 0;k < insts.length; k++)
|
|
1054
|
+
if (boxes[k] && insts[k].subPath?.includes(u))
|
|
1055
|
+
l.push(k);
|
|
1056
|
+
isoCache.set(u, l);
|
|
1008
1057
|
}
|
|
1009
|
-
|
|
1058
|
+
return l;
|
|
1059
|
+
};
|
|
1060
|
+
const subParts = new Map;
|
|
1061
|
+
for (let k = 0;k < insts.length; k++) {
|
|
1062
|
+
const u = insts[k].sub;
|
|
1063
|
+
if (u !== undefined && boxes[k])
|
|
1064
|
+
(subParts.get(u) ?? subParts.set(u, []).get(u)).push(k);
|
|
1010
1065
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1066
|
+
let size = 0;
|
|
1067
|
+
for (const b of boxes)
|
|
1068
|
+
if (b)
|
|
1069
|
+
size = Math.max(size, b[3] - b[0], b[4] - b[1], b[5] - b[2]);
|
|
1070
|
+
let ext = 0;
|
|
1071
|
+
for (const b of boxes)
|
|
1072
|
+
if (b)
|
|
1073
|
+
ext = Math.max(ext, Math.abs(b[0]), Math.abs(b[2]), Math.abs(b[3]), Math.abs(b[5]), Math.abs(b[1]), Math.abs(b[4]));
|
|
1074
|
+
const grid = new BoxGrid(boxes, Math.max(20, Math.min(160, size || 40), ext / 1000));
|
|
1075
|
+
const def = viewDir(o.azimuth ?? 45, o.elevation ?? 30), minVis = o.minVis ?? MIN_VIS, reorient = o.reorient ?? REORIENT, turn = o.turnCost ?? 0.002;
|
|
1076
|
+
const above = [], below = [];
|
|
1077
|
+
for (let az = 0;az < 360; az += 45) {
|
|
1078
|
+
for (const el of [15, 30, 50])
|
|
1079
|
+
above.push(viewDir(az, el));
|
|
1080
|
+
below.push(viewDir(az, -30));
|
|
1081
|
+
}
|
|
1082
|
+
const built = [Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity];
|
|
1083
|
+
const views = [];
|
|
1084
|
+
let prevMain = def;
|
|
1085
|
+
const prevIso = new Map;
|
|
1086
|
+
const local = new Map;
|
|
1087
|
+
const localOf = (u) => {
|
|
1088
|
+
let l = local.get(u);
|
|
1089
|
+
if (l)
|
|
1090
|
+
return l;
|
|
1091
|
+
const k0 = isoParts(u)[0];
|
|
1092
|
+
const i0 = insts[k0];
|
|
1093
|
+
const P = i0.subMats?.[i0.subPath.indexOf(u)] ?? null;
|
|
1094
|
+
const inv = P ? invert(P) : null;
|
|
1095
|
+
const lb = new Array(insts.length).fill(null);
|
|
1096
|
+
const own = isoParts(u);
|
|
1097
|
+
const loc = instanceBoxes(own.map((k) => ({ part: insts[k].part, m: inv ? mul(inv, insts[k].m) : insts[k].m })), parts);
|
|
1098
|
+
own.forEach((k, j) => lb[k] = loc[j]);
|
|
1099
|
+
local.set(u, l = { boxes: lb, P: P && inv ? [...P] : [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1] });
|
|
1100
|
+
return l;
|
|
1101
|
+
};
|
|
1102
|
+
let g = grid;
|
|
1103
|
+
const score = (ids, d) => {
|
|
1104
|
+
let mn = 1, sum = 0, n = 0;
|
|
1105
|
+
for (const id of ids) {
|
|
1106
|
+
const v = boxVisibility(g, id, d);
|
|
1107
|
+
if (v < 0)
|
|
1108
|
+
continue;
|
|
1109
|
+
mn = Math.min(mn, v);
|
|
1110
|
+
sum += v;
|
|
1111
|
+
n++;
|
|
1112
|
+
}
|
|
1113
|
+
return { mn: n ? mn : 1, mean: n ? sum / n : 1 };
|
|
1114
|
+
};
|
|
1115
|
+
const pref = (d) => {
|
|
1116
|
+
const h = Math.hypot(d[0], d[2]) || 1, el = Math.asin(Math.max(-1, Math.min(1, -d[1]))) / deg;
|
|
1117
|
+
return Math.abs(d[0] / h * (d[2] / h)) + 0.5 * Math.max(0, -d[2] / h) - Math.abs(el - 30) / 90;
|
|
1118
|
+
};
|
|
1119
|
+
const next = () => {
|
|
1120
|
+
const s = views.length, add = byStep[s];
|
|
1121
|
+
for (const id of add) {
|
|
1122
|
+
grid.add(id);
|
|
1123
|
+
const b = boxes[id];
|
|
1124
|
+
for (let k = 0;k < 3; k++) {
|
|
1125
|
+
built[k] = Math.min(built[k], b[k]);
|
|
1126
|
+
built[k + 3] = Math.max(built[k + 3], b[k + 3]);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
const iso = add.length ? commonSub(insts, add, (u) => isoParts(u).length >= nBoxed) : undefined;
|
|
1130
|
+
let isoBox = null;
|
|
1131
|
+
g = grid;
|
|
1132
|
+
if (iso !== undefined) {
|
|
1133
|
+
const L = localOf(iso);
|
|
1134
|
+
const own = isoParts(iso).filter((id) => stepOf[id] <= s);
|
|
1135
|
+
g = new BoxGrid(L.boxes, grid.cell);
|
|
1136
|
+
for (const id of own)
|
|
1137
|
+
g.add(id);
|
|
1138
|
+
isoBox = [Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity];
|
|
1139
|
+
for (const id of own) {
|
|
1140
|
+
const b = L.boxes[id];
|
|
1141
|
+
for (let k = 0;k < 3; k++) {
|
|
1142
|
+
isoBox[k] = Math.min(isoBox[k], b[k]);
|
|
1143
|
+
isoBox[k + 3] = Math.max(isoBox[k + 3], b[k + 3]);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
const prev = iso !== undefined ? prevIso.get(iso) ?? def : prevMain, ref = isoBox ?? built;
|
|
1148
|
+
const ids = spread(add, 24);
|
|
1149
|
+
let dir = o.fixed?.(s) ?? null, r = dir ? score(ids, dir) : score(ids, prev);
|
|
1150
|
+
if (!dir) {
|
|
1151
|
+
dir = prev;
|
|
1152
|
+
if (r.mean >= minVis && prev !== def) {
|
|
1153
|
+
const v = score(ids, def);
|
|
1154
|
+
if (v.mean >= minVis) {
|
|
1155
|
+
dir = def;
|
|
1156
|
+
r = v;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
if (r.mean < minVis) {
|
|
1160
|
+
let best = -Infinity;
|
|
1161
|
+
const ex = [ref[3] - ref[0], ref[4] - ref[1], ref[5] - ref[2]], area = (d) => Math.abs(d[0]) * ex[1] * ex[2] + Math.abs(d[1]) * ex[0] * ex[2] + Math.abs(d[2]) * ex[0] * ex[1];
|
|
1162
|
+
let amax = 0;
|
|
1163
|
+
for (const d of above)
|
|
1164
|
+
amax = Math.max(amax, area(d));
|
|
1165
|
+
const consider = (cands) => {
|
|
1166
|
+
for (const d of cands) {
|
|
1167
|
+
const v = score(ids, d);
|
|
1168
|
+
const sc = v.mean + 0.3 * v.mn + 0.25 * pref(d) + 0.15 * (amax ? area(d) / amax : 1) - turn * angle(prev, d);
|
|
1169
|
+
if (sc > best) {
|
|
1170
|
+
best = sc;
|
|
1171
|
+
dir = d;
|
|
1172
|
+
r = v;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1176
|
+
consider([prev, ...above]);
|
|
1177
|
+
if (r.mean < reorient)
|
|
1178
|
+
consider(below);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
const diag = (b) => Math.hypot(b[3] - b[0], b[4] - b[1], b[5] - b[2]);
|
|
1182
|
+
let fb = built;
|
|
1183
|
+
const sub = add.length ? insts[add[0]].sub : undefined;
|
|
1184
|
+
if (isoBox)
|
|
1185
|
+
fb = isoBox;
|
|
1186
|
+
else if (sub !== undefined && add.every((id) => insts[id].sub === sub)) {
|
|
1187
|
+
const sb = [Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity];
|
|
1188
|
+
for (const id of subParts.get(sub) ?? []) {
|
|
1189
|
+
if (stepOf[id] > s)
|
|
1190
|
+
continue;
|
|
1191
|
+
const b = boxes[id];
|
|
1192
|
+
for (let k = 0;k < 3; k++) {
|
|
1193
|
+
sb[k] = Math.min(sb[k], b[k]);
|
|
1194
|
+
sb[k + 3] = Math.max(sb[k + 3], b[k + 3]);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
if (isFinite(sb[0]) && diag(sb) * 2.5 < diag(built)) {
|
|
1198
|
+
const g = diag(sb) * 0.35;
|
|
1199
|
+
fb = sb.map((v, k) => k < 3 ? v - g : v + g);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
const target = isFinite(fb[0]) ? [(fb[0] + fb[3]) / 2, (fb[1] + fb[4]) / 2, (fb[2] + fb[5]) / 2] : [0, 0, 0];
|
|
1203
|
+
views.push({ dir, target, radius: isFinite(fb[0]) ? diag(fb) / 2 : 1, minVis: r.mn, meanVis: r.mean, below: dir[1] > 0, ...iso !== undefined ? { isolate: iso, frame: localOf(iso).P } : {} });
|
|
1204
|
+
if (iso !== undefined)
|
|
1205
|
+
prevIso.set(iso, dir);
|
|
1206
|
+
else
|
|
1207
|
+
prevMain = dir;
|
|
1208
|
+
};
|
|
1209
|
+
return {
|
|
1210
|
+
stepCount: nSteps,
|
|
1211
|
+
view(step) {
|
|
1212
|
+
step = Math.max(0, Math.min(nSteps - 1, step));
|
|
1213
|
+
while (views.length <= step)
|
|
1214
|
+
next();
|
|
1215
|
+
return views[step];
|
|
1216
|
+
}
|
|
1032
1217
|
};
|
|
1033
|
-
return l;
|
|
1034
|
-
}
|
|
1035
|
-
function sharedLines(pos, im, material = sharedLineMat()) {
|
|
1036
|
-
const { P, I } = weldLines(pos);
|
|
1037
|
-
const g = new THREE.InstancedBufferGeometry;
|
|
1038
|
-
g.setAttribute("position", new THREE.BufferAttribute(P, 3));
|
|
1039
|
-
g.setIndex(new THREE.BufferAttribute(I, 1));
|
|
1040
|
-
g.setAttribute("instanceMatrix", im.instanceMatrix);
|
|
1041
|
-
g.instanceCount = im.count;
|
|
1042
|
-
const l = new THREE.LineSegments(g, material);
|
|
1043
|
-
l.frustumCulled = false;
|
|
1044
|
-
return l;
|
|
1045
|
-
}
|
|
1046
|
-
function instancedLines(pos, mats, count) {
|
|
1047
|
-
const g = new THREE.InstancedBufferGeometry;
|
|
1048
|
-
g.setAttribute("position", new THREE.BufferAttribute(pos, 3));
|
|
1049
|
-
const ib = new THREE.InstancedInterleavedBuffer(mats, 16);
|
|
1050
|
-
for (let i = 0;i < 4; i++)
|
|
1051
|
-
g.setAttribute("im" + i, new THREE.InterleavedBufferAttribute(ib, 4, i * 4));
|
|
1052
|
-
g.instanceCount = count;
|
|
1053
|
-
const l = new THREE.LineSegments(g, lineMat());
|
|
1054
|
-
l.frustumCulled = false;
|
|
1055
|
-
return l;
|
|
1056
|
-
}
|
|
1057
|
-
function writeM4(t, o, m, mo = 0) {
|
|
1058
|
-
t[o] = m[mo + 3];
|
|
1059
|
-
t[o + 1] = m[mo + 6];
|
|
1060
|
-
t[o + 2] = m[mo + 9];
|
|
1061
|
-
t[o + 3] = 0;
|
|
1062
|
-
t[o + 4] = m[mo + 4];
|
|
1063
|
-
t[o + 5] = m[mo + 7];
|
|
1064
|
-
t[o + 6] = m[mo + 10];
|
|
1065
|
-
t[o + 7] = 0;
|
|
1066
|
-
t[o + 8] = m[mo + 5];
|
|
1067
|
-
t[o + 9] = m[mo + 8];
|
|
1068
|
-
t[o + 10] = m[mo + 11];
|
|
1069
|
-
t[o + 11] = 0;
|
|
1070
|
-
t[o + 12] = m[mo];
|
|
1071
|
-
t[o + 13] = m[mo + 1];
|
|
1072
|
-
t[o + 14] = m[mo + 2];
|
|
1073
|
-
t[o + 15] = 1;
|
|
1074
1218
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1219
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/render.ts
|
|
1220
|
+
import * as THREE from "three";
|
|
1221
|
+
|
|
1222
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/pack-io.ts
|
|
1223
|
+
import { decompress } from "fzstd";
|
|
1224
|
+
async function decompressPack(data) {
|
|
1225
|
+
const u = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
1226
|
+
const own = (o) => o.buffer.slice(o.byteOffset, o.byteOffset + o.byteLength);
|
|
1227
|
+
if (u[0] === 40 && u[1] === 181 && u[2] === 47 && u[3] === 253)
|
|
1228
|
+
return own(decompress(u));
|
|
1229
|
+
if (u[0] === 31 && u[1] === 139)
|
|
1230
|
+
return new Response(new Blob([u]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();
|
|
1231
|
+
return own(u);
|
|
1080
1232
|
}
|
|
1081
|
-
function
|
|
1082
|
-
const
|
|
1083
|
-
const
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
color(it.color).toArray(C, k * 3);
|
|
1088
|
-
}
|
|
1089
|
-
im.instanceColor = new THREE.InstancedBufferAttribute(C, 3);
|
|
1233
|
+
function decodePack(buf) {
|
|
1234
|
+
const hl = new DataView(buf).getUint32(0, true);
|
|
1235
|
+
const header = JSON.parse(new TextDecoder().decode(new Uint8Array(buf, 4, hl)));
|
|
1236
|
+
const base = 4 + hl;
|
|
1237
|
+
const arr = (r) => r && (r[2] === "f32" ? new Float32Array(buf, base + r[0], r[1]) : r[2] === "u16" ? new Uint16Array(buf, base + r[0], r[1]) : r[2] === "u8" ? new Uint8Array(buf, base + r[0], r[1]) : new Uint32Array(buf, base + r[0], r[1]));
|
|
1238
|
+
return { header, arr, bytes: buf.byteLength, buffer: buf };
|
|
1090
1239
|
}
|
|
1240
|
+
|
|
1241
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/cull.ts
|
|
1091
1242
|
var upright = (m, o = 0) => Math.abs(m[o + 7] - 1) < 0.001 && Math.abs(m[o + 4]) < 0.001 && Math.abs(m[o + 10]) < 0.001;
|
|
1092
1243
|
var prepCache = new WeakMap;
|
|
1093
1244
|
function prepPart(H, part) {
|
|
@@ -1133,76 +1284,84 @@ function mul12To(a, b, bo, w, ao = 0) {
|
|
|
1133
1284
|
w[3 + i * 3 + j] = a[ao + 3 + i * 3] * b[bo + 3 + j] + a[ao + 4 + i * 3] * b[bo + 6 + j] + a[ao + 5 + i * 3] * b[bo + 9 + j];
|
|
1134
1285
|
}
|
|
1135
1286
|
var det12 = (m) => m[3] * (m[7] * m[11] - m[8] * m[10]) - m[4] * (m[6] * m[11] - m[8] * m[9]) + m[5] * (m[6] * m[10] - m[7] * m[9]);
|
|
1136
|
-
var
|
|
1137
|
-
var topKey = (x, y, z) => {
|
|
1138
|
-
const rx = Math.round(x), ry = Math.round(y), rz = Math.round(z);
|
|
1139
|
-
return rx < -131072 || rx >= 131072 || ry < -65536 || ry >= 65536 || rz < -131072 || rz >= 131072 ? -1 : (rx + 131072) * 34359738368 + (ry + 65536) * 262144 + (rz + 131072);
|
|
1140
|
-
};
|
|
1287
|
+
var BIG = 1073741824;
|
|
1141
1288
|
|
|
1142
|
-
class
|
|
1143
|
-
|
|
1289
|
+
class Int3Table {
|
|
1290
|
+
a;
|
|
1291
|
+
b;
|
|
1292
|
+
c;
|
|
1144
1293
|
vals;
|
|
1294
|
+
used;
|
|
1145
1295
|
mask;
|
|
1146
1296
|
size = 0;
|
|
1147
1297
|
constructor(cap = 1024) {
|
|
1148
1298
|
let n = 1024;
|
|
1149
1299
|
while (n < cap * 2)
|
|
1150
1300
|
n *= 2;
|
|
1151
|
-
this.
|
|
1301
|
+
this.a = new Int32Array(n);
|
|
1302
|
+
this.b = new Int32Array(n);
|
|
1303
|
+
this.c = new Int32Array(n);
|
|
1152
1304
|
this.vals = new Int32Array(n);
|
|
1305
|
+
this.used = new Uint8Array(n);
|
|
1153
1306
|
this.mask = n - 1;
|
|
1154
1307
|
}
|
|
1155
|
-
slot(
|
|
1156
|
-
|
|
1157
|
-
let h = Math.imul(lo ^ Math.imul(hi, 2654435761), 2246822507);
|
|
1308
|
+
slot(x, y, z) {
|
|
1309
|
+
let h = Math.imul(x, 2654435761) ^ Math.imul(y, 2246822507) ^ Math.imul(z, 3266489909);
|
|
1158
1310
|
h ^= h >>> 15;
|
|
1311
|
+
h = Math.imul(h, 739982445);
|
|
1312
|
+
h ^= h >>> 12;
|
|
1159
1313
|
return h & this.mask;
|
|
1160
1314
|
}
|
|
1161
|
-
get(
|
|
1162
|
-
|
|
1163
|
-
|
|
1315
|
+
get(x, y, z) {
|
|
1316
|
+
let i = this.slot(x, y, z);
|
|
1317
|
+
const U = this.used, A = this.a, B = this.b, C = this.c;
|
|
1164
1318
|
for (;; ) {
|
|
1165
|
-
|
|
1166
|
-
if (x === k)
|
|
1167
|
-
return this.vals[i];
|
|
1168
|
-
if (x === -1)
|
|
1319
|
+
if (!U[i])
|
|
1169
1320
|
return -1;
|
|
1321
|
+
if (A[i] === x && B[i] === y && C[i] === z)
|
|
1322
|
+
return this.vals[i];
|
|
1170
1323
|
i = i + 1 & this.mask;
|
|
1171
1324
|
}
|
|
1172
1325
|
}
|
|
1173
|
-
put(
|
|
1174
|
-
if ((this.size + 1) * 2 > this.
|
|
1326
|
+
put(x, y, z, v) {
|
|
1327
|
+
if ((this.size + 1) * 2 > this.used.length)
|
|
1175
1328
|
this.grow();
|
|
1176
|
-
|
|
1177
|
-
|
|
1329
|
+
let i = this.slot(x, y, z);
|
|
1330
|
+
const U = this.used, A = this.a, B = this.b, C = this.c;
|
|
1178
1331
|
for (;; ) {
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
}
|
|
1185
|
-
if (x === -1) {
|
|
1186
|
-
K[i] = k;
|
|
1332
|
+
if (!U[i]) {
|
|
1333
|
+
U[i] = 1;
|
|
1334
|
+
A[i] = x;
|
|
1335
|
+
B[i] = y;
|
|
1336
|
+
C[i] = z;
|
|
1187
1337
|
this.vals[i] = v;
|
|
1188
1338
|
this.size++;
|
|
1189
1339
|
return -1;
|
|
1190
1340
|
}
|
|
1341
|
+
if (A[i] === x && B[i] === y && C[i] === z) {
|
|
1342
|
+
const o = this.vals[i];
|
|
1343
|
+
this.vals[i] = v;
|
|
1344
|
+
return o;
|
|
1345
|
+
}
|
|
1191
1346
|
i = i + 1 & this.mask;
|
|
1192
1347
|
}
|
|
1193
1348
|
}
|
|
1194
1349
|
grow() {
|
|
1195
|
-
const
|
|
1196
|
-
const n =
|
|
1197
|
-
this.
|
|
1350
|
+
const { a, b, c, vals, used } = this;
|
|
1351
|
+
const n = used.length * 2;
|
|
1352
|
+
this.a = new Int32Array(n);
|
|
1353
|
+
this.b = new Int32Array(n);
|
|
1354
|
+
this.c = new Int32Array(n);
|
|
1198
1355
|
this.vals = new Int32Array(n);
|
|
1356
|
+
this.used = new Uint8Array(n);
|
|
1199
1357
|
this.mask = n - 1;
|
|
1200
1358
|
this.size = 0;
|
|
1201
|
-
for (let i = 0;i <
|
|
1202
|
-
if (
|
|
1203
|
-
this.put(
|
|
1359
|
+
for (let i = 0;i < used.length; i++)
|
|
1360
|
+
if (used[i])
|
|
1361
|
+
this.put(a[i], b[i], c[i], vals[i]);
|
|
1204
1362
|
}
|
|
1205
1363
|
}
|
|
1364
|
+
var inRange = (x, y, z) => x > -BIG && x < BIG && y > -BIG && y < BIG && z > -BIG && z < BIG;
|
|
1206
1365
|
var STEP_NEVER = 2147483647;
|
|
1207
1366
|
function forEachStud(insts, H, fn) {
|
|
1208
1367
|
const w = new Float64Array(12);
|
|
@@ -1222,7 +1381,7 @@ function forEachStud(insts, H, fn) {
|
|
|
1222
1381
|
function cullCore(insts, H, steps) {
|
|
1223
1382
|
const CELL = 40;
|
|
1224
1383
|
const rx0 = [], rx1 = [], rz0 = [], rz1 = [], rInst = [], rPrep = [], rBx = [], rBz = [];
|
|
1225
|
-
const cells = new
|
|
1384
|
+
const cells = new Int3Table(insts.length * 2);
|
|
1226
1385
|
const nextE = [], rectE = [];
|
|
1227
1386
|
for (let idx = 0;idx < insts.length; idx++) {
|
|
1228
1387
|
const it = insts[idx];
|
|
@@ -1257,21 +1416,27 @@ function cullCore(insts, H, steps) {
|
|
|
1257
1416
|
const lv2 = Math.round((m[1] + b[4]) * 2);
|
|
1258
1417
|
for (let cx = Math.floor(x0 / CELL);cx <= Math.floor(x1 / CELL); cx++)
|
|
1259
1418
|
for (let cz = Math.floor(z0 / CELL);cz <= Math.floor(z1 / CELL); cz++) {
|
|
1260
|
-
|
|
1261
|
-
if (k < 0)
|
|
1419
|
+
if (!inRange(lv2, cx, cz))
|
|
1262
1420
|
continue;
|
|
1263
1421
|
const e = rectE.length;
|
|
1264
1422
|
rectE.push(ri);
|
|
1265
|
-
nextE.push(cells.put(
|
|
1423
|
+
nextE.push(cells.put(lv2, cx, cz, e));
|
|
1266
1424
|
}
|
|
1267
1425
|
}
|
|
1268
1426
|
const SX = [0, 5, -5, 5, -5], SZ = [0, 5, 5, -5, -5];
|
|
1427
|
+
let kl = NaN, kx = NaN, kz = NaN, ke = -1;
|
|
1269
1428
|
const coverStep = (x, y, z, self) => {
|
|
1270
|
-
const
|
|
1271
|
-
if (
|
|
1429
|
+
const l2 = Math.round(y * 2), gx = Math.floor(x / CELL), gz = Math.floor(z / CELL);
|
|
1430
|
+
if (!inRange(l2, gx, gz))
|
|
1272
1431
|
return STEP_NEVER;
|
|
1273
1432
|
let best = STEP_NEVER;
|
|
1274
|
-
|
|
1433
|
+
if (l2 !== kl || gx !== kx || gz !== kz) {
|
|
1434
|
+
kl = l2;
|
|
1435
|
+
kx = gx;
|
|
1436
|
+
kz = gz;
|
|
1437
|
+
ke = cells.get(l2, gx, gz);
|
|
1438
|
+
}
|
|
1439
|
+
for (let e = ke;e >= 0; e = nextE[e]) {
|
|
1275
1440
|
const ri = rectE[e];
|
|
1276
1441
|
if (rInst[ri] === self || !(x - 6 >= rx0[ri] - 0.5 && x + 6 <= rx1[ri] + 0.5 && z - 6 >= rz0[ri] - 0.5 && z + 6 <= rz1[ri] + 0.5))
|
|
1277
1442
|
continue;
|
|
@@ -1299,71 +1464,448 @@ function cullCore(insts, H, steps) {
|
|
|
1299
1464
|
}
|
|
1300
1465
|
return best;
|
|
1301
1466
|
};
|
|
1302
|
-
let nStuds = 0;
|
|
1303
|
-
for (const it of insts) {
|
|
1304
|
-
const pp = prepPart(H, it.part);
|
|
1305
|
-
if (pp)
|
|
1306
|
-
nStuds += pp.nStuds;
|
|
1467
|
+
let nStuds = 0;
|
|
1468
|
+
for (const it of insts) {
|
|
1469
|
+
const pp = prepPart(H, it.part);
|
|
1470
|
+
if (pp)
|
|
1471
|
+
nStuds += pp.nStuds;
|
|
1472
|
+
}
|
|
1473
|
+
const studHidden = new Uint8Array(nStuds), studUp = new Uint8Array(nStuds);
|
|
1474
|
+
const tops = new Int3Table(nStuds);
|
|
1475
|
+
let studsHidden = 0;
|
|
1476
|
+
const studHideStep = steps ? new Int32Array(nStuds).fill(STEP_NEVER) : undefined;
|
|
1477
|
+
for (let idx = 0, j = 0;idx < insts.length; idx++) {
|
|
1478
|
+
const it = insts[idx];
|
|
1479
|
+
const pp = prepPart(H, it.part);
|
|
1480
|
+
if (!pp)
|
|
1481
|
+
continue;
|
|
1482
|
+
const m = it.m, S = pp.studM;
|
|
1483
|
+
const m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3], m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7], m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11];
|
|
1484
|
+
for (let s = 0;s < pp.nStuds; s++, j++) {
|
|
1485
|
+
const o = s * 12;
|
|
1486
|
+
const b4 = S[o + 4], b7 = S[o + 7], b10 = S[o + 10];
|
|
1487
|
+
if (!(Math.abs(m6 * b4 + m7 * b7 + m8 * b10 - 1) < 0.001 && Math.abs(m3 * b4 + m4 * b7 + m5 * b10) < 0.001 && Math.abs(m9 * b4 + m10 * b7 + m11 * b10) < 0.001))
|
|
1488
|
+
continue;
|
|
1489
|
+
studUp[j] = 1;
|
|
1490
|
+
const b0 = S[o], b1 = S[o + 1], b2 = S[o + 2];
|
|
1491
|
+
const x = m0 + m3 * b0 + m4 * b1 + m5 * b2, y = m1 + m6 * b0 + m7 * b1 + m8 * b2, z = m2 + m9 * b0 + m10 * b1 + m11 * b2;
|
|
1492
|
+
const cs = coverStep(x, y, z, idx);
|
|
1493
|
+
if (cs !== STEP_NEVER) {
|
|
1494
|
+
studHidden[j] = 1;
|
|
1495
|
+
studsHidden++;
|
|
1496
|
+
if (studHideStep)
|
|
1497
|
+
studHideStep[j] = cs;
|
|
1498
|
+
}
|
|
1499
|
+
const rx = Math.round(x), ry = Math.round(y), rz = Math.round(z);
|
|
1500
|
+
if (!inRange(rx, ry, rz))
|
|
1501
|
+
continue;
|
|
1502
|
+
if (!steps) {
|
|
1503
|
+
tops.put(rx, ry, rz, 1);
|
|
1504
|
+
continue;
|
|
1505
|
+
}
|
|
1506
|
+
const st = steps[idx], t = tops.get(rx, ry, rz);
|
|
1507
|
+
if (t < 0 || st < t)
|
|
1508
|
+
tops.put(rx, ry, rz, st);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
const underHidden = new Uint8Array(insts.length);
|
|
1512
|
+
const underHideStep = steps ? new Int32Array(insts.length).fill(STEP_NEVER) : undefined;
|
|
1513
|
+
for (let idx = 0;idx < insts.length; idx++) {
|
|
1514
|
+
const it = insts[idx];
|
|
1515
|
+
const p = H.parts[it.part];
|
|
1516
|
+
if (!p || !p.under || !upright(it.m))
|
|
1517
|
+
continue;
|
|
1518
|
+
const b = p.bbox;
|
|
1519
|
+
const nx = Math.round((b[3] - b[0]) / 20), nz = Math.round((b[5] - b[2]) / 20);
|
|
1520
|
+
if (!nx || !nz || nx * nz > 4096)
|
|
1521
|
+
continue;
|
|
1522
|
+
const m = it.m;
|
|
1523
|
+
let all = true, at = 0;
|
|
1524
|
+
for (let a = 0;a < nx && all; a++)
|
|
1525
|
+
for (let c = 0;c < nz; c++) {
|
|
1526
|
+
const lx = b[0] + 10 + 20 * a, lz = b[2] + 10 + 20 * c;
|
|
1527
|
+
const x = m[0] + m[3] * lx + m[5] * lz, z = m[2] + m[9] * lx + m[11] * lz;
|
|
1528
|
+
const rx = Math.round(x), ry = Math.round(m[1] + b[4]), rz = Math.round(z);
|
|
1529
|
+
const t = inRange(rx, ry, rz) ? tops.get(rx, ry, rz) : -1;
|
|
1530
|
+
if (t < 0) {
|
|
1531
|
+
all = false;
|
|
1532
|
+
break;
|
|
1533
|
+
}
|
|
1534
|
+
if (t > at)
|
|
1535
|
+
at = t;
|
|
1536
|
+
}
|
|
1537
|
+
if (all) {
|
|
1538
|
+
underHidden[idx] = 1;
|
|
1539
|
+
if (underHideStep)
|
|
1540
|
+
underHideStep[idx] = at;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
return { nStuds, studHidden, studUp, underHidden, studsHidden, studHideStep, underHideStep };
|
|
1544
|
+
}
|
|
1545
|
+
function sceneInstances(instances, H, useTex) {
|
|
1546
|
+
const pick = (i) => useTex && i.texPart && H.parts[i.texPart] ? i.texPart : i.part;
|
|
1547
|
+
const all = instances.map((i) => ({ part: pick(i), color: String(i.color), m: i.m, steps: i.steps }));
|
|
1548
|
+
const keys = all.map((i) => stepKey(i.steps));
|
|
1549
|
+
const uniq = [...new Set(keys)].sort();
|
|
1550
|
+
const rank = new Map(uniq.map((k, j) => [k, j]));
|
|
1551
|
+
return { all, stepOf: keys.map((k) => rank.get(k)), nSteps: uniq.length };
|
|
1552
|
+
}
|
|
1553
|
+
function precomputeCull(instances, H, useTex = true) {
|
|
1554
|
+
const s = sceneInstances(instances, H, useTex);
|
|
1555
|
+
return cullCore(s.all, H, s.nSteps > 1 ? s.stepOf : undefined);
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/render.ts
|
|
1559
|
+
async function loadPack(url) {
|
|
1560
|
+
const res = await fetch(url);
|
|
1561
|
+
if (!res.ok)
|
|
1562
|
+
throw new Error(`ldr: ${res.status} fetching ${url}`);
|
|
1563
|
+
return decodePack(await decompressPack(await res.arrayBuffer()));
|
|
1564
|
+
}
|
|
1565
|
+
var toI8 = (a) => {
|
|
1566
|
+
const o = new Int8Array(a.length);
|
|
1567
|
+
for (let i = 0;i < a.length; i++)
|
|
1568
|
+
o[i] = Math.round(Math.max(-1, Math.min(1, a[i])) * 127);
|
|
1569
|
+
return o;
|
|
1570
|
+
};
|
|
1571
|
+
var toU8 = (a) => {
|
|
1572
|
+
const o = new Uint8Array(a.length);
|
|
1573
|
+
for (let i = 0;i < a.length; i++)
|
|
1574
|
+
o[i] = Math.round(Math.max(0, Math.min(1, a[i])) * 255);
|
|
1575
|
+
return o;
|
|
1576
|
+
};
|
|
1577
|
+
function flatNormals(pos, idx) {
|
|
1578
|
+
const n = new Float32Array(pos.length);
|
|
1579
|
+
for (let t = 0;t < idx.length; t += 3) {
|
|
1580
|
+
const a = idx[t] * 3, b = idx[t + 1] * 3, c = idx[t + 2] * 3;
|
|
1581
|
+
const ux = pos[b] - pos[a], uy = pos[b + 1] - pos[a + 1], uz = pos[b + 2] - pos[a + 2], vx = pos[c] - pos[a], vy = pos[c + 1] - pos[a + 1], vz = pos[c + 2] - pos[a + 2];
|
|
1582
|
+
let nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;
|
|
1583
|
+
const l = Math.hypot(nx, ny, nz) || 1;
|
|
1584
|
+
nx /= l;
|
|
1585
|
+
ny /= l;
|
|
1586
|
+
nz /= l;
|
|
1587
|
+
for (const o of [a, b, c]) {
|
|
1588
|
+
n[o] = nx;
|
|
1589
|
+
n[o + 1] = ny;
|
|
1590
|
+
n[o + 2] = nz;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
return n;
|
|
1594
|
+
}
|
|
1595
|
+
var geomCache = new WeakMap;
|
|
1596
|
+
function geom(b, arr) {
|
|
1597
|
+
if (!b)
|
|
1598
|
+
return null;
|
|
1599
|
+
let c = geomCache.get(arr);
|
|
1600
|
+
if (!c)
|
|
1601
|
+
geomCache.set(arr, c = new Map);
|
|
1602
|
+
let g = c.get(b);
|
|
1603
|
+
if (g)
|
|
1604
|
+
return g;
|
|
1605
|
+
g = new THREE.BufferGeometry;
|
|
1606
|
+
g.setAttribute("position", new THREE.BufferAttribute(arr(b.pos), 3));
|
|
1607
|
+
const nrm = b.nrm ? arr(b.nrm) : flatNormals(arr(b.pos), arr(b.idx));
|
|
1608
|
+
const col = arr(b.col);
|
|
1609
|
+
g.setAttribute("normal", new THREE.BufferAttribute(toI8(nrm), 3, true));
|
|
1610
|
+
g.setAttribute("ldrColor", new THREE.BufferAttribute(col instanceof Uint8Array ? col : toU8(col), 4, true));
|
|
1611
|
+
if (b.idx)
|
|
1612
|
+
g.setIndex(new THREE.BufferAttribute(arr(b.idx), 1));
|
|
1613
|
+
if (b.uv)
|
|
1614
|
+
g.setAttribute("ldrUV", new THREE.BufferAttribute(arr(b.uv), 2));
|
|
1615
|
+
c.set(b, g);
|
|
1616
|
+
return g;
|
|
1617
|
+
}
|
|
1618
|
+
function makeMaterial(side) {
|
|
1619
|
+
const m = new THREE.MeshStandardMaterial({ vertexColors: true, roughness: 0.45, side });
|
|
1620
|
+
m.onBeforeCompile = (s) => {
|
|
1621
|
+
s.vertexShader = `attribute vec4 ldrColor;
|
|
1622
|
+
` + s.vertexShader.replace("#include <color_vertex>", `#include <color_vertex>
|
|
1623
|
+
#ifdef USE_INSTANCING_COLOR
|
|
1624
|
+
vColor.rgb = ldrColor.a > 0.5 ? pow(ldrColor.rgb, vec3(2.2)) : instanceColor.rgb; // baked LDConfig colours are sRGB
|
|
1625
|
+
#else
|
|
1626
|
+
vColor.rgb = pow(ldrColor.rgb, vec3(2.2));
|
|
1627
|
+
#endif`);
|
|
1628
|
+
};
|
|
1629
|
+
m.customProgramCacheKey = () => "ldrColor";
|
|
1630
|
+
return m;
|
|
1631
|
+
}
|
|
1632
|
+
function makeTexturedMaterial(side, map, wrapU = false) {
|
|
1633
|
+
const m = makeMaterial(side);
|
|
1634
|
+
const base = m.onBeforeCompile;
|
|
1635
|
+
m.onBeforeCompile = (sh, r) => {
|
|
1636
|
+
base.call(m, sh, r);
|
|
1637
|
+
sh.uniforms.ldrMap = { value: map };
|
|
1638
|
+
sh.uniforms.ldrWrapU = { value: wrapU ? 1 : 0 };
|
|
1639
|
+
sh.vertexShader = `attribute vec2 ldrUV; varying vec2 vLdrUV;
|
|
1640
|
+
` + sh.vertexShader.replace("#include <uv_vertex>", `#include <uv_vertex>
|
|
1641
|
+
vLdrUV = ldrUV;`);
|
|
1642
|
+
sh.fragmentShader = `uniform sampler2D ldrMap; uniform int ldrWrapU; varying vec2 vLdrUV;
|
|
1643
|
+
` + sh.fragmentShader.replace("#include <color_fragment>", `#include <color_fragment>
|
|
1644
|
+
{ vec2 uv = vec2(ldrWrapU == 1 ? fract(vLdrUV.x) : vLdrUV.x, vLdrUV.y); vec4 t = texture2D(ldrMap, uv);
|
|
1645
|
+
float inside = step(0.0, uv.x) * step(uv.x, 1.0) * step(0.0, uv.y) * step(uv.y, 1.0);
|
|
1646
|
+
diffuseColor.rgb = mix(diffuseColor.rgb, t.rgb, t.a * inside); }`);
|
|
1647
|
+
};
|
|
1648
|
+
m.customProgramCacheKey = () => "ldrColorTex";
|
|
1649
|
+
m.userData.ldrMap = map;
|
|
1650
|
+
return m;
|
|
1651
|
+
}
|
|
1652
|
+
function packTexture(pack, i) {
|
|
1653
|
+
const t = new THREE.Texture;
|
|
1654
|
+
t.flipY = false;
|
|
1655
|
+
t.colorSpace = THREE.SRGBColorSpace;
|
|
1656
|
+
t.wrapS = t.wrapT = THREE.ClampToEdgeWrapping;
|
|
1657
|
+
const e = pack.header.textures?.[i];
|
|
1658
|
+
const bytes = e?.data ? pack.arr(e.data) : null;
|
|
1659
|
+
if (!bytes || typeof createImageBitmap === "undefined")
|
|
1660
|
+
return { texture: t, ready: Promise.resolve() };
|
|
1661
|
+
const ready = createImageBitmap(new Blob([bytes], { type: e.mime || "image/png" }), { premultiplyAlpha: "none", colorSpaceConversion: "none" }).then((img) => {
|
|
1662
|
+
t.image = img;
|
|
1663
|
+
t.needsUpdate = true;
|
|
1664
|
+
}).catch(() => {});
|
|
1665
|
+
return { texture: t, ready };
|
|
1666
|
+
}
|
|
1667
|
+
var sharedLineMat = () => new THREE.ShaderMaterial({
|
|
1668
|
+
vertexShader: `attribute mat4 instanceMatrix; void main(){ gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position,1.0); }`,
|
|
1669
|
+
fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
|
|
1670
|
+
});
|
|
1671
|
+
var weldLines = (pos, byLength = false) => {
|
|
1672
|
+
const map = new Map;
|
|
1673
|
+
const P = [];
|
|
1674
|
+
const I = [];
|
|
1675
|
+
const n = Math.floor(pos.length / 6);
|
|
1676
|
+
const len = new Float32Array(n);
|
|
1677
|
+
for (let s = 0;s < n; s++) {
|
|
1678
|
+
const o = s * 6;
|
|
1679
|
+
len[s] = Math.hypot(pos[o + 3] - pos[o], pos[o + 4] - pos[o + 1], pos[o + 5] - pos[o + 2]);
|
|
1680
|
+
}
|
|
1681
|
+
const order = Array.from({ length: n }, (_, s) => s);
|
|
1682
|
+
if (byLength)
|
|
1683
|
+
order.sort((a, b) => len[b] - len[a]);
|
|
1684
|
+
for (const sg of order)
|
|
1685
|
+
for (let e = 0;e < 2; e++) {
|
|
1686
|
+
const i = sg * 6 + e * 3;
|
|
1687
|
+
const k = pos[i].toFixed(2) + "," + pos[i + 1].toFixed(2) + "," + pos[i + 2].toFixed(2);
|
|
1688
|
+
let j = map.get(k);
|
|
1689
|
+
if (j === undefined) {
|
|
1690
|
+
j = P.length / 3;
|
|
1691
|
+
map.set(k, j);
|
|
1692
|
+
P.push(pos[i], pos[i + 1], pos[i + 2]);
|
|
1693
|
+
}
|
|
1694
|
+
I.push(j);
|
|
1695
|
+
}
|
|
1696
|
+
return { P: new Float32Array(P), I: P.length / 3 < 65536 ? new Uint16Array(I) : new Uint32Array(I), lens: Float32Array.from(order, (sg) => len[sg]) };
|
|
1697
|
+
};
|
|
1698
|
+
function createInstancedEdges(pos, im, material = sharedLineMat()) {
|
|
1699
|
+
return sharedLines(pos, im, material);
|
|
1700
|
+
}
|
|
1701
|
+
function conditionalLines(pack, entry, which = "all") {
|
|
1702
|
+
if (which === "all") {
|
|
1703
|
+
const a = conditionalLines(pack, entry, "body"), b = conditionalLines(pack, entry, "under");
|
|
1704
|
+
if (!a || !b)
|
|
1705
|
+
return a ?? b;
|
|
1706
|
+
const o = new Float32Array(a.length + b.length);
|
|
1707
|
+
o.set(a);
|
|
1708
|
+
o.set(b, a.length);
|
|
1709
|
+
return o;
|
|
1710
|
+
}
|
|
1711
|
+
const c = which === "under" ? entry?.condlu : entry?.condl;
|
|
1712
|
+
if (!c)
|
|
1713
|
+
return null;
|
|
1714
|
+
const { arr } = pack;
|
|
1715
|
+
if (c.raw)
|
|
1716
|
+
return arr(c.raw);
|
|
1717
|
+
const pools = [entry.body ? arr(entry.body.pos) : [], entry.under ? arr(entry.under.pos) : [], entry.edges ? arr(entry.edges) : [], c.x ? arr(c.x) : []];
|
|
1718
|
+
const idx = arr(c.idx);
|
|
1719
|
+
const out = new Float32Array(idx.length * 3);
|
|
1720
|
+
const starts = [];
|
|
1721
|
+
let base = 0;
|
|
1722
|
+
for (const p of pools) {
|
|
1723
|
+
starts.push(base);
|
|
1724
|
+
base += p.length / 3;
|
|
1725
|
+
}
|
|
1726
|
+
let prev = 0;
|
|
1727
|
+
for (let i = 0;i < idx.length; i++) {
|
|
1728
|
+
const z = idx[i];
|
|
1729
|
+
const j = prev + (z & 1 ? -(z + 1) / 2 : z / 2);
|
|
1730
|
+
prev = j;
|
|
1731
|
+
let k = 3;
|
|
1732
|
+
while (k > 0 && j < starts[k])
|
|
1733
|
+
k--;
|
|
1734
|
+
const p = pools[k], o = (j - starts[k]) * 3;
|
|
1735
|
+
out[i * 3] = p[o];
|
|
1736
|
+
out[i * 3 + 1] = p[o + 1];
|
|
1737
|
+
out[i * 3 + 2] = p[o + 2];
|
|
1738
|
+
}
|
|
1739
|
+
return out;
|
|
1740
|
+
}
|
|
1741
|
+
var condLineMat = () => new THREE.ShaderMaterial({
|
|
1742
|
+
uniforms: { ldrViewProj: { value: new THREE.Matrix4 } },
|
|
1743
|
+
vertexShader: `uniform mat4 ldrViewProj; attribute mat4 instanceMatrix; attribute vec3 ldrP1; attribute vec3 ldrC0; attribute vec3 ldrC1; attribute float ldrSide;
|
|
1744
|
+
void main(){
|
|
1745
|
+
mat4 mvp = ldrViewProj * instanceMatrix;
|
|
1746
|
+
vec4 a = mvp * vec4(position, 1.0), b = mvp * vec4(ldrP1, 1.0), c0 = mvp * vec4(ldrC0, 1.0), c1 = mvp * vec4(ldrC1, 1.0);
|
|
1747
|
+
vec2 A = a.xy / a.w, B = b.xy / b.w, C0 = c0.xy / c0.w, C1 = c1.xy / c1.w, d = B - A;
|
|
1748
|
+
float s0 = d.x * (C0.y - A.y) - d.y * (C0.x - A.x), s1 = d.x * (C1.y - A.y) - d.y * (C1.x - A.x);
|
|
1749
|
+
gl_Position = s0 * s1 >= 0.0 ? (ldrSide > 0.5 ? b : a) : vec4(2.0, 2.0, 2.0, 1.0);
|
|
1750
|
+
}`,
|
|
1751
|
+
fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
|
|
1752
|
+
});
|
|
1753
|
+
function conditionalLineVisible(cond, i, mvp) {
|
|
1754
|
+
const e = mvp.elements;
|
|
1755
|
+
const pr = (o) => {
|
|
1756
|
+
const x = cond[o], y = cond[o + 1], z = cond[o + 2];
|
|
1757
|
+
const w = e[3] * x + e[7] * y + e[11] * z + e[15];
|
|
1758
|
+
return [(e[0] * x + e[4] * y + e[8] * z + e[12]) / w, (e[1] * x + e[5] * y + e[9] * z + e[13]) / w];
|
|
1759
|
+
};
|
|
1760
|
+
const o = i * 12;
|
|
1761
|
+
const A = pr(o), B = pr(o + 3), C0 = pr(o + 6), C1 = pr(o + 9);
|
|
1762
|
+
const dx = B[0] - A[0], dy = B[1] - A[1];
|
|
1763
|
+
const s0 = dx * (C0[1] - A[1]) - dy * (C0[0] - A[0]), s1 = dx * (C1[1] - A[1]) - dy * (C1[0] - A[0]);
|
|
1764
|
+
return s0 * s1 >= 0;
|
|
1765
|
+
}
|
|
1766
|
+
function createInstancedConditionalEdges(cond, im, material = condLineMat()) {
|
|
1767
|
+
return condEdges(condBuffers(cond), im, material);
|
|
1768
|
+
}
|
|
1769
|
+
function condBuffers(cond) {
|
|
1770
|
+
const n = Math.floor(cond.length / 12);
|
|
1771
|
+
const buf = new Float32Array(n * 24), side = new Float32Array(n * 2);
|
|
1772
|
+
for (let l = 0;l < n; l++) {
|
|
1773
|
+
for (let k = 0;k < 12; k++) {
|
|
1774
|
+
const v = cond[l * 12 + k];
|
|
1775
|
+
buf[l * 24 + k] = v;
|
|
1776
|
+
buf[l * 24 + 12 + k] = v;
|
|
1777
|
+
}
|
|
1778
|
+
side[l * 2 + 1] = 1;
|
|
1307
1779
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
const
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
const
|
|
1324
|
-
if (
|
|
1780
|
+
return { ib: new THREE.InterleavedBuffer(buf, 12), side: new THREE.BufferAttribute(side, 1) };
|
|
1781
|
+
}
|
|
1782
|
+
function condEdges({ ib, side }, im, material) {
|
|
1783
|
+
const g = new THREE.InstancedBufferGeometry;
|
|
1784
|
+
g.setAttribute("position", new THREE.InterleavedBufferAttribute(ib, 3, 0));
|
|
1785
|
+
g.setAttribute("ldrP1", new THREE.InterleavedBufferAttribute(ib, 3, 3));
|
|
1786
|
+
g.setAttribute("ldrC0", new THREE.InterleavedBufferAttribute(ib, 3, 6));
|
|
1787
|
+
g.setAttribute("ldrC1", new THREE.InterleavedBufferAttribute(ib, 3, 9));
|
|
1788
|
+
g.setAttribute("ldrSide", side);
|
|
1789
|
+
g.setAttribute("instanceMatrix", im.instanceMatrix);
|
|
1790
|
+
g.instanceCount = im.count;
|
|
1791
|
+
const l = new THREE.LineSegments(g, material);
|
|
1792
|
+
l.frustumCulled = false;
|
|
1793
|
+
l.name = "ldrCondLines";
|
|
1794
|
+
l.onBeforeRender = (_r, _s, cam, _g, mat) => {
|
|
1795
|
+
const u = mat.uniforms?.ldrViewProj;
|
|
1796
|
+
if (!u)
|
|
1325
1797
|
return;
|
|
1326
|
-
|
|
1327
|
-
|
|
1798
|
+
l.modelViewMatrix.multiplyMatrices(cam.matrixWorldInverse, l.matrixWorld);
|
|
1799
|
+
u.value.multiplyMatrices(cam.projectionMatrix, l.modelViewMatrix);
|
|
1800
|
+
mat.uniformsNeedUpdate = true;
|
|
1801
|
+
};
|
|
1802
|
+
return l;
|
|
1803
|
+
}
|
|
1804
|
+
function sharedLines(pos, im, material = sharedLineMat()) {
|
|
1805
|
+
const { P, I } = weldLines(pos);
|
|
1806
|
+
const g = new THREE.InstancedBufferGeometry;
|
|
1807
|
+
g.setAttribute("position", new THREE.BufferAttribute(P, 3));
|
|
1808
|
+
g.setIndex(new THREE.BufferAttribute(I, 1));
|
|
1809
|
+
g.setAttribute("instanceMatrix", im.instanceMatrix);
|
|
1810
|
+
g.instanceCount = im.count;
|
|
1811
|
+
const l = new THREE.LineSegments(g, material);
|
|
1812
|
+
l.frustumCulled = false;
|
|
1813
|
+
return l;
|
|
1814
|
+
}
|
|
1815
|
+
function writeM4(t, o, m, mo = 0) {
|
|
1816
|
+
t[o] = m[mo + 3];
|
|
1817
|
+
t[o + 1] = m[mo + 6];
|
|
1818
|
+
t[o + 2] = m[mo + 9];
|
|
1819
|
+
t[o + 3] = 0;
|
|
1820
|
+
t[o + 4] = m[mo + 4];
|
|
1821
|
+
t[o + 5] = m[mo + 7];
|
|
1822
|
+
t[o + 6] = m[mo + 10];
|
|
1823
|
+
t[o + 7] = 0;
|
|
1824
|
+
t[o + 8] = m[mo + 5];
|
|
1825
|
+
t[o + 9] = m[mo + 8];
|
|
1826
|
+
t[o + 10] = m[mo + 11];
|
|
1827
|
+
t[o + 11] = 0;
|
|
1828
|
+
t[o + 12] = m[mo];
|
|
1829
|
+
t[o + 13] = m[mo + 1];
|
|
1830
|
+
t[o + 14] = m[mo + 2];
|
|
1831
|
+
t[o + 15] = 1;
|
|
1832
|
+
}
|
|
1833
|
+
function newIM(g, mat, n) {
|
|
1834
|
+
const im = new THREE.InstancedMesh(g, mat, 0);
|
|
1835
|
+
im.instanceMatrix = new THREE.InstancedBufferAttribute(new Float32Array(n * 16), 16);
|
|
1836
|
+
im.count = n;
|
|
1837
|
+
return im;
|
|
1838
|
+
}
|
|
1839
|
+
function instancedBoundingSphere(im) {
|
|
1840
|
+
const g = im.geometry;
|
|
1841
|
+
if (!g.boundingSphere)
|
|
1842
|
+
g.computeBoundingSphere();
|
|
1843
|
+
const gs = g.boundingSphere;
|
|
1844
|
+
const gx = gs.center.x, gy = gs.center.y, gz = gs.center.z, gr = gs.radius;
|
|
1845
|
+
const A = im.instanceMatrix.array;
|
|
1846
|
+
let cx = 0, cy = 0, cz = 0, r = -1;
|
|
1847
|
+
const expand = (px, py, pz) => {
|
|
1848
|
+
if (r < 0) {
|
|
1849
|
+
cx = px;
|
|
1850
|
+
cy = py;
|
|
1851
|
+
cz = pz;
|
|
1852
|
+
r = 0;
|
|
1328
1853
|
return;
|
|
1329
1854
|
}
|
|
1330
|
-
const
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1855
|
+
const vx = px - cx, vy = py - cy, vz = pz - cz;
|
|
1856
|
+
const l2 = vx * vx + vy * vy + vz * vz;
|
|
1857
|
+
if (l2 > r * r) {
|
|
1858
|
+
const l = Math.sqrt(l2);
|
|
1859
|
+
const d = (l - r) * 0.5;
|
|
1860
|
+
const f = d / l;
|
|
1861
|
+
cx += vx * f;
|
|
1862
|
+
cy += vy * f;
|
|
1863
|
+
cz += vz * f;
|
|
1864
|
+
r += d;
|
|
1865
|
+
}
|
|
1866
|
+
};
|
|
1867
|
+
for (let i = 0, n = im.count;i < n; i++) {
|
|
1868
|
+
const o = i * 16;
|
|
1869
|
+
const e0 = A[o], e1 = A[o + 1], e2 = A[o + 2], e3 = A[o + 3], e4 = A[o + 4], e5 = A[o + 5], e6 = A[o + 6], e7 = A[o + 7], e8 = A[o + 8], e9 = A[o + 9], e10 = A[o + 10], e11 = A[o + 11];
|
|
1870
|
+
const w = 1 / (e3 * gx + e7 * gy + e11 * gz + A[o + 15]);
|
|
1871
|
+
const x = (e0 * gx + e4 * gy + e8 * gz + A[o + 12]) * w, y = (e1 * gx + e5 * gy + e9 * gz + A[o + 13]) * w, z = (e2 * gx + e6 * gy + e10 * gz + A[o + 14]) * w;
|
|
1872
|
+
const sr = gr * Math.sqrt(Math.max(e0 * e0 + e1 * e1 + e2 * e2, e4 * e4 + e5 * e5 + e6 * e6, e8 * e8 + e9 * e9 + e10 * e10));
|
|
1873
|
+
if (r < 0) {
|
|
1874
|
+
cx = x;
|
|
1875
|
+
cy = y;
|
|
1876
|
+
cz = z;
|
|
1877
|
+
r = sr;
|
|
1340
1878
|
continue;
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1879
|
+
}
|
|
1880
|
+
if (x === cx && y === cy && z === cz) {
|
|
1881
|
+
r = Math.max(r, sr);
|
|
1344
1882
|
continue;
|
|
1345
|
-
const m = it.m;
|
|
1346
|
-
let all = true, at = 0;
|
|
1347
|
-
for (let a = 0;a < nx && all; a++)
|
|
1348
|
-
for (let c = 0;c < nz; c++) {
|
|
1349
|
-
const lx = b[0] + 10 + 20 * a, lz = b[2] + 10 + 20 * c;
|
|
1350
|
-
const x = m[0] + m[3] * lx + m[5] * lz, z = m[2] + m[9] * lx + m[11] * lz;
|
|
1351
|
-
const k = topKey(x, m[1] + b[4], z);
|
|
1352
|
-
const t = k < 0 ? -1 : tops.get(k);
|
|
1353
|
-
if (t < 0) {
|
|
1354
|
-
all = false;
|
|
1355
|
-
break;
|
|
1356
|
-
}
|
|
1357
|
-
if (t > at)
|
|
1358
|
-
at = t;
|
|
1359
|
-
}
|
|
1360
|
-
if (all) {
|
|
1361
|
-
underHidden[idx] = 1;
|
|
1362
|
-
if (underHideStep)
|
|
1363
|
-
underHideStep[idx] = at;
|
|
1364
1883
|
}
|
|
1884
|
+
let dx = x - cx, dy = y - cy, dz = z - cz;
|
|
1885
|
+
const inv = 1 / (Math.sqrt(dx * dx + dy * dy + dz * dz) || 1);
|
|
1886
|
+
dx = dx * inv * sr;
|
|
1887
|
+
dy = dy * inv * sr;
|
|
1888
|
+
dz = dz * inv * sr;
|
|
1889
|
+
expand(x + dx, y + dy, z + dz);
|
|
1890
|
+
expand(x - dx, y - dy, z - dz);
|
|
1365
1891
|
}
|
|
1366
|
-
|
|
1892
|
+
const sph = im.boundingSphere ?? new THREE.Sphere;
|
|
1893
|
+
sph.center.set(cx, cy, cz);
|
|
1894
|
+
sph.radius = r;
|
|
1895
|
+
if (r < 0)
|
|
1896
|
+
sph.makeEmpty();
|
|
1897
|
+
im.boundingSphere = sph;
|
|
1898
|
+
return sph;
|
|
1899
|
+
}
|
|
1900
|
+
function fillInstances(im, ids, insts, color) {
|
|
1901
|
+
const M = im.instanceMatrix.array;
|
|
1902
|
+
const C = new Float32Array(ids.length * 3);
|
|
1903
|
+
for (let k = 0;k < ids.length; k++) {
|
|
1904
|
+
const it = insts[ids[k]];
|
|
1905
|
+
writeM4(M, k * 16, it.m);
|
|
1906
|
+
color(it.color).toArray(C, k * 3);
|
|
1907
|
+
}
|
|
1908
|
+
im.instanceColor = new THREE.InstancedBufferAttribute(C, 3);
|
|
1367
1909
|
}
|
|
1368
1910
|
function computeCulling(insts, H) {
|
|
1369
1911
|
const c = cullCore(insts, H);
|
|
@@ -1419,7 +1961,8 @@ class LdrLodRoot extends THREE.LOD {
|
|
|
1419
1961
|
clusters = [];
|
|
1420
1962
|
vpH = 1080;
|
|
1421
1963
|
px = 0.5;
|
|
1422
|
-
edgePpl = 0.
|
|
1964
|
+
edgePpl = 0.5 / 20;
|
|
1965
|
+
edgeMinPx = 0.15;
|
|
1423
1966
|
enabled = true;
|
|
1424
1967
|
apply = () => {};
|
|
1425
1968
|
inv = new THREE.Matrix4;
|
|
@@ -1449,37 +1992,90 @@ class LdrLodRoot extends THREE.LOD {
|
|
|
1449
1992
|
L = i;
|
|
1450
1993
|
break;
|
|
1451
1994
|
}
|
|
1995
|
+
if (c.below !== undefined && x * c.ax[0] + y * c.ax[1] + z * c.ax[2] < c.below - 1 && ppl * 20 < 4)
|
|
1996
|
+
L = -1;
|
|
1997
|
+
if (c.boxErr !== undefined && c.boxErr * ppl <= tau)
|
|
1998
|
+
L = -1;
|
|
1452
1999
|
const e = ppl >= eppl;
|
|
1453
2000
|
if (L !== c.cur || e !== c.edgeOk) {
|
|
1454
2001
|
c.cur = L;
|
|
1455
2002
|
c.edgeOk = e;
|
|
1456
2003
|
this.apply(c);
|
|
1457
2004
|
}
|
|
2005
|
+
if (e && c.lines.length) {
|
|
2006
|
+
const minLen = this.edgeMinPx / ppl;
|
|
2007
|
+
for (const l of c.lines) {
|
|
2008
|
+
const lens = l.userData.ldrLens;
|
|
2009
|
+
if (!lens)
|
|
2010
|
+
continue;
|
|
2011
|
+
let lo = 0, hi = lens.length;
|
|
2012
|
+
while (lo < hi) {
|
|
2013
|
+
const mid = lo + hi >> 1;
|
|
2014
|
+
if (lens[mid] >= minLen)
|
|
2015
|
+
lo = mid + 1;
|
|
2016
|
+
else
|
|
2017
|
+
hi = mid;
|
|
2018
|
+
}
|
|
2019
|
+
l.geometry.drawRange.count = lo * 2;
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
1458
2022
|
}
|
|
1459
2023
|
}
|
|
1460
2024
|
}
|
|
1461
|
-
function buildStudMeshes(insts, H, cull, arr,
|
|
2025
|
+
function buildStudMeshes(insts, H, cull, arr, LOD, color, matF, matB, steps, colorIndex) {
|
|
1462
2026
|
const bucketOf = new Map;
|
|
1463
2027
|
const bKind = [], bMirror = [];
|
|
1464
2028
|
const bAll = [];
|
|
1465
2029
|
const studBucket = new Uint16Array(cull.nStuds);
|
|
1466
2030
|
const sx = new Float32Array(cull.nStuds), sz = new Float32Array(cull.nStuds);
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
2031
|
+
const kindIds = new Map;
|
|
2032
|
+
const kindNames = [];
|
|
2033
|
+
const bucketOfKM = [];
|
|
2034
|
+
const partStud = new Map;
|
|
2035
|
+
for (let idx = 0, j = 0;idx < insts.length; idx++) {
|
|
2036
|
+
const it = insts[idx];
|
|
2037
|
+
const pp = prepPart(H, it.part);
|
|
2038
|
+
if (!pp || !pp.nStuds)
|
|
2039
|
+
continue;
|
|
2040
|
+
const a = it.m;
|
|
2041
|
+
let ps = partStud.get(pp);
|
|
2042
|
+
if (!ps) {
|
|
2043
|
+
const kid = new Int32Array(pp.nStuds), neg = new Uint8Array(pp.nStuds);
|
|
2044
|
+
for (let si = 0;si < pp.nStuds; si++) {
|
|
2045
|
+
const kn = pp.kind[si];
|
|
2046
|
+
let id = kindIds.get(kn);
|
|
2047
|
+
if (id === undefined) {
|
|
2048
|
+
id = kindNames.length;
|
|
2049
|
+
kindIds.set(kn, id);
|
|
2050
|
+
kindNames.push(kn);
|
|
2051
|
+
}
|
|
2052
|
+
kid[si] = id;
|
|
2053
|
+
neg[si] = det12(pp.studM.subarray(si * 12, si * 12 + 12)) < 0 ? 1 : 0;
|
|
2054
|
+
}
|
|
2055
|
+
partStud.set(pp, ps = { kid, neg });
|
|
2056
|
+
}
|
|
2057
|
+
const instNeg = det12(a) < 0 ? 1 : 0;
|
|
2058
|
+
const B = pp.studM;
|
|
2059
|
+
for (let si = 0;si < pp.nStuds; si++, j++) {
|
|
2060
|
+
const o = si * 12, b0 = B[o], b1 = B[o + 1], b2 = B[o + 2];
|
|
2061
|
+
const neg = (instNeg ^ ps.neg[si]) === 1;
|
|
2062
|
+
const km = ps.kid[si] * 2 + (neg ? 1 : 0);
|
|
2063
|
+
let b = bucketOfKM[km];
|
|
2064
|
+
if (b === undefined) {
|
|
2065
|
+
const kn = kindNames[ps.kid[si]];
|
|
2066
|
+
b = bKind.length;
|
|
2067
|
+
bucketOfKM[km] = b;
|
|
2068
|
+
bucketOf.set(neg ? kn + "#m" : kn, b);
|
|
2069
|
+
bKind.push(kn);
|
|
2070
|
+
bMirror.push(neg);
|
|
2071
|
+
bAll.push(0);
|
|
2072
|
+
}
|
|
2073
|
+
studBucket[j] = b;
|
|
2074
|
+
bAll[b]++;
|
|
2075
|
+
sx[j] = a[0] + a[3] * b0 + a[4] * b1 + a[5] * b2;
|
|
2076
|
+
sz[j] = a[2] + a[9] * b0 + a[10] * b1 + a[11] * b2;
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
1483
2079
|
const bIds = bAll.map((n) => new Int32Array(n));
|
|
1484
2080
|
{
|
|
1485
2081
|
const f = bAll.map(() => 0);
|
|
@@ -1491,7 +2087,7 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
|
|
|
1491
2087
|
const studCl = new Int32Array(cull.nStuds), studSlot = new Int32Array(cull.nStuds);
|
|
1492
2088
|
const sMesh = [];
|
|
1493
2089
|
bKind.forEach((kind, b) => {
|
|
1494
|
-
const g = geom(H.studKinds[kind].body, arr
|
|
2090
|
+
const g = geom(H.studKinds[kind].body, arr);
|
|
1495
2091
|
const ids = bIds[b];
|
|
1496
2092
|
for (const c of gridClusters(ids.length, (i) => sx[ids[i]], (i) => sz[ids[i]], LOD ? 16384 : Infinity)) {
|
|
1497
2093
|
const ci = sMesh.length;
|
|
@@ -1515,6 +2111,13 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
|
|
|
1515
2111
|
sMesh.push({ im, kind, vis: v, ...steps ? { slots: { own: new Int32Array(n), hide: new Int32Array(n), inst: new Int32Array(n), stud: new Int16Array(n), col: new Uint16Array(n) } } : {} });
|
|
1516
2112
|
}
|
|
1517
2113
|
});
|
|
2114
|
+
const colCache = new Map;
|
|
2115
|
+
const colorOf = (c) => {
|
|
2116
|
+
let x = colCache.get(c);
|
|
2117
|
+
if (!x)
|
|
2118
|
+
colCache.set(c, x = color(c));
|
|
2119
|
+
return x;
|
|
2120
|
+
};
|
|
1518
2121
|
forEachStud(insts, H, (j, owner, w, _kind, col, si) => {
|
|
1519
2122
|
const sm = sMesh[studCl[j]];
|
|
1520
2123
|
if (!sm)
|
|
@@ -1530,18 +2133,46 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
|
|
|
1530
2133
|
t.col[slot] = colorIndex(col);
|
|
1531
2134
|
}
|
|
1532
2135
|
writeM4(im.instanceMatrix.array, slot * 16, w);
|
|
1533
|
-
|
|
2136
|
+
colorOf(col).toArray(im.instanceColor.array, slot * 3);
|
|
1534
2137
|
});
|
|
1535
2138
|
return sMesh;
|
|
1536
2139
|
}
|
|
2140
|
+
function undersideGroups(ids, insts) {
|
|
2141
|
+
const by = new Map;
|
|
2142
|
+
const rest = [];
|
|
2143
|
+
for (const id of ids) {
|
|
2144
|
+
const m = insts[id].m;
|
|
2145
|
+
const l = Math.hypot(m[4], m[7], m[10]);
|
|
2146
|
+
if (!(l > 0.000001)) {
|
|
2147
|
+
rest.push(id);
|
|
2148
|
+
continue;
|
|
2149
|
+
}
|
|
2150
|
+
const ax = [m[4] / l, m[7] / l, m[10] / l, l];
|
|
2151
|
+
const k = ax.map((v) => Math.round(v * 1000)).join();
|
|
2152
|
+
let g = by.get(k);
|
|
2153
|
+
if (!g) {
|
|
2154
|
+
if (by.size >= 12) {
|
|
2155
|
+
rest.push(id);
|
|
2156
|
+
continue;
|
|
2157
|
+
}
|
|
2158
|
+
by.set(k, g = { ids: [], ax });
|
|
2159
|
+
}
|
|
2160
|
+
g.ids.push(id);
|
|
2161
|
+
}
|
|
2162
|
+
const out = [...by.values()];
|
|
2163
|
+
if (rest.length)
|
|
2164
|
+
out.push({ ids: rest, ax: null });
|
|
2165
|
+
return out;
|
|
2166
|
+
}
|
|
1537
2167
|
function buildLdrScene(insts, pack, P, color, mark) {
|
|
1538
2168
|
const { header: H, arr } = pack;
|
|
1539
|
-
const Q = P.quant !== false;
|
|
1540
2169
|
const LOD = P.lod !== false;
|
|
2170
|
+
const EDGES = !!P.edges;
|
|
1541
2171
|
const root = new LdrLodRoot;
|
|
1542
2172
|
root.enabled = LOD;
|
|
1543
2173
|
root.px = P.lodPx ?? 0.5;
|
|
1544
2174
|
root.edgePpl = (P.lodEdgePx ?? 0.5) / 20;
|
|
2175
|
+
root.edgeMinPx = P.lodEdgeMinPx ?? 0.15;
|
|
1545
2176
|
const trackVp = (r) => {
|
|
1546
2177
|
const rt = r.getRenderTarget();
|
|
1547
2178
|
const h = rt ? rt.height : r.getContext().drawingBufferHeight;
|
|
@@ -1559,7 +2190,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1559
2190
|
}
|
|
1560
2191
|
});
|
|
1561
2192
|
const steps = P.steps;
|
|
1562
|
-
let cull = cullCore(insts, H, steps);
|
|
2193
|
+
let cull = P.cull ?? cullCore(insts, H, steps);
|
|
1563
2194
|
mark("culling");
|
|
1564
2195
|
const stepBatches = [];
|
|
1565
2196
|
const instM = steps ? new Float64Array(insts.length * 12) : null;
|
|
@@ -1585,7 +2216,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1585
2216
|
});
|
|
1586
2217
|
const edgeObjs = [];
|
|
1587
2218
|
const condObjs = [];
|
|
1588
|
-
const wantCond = P.cond !== false &&
|
|
2219
|
+
const wantCond = P.cond !== false && EDGES;
|
|
1589
2220
|
let condMat = null;
|
|
1590
2221
|
const cmat = () => condMat ??= condLineMat();
|
|
1591
2222
|
let lineMatShared = null;
|
|
@@ -1616,8 +2247,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1616
2247
|
const addLines = (ref, im, cl) => {
|
|
1617
2248
|
let w = lineCache.get(ref);
|
|
1618
2249
|
if (!w) {
|
|
1619
|
-
const r = weldLines(arr(ref));
|
|
1620
|
-
lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1) });
|
|
2250
|
+
const r = weldLines(arr(ref), LOD);
|
|
2251
|
+
lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1), lens: r.lens });
|
|
1621
2252
|
}
|
|
1622
2253
|
const g = new THREE.InstancedBufferGeometry;
|
|
1623
2254
|
g.setAttribute("position", w.P);
|
|
@@ -1626,6 +2257,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1626
2257
|
g.instanceCount = im.count;
|
|
1627
2258
|
const l = new THREE.LineSegments(g, lmat());
|
|
1628
2259
|
l.frustumCulled = false;
|
|
2260
|
+
if (LOD)
|
|
2261
|
+
l.userData.ldrLens = w.lens;
|
|
1629
2262
|
edgeObjs.push(l);
|
|
1630
2263
|
cl.lines.push(l);
|
|
1631
2264
|
root.add(l);
|
|
@@ -1633,7 +2266,6 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1633
2266
|
};
|
|
1634
2267
|
const stats = { studsTotal: cull.nStuds, studsHidden: cull.studsHidden, undersTotal: 0, undersHidden: 0 };
|
|
1635
2268
|
const toggles = [];
|
|
1636
|
-
const studMeshes = [];
|
|
1637
2269
|
const countTo = (objs) => ({ set count(n) {
|
|
1638
2270
|
for (const o of objs()) {
|
|
1639
2271
|
if (o.isInstancedMesh)
|
|
@@ -1668,8 +2300,9 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1668
2300
|
root.clusters.push(c);
|
|
1669
2301
|
return c;
|
|
1670
2302
|
};
|
|
1671
|
-
const lodLevels = (b, base, mat) => !LOD ||
|
|
1672
|
-
const im = new THREE.InstancedMesh(geom(l, arr
|
|
2303
|
+
const lodLevels = (b, base, mat) => !LOD || !b?.lod ? [] : b.lod.map((l) => {
|
|
2304
|
+
const im = new THREE.InstancedMesh(geom(l, arr), mat, 0);
|
|
2305
|
+
im.userData = { ...base.userData };
|
|
1673
2306
|
im.instanceMatrix = base.instanceMatrix;
|
|
1674
2307
|
im.count = base.count;
|
|
1675
2308
|
im.instanceColor = base.instanceColor;
|
|
@@ -1685,10 +2318,10 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1685
2318
|
for (const [pk, idsAll] of byPart) {
|
|
1686
2319
|
const part = pk.replace(/#m$/, "");
|
|
1687
2320
|
const p = H.parts[part];
|
|
1688
|
-
const mat =
|
|
2321
|
+
const mat = p.uncert ? (nUncert++, matD) : pk.endsWith("#m") ? matB : matF;
|
|
1689
2322
|
const textured = wantTex && !!p.tex;
|
|
1690
2323
|
const bodyB = textured ? p.tbody : p.body;
|
|
1691
|
-
const body = geom(bodyB, arr
|
|
2324
|
+
const body = geom(bodyB, arr);
|
|
1692
2325
|
const groups = gridClusters(idsAll.length, (i) => insts[idsAll[i]].m[0], (i) => insts[idsAll[i]].m[2], textured ? Infinity : kFor(tris(p.body) + tris(p.under)));
|
|
1693
2326
|
for (const g of groups) {
|
|
1694
2327
|
const ids = Array.from(g, (i) => idsAll[i]);
|
|
@@ -1696,7 +2329,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1696
2329
|
const lv0 = [];
|
|
1697
2330
|
const place = (im) => {
|
|
1698
2331
|
fillInstances(im, ids, insts, color);
|
|
1699
|
-
im
|
|
2332
|
+
instancedBoundingSphere(im);
|
|
2333
|
+
im.userData.ldrPart = part;
|
|
1700
2334
|
root.add(im);
|
|
1701
2335
|
};
|
|
1702
2336
|
if (body) {
|
|
@@ -1706,7 +2340,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1706
2340
|
}
|
|
1707
2341
|
if (textured)
|
|
1708
2342
|
for (const tb of p.tex) {
|
|
1709
|
-
const gg = geom(tb, arr
|
|
2343
|
+
const gg = geom(tb, arr);
|
|
1710
2344
|
const im = newIM(gg, texMat(tb.t, mat, !!tb.wrapU), ids.length);
|
|
1711
2345
|
texBatches++;
|
|
1712
2346
|
lv0.push(im);
|
|
@@ -1724,49 +2358,57 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1724
2358
|
const cl = newCluster(bodyIm.boundingSphere);
|
|
1725
2359
|
lv0.forEach((o) => o.onBeforeRender = trackVp);
|
|
1726
2360
|
cl.lv.push({ objs: lv0, err: 0 }, ...textured ? [] : lodLevels(p.body, bodyIm, mat));
|
|
1727
|
-
if (
|
|
2361
|
+
if (EDGES && p.edges)
|
|
1728
2362
|
addLines(p.edges, bodyIm, cl);
|
|
1729
2363
|
addCond(p, bodyIm, cl);
|
|
1730
2364
|
if (steps)
|
|
1731
2365
|
stepBatches.push({ im: bodyIm, objs: [...cl.lv.flatMap((l) => l.objs), ...cl.lines, ...cl.cond], own: Int32Array.from(ids, (id) => steps[id]), hide: null, flag: "body", inst: Int32Array.from(ids), stud: null, col: Uint16Array.from(ids, (id) => instCol[id]) });
|
|
1732
|
-
if (P.edges === true && p.edges) {
|
|
1733
|
-
const mats = new Float32Array(ids.length * 16);
|
|
1734
|
-
ids.forEach((id, k) => writeM4(mats, k * 16, insts[id].m));
|
|
1735
|
-
{
|
|
1736
|
-
const l = instancedLines(arr(p.edges), mats, ids.length);
|
|
1737
|
-
edgeObjs.push(l);
|
|
1738
|
-
cl.lines.push(l);
|
|
1739
|
-
root.add(l);
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
2366
|
}
|
|
1743
|
-
const under = geom(p.under, arr
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
const
|
|
1747
|
-
|
|
1748
|
-
stats.
|
|
1749
|
-
|
|
2367
|
+
const under = geom(p.under, arr);
|
|
2368
|
+
const uGroups = !under ? [] : LOD && P.lodUnder !== false ? undersideGroups(ids, insts) : [{ ids, ax: null }];
|
|
2369
|
+
for (const { ids: uids, ax } of uGroups) {
|
|
2370
|
+
const ord = [...uids.filter((i) => !cull.underHidden[i]), ...uids.filter((i) => cull.underHidden[i])];
|
|
2371
|
+
const vis = uids.length - uids.reduce((a, i) => a + cull.underHidden[i], 0);
|
|
2372
|
+
stats.undersTotal += uids.length;
|
|
2373
|
+
stats.undersHidden += uids.length - vis;
|
|
2374
|
+
const im = newIM(under, mat, uids.length);
|
|
1750
2375
|
fillInstances(im, ord, insts, color);
|
|
1751
2376
|
im.onBeforeRender = trackVp;
|
|
1752
|
-
im.
|
|
1753
|
-
im.
|
|
2377
|
+
im.userData.ldrUnder = true;
|
|
2378
|
+
im.userData.ldrPart = part;
|
|
2379
|
+
instancedBoundingSphere(im);
|
|
2380
|
+
im.count = P.cullUnder ? vis : uids.length;
|
|
1754
2381
|
root.add(im);
|
|
1755
2382
|
const cl = newCluster(im.boundingSphere);
|
|
1756
2383
|
cl.lv.push({ objs: [im], err: 0 }, ...lodLevels(p.under, im, mat));
|
|
2384
|
+
{
|
|
2385
|
+
const bl = p.body?.lod;
|
|
2386
|
+
const last = bl?.[bl.length - 1];
|
|
2387
|
+
if (LOD && P.lodUnder !== false && last && last.tris === 12)
|
|
2388
|
+
cl.boxErr = last.err;
|
|
2389
|
+
}
|
|
2390
|
+
if (ax) {
|
|
2391
|
+
let below = Infinity;
|
|
2392
|
+
for (const id of uids) {
|
|
2393
|
+
const m = insts[id].m;
|
|
2394
|
+
below = Math.min(below, m[0] * ax[0] + m[1] * ax[1] + m[2] * ax[2] + p.bbox[4] * ax[3]);
|
|
2395
|
+
}
|
|
2396
|
+
cl.below = below;
|
|
2397
|
+
cl.ax = ax.slice(0, 3);
|
|
2398
|
+
}
|
|
1757
2399
|
addCond(p, im, cl, "under");
|
|
1758
2400
|
const objs = [...cl.lv.flatMap((l) => l.objs), ...cl.cond];
|
|
1759
2401
|
objs.forEach((o) => {
|
|
1760
2402
|
if (!o.isInstancedMesh)
|
|
1761
2403
|
o.geometry.instanceCount = im.count;
|
|
1762
2404
|
});
|
|
1763
|
-
toggles.push({ mesh: countTo(() => objs), all:
|
|
2405
|
+
toggles.push({ mesh: countTo(() => objs), all: uids.length, visible: vis, flag: "under" });
|
|
1764
2406
|
if (steps)
|
|
1765
2407
|
stepBatches.push({ im, objs, own: Int32Array.from(ord, (id) => steps[id]), hide: Int32Array.from(ord, (id) => cull.underHideStep[id]), flag: "under", inst: Int32Array.from(ord), stud: null, col: Uint16Array.from(ord, (id) => instCol[id]) });
|
|
1766
2408
|
}
|
|
1767
2409
|
}
|
|
1768
2410
|
}
|
|
1769
|
-
const sMesh = buildStudMeshes(insts, H, cull, arr,
|
|
2411
|
+
const sMesh = buildStudMeshes(insts, H, cull, arr, LOD, color, matF, matB, steps, steps && colorIndex);
|
|
1770
2412
|
const sKind = sMesh.map((x) => x?.kind ?? "");
|
|
1771
2413
|
const sVis = sMesh.map((x) => x?.vis ?? 0);
|
|
1772
2414
|
const STUD_ERR = 12;
|
|
@@ -1777,26 +2419,19 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1777
2419
|
const kind = sKind[ci];
|
|
1778
2420
|
const k = H.studKinds[kind];
|
|
1779
2421
|
const vis = sVis[ci], all = im.instanceMatrix.count;
|
|
1780
|
-
im
|
|
2422
|
+
instancedBoundingSphere(im);
|
|
1781
2423
|
im.count = P.cullStuds ? vis : all;
|
|
1782
2424
|
im.onBeforeRender = trackVp;
|
|
1783
2425
|
im.userData.ldrStud = true;
|
|
1784
2426
|
root.add(im);
|
|
1785
|
-
studMeshes.push({ im, kind });
|
|
1786
2427
|
const cl = newCluster(im.boundingSphere);
|
|
1787
2428
|
cl.lv.push({ objs: [im], err: 0 });
|
|
1788
|
-
if (LOD
|
|
2429
|
+
if (LOD)
|
|
1789
2430
|
cl.lv.push({ objs: [], err: STUD_ERR });
|
|
1790
|
-
if (
|
|
2431
|
+
if (EDGES && k.edges)
|
|
1791
2432
|
addLines(k.edges, im, cl);
|
|
1792
2433
|
if (P.condStuds !== false)
|
|
1793
2434
|
addCond(k, im, cl);
|
|
1794
|
-
if (P.edges === true && k.edges) {
|
|
1795
|
-
const l = instancedLines(arr(k.edges), im.instanceMatrix.array.slice(), im.count);
|
|
1796
|
-
edgeObjs.push(l);
|
|
1797
|
-
cl.lines.push(l);
|
|
1798
|
-
root.add(l);
|
|
1799
|
-
}
|
|
1800
2435
|
const objs = [im, ...cl.lines, ...cl.cond];
|
|
1801
2436
|
objs.forEach((o) => {
|
|
1802
2437
|
if (!o.isInstancedMesh)
|
|
@@ -1814,7 +2449,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1814
2449
|
for (const o of l.objs)
|
|
1815
2450
|
o.visible = i === c.cur;
|
|
1816
2451
|
});
|
|
1817
|
-
const lineVis = edgesOn && c.edgeOk && (c.cur === 0 || !LOD || c.lv[c.cur].objs.length > 0);
|
|
2452
|
+
const lineVis = edgesOn && c.edgeOk && c.cur >= 0 && (c.cur === 0 || !LOD || c.lv[c.cur].objs.length > 0);
|
|
1818
2453
|
for (const o of c.lines)
|
|
1819
2454
|
o.visible = lineVis;
|
|
1820
2455
|
for (const o of c.cond)
|
|
@@ -1836,9 +2471,10 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1836
2471
|
stats.clusters = root.clusters.length;
|
|
1837
2472
|
const texturesReady = Promise.all(pending).then(() => {});
|
|
1838
2473
|
let stepS = STEP_NEVER - 1, cullS = !!P.cullStuds, cullU = !!P.cullUnder;
|
|
2474
|
+
let only = null;
|
|
1839
2475
|
const applySteps = () => {
|
|
1840
2476
|
const st = { studsTotal: 0, studsHidden: 0, undersTotal: 0, undersHidden: 0 };
|
|
1841
|
-
const S = stepS;
|
|
2477
|
+
const S = stepS, O = only;
|
|
1842
2478
|
const wm = new Float64Array(12);
|
|
1843
2479
|
for (const b of stepBatches) {
|
|
1844
2480
|
const MA = b.im.instanceMatrix.array, CA = b.im.instanceColor.array;
|
|
@@ -1861,6 +2497,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1861
2497
|
if (useHide && hid)
|
|
1862
2498
|
continue;
|
|
1863
2499
|
const n = inst[i];
|
|
2500
|
+
if (O && !O[n])
|
|
2501
|
+
continue;
|
|
1864
2502
|
if (stud) {
|
|
1865
2503
|
mul12To(instM, instPP[n].studM, stud[i] * 12, wm, n * 12);
|
|
1866
2504
|
writeM4(MA, w * 16, wm);
|
|
@@ -1890,10 +2528,11 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1890
2528
|
for (const t of toggles)
|
|
1891
2529
|
t.mesh.count = (t.flag === "studs" ? studs : under) ? t.visible : t.all;
|
|
1892
2530
|
};
|
|
1893
|
-
const setStep = (s) => {
|
|
2531
|
+
const setStep = (s, mask = null) => {
|
|
1894
2532
|
if (!steps)
|
|
1895
2533
|
throw new Error("buildLdrScene: setStep needs P.steps");
|
|
1896
2534
|
stepS = s == null ? STEP_NEVER - 1 : s;
|
|
2535
|
+
only = mask;
|
|
1897
2536
|
return applySteps();
|
|
1898
2537
|
};
|
|
1899
2538
|
const box = new THREE.Box3;
|
|
@@ -1924,21 +2563,14 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1924
2563
|
m.needsUpdate = true;
|
|
1925
2564
|
}
|
|
1926
2565
|
};
|
|
1927
|
-
const swapStuds = (alt) => {
|
|
1928
|
-
const saved = studMeshes.map((s) => s.im.geometry);
|
|
1929
|
-
for (const s of studMeshes) {
|
|
1930
|
-
const k2 = alt.header.studKinds[s.kind] ? s.kind : Object.keys(alt.header.studKinds).find((k) => k.replace("p/8/", "p/") === s.kind.replace("p/8/", "p/"));
|
|
1931
|
-
if (k2)
|
|
1932
|
-
s.im.geometry = geom(alt.header.studKinds[k2].body, alt.arr, Q);
|
|
1933
|
-
}
|
|
1934
|
-
return () => studMeshes.forEach((s, i) => s.im.geometry = saved[i]);
|
|
1935
|
-
};
|
|
1936
2566
|
const setLod = (on) => {
|
|
1937
2567
|
root.enabled = on && LOD;
|
|
1938
2568
|
if (!root.enabled) {
|
|
1939
2569
|
for (const c of root.clusters) {
|
|
1940
2570
|
c.cur = 0;
|
|
1941
2571
|
c.edgeOk = true;
|
|
2572
|
+
for (const l of c.lines)
|
|
2573
|
+
l.geometry.drawRange.count = Infinity;
|
|
1942
2574
|
}
|
|
1943
2575
|
refresh();
|
|
1944
2576
|
}
|
|
@@ -1946,9 +2578,31 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1946
2578
|
insts = null;
|
|
1947
2579
|
cull = null;
|
|
1948
2580
|
byPart.clear();
|
|
1949
|
-
return { root, stats, setCull, setSide, setEdges, setCond,
|
|
2581
|
+
return { root, stats, setCull, setSide, setEdges, setCond, setLod, setStep, box, texturesReady };
|
|
2582
|
+
}
|
|
2583
|
+
async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
|
|
2584
|
+
const { header: H, arr } = pack;
|
|
2585
|
+
const list = [];
|
|
2586
|
+
for (const p of Object.values(H.parts ?? {}))
|
|
2587
|
+
for (const b of [p.body, p.under])
|
|
2588
|
+
if (b) {
|
|
2589
|
+
list.push(b);
|
|
2590
|
+
for (const l of b.lod ?? [])
|
|
2591
|
+
list.push(l);
|
|
2592
|
+
}
|
|
2593
|
+
for (const k of Object.values(H.studKinds ?? {}))
|
|
2594
|
+
if (k?.body)
|
|
2595
|
+
list.push(k.body);
|
|
2596
|
+
let i = 0;
|
|
2597
|
+
while (i < list.length && !stop()) {
|
|
2598
|
+
const t = performance.now();
|
|
2599
|
+
while (i < list.length && performance.now() - t < sliceMs)
|
|
2600
|
+
geom(list[i++], arr);
|
|
2601
|
+
if (i < list.length)
|
|
2602
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
2603
|
+
}
|
|
1950
2604
|
}
|
|
1951
|
-
// ../../../../../../../tmp/ldr-build-
|
|
2605
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/scene.ts
|
|
1952
2606
|
import * as THREE2 from "three";
|
|
1953
2607
|
function colorFn(src, pack, fallback) {
|
|
1954
2608
|
const table = new Map;
|
|
@@ -1993,12 +2647,8 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1993
2647
|
const o = { edges: true, conditionalLines: true, cullStuds: true, cullUndersides: true, side: "front", material: "plastic", ...options };
|
|
1994
2648
|
const color = colorFn(o.colors, pack, new THREE2.Color(o.fallbackColor ?? 10528169));
|
|
1995
2649
|
const useTex = o.textures !== false;
|
|
1996
|
-
const
|
|
1997
|
-
const
|
|
1998
|
-
const key = (i) => i.steps.map((x) => String(x).padStart(6, "0")).join(".");
|
|
1999
|
-
const uniq = [...new Set(all.map(key))].sort();
|
|
2000
|
-
const rank = new Map(uniq.map((k, j) => [k, j]));
|
|
2001
|
-
const stepOf = all.map((i) => rank.get(key(i)));
|
|
2650
|
+
const { all, stepOf, nSteps } = sceneInstances(instances, pack.header, useTex);
|
|
2651
|
+
const uniq = { length: nSteps };
|
|
2002
2652
|
const stepViews = new Array(uniq.length).fill(null);
|
|
2003
2653
|
instances.forEach((i, k) => {
|
|
2004
2654
|
if (i.view)
|
|
@@ -2034,10 +2684,10 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
2034
2684
|
cur = null;
|
|
2035
2685
|
};
|
|
2036
2686
|
const multiStep = uniq.length > 1;
|
|
2037
|
-
const drawnAt = (step) => all.filter((i, k) => (step == null || stepOf[k] <= step) && pack.header.parts[i.part]).length;
|
|
2687
|
+
const drawnAt = (step, mask) => all.filter((i, k) => (step == null || stepOf[k] <= step) && (!mask || mask[k]) && pack.header.parts[i.part]).length;
|
|
2038
2688
|
const build = () => {
|
|
2039
2689
|
const t0 = performance.now();
|
|
2040
|
-
cur = buildLdrScene(all, pack, {
|
|
2690
|
+
cur = buildLdrScene(all, pack, { cullStuds: cs, cullUnder: cu, edges, side, cond, condStuds: o.conditionalStudLines !== false, tex: o.textures !== false, lod: o.lod !== false, lodPx: o.lodPx, lodEdgePx: o.lodEdgePx, lodEdgeMinPx: o.lodEdgeMinPx, lodUnder: o.lodUnder, steps: multiStep ? stepOf : undefined, cull: o.precomputedCull }, color, () => {});
|
|
2041
2691
|
pairs.clear();
|
|
2042
2692
|
if (o.material === "plastic")
|
|
2043
2693
|
cur.root.traverse((x) => {
|
|
@@ -2055,11 +2705,11 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
2055
2705
|
Object.assign(stats, { drawn: drawnAt(null), studsTotal: cur.stats.studsTotal, studsHidden: cur.stats.studsHidden, undersTotal: cur.stats.undersTotal, undersHidden: cur.stats.undersHidden, condBatches: cur.stats.condBatches ?? 0, texBatches: cur.stats.texBatches ?? 0, textures: cur.stats.textures ?? 0, clusters: cur.stats.clusters ?? 0, buildMs: performance.now() - t0 });
|
|
2056
2706
|
api.texturesReady = cur.texturesReady;
|
|
2057
2707
|
};
|
|
2058
|
-
const setStep = (step) => {
|
|
2708
|
+
const setStep = (step, mask = null) => {
|
|
2059
2709
|
if (!multiStep)
|
|
2060
2710
|
return;
|
|
2061
2711
|
const t0 = performance.now();
|
|
2062
|
-
Object.assign(stats, cur.setStep(step), { drawn: drawnAt(step), buildMs: performance.now() - t0 });
|
|
2712
|
+
Object.assign(stats, cur.setStep(step, mask), { drawn: drawnAt(step, mask), buildMs: performance.now() - t0 });
|
|
2063
2713
|
};
|
|
2064
2714
|
const api = { texturesReady: Promise.resolve() };
|
|
2065
2715
|
build();
|
|
@@ -2108,18 +2758,7 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
2108
2758
|
dispose: disposeCur
|
|
2109
2759
|
});
|
|
2110
2760
|
}
|
|
2111
|
-
// ../../../../../../../tmp/ldr-build-
|
|
2112
|
-
import { decompress } from "fzstd";
|
|
2113
|
-
async function decompressPack(data) {
|
|
2114
|
-
const u = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
2115
|
-
const own = (o) => o.buffer.slice(o.byteOffset, o.byteOffset + o.byteLength);
|
|
2116
|
-
if (u[0] === 40 && u[1] === 181 && u[2] === 47 && u[3] === 253)
|
|
2117
|
-
return own(decompress(u));
|
|
2118
|
-
if (u[0] === 31 && u[1] === 139)
|
|
2119
|
-
return new Response(new Blob([u]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();
|
|
2120
|
-
return own(u);
|
|
2121
|
-
}
|
|
2122
|
-
// ../../../../../../../tmp/ldr-build-pIke9r/src/cdn.ts
|
|
2761
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/parts-cdn.ts
|
|
2123
2762
|
import { decompress as decompress2 } from "fzstd";
|
|
2124
2763
|
var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
|
|
2125
2764
|
var indexCache = new Map;
|
|
@@ -2180,7 +2819,22 @@ function mergePacks(packs, extra = {}) {
|
|
|
2180
2819
|
return decodePack(out.buffer);
|
|
2181
2820
|
}
|
|
2182
2821
|
async function loadParts(names, o = {}) {
|
|
2183
|
-
|
|
2822
|
+
names = [...names];
|
|
2823
|
+
try {
|
|
2824
|
+
return await loadPartsOnce(names, o);
|
|
2825
|
+
} catch (e) {
|
|
2826
|
+
const cdn = o.cdn ?? DEFAULT_PARTS_CDN, f = o.fetch ?? fetch;
|
|
2827
|
+
indexCache.delete(cdn);
|
|
2828
|
+
const fresh = (u, i) => f(u, { ...i, cache: "reload" });
|
|
2829
|
+
try {
|
|
2830
|
+
return await loadPartsOnce(names, { ...o, fetch: fresh });
|
|
2831
|
+
} catch {
|
|
2832
|
+
throw e;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
async function loadPartsOnce(names, o) {
|
|
2837
|
+
const cdn = o.cdn ?? DEFAULT_PARTS_CDN, f = o.fetch ?? fetch, gap = o.gap ?? 16384;
|
|
2184
2838
|
const idx = await loadPartsIndex(cdn, f);
|
|
2185
2839
|
const want = [...new Set([...names].map(norm))];
|
|
2186
2840
|
const missing = [];
|
|
@@ -2223,7 +2877,7 @@ async function loadParts(names, o = {}) {
|
|
|
2223
2877
|
}
|
|
2224
2878
|
}
|
|
2225
2879
|
};
|
|
2226
|
-
await Promise.all(Array.from({ length: Math.min(o.concurrency ??
|
|
2880
|
+
await Promise.all(Array.from({ length: Math.min(o.concurrency ?? 24, groups.length) }, worker));
|
|
2227
2881
|
const shards = want.filter((n) => shardCache.has(cdn + n)).map((n) => shardCache.get(cdn + n));
|
|
2228
2882
|
const pack = shards.length ? mergePacks(shards, { colors: idx.colors }) : decodePack(emptyPack(idx.colors));
|
|
2229
2883
|
return { pack, missing, requests: groups.length, bytes };
|
|
@@ -2236,10 +2890,11 @@ function emptyPack(colors) {
|
|
|
2236
2890
|
b.set(h, 4);
|
|
2237
2891
|
return b.buffer;
|
|
2238
2892
|
}
|
|
2239
|
-
async function
|
|
2893
|
+
async function prepareModel(source, o = {}) {
|
|
2240
2894
|
const t0 = performance.now();
|
|
2241
2895
|
const f = o.fetch ?? fetch;
|
|
2242
2896
|
const idxP = loadPartsIndex(o.cdn ?? DEFAULT_PARTS_CDN, f);
|
|
2897
|
+
idxP.catch(() => {});
|
|
2243
2898
|
const text = o.text ? source : await f(source).then((r) => {
|
|
2244
2899
|
if (!r.ok)
|
|
2245
2900
|
throw new Error(`ldr: ${r.status} fetching ${source}`);
|
|
@@ -2247,23 +2902,140 @@ async function loadModel(source, o = {}) {
|
|
|
2247
2902
|
});
|
|
2248
2903
|
const t1 = performance.now();
|
|
2249
2904
|
const name = o.name ?? (o.text ? "main.ldr" : decodeURIComponent(source.split(/[?#]/)[0].split("/").pop() || "main.ldr"));
|
|
2250
|
-
const insts = parseModel(text, name, { looseGeometry: false });
|
|
2905
|
+
const insts = parseModel(text, name, { looseGeometry: false, callouts: o.callouts });
|
|
2251
2906
|
const t2 = performance.now();
|
|
2907
|
+
o.onParsed?.(insts);
|
|
2252
2908
|
await idxP;
|
|
2253
2909
|
const { pack, missing, requests, bytes } = await loadParts(insts.filter((i) => !i.embedded).map((i) => i.part), o);
|
|
2254
2910
|
const t3 = performance.now();
|
|
2255
|
-
const
|
|
2256
|
-
|
|
2911
|
+
const cull = o.cull ? precomputeCull(insts, pack.header, o.textures !== false) : undefined;
|
|
2912
|
+
return { insts, pack, missing, requests, bytes, cull, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, ...cull ? { cull: performance.now() - t3 } : {} } };
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2915
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/load-worker.gen.ts
|
|
2916
|
+
var load_worker_gen_default = 'var mt=ArrayBuffer,_=Uint8Array,ge=Uint16Array,ht=Int16Array;var be=Int32Array,Se=function(e,t,n){if(_.prototype.slice)return _.prototype.slice.call(e,t,n);if(t==null||t<0)t=0;if(n==null||n>e.length)n=e.length;var r=new _(n-t);return r.set(e.subarray(t,n)),r},ce=function(e,t,n,r){if(_.prototype.fill)return _.prototype.fill.call(e,t,n,r);if(n==null||n<0)n=0;if(r==null||r>e.length)r=e.length;for(;n<r;++n)e[n]=t;return e},gt=function(e,t,n,r){if(_.prototype.copyWithin)return _.prototype.copyWithin.call(e,t,n,r);if(n==null||n<0)n=0;if(r==null||r>e.length)r=e.length;while(n<r)e[t++]=e[n++]};var bt=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],K=function(e,t,n){var r=Error(t||bt[e]);if(r.code=e,Error.captureStackTrace)Error.captureStackTrace(r,K);if(!n)throw r;return r},Ne=function(e,t,n){var r=0,o=0;for(;r<n;++r)o|=e[t++]<<(r<<3);return o},yt=function(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0},dt=function(e,t){var n=e[0]|e[1]<<8|e[2]<<16;if(n==3126568&&e[3]==253){var r=e[4],o=r>>5&1,s=r>>2&1,i=r&3,c=r>>6;if(r&8)K(0);var a=6-o,l=i==3?4:i,f=Ne(e,a,l);a+=l;var p=c?1<<c:o,m=Ne(e,a,p)+(c==1&&256),b=m;if(!o){var A=1<<10+(e[5]>>3);b=A+(A>>3)*(e[5]&7)}if(b>2145386496)K(1);var u=new _((t==1?m||b:t?0:b)+12);return u[0]=1,u[4]=4,u[8]=8,{b:a+p,y:0,l:0,d:f,w:t&&t!=1?t:u.subarray(12),e:b,o:new be(u.buffer,0,3),u:m,c:s,m:Math.min(131072,b)}}else if((n>>4|e[3]<<20)==25481893)return yt(e,4)+8;K(0)},re=function(e){var t=0;for(;1<<t<=e;++t);return t-1},ue=function(e,t,n){var r=(t<<3)+4,o=(e[t]&15)+5;if(o>n)K(3);var s=1<<o,i=s,c=-1,a=-1,l=-1,f=s,p=new mt(512+(s<<2)),m=new ht(p,0,256),b=new ge(p,0,256),A=new ge(p,512,s),u=512+(s<<1),h=new _(p,u,s),E=new _(p,u+s);while(c<255&&i>0){var y=re(i+1),g=r>>3,C=(1<<y+1)-1,B=(e[g]|e[g+1]<<8|e[g+2]<<16)>>(r&7)&C,d=(1<<y)-1,M=C-i-1,P=B&d;if(P<M)r+=y,B=P;else if(r+=y+1,B>d)B-=M;if(m[++c]=--B,B==-1)i+=B,h[--f]=c;else i-=B;if(!B)do{var F=r>>3;a=(e[F]|e[F+1]<<8)>>(r&7)&3,r+=2,c+=a}while(a==3)}if(c>255||i)K(0);var S=0,U=(s>>1)+(s>>3)+3,W=s-1;for(var H=0;H<=c;++H){var v=m[H];if(v<1){b[H]=-v;continue}for(l=0;l<v;++l){h[S]=H;do S=S+U&W;while(S>=f)}}if(S)K(0);for(l=0;l<s;++l){var w=b[h[l]]++,L=E[l]=o-re(w);A[l]=(w<<L)-s}return[r+7>>3,{b:o,s:h,n:E,t:A}]},xt=function(e,t){var n=0,r=-1,o=new _(292),s=e[t],i=o.subarray(0,256),c=o.subarray(256,268),a=new ge(o.buffer,268);if(s<128){var l=ue(e,t+1,6),f=l[0],p=l[1];t+=s;var m=f<<3,b=e[t];if(!b)K(0);var A=0,u=0,h=p.b,E=h,y=(++t<<3)-8+re(b);for(;;){if(y-=h,y<m)break;var g=y>>3;if(A+=(e[g]|e[g+1]<<8)>>(y&7)&(1<<h)-1,i[++r]=p.s[A],y-=E,y<m)break;g=y>>3,u+=(e[g]|e[g+1]<<8)>>(y&7)&(1<<E)-1,i[++r]=p.s[u],h=p.n[A],A=p.t[A],E=p.n[u],u=p.t[u]}if(++r>255)K(0)}else{r=s-127;for(;n<r;n+=2){var C=e[++t];i[n]=C>>4,i[n+1]=C&15}++t}var B=0;for(n=0;n<r;++n){var d=i[n];if(d>11)K(0);B+=d&&1<<d-1}var M=re(B)+1,P=1<<M,F=P-B;if(F&F-1)K(0);i[r++]=re(F)+1;for(n=0;n<r;++n){var d=i[n];++c[i[n]=d&&M+1-d]}var S=new _(P<<1),U=S.subarray(0,P),W=S.subarray(P);a[M]=0;for(n=M;n>0;--n){var H=a[n];ce(W,n,H,a[n-1]=H+c[n]*(1<<M-n))}if(a[0]!=P)K(0);for(n=0;n<r;++n){var v=i[n];if(v){var w=a[v];ce(U,n,w,a[v]=w+(1<<M-v))}}return[t,{n:W,b:M,s:U}]},wt=ue(new _([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],vt=ue(new _([33,20,196,24,99,140,33,132,16,66,8,33,132,16,66,8,33,68,68,68,68,68,68,68,68,36,9]),0,6)[1],At=ue(new _([32,132,16,66,102,70,68,68,68,68,36,73,2]),0,5)[1],$e=function(e,t){var n=e.length,r=new be(n);for(var o=0;o<n;++o)r[o]=t,t+=1<<e[o];return r},Ce=new _(new be([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),Mt=$e(Ce,0),Pe=new _(new be([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),St=$e(Pe,3),le=function(e,t,n){var r=e.length,o=t.length,s=e[r-1],i=(1<<n.b)-1,c=-n.b;if(!s)K(0);var a=0,l=n.b,f=(r<<3)-8+re(s)-l,p=-1;for(;f>c&&p<o;){var m=f>>3,b=(e[m]|e[m+1]<<8|e[m+2]<<16)>>(f&7);a=(a<<l|b)&i,t[++p]=n.s[a],f-=l=n.n[a]}if(f!=c||p+1!=o)K(0)},Ct=function(e,t,n){var r=6,o=t.length,s=o+3>>2,i=s<<1,c=s+i;le(e.subarray(r,r+=e[0]|e[1]<<8),t.subarray(0,s),n),le(e.subarray(r,r+=e[2]|e[3]<<8),t.subarray(s,i),n),le(e.subarray(r,r+=e[4]|e[5]<<8),t.subarray(i,c),n),le(e.subarray(r),t.subarray(c),n)},Pt=function(e,t,n){var r,o=t.b,s=e[o],i=s>>1&3;t.l=s&1;var c=s>>3|e[o+1]<<5|e[o+2]<<13,a=(o+=3)+c;if(i==1){if(o>=e.length)return;if(t.b=o+1,n)return ce(n,e[o],t.y,t.y+=c),n;return ce(new _(c),e[o])}if(a>e.length)return;if(i==0){if(t.b=a,n)return n.set(e.subarray(o,a),t.y),t.y+=c,n;return Se(e,o,a)}if(i==2){var l=e[o],f=l&3,p=l>>2&3,m=l>>4,b=0,A=0;if(f<2)if(p&1)m|=e[++o]<<4|(p&2&&e[++o]<<12);else m=l>>3;else if(A=p,p<2)m|=(e[++o]&63)<<4,b=e[o]>>6|e[++o]<<2;else if(p==2)m|=e[++o]<<4|(e[++o]&3)<<12,b=e[o]>>2|e[++o]<<6;else m|=e[++o]<<4|(e[++o]&63)<<12,b=e[o]>>6|e[++o]<<2|e[++o]<<10;++o;var u=n?n.subarray(t.y,t.y+t.m):new _(t.m),h=u.length-m;if(f==0)u.set(e.subarray(o,o+=m),h);else if(f==1)ce(u,e[o++],h);else{var E=t.h;if(f==2){var y=xt(e,o);b+=o-(o=y[0]),t.h=E=y[1]}else if(!E)K(0);(A?Ct:le)(e.subarray(o,o+=b),u.subarray(h),E)}var g=e[o++];if(g){if(g==255)g=(e[o++]|e[o++]<<8)+32512;else if(g>127)g=g-128<<8|e[o++];var C=e[o++];if(C&3)K(0);var B=[vt,At,wt];for(var d=2;d>-1;--d){var M=C>>(d<<1)+2&3;if(M==1){var P=new _([0,0,e[o++]]);B[d]={s:P.subarray(2,3),n:P.subarray(0,1),t:new ge(P.buffer,0,1),b:0}}else if(M==2)r=ue(e,o,9-(d&1)),o=r[0],B[d]=r[1];else if(M==3){if(!t.t)K(0);B[d]=t.t[d]}}var F=t.t=B,S=F[0],U=F[1],W=F[2],H=e[a-1];if(!H)K(0);var v=(a<<3)-8+re(H)-W.b,w=v>>3,L=0,V=(e[w]|e[w+1]<<8)>>(v&7)&(1<<W.b)-1;w=(v-=U.b)>>3;var I=(e[w]|e[w+1]<<8)>>(v&7)&(1<<U.b)-1;w=(v-=S.b)>>3;var N=(e[w]|e[w+1]<<8)>>(v&7)&(1<<S.b)-1;for(++g;--g;){var T=W.s[V],x=W.n[V],z=S.s[N],R=S.n[N],D=U.s[I],O=U.n[I];w=(v-=D)>>3;var j=1<<D,k=j+((e[w]|e[w+1]<<8|e[w+2]<<16|e[w+3]<<24)>>>(v&7)&j-1);w=(v-=Pe[z])>>3;var G=St[z]+((e[w]|e[w+1]<<8|e[w+2]<<16)>>(v&7)&(1<<Pe[z])-1);w=(v-=Ce[T])>>3;var X=Mt[T]+((e[w]|e[w+1]<<8|e[w+2]<<16)>>(v&7)&(1<<Ce[T])-1);if(w=(v-=x)>>3,V=W.t[V]+((e[w]|e[w+1]<<8)>>(v&7)&(1<<x)-1),w=(v-=R)>>3,N=S.t[N]+((e[w]|e[w+1]<<8)>>(v&7)&(1<<R)-1),w=(v-=O)>>3,I=U.t[I]+((e[w]|e[w+1]<<8)>>(v&7)&(1<<O)-1),k>3)t.o[2]=t.o[1],t.o[1]=t.o[0],t.o[0]=k-=3;else{var Y=k-(X!=0);if(Y){if(k=Y==3?t.o[0]-1:t.o[Y],Y>1)t.o[2]=t.o[1];t.o[1]=t.o[0],t.o[0]=k}else k=t.o[0]}for(var d=0;d<X;++d)u[L+d]=u[h+d];L+=X,h+=X;var Z=L-k;if(Z<0){var J=-Z,ee=t.e+Z;if(J>G)J=G;for(var d=0;d<J;++d)u[L+d]=t.w[ee+d];L+=J,G-=J,Z=0}for(var d=0;d<G;++d)u[L+d]=u[Z+d];L+=G}if(L!=h)while(h<u.length)u[L++]=u[h++];else L=u.length;if(n)t.y+=L;else u=Se(u,0,L)}else if(n){if(t.y+=m,h)for(var d=0;d<m;++d)u[d]=u[h+d]}else if(h)u=Se(u,h);return t.b=a,u}K(2)},Et=function(e,t){if(e.length==1)return e[0];var n=new _(t);for(var r=0,o=0;r<e.length;++r){var s=e[r];n.set(s,o),o+=s.length}return n};function je(e,t){var n=[],r=+!t,o=0,s=0;for(;e.length;){var i=dt(e,r||t);if(typeof i=="object"){if(r){if(t=null,i.w.length==i.u)n.push(t=i.w),s+=i.u}else n.push(t),i.e=0;for(;!i.l;){var c=Pt(e,i,t);if(!c)K(5);if(t)i.e=i.y;else n.push(c),s+=c.length,gt(i.w,0,c.length),i.w.set(c,i.w.length-c.length)}o=i.b+i.c*4}else o=i;e=e.subarray(o)}return Et(n,s)}function ye(e){let t=new DataView(e).getUint32(0,!0),n=JSON.parse(new TextDecoder().decode(new Uint8Array(e,4,t))),r=4+t;return{header:n,arr:(s)=>s&&(s[2]==="f32"?new Float32Array(e,r+s[0],s[1]):s[2]==="u16"?new Uint16Array(e,r+s[0],s[1]):s[2]==="u8"?new Uint8Array(e,r+s[0],s[1]):new Uint32Array(e,r+s[0],s[1])),bytes:e.byteLength,buffer:e}}var q=(e)=>e.trim().toLowerCase().replace(/\\\\/g,"/").replace(/\\/+/g,"/");function Ee(e){if(/^0x/i.test(e))return parseInt(e,16);return+e}var Ve=/^~?\\s*moved\\s+to\\s+(.+)$/i,Tt=new Set(["FILE","NOFILE","!DATA","!:","STEP","BFC","ROTSTEP","BUFEXCHG","!TEXMAP"]),Je=new Set(["part","subpart","primitive","8_primitive","48_primitive","shortcut","helper"]),Lt=new Set(["model","submodel","configuration"]),It=/^(?:!?LDRAW_ORG|Unofficial|Official\\s+LCAD)\\s+(\\S+)/i;function He(e){let t=It.exec(e);if(!t)return;let n=t[1].toLowerCase().replace(/^unofficial_/,"");return Je.has(n)||Lt.has(n)?n:void 0}function kt(e){let t=[],n=0;while(n<e.length){while(e[n]===" "||e[n]==="\\t")n++;if(n>=e.length)break;if(e[n]===\'"\'){let r="";n++;while(n<e.length&&e[n]!==\'"\'){if(e[n]==="\\\\"&&n+1<e.length)n++;r+=e[n++]}n++,t.push(r)}else{let r=n;while(r<e.length&&e[r]!==" "&&e[r]!=="\\t")r++;t.push(e.slice(n,r)),n=r}}return t}function Rt(e,t=!1){let n=/^\\s*(\\S+)\\s+(.*)$/.exec(e);if(!n)return null;let r=n[1].toUpperCase(),o=r==="PLANAR"?9:r==="CYLINDRICAL"?10:r==="SPHERICAL"?11:0;if(!o)return null;let s=n[2].trim().split(/\\s+/);if(s.length<o+1)return null;let i=s.slice(0,o).map(Number);if(!i.every(Number.isFinite))return null;let c=n[2].trim();for(let p=0;p<o;p++)c=c.replace(/^\\S+\\s*/,"");let a=kt(c);if(!a.length)return null;let l={method:r,p1:i.slice(0,3),p2:i.slice(3,6),p3:i.slice(6,9),texture:a[0]};if(o>=10)l.a=i[9];if(o===11)l.b=i[10];let f=a.findIndex((p,m)=>m>0&&p.toUpperCase()==="GLOSSMAP");if(f>0&&a[f+1])l.glossmap=a[f+1];if(t)l.next=!0;return l}var Dt=(e)=>{let t=e.replace(/[^A-Za-z0-9+/]/g,""),n=t+"=".repeat((4-t.length%4)%4),r=atob(n),o=new Uint8Array(r.length);for(let s=0;s<r.length;s++)o[s]=r.charCodeAt(s);return o};function Ft(e){let t=e.length,n=1,r=(l)=>l===32||l===9,o=()=>{while(n<t&&r(e.charCodeAt(n)))n++;let l=n;while(n<t&&!r(e.charCodeAt(n)))n++;return l<n?e.slice(l,n):null},s=o();if(s===null)return null;let i=Array(12);for(let l=0;l<12;l++){let f=o();if(f===null)return null;i[l]=+f}while(n<t&&r(e.charCodeAt(n)))n++;if(n>=t)return null;let c=e.slice(n),a=/[ \\t]{2,}|\\t/.test(c)?c.split(/\\s+/).join(" "):c;return{t:1,color:Ee(s),m:i,file:q(a)}}function Ge(e){let t=+e[0];if(!(t>=1&&t<=5)||e.length<2)return null;let n=Ee(e[1]),r=e.slice(2).map(Number);if(t===1)return{t:1,color:n,m:r.slice(0,12),file:q(e.slice(14).join(" "))};if(t===2)return{t:2,color:n,p:r.slice(0,6)};if(t===3)return{t:3,color:n,p:r.slice(0,9)};if(t===4)return{t:4,color:n,p:r.slice(0,12)};return{t:5,color:n,p:r.slice(0,12)}}function Ze(e,t="main.ldr",n={}){let r=!!n.geometryText,o=new Map,s=null,i="",c,a=null,l=[],f=null,p=()=>{if(!a)return;let y=Dt(a.chunks.join("")),g=y[0]===137&&y[1]===80&&y[2]===78&&y[3]===71;(c??=new Map).set(q(a.name),{name:a.name,bytes:y,...g?{mime:"image/png"}:{}}),a=null},m=!0,b=(y)=>{if(p(),s={name:q(y),cmds:[]},o.set(s.name,s),!i)i=s.name;l=[],f=null,m=!0},A=!1,u=!1,h=()=>{if(u)return;u=!0,o.clear(),s=null,i=""},E=(y,g)=>{if(f){y.tex=f,f=null;return}let C=l[l.length-1];if(!C)return;if(C.fallback){if(!g)y.fallback=!0}else y.tex=C.map};for(let y of e.split(`\n`)){let g=y.trim();if(!g)continue;if(r&&g.charCodeAt(0)>=50&&g.charCodeAt(0)<=53&&(g.charCodeAt(1)===32||g.charCodeAt(1)===9)){if(a||A)continue;if(!s)b(t);let M=g.slice(2).trimStart(),P=M.search(/\\s/),F={t:g.charCodeAt(0)-48,color:Ee(P<0?M:M.slice(0,P)),p:[],src:g};E(F,!1),s.cmds.push(F),m=!1;continue}if(g.charCodeAt(0)===48&&(g.charCodeAt(1)===32||g.charCodeAt(1)===9)){let M=2;while(g.charCodeAt(M)===32||g.charCodeAt(M)===9)M++;let P=M;while(P<g.length&&g.charCodeAt(P)!==32&&g.charCodeAt(P)!==9)P++;let F=g.slice(M,P);if(!Tt.has(F)){if(A||a)continue;if(!s)b(t);let S=g.slice(M),U={t:0,text:S};if(F.charCodeAt(0)===33)U.meta=F;if(f=null,m&&!s.org){let H=He(S);if(H)s.org=H}let W=S.match(Ve);if(W&&!s.movedTo){let H=W[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(H))H+=".dat";s.movedTo=q(H)}s.cmds.push(U);continue}}if(g.charCodeAt(0)===49&&(g.charCodeAt(1)===32||g.charCodeAt(1)===9)&&!a&&!A){let M=Ft(g);if(M){if(!s)b(t);E(M,!1),s.cmds.push(M),m=!1;continue}}let C=g.split(/\\s+/);if(+C[0]===0){let M=g.slice(1).trim();if(C[1]==="FILE"){h(),A=!1,b(M.slice(5));continue}if(C[1]==="NOFILE"){p(),s=null,A=!0;continue}if(C[1]==="!DATA"){h(),p(),s=null,A=!1,a={name:M.slice(5).trim(),chunks:[]};continue}if(A)continue;if(a){if(C[1]==="!:")a.chunks.push(C.slice(2).join(""));continue}if(!s)b(t);let P={t:0,text:M};if(C[1]==="STEP")P.step=!0,l=[],f=null;else if(C[1]==="BFC")P.bfc=C.slice(2).join(" ");else if(C[1]==="ROTSTEP")if(P.meta="ROTSTEP",P.step=!0,l=[],f=null,(C[2]??"").toUpperCase()==="END")P.rotstep={x:0,y:0,z:0,mode:"END"};else{let S=(C[5]??"REL").toUpperCase();P.rotstep={x:+C[2]||0,y:+C[3]||0,z:+C[4]||0,mode:["REL","ABS","ADD"].includes(S)?S:"REL"}}else if(C[1]==="BUFEXCHG"){P.meta="BUFEXCHG";let S=(C[2]??"").toUpperCase();P.bufexchg={op:S==="RETRIEVE"?"RETRIEVE":"STORE",buf:C[3]??"A"}}else if(C[1]?.startsWith("!"))P.meta=C[1];if(m&&!s.org){let S=He(M);if(S)s.org=S}if(C[1]==="!TEXMAP"){let S=(C[2]??"").toUpperCase();if(f=null,S==="START"||S==="NEXT"){let U=Rt(M.replace(/^!TEXMAP\\s+\\S+/i,""),S==="NEXT");if(P.texmap={op:S,...U?{map:U}:{}},U)if((s.texmaps??=[]).push(U),S==="START")l.push({map:U,fallback:!1});else f=U}else if(S==="FALLBACK"){P.texmap={op:S};let U=l[l.length-1];if(U)U.fallback=!0}else if(S==="END")P.texmap={op:S},l.pop()}else if(C[1]==="!:"){f=null;let S=Ge(C.slice(2));if(S)E(S,!0),P.geom=S}else f=null;let F=M.match(Ve);if(F&&!s.movedTo){let S=F[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(S))S+=".dat";s.movedTo=q(S)}s.cmds.push(P);continue}if(a||A)continue;if(!s)b(t);let d=Ge(C);if(!d)continue;E(d,!1),s.cmds.push(d),m=!1}return p(),c?{main:i,files:o,data:c}:{main:i,files:o}}var Zt=Math.PI/180;function qe(e,t){let n=(r)=>[t[3]*r[0]+t[4]*r[1]+t[5]*r[2]+t[0],t[6]*r[0]+t[7]*r[1]+t[8]*r[2]+t[1],t[9]*r[0]+t[10]*r[1]+t[11]*r[2]+t[2]];return{...e,p1:n(e.p1),p2:n(e.p2),p3:n(e.p3)}}function Qe(e,t){let[n,r,o,s,i,c,a,l,f,p,m,b]=e,[A,u,h,E,y,g,C,B,d,M,P,F]=t;return[s*A+i*u+c*h+n,a*A+l*u+f*h+r,p*A+m*u+b*h+o,s*E+i*C+c*M,s*y+i*B+c*P,s*g+i*d+c*F,a*E+l*C+f*M,a*y+l*B+f*P,a*g+l*d+f*F,p*E+m*C+b*M,p*y+m*B+b*P,p*g+m*d+b*F]}var Te=[0,0,0,1,0,0,0,1,0,0,0,1];var Xe=new WeakMap,Ut=/^(s|8|48)\\//;function Le(e,t){let n=e.files.get(q(t));if(!n)return"part";let r=Xe.get(n);if(r)return r;if(n.org)r=Je.has(n.org)?"part":"model";else if(n.name===e.main)r="model";else r=n.cmds.some((o)=>o.t>=2||o.t===0&&!!o.geom||o.t===1&&Ut.test(o.file))?"part":"model";return Xe.set(n,r),r}var _e=new WeakMap;function et(e){let t=_e.get(e);if(t)return t;t=[];let n=0;for(let r of e.cmds){if(r.t===0&&r.step){n++;continue}if((r.t>=2||r.t===0&&r.geom&&r.geom.t>=2)&&t[t.length-1]!==n)t.push(n)}return _e.set(e,t),t}var Ke=(e)=>e>16777215?"0x"+e.toString(16).toUpperCase():String(e),Ot=(e)=>e.t===0?"0 "+e.text:e.t===1?`1 ${Ke(e.color)} ${e.m.join(" ")} ${e.file}`:e.src?e.src:`${e.t} ${Ke(e.color)} ${e.p.join(" ")}`,Ie=(e,t)=>`${q(e)}#${t}`;function zt(e,t){let n=[],r=0,o=(s)=>!!s&&s.t===0&&s.texmap?.op==="NEXT";for(let s of e.cmds){if(s.t===0){if(s.step){r++;continue}if(s.bfc!==void 0){n.push(s);continue}if(r!==t)continue;if(s.texmap)n.push(s);else if(s.geom){if(s.geom.t>=2)n.push(s);else if(o(n[n.length-1]))n.pop()}continue}if(r!==t)continue;if(s.t===1){if(o(n[n.length-1]))n.pop();continue}n.push(s)}return{name:Ie(e.name,t),cmds:n}}function tt(e,t){return[`0 ldr: own geometry of ${e.name}, step ${t}`,...zt(e,t).cmds.map(Ot)].join(`\n`)+`\n`}function Bt(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function nt(e){let[t,n,r,o,s,i,c,a,l,f,p,m]=e,b=a*m-l*p,A=-(c*m-l*f),u=c*p-a*f,h=o*b+s*A+i*u;if(!Number.isFinite(h)||Math.abs(h)<0.000000000001)return null;let E=1/h,y=[b*E,-(s*m-i*p)*E,(s*l-i*a)*E,A*E,(o*m-i*f)*E,-(o*l-i*c)*E,u*E,-(o*p-s*f)*E,(o*a-s*c)*E];return[-(y[0]*t+y[1]*n+y[2]*r),-(y[3]*t+y[4]*n+y[5]*r),-(y[6]*t+y[7]*n+y[8]*r),...y]}var Nt=(e)=>String(+e.toFixed(6)||0),We=(e)=>\'"\'+e.replace(/\\\\/g,"\\\\\\\\").replace(/"/g,"\\\\\\"")+\'"\';function rt(e,t){let n=[...t.p1,...t.p2,...t.p3,...t.method!=="PLANAR"?[t.a??360]:[],...t.method==="SPHERICAL"?[t.b??180]:[]].map(Nt).join(" "),r=`0 ldr: ${e} with a model-level !TEXMAP\n0 BFC CERTIFY CCW\n0 !TEXMAP START ${t.method} ${n} ${We(t.texture)}${t.glossmap?" GLOSSMAP "+We(t.glossmap):""}\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 ${q(e)}\n0 !TEXMAP END\n`;return{name:`${q(e)}#tex-${Bt(r)}`,source:r}}var $t=(e,t)=>{let n=[,,,,,,,,,];for(let r=0;r<3;r++)for(let o=0;o<3;o++)n[r*3+o]=e[r*3]*t[o]+e[r*3+1]*t[3+o]+e[r*3+2]*t[6+o];return n};function jt(e,t,n){let r=Math.PI/180,o=Math.sin(e*r),s=Math.cos(e*r),i=Math.sin(t*r),c=Math.cos(t*r),a=Math.sin(n*r),l=Math.cos(n*r);return[c*l,-c*a,i,s*a+o*i*l,s*l-o*i*a,-o*c,o*a-s*i*l,o*l+s*i*a,s*c]}var Ye=new WeakMap;function ot(e){let t=Ye.get(e);if(t)return t;let n=[],r=null;for(let o of e.cmds){if(o.t!==0||!o.step)continue;let s=o.rotstep;if(s)if(s.mode==="END")r=null;else{let i=jt(s.x,s.y,s.z);r=s.mode==="ABS"?{abs:!0,m:i,rotstep:s}:s.mode==="ADD"&&r?{abs:r.abs,m:$t(r.m,i),rotstep:s}:{abs:!1,m:i,rotstep:s}}n.push(r)}return n.push(r),Ye.set(e,n),n}var st=999999,it=(e)=>e.map((t)=>String(t).padStart(6,"0")).join(".")+"~";function Vt(e,t={}){let n=[],r=t.maxDepth??64,o=t.looseGeometry!==!1,s=!!t.textures,i=!!t.callouts,c=new Map,a=0,l=(p,m)=>{let b=p.name+"#"+m,A=c.get(b);if(!A){let u;A=Object.assign(()=>u??=tt(p,m),{file:p,step:m}),c.set(b,A)}return A},f=(p,m,b,A,u,h,E,y,g=null,C=[],B=[])=>{let d=p.files.get(m);if(!d||E>r)return;let M=0,P=E>0?++a:0,F=i&&P?[...C,P]:C,S=i&&P?[...B,b]:B,U=i&&!g?new Map:null,W=-1,H=0,v=(T,x,z,R,D,O)=>{if(W!==M)W=M,H=0;let j=U?.get(M+"|"+x);if(j)return j.n++,f(T,T===p?x:T.main,z,R,u+"/"+x,[...D,st],E+1,O,[...D,st],F,S);let k=[...D,H++],G=n.length;f(T,T===p?x:T.main,z,R,u+"/"+x,k,E+1,O,g,F,S),U?.set(M+"|"+x,{n:1,from:G,to:n.length})},w=ot(d),L=o?et(d):[],V=0,I=(T,x,z,R,D,O,j)=>{if(g)R=g;let k={part:T,color:x,m:z,step:R[0],steps:R,localStep:D,path:u};if(P){if(k.sub=P,i)k.subPath=F,k.subMats=S}if(O)k.embedded=!0;if(j){let X=rt(T,j);k.texPart=X.name,k.texSource=X.source}let G=w[D];if(G)k.view=G;return n.push(k),k},N=(T)=>{while(V<L.length&&L[V]<=T){let x=L[V++];I(Ie(d.name,x),A,b,[...h,x],x,!1,null).source=l(d,x)}};for(let T of d.cmds){if(T.t===0&&T.step){M++;continue}let x=T;if(x.t>=2||x.t===0&&x.geom&&x.geom.t>=2){N(M);continue}if(x.t===0)if(s&&x.geom?.t===1)x=x.geom;else continue;if(x.t!==1)continue;if(s&&x.fallback)continue;let z=x.color===16?A:x.color,R=Qe(b,x.m),D=[...h,M],O=s?x.tex??y:null,j=O?nt(x.m):null,k=O&&j?qe(O,j):null;if(p.files.has(x.file)){if(Le(p,x.file)==="model"){v(p,x.file,R,z,D,k);continue}I(x.file,z,R,D,M,!0,k);continue}let G=t.resolveModel?.(x.file);if(G){v(G,x.file,R,z,D,k);continue}I(x.file,z,R,D,M,!1,k)}if(N(1/0),U){for(let T of U.values())if(T.n>1)for(let x=T.from;x<T.to;x++)n[x].mult??=T.n}};if(Le(e,e.main)==="part"){if(e.files.get(e.main))n.push({part:e.main,color:16,m:[...Te],step:0,steps:[0],localStep:0,path:e.main,embedded:!0});return n}return f(e,e.main,Te,16,e.main,[],0,null),n}function at(e,t="main.ldr",n){return Vt(Ze(e,t,{geometryText:!0}),n)}var lt=(e,t=0)=>Math.abs(e[t+7]-1)<0.001&&Math.abs(e[t+4])<0.001&&Math.abs(e[t+10])<0.001,ct=new WeakMap;function ke(e,t){let n=ct.get(e);if(!n)ct.set(e,n=new Map);let r=n.get(t);if(r!==void 0)return r;let o=e.parts[t];if(!o)return n.set(t,null),null;let s=o.studs.length,i=new Float64Array(s*12),c=[],a=[];o.studs.forEach((m,b)=>{c.push(m[0]),a.push(m[1]);for(let A=0;A<12;A++)i[b*12+A]=m[2+A]});let l=null,f=0,p=0;if(o.mask){f=o.mask[0],p=o.mask[1];let m=o.mask[2];l=new Uint8Array(m.length);for(let b=0;b<m.length;b++)l[b]=m.charCodeAt(b)===49?1:0}return n.set(t,r={nStuds:s,studM:i,kind:c,color:a,mask:l,nx:f,nz:p}),r}var ie=1073741824;class Re{a;b;c;vals;used;mask;size=0;constructor(e=1024){let t=1024;while(t<e*2)t*=2;this.a=new Int32Array(t),this.b=new Int32Array(t),this.c=new Int32Array(t),this.vals=new Int32Array(t),this.used=new Uint8Array(t),this.mask=t-1}slot(e,t,n){let r=Math.imul(e,2654435761)^Math.imul(t,2246822507)^Math.imul(n,3266489909);return r^=r>>>15,r=Math.imul(r,739982445),r^=r>>>12,r&this.mask}get(e,t,n){let r=this.slot(e,t,n),o=this.used,s=this.a,i=this.b,c=this.c;for(;;){if(!o[r])return-1;if(s[r]===e&&i[r]===t&&c[r]===n)return this.vals[r];r=r+1&this.mask}}put(e,t,n,r){if((this.size+1)*2>this.used.length)this.grow();let o=this.slot(e,t,n),s=this.used,i=this.a,c=this.b,a=this.c;for(;;){if(!s[o])return s[o]=1,i[o]=e,c[o]=t,a[o]=n,this.vals[o]=r,this.size++,-1;if(i[o]===e&&c[o]===t&&a[o]===n){let l=this.vals[o];return this.vals[o]=r,l}o=o+1&this.mask}}grow(){let{a:e,b:t,c:n,vals:r,used:o}=this,s=o.length*2;this.a=new Int32Array(s),this.b=new Int32Array(s),this.c=new Int32Array(s),this.vals=new Int32Array(s),this.used=new Uint8Array(s),this.mask=s-1,this.size=0;for(let i=0;i<o.length;i++)if(o[i])this.put(e[i],t[i],n[i],r[i])}}var de=(e,t,n)=>e>-ie&&e<ie&&t>-ie&&t<ie&&n>-ie&&n<ie,fe=2147483647;function Ht(e,t,n){let o=[],s=[],i=[],c=[],a=[],l=[],f=[],p=[],m=new Re(e.length*2),b=[],A=[];for(let v=0;v<e.length;v++){let w=e[v],L=w.m,V=t.parts[w.part];if(!V||!V.mask||!lt(L))continue;let I=V.bbox,N=1/0,T=-1/0,x=1/0,z=-1/0;for(let O=0;O<2;O++)for(let j=0;j<2;j++){let k=O?I[3]:I[0],G=j?I[5]:I[2],X=L[0]+L[3]*k+L[5]*G,Y=L[2]+L[9]*k+L[11]*G;if(X<N)N=X;if(X>T)T=X;if(Y<x)x=Y;if(Y>z)z=Y}let R=a.length;o.push(N),s.push(T),i.push(x),c.push(z),a.push(v),l.push(ke(t,w.part)),f.push(I[0]),p.push(I[2]);let D=Math.round((L[1]+I[4])*2);for(let O=Math.floor(N/40);O<=Math.floor(T/40);O++)for(let j=Math.floor(x/40);j<=Math.floor(z/40);j++){if(!de(D,O,j))continue;let k=A.length;A.push(R),b.push(m.put(D,O,j,k))}}let u=[0,5,-5,5,-5],h=[0,5,5,-5,-5],E=NaN,y=NaN,g=NaN,C=-1,B=(v,w,L,V)=>{let I=Math.round(w*2),N=Math.floor(v/40),T=Math.floor(L/40);if(!de(I,N,T))return fe;let x=fe;if(I!==E||N!==y||T!==g)E=I,y=N,g=T,C=m.get(I,N,T);for(let z=C;z>=0;z=b[z]){let R=A[z];if(a[R]===V||!(v-6>=o[R]-0.5&&v+6<=s[R]+0.5&&L-6>=i[R]-0.5&&L+6<=c[R]+0.5))continue;let D=e[a[R]].m,O=l[R],j=f[R],k=p[R],G=v-D[0],X=w-D[1],Y=L-D[2],Z=D[3]*G+D[6]*X+D[9]*Y,J=D[5]*G+D[8]*X+D[11]*Y,{nx:ee,nz:oe,mask:ae}=O,se=!0;for(let Q=0;Q<5;Q++){let te=Math.floor((Z+u[Q]-j)/20),ne=Math.floor((J+h[Q]-k)/20);if(te<0||ne<0||te>=ee||ne>=oe||ae[te*oe+ne]!==1){se=!1;break}}if(se){if(!n)return 0;let Q=n[a[R]];if(Q<x)x=Q}}return x},d=0;for(let v of e){let w=ke(t,v.part);if(w)d+=w.nStuds}let M=new Uint8Array(d),P=new Uint8Array(d),F=new Re(d),S=0,U=n?new Int32Array(d).fill(fe):void 0;for(let v=0,w=0;v<e.length;v++){let L=e[v],V=ke(t,L.part);if(!V)continue;let I=L.m,N=V.studM,T=I[0],x=I[1],z=I[2],R=I[3],D=I[4],O=I[5],j=I[6],k=I[7],G=I[8],X=I[9],Y=I[10],Z=I[11];for(let J=0;J<V.nStuds;J++,w++){let ee=J*12,oe=N[ee+4],ae=N[ee+7],se=N[ee+10];if(!(Math.abs(j*oe+k*ae+G*se-1)<0.001&&Math.abs(R*oe+D*ae+O*se)<0.001&&Math.abs(X*oe+Y*ae+Z*se)<0.001))continue;P[w]=1;let Q=N[ee],te=N[ee+1],ne=N[ee+2],De=T+R*Q+D*te+O*ne,Fe=x+j*Q+k*te+G*ne,Ue=z+X*Q+Y*te+Z*ne,Oe=B(De,Fe,Ue,v);if(Oe!==fe){if(M[w]=1,S++,U)U[w]=Oe}let pe=Math.round(De),me=Math.round(Fe),he=Math.round(Ue);if(!de(pe,me,he))continue;if(!n){F.put(pe,me,he,1);continue}let ze=n[v],Be=F.get(pe,me,he);if(Be<0||ze<Be)F.put(pe,me,he,ze)}}let W=new Uint8Array(e.length),H=n?new Int32Array(e.length).fill(fe):void 0;for(let v=0;v<e.length;v++){let w=e[v],L=t.parts[w.part];if(!L||!L.under||!lt(w.m))continue;let V=L.bbox,I=Math.round((V[3]-V[0])/20),N=Math.round((V[5]-V[2])/20);if(!I||!N||I*N>4096)continue;let T=w.m,x=!0,z=0;for(let R=0;R<I&&x;R++)for(let D=0;D<N;D++){let O=V[0]+10+20*R,j=V[2]+10+20*D,k=T[0]+T[3]*O+T[5]*j,G=T[2]+T[9]*O+T[11]*j,X=Math.round(k),Y=Math.round(T[1]+V[4]),Z=Math.round(G),J=de(X,Y,Z)?F.get(X,Y,Z):-1;if(J<0){x=!1;break}if(J>z)z=J}if(x){if(W[v]=1,H)H[v]=z}}return{nStuds:d,studHidden:M,studUp:P,underHidden:W,studsHidden:S,studHideStep:U,underHideStep:H}}function Gt(e,t,n){let r=(a)=>n&&a.texPart&&t.parts[a.texPart]?a.texPart:a.part,o=e.map((a)=>({part:r(a),color:String(a.color),m:a.m,steps:a.steps})),s=o.map((a)=>it(a.steps)),i=[...new Set(s)].sort(),c=new Map(i.map((a,l)=>[a,l]));return{all:o,stepOf:s.map((a)=>c.get(a)),nSteps:i.length}}function xe(e,t,n=!0){let r=Gt(e,t,n);return Ht(r.all,t,r.nSteps>1?r.stepOf:void 0)}var Me="https://ldr-demo.vercel.app/cdn/v1/",ve=new Map,we=new Map;function ft(e=Me,t=fetch){let n=ve.get(e);if(!n)n=t(e+"parts.json").then((r)=>{if(!r.ok)throw Error(`ldr: parts CDN index ${r.status} (${e}parts.json)`);return r.json()}),n.catch(()=>ve.delete(e)),ve.set(e,n);return n}var Xt=(e)=>Array.isArray(e)&&e.length===3&&typeof e[0]==="number"&&typeof e[1]==="number"&&(e[2]==="f32"||e[2]==="u16"||e[2]==="u8"||e[2]==="u32"),Ae=(e,t)=>Xt(e)?[e[0]+t,e[1],e[2]]:Array.isArray(e)?e.map((n)=>Ae(n,t)):e&&typeof e==="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,Ae(r,t)])):e;function _t(e,t={}){let n=[],r=0,o={},s={};for(let m of e){let b=m.buffer;if(!b)throw Error("ldr: mergePacks needs packs from decodePack/loadPack");let A=new DataView(b).getUint32(0,!0),u=new Uint8Array(b,4+A),h=r;n.push(u),r+=u.byteLength;let E=(4-r%4)%4;if(E)n.push(new Uint8Array(E)),r+=E;for(let[y,g]of Object.entries(m.header.parts??{}))if(!(y in o))o[y]=Ae(g,h);for(let[y,g]of Object.entries(m.header.studKinds??{}))if(!(y in s))s[y]=Ae(g,h)}let i=e[0]?.header??{version:1,weld:!0},c=new TextEncoder().encode(JSON.stringify({...i,parts:o,studKinds:s,...t})),a=(4-(4+c.length)%4)%4,l=4+c.length+a,f=new Uint8Array(l+r);new DataView(f.buffer).setUint32(0,c.length+a,!0),f.set(c,4),f.fill(32,4+c.length,l);let p=l;for(let m of n)f.set(m,p),p+=m.byteLength;return ye(f.buffer)}async function Kt(e,t={}){e=[...e];try{return await ut(e,t)}catch(n){let r=t.cdn??Me,o=t.fetch??fetch;ve.delete(r);let s=(i,c)=>o(i,{...c,cache:"reload"});try{return await ut(e,{...t,fetch:s})}catch{throw n}}}async function ut(e,t){let n=t.cdn??Me,r=t.fetch??fetch,o=t.gap??16384,s=await ft(n,r),i=[...new Set([...e].map(q))],c=[],a=[];for(let u of i){if(we.has(n+u))continue;let h=s.parts[u];if(h)a.push({name:u,off:h[0],len:h[1],file:h[2]??0});else c.push(u)}a.sort((u,h)=>u.file-h.file||u.off-h.off);let l=[];for(let u of a){let h=l[l.length-1];if(h&&h.file===u.file&&u.off-h.end<=o)h.end=Math.max(h.end,u.off+u.len),h.items.push(u);else l.push({file:u.file,start:u.off,end:u.off+u.len,items:[u]})}let f=0,p=0,m=async()=>{while(p<l.length){let u=l[p++],h=await r(new URL(s.archives[u.file],n).href,{headers:{Range:`bytes=${u.start}-${u.end-1}`}});if(!h.ok)throw Error(`ldr: parts CDN ${h.status}`);let E=new Uint8Array(await h.arrayBuffer());if(h.status===200)E=E.subarray(u.start,u.end);f+=E.byteLength;for(let y of u.items){let g=je(E.subarray(y.off-u.start,y.off-u.start+y.len)),C=g.buffer.slice(g.byteOffset,g.byteOffset+g.byteLength);we.set(n+y.name,ye(C))}}};await Promise.all(Array.from({length:Math.min(t.concurrency??24,l.length)},m));let b=i.filter((u)=>we.has(n+u)).map((u)=>we.get(n+u));return{pack:b.length?_t(b,{colors:s.colors}):ye(Wt(s.colors)),missing:c,requests:l.length,bytes:f}}function Wt(e){let t=new TextEncoder().encode(JSON.stringify({version:1,weld:!0,parts:{},studKinds:{},colors:e})),n=(4-(4+t.length)%4)%4,r=new Uint8Array(4+t.length+n).fill(32);return new DataView(r.buffer).setUint32(0,t.length+n,!0),r.set(t,4),r.buffer}async function pt(e,t={}){let n=performance.now(),r=t.fetch??fetch,o=ft(t.cdn??Me,r);o.catch(()=>{});let s=t.text?e:await r(e).then((h)=>{if(!h.ok)throw Error(`ldr: ${h.status} fetching ${e}`);return h.text()}),i=performance.now(),c=t.name??(t.text?"main.ldr":decodeURIComponent(e.split(/[?#]/)[0].split("/").pop()||"main.ldr")),a=at(s,c,{looseGeometry:!1,callouts:t.callouts}),l=performance.now();t.onParsed?.(a),await o;let{pack:f,missing:p,requests:m,bytes:b}=await Kt(a.filter((h)=>!h.embedded).map((h)=>h.part),t),A=performance.now(),u=t.cull?xe(a,f.header,t.textures!==!1):void 0;return{insts:a,pack:f,missing:p,requests:m,bytes:b,cull:u,timings:{fetchModel:i-n,parse:l-i,parts:A-l,...u?{cull:performance.now()-A}:{}}}}self.onmessage=async(e)=>{let{id:t,source:n,opts:r}=e.data;try{let o=await pt(n,{...r,cull:!1,onParsed:(f)=>self.postMessage({id:t,insts:f})}),s=o.pack.buffer;if(self.postMessage({id:t,buffer:s,missing:o.missing,requests:o.requests,bytes:o.bytes,timings:o.timings},[s]),!r.cull)return;let i=performance.now(),c=xe(o.insts,o.pack.header,r.textures!==!1),a=performance.now()-i,l=[];for(let f of[c.studHidden,c.studUp,c.underHidden,c.studHideStep,c.underHideStep])if(f)l.push(f.buffer);self.postMessage({id:t,cull:c,ms:a},l)}catch(o){self.postMessage({id:t,phase:"error",error:String(o?.message??o)})}};\n';
|
|
2917
|
+
|
|
2918
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/cdn.ts
|
|
2919
|
+
var worker;
|
|
2920
|
+
var seq = 0;
|
|
2921
|
+
var pending = new Map;
|
|
2922
|
+
var pendingInsts = new Map;
|
|
2923
|
+
var pendingCull = new Map;
|
|
2924
|
+
function getWorker() {
|
|
2925
|
+
if (worker !== undefined)
|
|
2926
|
+
return worker;
|
|
2927
|
+
try {
|
|
2928
|
+
if (typeof Worker === "undefined" || typeof Blob === "undefined" || typeof URL?.createObjectURL !== "function" || !load_worker_gen_default)
|
|
2929
|
+
return worker = null;
|
|
2930
|
+
const url = URL.createObjectURL(new Blob([load_worker_gen_default], { type: "text/javascript" }));
|
|
2931
|
+
const w = new Worker(url, { type: "module", name: "ldr-load" });
|
|
2932
|
+
w.onmessage = (e) => {
|
|
2933
|
+
const d = e.data;
|
|
2934
|
+
if (d.insts) {
|
|
2935
|
+
pendingInsts.get(d.id)?.(d.insts);
|
|
2936
|
+
pendingInsts.delete(d.id);
|
|
2937
|
+
return;
|
|
2938
|
+
}
|
|
2939
|
+
const map = d.cull || d.error && !pending.has(d.id) ? pendingCull : pending;
|
|
2940
|
+
const p = map.get(d.id);
|
|
2941
|
+
if (!p)
|
|
2942
|
+
return;
|
|
2943
|
+
map.delete(d.id);
|
|
2944
|
+
d.error ? p.rej(new Error(d.error)) : p.res(d);
|
|
2945
|
+
};
|
|
2946
|
+
w.onerror = (e) => {
|
|
2947
|
+
e.preventDefault?.();
|
|
2948
|
+
worker = null;
|
|
2949
|
+
w.terminate();
|
|
2950
|
+
const err = new Error("ldr: load worker failed: " + (e.message || "error"));
|
|
2951
|
+
err.workerFailed = true;
|
|
2952
|
+
for (const m of [pending, pendingCull]) {
|
|
2953
|
+
for (const p of m.values())
|
|
2954
|
+
p.rej(err);
|
|
2955
|
+
m.clear();
|
|
2956
|
+
}
|
|
2957
|
+
};
|
|
2958
|
+
return worker = w;
|
|
2959
|
+
} catch {
|
|
2960
|
+
return worker = null;
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2963
|
+
var abs = (u) => {
|
|
2964
|
+
try {
|
|
2965
|
+
return new URL(u, globalThis.location?.href).href;
|
|
2966
|
+
} catch {
|
|
2967
|
+
return u;
|
|
2968
|
+
}
|
|
2969
|
+
};
|
|
2970
|
+
function prepareInWorker(w, source, o) {
|
|
2971
|
+
const id = ++seq;
|
|
2972
|
+
const opts = { cdn: abs(o.cdn ?? DEFAULT_PARTS_CDN), gap: o.gap, concurrency: o.concurrency, text: o.text, name: o.name, cull: true, textures: o.textures, callouts: o.callouts };
|
|
2973
|
+
const name = o.name ?? (o.text ? undefined : decodeURIComponent(source.split(/[?#]/)[0].split("/").pop() || "main.ldr"));
|
|
2974
|
+
let insts;
|
|
2975
|
+
pendingInsts.set(id, (v) => {
|
|
2976
|
+
insts = v;
|
|
2977
|
+
});
|
|
2978
|
+
const cull = new Promise((res, rej) => pendingCull.set(id, { res, rej }));
|
|
2979
|
+
cull.catch(() => {});
|
|
2980
|
+
return new Promise((res, rej) => {
|
|
2981
|
+
pending.set(id, { res, rej });
|
|
2982
|
+
w.postMessage({ id, source: o.text ? source : abs(source), opts: { ...opts, name } });
|
|
2983
|
+
}).then(async (d) => {
|
|
2984
|
+
const pack = decodePack(d.buffer);
|
|
2985
|
+
let done = false;
|
|
2986
|
+
cull.then(() => done = true, () => done = true);
|
|
2987
|
+
await warmPackGeometry(pack, () => done);
|
|
2988
|
+
const c = await cull;
|
|
2989
|
+
pendingInsts.delete(id);
|
|
2990
|
+
return { insts, pack, missing: d.missing, requests: d.requests, bytes: d.bytes, timings: { ...d.timings, cull: c.ms }, cull: c.cull };
|
|
2991
|
+
}, (e) => {
|
|
2992
|
+
pendingCull.delete(id);
|
|
2993
|
+
pendingInsts.delete(id);
|
|
2994
|
+
throw e;
|
|
2995
|
+
});
|
|
2996
|
+
}
|
|
2997
|
+
async function loadModel(source, o = {}) {
|
|
2998
|
+
const t0 = performance.now();
|
|
2999
|
+
const w = o.worker !== false && !o.fetch ? getWorker() : null;
|
|
3000
|
+
let prep, ranIn = "main";
|
|
3001
|
+
if (w) {
|
|
3002
|
+
try {
|
|
3003
|
+
prep = await prepareInWorker(w, source, o);
|
|
3004
|
+
ranIn = "worker";
|
|
3005
|
+
} catch (e) {
|
|
3006
|
+
if (!e?.workerFailed)
|
|
3007
|
+
throw e;
|
|
3008
|
+
prep = await prepareModel(source, o);
|
|
3009
|
+
}
|
|
3010
|
+
} else
|
|
3011
|
+
prep = await prepareModel(source, o);
|
|
3012
|
+
const t3 = performance.now();
|
|
3013
|
+
const obj = createLdrObject(prep.insts, prep.pack, prep.cull ? { ...o, precomputedCull: prep.cull } : o);
|
|
3014
|
+
for (const m of prep.missing)
|
|
2257
3015
|
if (!obj.stats.missing.includes(m))
|
|
2258
3016
|
obj.stats.missing.push(m);
|
|
2259
3017
|
const t4 = performance.now();
|
|
2260
|
-
return Object.assign(obj, {
|
|
3018
|
+
return Object.assign(obj, {
|
|
3019
|
+
pack: prep.pack,
|
|
3020
|
+
instances: prep.insts,
|
|
3021
|
+
requests: prep.requests,
|
|
3022
|
+
bytes: prep.bytes,
|
|
3023
|
+
ranIn,
|
|
3024
|
+
timings: { ...prep.timings, parts: t3 - t0 - prep.timings.fetchModel - prep.timings.parse, build: t4 - t3, total: t4 - t0 }
|
|
3025
|
+
});
|
|
2261
3026
|
}
|
|
2262
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3027
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/node/library.ts
|
|
2263
3028
|
import { existsSync, readFileSync } from "fs";
|
|
2264
3029
|
import { join } from "path";
|
|
2265
3030
|
var xf = (m, x, y, z) => [m[3] * x + m[4] * y + m[5] * z + m[0], m[6] * x + m[7] * y + m[8] * z + m[1], m[9] * x + m[10] * y + m[11] * z + m[2]];
|
|
2266
3031
|
var det = (m) => m[3] * (m[7] * m[11] - m[8] * m[10]) - m[4] * (m[6] * m[11] - m[8] * m[9]) + m[5] * (m[6] * m[10] - m[7] * m[9]);
|
|
3032
|
+
var IDENTITY12 = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1];
|
|
3033
|
+
function isPlainAlias(f, target) {
|
|
3034
|
+
if (STUB_OVERRIDES[norm(f.name)] === target)
|
|
3035
|
+
return true;
|
|
3036
|
+
const refs = f.cmds.filter((c) => c.t === 1);
|
|
3037
|
+
return refs.length <= 1 && refs.every((c) => norm(c.file) === target && c.m.every((v, k) => Math.abs(v - IDENTITY12[k]) < 0.000001));
|
|
3038
|
+
}
|
|
2267
3039
|
|
|
2268
3040
|
class Library {
|
|
2269
3041
|
root;
|
|
@@ -2297,7 +3069,7 @@ class Library {
|
|
|
2297
3069
|
if (!hit)
|
|
2298
3070
|
return null;
|
|
2299
3071
|
const file = hit.doc.files.get(hit.doc.main);
|
|
2300
|
-
if (file?.movedTo && file.movedTo !== name) {
|
|
3072
|
+
if (file?.movedTo && file.movedTo !== name && isPlainAlias(file, file.movedTo)) {
|
|
2301
3073
|
const target = this.where(file.movedTo, seen);
|
|
2302
3074
|
if (target)
|
|
2303
3075
|
return { ...target, aliasOf: name };
|
|
@@ -2511,11 +3283,11 @@ class Library {
|
|
|
2511
3283
|
return insts;
|
|
2512
3284
|
}
|
|
2513
3285
|
}
|
|
2514
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3286
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/node/build-pack.ts
|
|
2515
3287
|
import fs3 from "node:fs";
|
|
2516
3288
|
import path3 from "node:path";
|
|
2517
3289
|
|
|
2518
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3290
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/node/resolver.ts
|
|
2519
3291
|
import fs from "node:fs";
|
|
2520
3292
|
import path from "node:path";
|
|
2521
3293
|
var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
|
|
@@ -2587,7 +3359,7 @@ class Library2 {
|
|
|
2587
3359
|
return key;
|
|
2588
3360
|
}
|
|
2589
3361
|
resolve(ref) {
|
|
2590
|
-
const
|
|
3362
|
+
const n0 = norm2(ref), n = STUB_OVERRIDES[n0] ?? n0;
|
|
2591
3363
|
if (this.virtual.size && this.virtual.has(n))
|
|
2592
3364
|
return "mpd/" + n;
|
|
2593
3365
|
for (const pre of ["parts/", "p/", "models/"])
|
|
@@ -2787,11 +3559,11 @@ function collectDeps(lib, refs) {
|
|
|
2787
3559
|
return out;
|
|
2788
3560
|
}
|
|
2789
3561
|
|
|
2790
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3562
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/node/compile.ts
|
|
2791
3563
|
import fs2 from "node:fs";
|
|
2792
3564
|
import path2 from "node:path";
|
|
2793
3565
|
|
|
2794
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3566
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/node/lod.ts
|
|
2795
3567
|
import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
|
|
2796
3568
|
await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
|
|
2797
3569
|
function reorderMesh(P, N, C, I) {
|
|
@@ -2814,8 +3586,10 @@ function reorderMesh(P, N, C, I) {
|
|
|
2814
3586
|
}
|
|
2815
3587
|
return { P: P2, N: N2, C: C2, I: idx };
|
|
2816
3588
|
}
|
|
2817
|
-
var TARGETS = [0.25, 0.08];
|
|
3589
|
+
var TARGETS = [0.25, 0.08, 0.025];
|
|
2818
3590
|
var MIN_TRIS = 64;
|
|
3591
|
+
var MIN_BOX_TRIS = 24;
|
|
3592
|
+
var COVERAGE_WEIGHT = Number(process.env.LDR_LOD_COVERAGE ?? 0.5);
|
|
2819
3593
|
function flatMesh(tris) {
|
|
2820
3594
|
const map = new Map;
|
|
2821
3595
|
const P = [], N = [], C = [], I = [];
|
|
@@ -2845,9 +3619,62 @@ function flatMesh(tris) {
|
|
|
2845
3619
|
}
|
|
2846
3620
|
return { P: new Float32Array(P), N: new Float32Array(N), C: new Float32Array(C), I: new Uint32Array(I) };
|
|
2847
3621
|
}
|
|
3622
|
+
var G = 64;
|
|
3623
|
+
function silhouettes(P, I, box) {
|
|
3624
|
+
const masks = [0, 1, 2].map(() => new Uint8Array(G * G));
|
|
3625
|
+
for (let ax = 0;ax < 3; ax++) {
|
|
3626
|
+
const u = (ax + 1) % 3, v = (ax + 2) % 3;
|
|
3627
|
+
const m = masks[ax];
|
|
3628
|
+
const su = (box.hi[u] - box.lo[u]) / G || 1, sv = (box.hi[v] - box.lo[v]) / G || 1;
|
|
3629
|
+
for (let t = 0;t < I.length; t += 3) {
|
|
3630
|
+
const p = [I[t], I[t + 1], I[t + 2]].map((k) => [(P[k * 3 + u] - box.lo[u]) / su, (P[k * 3 + v] - box.lo[v]) / sv]);
|
|
3631
|
+
const area = (p[1][0] - p[0][0]) * (p[2][1] - p[0][1]) - (p[2][0] - p[0][0]) * (p[1][1] - p[0][1]);
|
|
3632
|
+
if (Math.abs(area) < 0.000000000001)
|
|
3633
|
+
continue;
|
|
3634
|
+
const x0 = Math.max(0, Math.floor(Math.min(p[0][0], p[1][0], p[2][0]))), x1 = Math.min(G - 1, Math.ceil(Math.max(p[0][0], p[1][0], p[2][0])));
|
|
3635
|
+
const y0 = Math.max(0, Math.floor(Math.min(p[0][1], p[1][1], p[2][1]))), y1 = Math.min(G - 1, Math.ceil(Math.max(p[0][1], p[1][1], p[2][1])));
|
|
3636
|
+
for (let y = y0;y <= y1; y++)
|
|
3637
|
+
for (let x = x0;x <= x1; x++) {
|
|
3638
|
+
if (m[y * G + x])
|
|
3639
|
+
continue;
|
|
3640
|
+
const cx = x + 0.5, cy = y + 0.5;
|
|
3641
|
+
let inside = true;
|
|
3642
|
+
for (let e = 0;e < 3 && inside; e++) {
|
|
3643
|
+
const a0 = p[e], a1 = p[(e + 1) % 3];
|
|
3644
|
+
const w = (a1[0] - a0[0]) * (cy - a0[1]) - (cx - a0[0]) * (a1[1] - a0[1]);
|
|
3645
|
+
if (w * area < 0)
|
|
3646
|
+
inside = false;
|
|
3647
|
+
}
|
|
3648
|
+
if (inside)
|
|
3649
|
+
m[y * G + x] = 1;
|
|
3650
|
+
}
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
return masks;
|
|
3654
|
+
}
|
|
3655
|
+
function silhouetteDiff(a, b) {
|
|
3656
|
+
let worst = 0;
|
|
3657
|
+
for (let ax = 0;ax < 3; ax++) {
|
|
3658
|
+
let d = 0;
|
|
3659
|
+
for (let i = 0;i < G * G; i++)
|
|
3660
|
+
d += a[ax][i] ^ b[ax][i];
|
|
3661
|
+
worst = Math.max(worst, d / (G * G));
|
|
3662
|
+
}
|
|
3663
|
+
return worst;
|
|
3664
|
+
}
|
|
3665
|
+
function boxMesh(box, col) {
|
|
3666
|
+
const [x0, y0, z0] = box.lo, [x1, y1, z1] = box.hi;
|
|
3667
|
+
const c = [[x0, y0, z0], [x1, y0, z0], [x1, y1, z0], [x0, y1, z0], [x0, y0, z1], [x1, y0, z1], [x1, y1, z1], [x0, y1, z1]];
|
|
3668
|
+
const quads = [[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [3, 7, 6, 2], [0, 4, 7, 3], [1, 2, 6, 5]];
|
|
3669
|
+
const p = new Float32Array(c.flat());
|
|
3670
|
+
const idx = [];
|
|
3671
|
+
for (const q of quads)
|
|
3672
|
+
idx.push(q[0], q[1], q[2], q[0], q[2], q[3]);
|
|
3673
|
+
return flatMesh([{ p, i: Uint32Array.from(idx), col }]);
|
|
3674
|
+
}
|
|
2848
3675
|
function lodChain(P, C, I) {
|
|
2849
3676
|
const nTris = I.length / 3;
|
|
2850
|
-
if (nTris <
|
|
3677
|
+
if (nTris < MIN_BOX_TRIS)
|
|
2851
3678
|
return [];
|
|
2852
3679
|
const groups = new Map;
|
|
2853
3680
|
for (let t = 0;t < I.length; t += 3) {
|
|
@@ -2878,27 +3705,57 @@ function lodChain(P, C, I) {
|
|
|
2878
3705
|
});
|
|
2879
3706
|
const out = [];
|
|
2880
3707
|
let prevTris = nTris;
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
3708
|
+
const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
|
|
3709
|
+
for (let v = 0;v < P.length; v += 3)
|
|
3710
|
+
for (let k = 0;k < 3; k++) {
|
|
3711
|
+
lo[k] = Math.min(lo[k], P[v + k]);
|
|
3712
|
+
hi[k] = Math.max(hi[k], P[v + k]);
|
|
3713
|
+
}
|
|
3714
|
+
const box = { lo, hi };
|
|
3715
|
+
const diag = Math.hypot(hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]);
|
|
3716
|
+
const S0 = silhouettes(P, I, box);
|
|
3717
|
+
const coverageErr = (m) => COVERAGE_WEIGHT * silhouetteDiff(S0, silhouettes(m.P, m.I, box)) * diag;
|
|
3718
|
+
for (let li = 0;li < (nTris >= MIN_TRIS ? TARGETS.length : 0); li++) {
|
|
3719
|
+
let best = null;
|
|
3720
|
+
for (const sloppy of [false, true]) {
|
|
3721
|
+
let err = 0;
|
|
3722
|
+
const parts = [];
|
|
3723
|
+
for (const g of welded) {
|
|
3724
|
+
const target = Math.max(3, Math.floor(g.i.length * TARGETS[li] / 3) * 3);
|
|
3725
|
+
const [idx, e] = sloppy ? MeshoptSimplifier.simplifySloppy(g.i, g.p, 3, null, target, 1e9) : MeshoptSimplifier.simplify(g.i, g.p, 3, target, 1e9, li ? ["ErrorAbsolute", "Prune"] : ["ErrorAbsolute"]);
|
|
3726
|
+
err = Math.max(err, sloppy ? e * MeshoptSimplifier.getScale(g.p, 3) : e);
|
|
3727
|
+
if (idx.length)
|
|
3728
|
+
parts.push({ p: g.p, i: idx, col: g.col });
|
|
3729
|
+
}
|
|
3730
|
+
const m = flatMesh(parts);
|
|
3731
|
+
const t = m.I.length / 3;
|
|
3732
|
+
if (!t || t > prevTris * 0.7)
|
|
3733
|
+
continue;
|
|
3734
|
+
const e = +Math.max(err, coverageErr(m), 0.001).toFixed(3);
|
|
3735
|
+
if (!best || e < best.err)
|
|
3736
|
+
best = { ...m, err: e };
|
|
3737
|
+
}
|
|
3738
|
+
if (best) {
|
|
3739
|
+
out.push(best);
|
|
3740
|
+
prevTris = best.I.length / 3;
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
if (prevTris * 0.7 >= 12) {
|
|
3744
|
+
const main = welded.reduce((a, g) => g.i.length > a.i.length ? g : a);
|
|
3745
|
+
const m = boxMesh(box, main.col);
|
|
3746
|
+
let inner = 0;
|
|
3747
|
+
for (let v = 0;v < P.length; v += 3) {
|
|
3748
|
+
let d = Infinity;
|
|
3749
|
+
for (let k = 0;k < 3; k++)
|
|
3750
|
+
d = Math.min(d, P[v + k] - lo[k], hi[k] - P[v + k]);
|
|
3751
|
+
inner = Math.max(inner, d);
|
|
3752
|
+
}
|
|
3753
|
+
out.push({ ...m, err: +Math.max(inner, coverageErr(m) / COVERAGE_WEIGHT, out.length ? out[out.length - 1].err : 0, 0.001).toFixed(3) });
|
|
2897
3754
|
}
|
|
2898
3755
|
return out;
|
|
2899
3756
|
}
|
|
2900
3757
|
|
|
2901
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3758
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/node/compile.ts
|
|
2902
3759
|
function loadColors(root) {
|
|
2903
3760
|
const map = new Map;
|
|
2904
3761
|
for (const l of fs2.readFileSync(path2.join(root, "LDConfig.ldr"), "latin1").split(/\r?\n/)) {
|
|
@@ -3481,7 +4338,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
3481
4338
|
return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
|
|
3482
4339
|
}
|
|
3483
4340
|
|
|
3484
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4341
|
+
// ../../../../../../../tmp/ldr-build-zzND7A/src/node/build-pack.ts
|
|
3485
4342
|
function buildPack(o) {
|
|
3486
4343
|
const lib = new Library2(o.ldrawRoot);
|
|
3487
4344
|
const refs = new Map;
|
|
@@ -3544,10 +4401,13 @@ function buildPack(o) {
|
|
|
3544
4401
|
return { data: encodePack(parts, kinds, comp.opts.weld, extra, { texture, lod: o.lod !== false, reorder: !!o.reorder }), parts: parts.size, studKinds: kinds.size, missing: [...missing], ...warnings.length ? { warnings } : {} };
|
|
3545
4402
|
}
|
|
3546
4403
|
export {
|
|
4404
|
+
CALLOUT_END,
|
|
3547
4405
|
Compiler,
|
|
3548
4406
|
DEFAULT_PARTS_CDN,
|
|
3549
4407
|
I as IDENTITY,
|
|
3550
4408
|
Library,
|
|
4409
|
+
MIN_VIS,
|
|
4410
|
+
REORIENT,
|
|
3551
4411
|
Library2 as ResolverLibrary,
|
|
3552
4412
|
buildLdrScene,
|
|
3553
4413
|
buildPack,
|
|
@@ -3569,8 +4429,10 @@ export {
|
|
|
3569
4429
|
flatten2 as flattenWithLibrary,
|
|
3570
4430
|
forEachStud,
|
|
3571
4431
|
hash32,
|
|
4432
|
+
instanceBoxes,
|
|
3572
4433
|
invert,
|
|
3573
4434
|
isDirectColor,
|
|
4435
|
+
isolateMask,
|
|
3574
4436
|
loadColors,
|
|
3575
4437
|
loadModel,
|
|
3576
4438
|
loadPack,
|
|
@@ -3589,15 +4451,22 @@ export {
|
|
|
3589
4451
|
parseLDConfig,
|
|
3590
4452
|
parseModel,
|
|
3591
4453
|
parseTexMap,
|
|
4454
|
+
planStepViews,
|
|
4455
|
+
precomputeCull,
|
|
4456
|
+
prepareModel,
|
|
3592
4457
|
resolveTexture,
|
|
3593
4458
|
rotStepMatrix,
|
|
4459
|
+
sceneInstances,
|
|
3594
4460
|
sequenceSteps,
|
|
3595
4461
|
smoothNormals,
|
|
3596
4462
|
splitModel,
|
|
4463
|
+
stepKey,
|
|
3597
4464
|
stepViewMatrix,
|
|
3598
4465
|
texWrapper,
|
|
3599
4466
|
texmapTriangleUV,
|
|
3600
4467
|
texmapUV,
|
|
3601
4468
|
transformTexMap,
|
|
4469
|
+
viewDir,
|
|
4470
|
+
warmPackGeometry,
|
|
3602
4471
|
writePack
|
|
3603
4472
|
};
|