ldr 0.5.0 → 0.6.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 +12 -10
- package/dist/cdn.d.ts +8 -41
- package/dist/cli.js +157 -30
- package/dist/cull.d.ts +68 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +848 -503
- package/dist/load-worker.d.ts +1 -0
- package/dist/load-worker.gen.d.ts +2 -0
- package/dist/node/index.js +970 -540
- package/dist/pack-io.d.ts +9 -0
- package/dist/parts-cdn.d.ts +64 -0
- package/dist/render.d.ts +23 -43
- package/dist/scene.d.ts +10 -1
- package/package.json +4 -4
package/dist/node/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/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) {
|
|
@@ -647,7 +689,7 @@ function fileStepViews(f) {
|
|
|
647
689
|
viewMemo.set(f, out);
|
|
648
690
|
return out;
|
|
649
691
|
}
|
|
650
|
-
// ../../../../../../../tmp/ldr-build-
|
|
692
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/model.ts
|
|
651
693
|
function flatten(doc, opts = {}) {
|
|
652
694
|
const out = [];
|
|
653
695
|
const maxDepth = opts.maxDepth ?? 64;
|
|
@@ -743,7 +785,7 @@ function flatten(doc, opts = {}) {
|
|
|
743
785
|
return out;
|
|
744
786
|
}
|
|
745
787
|
function parseModel(text, name = "main.ldr", opts) {
|
|
746
|
-
return flatten(parse(text, name), opts);
|
|
788
|
+
return flatten(parse(text, name, { geometryText: true }), opts);
|
|
747
789
|
}
|
|
748
790
|
function sequenceSteps(insts) {
|
|
749
791
|
const key = (i) => i.steps.map((x) => String(x).padStart(6, "0")).join(".");
|
|
@@ -768,28 +810,19 @@ function parseLDConfig(text) {
|
|
|
768
810
|
}
|
|
769
811
|
return out;
|
|
770
812
|
}
|
|
771
|
-
// ../../../../../../../tmp/ldr-build-
|
|
813
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/render.ts
|
|
772
814
|
import * as THREE from "three";
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
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);
|
|
815
|
+
|
|
816
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/pack-io.ts
|
|
817
|
+
import { decompress } from "fzstd";
|
|
818
|
+
async function decompressPack(data) {
|
|
819
|
+
const u = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
820
|
+
const own = (o) => o.buffer.slice(o.byteOffset, o.byteOffset + o.byteLength);
|
|
821
|
+
if (u[0] === 40 && u[1] === 181 && u[2] === 47 && u[3] === 253)
|
|
822
|
+
return own(decompress(u));
|
|
823
|
+
if (u[0] === 31 && u[1] === 139)
|
|
824
|
+
return new Response(new Blob([u]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();
|
|
825
|
+
return own(u);
|
|
793
826
|
}
|
|
794
827
|
function decodePack(buf) {
|
|
795
828
|
const hl = new DataView(buf).getUint32(0, true);
|
|
@@ -798,295 +831,8 @@ function decodePack(buf) {
|
|
|
798
831
|
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
832
|
return { header, arr, bytes: buf.byteLength, buffer: buf };
|
|
800
833
|
}
|
|
801
|
-
|
|
802
|
-
|
|
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>", `#ifdef USE_INSTANCING_COLOR
|
|
860
|
-
vColor = vec4(ldrColor.a > 0.5 ? pow(ldrColor.rgb, vec3(2.2)) : instanceColor.rgb, 1.0); // baked LDConfig colours are sRGB
|
|
861
|
-
#else
|
|
862
|
-
vColor = vec4(pow(ldrColor.rgb, vec3(2.2)), 1.0);
|
|
863
|
-
#endif`);
|
|
864
|
-
};
|
|
865
|
-
m.customProgramCacheKey = () => "ldrColor";
|
|
866
|
-
return m;
|
|
867
|
-
}
|
|
868
|
-
function makeTexturedMaterial(side, map, wrapU = false) {
|
|
869
|
-
const m = makeMaterial(side);
|
|
870
|
-
const base = m.onBeforeCompile;
|
|
871
|
-
m.onBeforeCompile = (sh, r) => {
|
|
872
|
-
base.call(m, sh, r);
|
|
873
|
-
sh.uniforms.ldrMap = { value: map };
|
|
874
|
-
sh.uniforms.ldrWrapU = { value: wrapU ? 1 : 0 };
|
|
875
|
-
sh.vertexShader = `attribute vec2 ldrUV; varying vec2 vLdrUV;
|
|
876
|
-
` + sh.vertexShader.replace("#include <uv_vertex>", `#include <uv_vertex>
|
|
877
|
-
vLdrUV = ldrUV;`);
|
|
878
|
-
sh.fragmentShader = `uniform sampler2D ldrMap; uniform int ldrWrapU; varying vec2 vLdrUV;
|
|
879
|
-
` + sh.fragmentShader.replace("#include <color_fragment>", `#include <color_fragment>
|
|
880
|
-
{ vec2 uv = vec2(ldrWrapU == 1 ? fract(vLdrUV.x) : vLdrUV.x, vLdrUV.y); vec4 t = texture2D(ldrMap, uv);
|
|
881
|
-
float inside = step(0.0, uv.x) * step(uv.x, 1.0) * step(0.0, uv.y) * step(uv.y, 1.0);
|
|
882
|
-
diffuseColor.rgb = mix(diffuseColor.rgb, t.rgb, t.a * inside); }`);
|
|
883
|
-
};
|
|
884
|
-
m.customProgramCacheKey = () => "ldrColorTex";
|
|
885
|
-
m.userData.ldrMap = map;
|
|
886
|
-
return m;
|
|
887
|
-
}
|
|
888
|
-
function packTexture(pack, i) {
|
|
889
|
-
const t = new THREE.Texture;
|
|
890
|
-
t.flipY = false;
|
|
891
|
-
t.colorSpace = THREE.SRGBColorSpace;
|
|
892
|
-
t.wrapS = t.wrapT = THREE.ClampToEdgeWrapping;
|
|
893
|
-
const e = pack.header.textures?.[i];
|
|
894
|
-
const bytes = e?.data ? pack.arr(e.data) : null;
|
|
895
|
-
if (!bytes || typeof createImageBitmap === "undefined")
|
|
896
|
-
return { texture: t, ready: Promise.resolve() };
|
|
897
|
-
const ready = createImageBitmap(new Blob([bytes], { type: e.mime || "image/png" }), { premultiplyAlpha: "none", colorSpaceConversion: "none" }).then((img) => {
|
|
898
|
-
t.image = img;
|
|
899
|
-
t.needsUpdate = true;
|
|
900
|
-
}).catch(() => {});
|
|
901
|
-
return { texture: t, ready };
|
|
902
|
-
}
|
|
903
|
-
var lineMat = () => new THREE.ShaderMaterial({
|
|
904
|
-
vertexShader: `attribute vec4 im0; attribute vec4 im1; attribute vec4 im2; attribute vec4 im3;
|
|
905
|
-
void main(){ gl_Position = projectionMatrix * modelViewMatrix * mat4(im0,im1,im2,im3) * vec4(position,1.0); }`,
|
|
906
|
-
fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
|
|
907
|
-
});
|
|
908
|
-
var sharedLineMat = () => new THREE.ShaderMaterial({
|
|
909
|
-
vertexShader: `attribute mat4 instanceMatrix; void main(){ gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position,1.0); }`,
|
|
910
|
-
fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
|
|
911
|
-
});
|
|
912
|
-
var weldLines = (pos) => {
|
|
913
|
-
const map = new Map;
|
|
914
|
-
const P = [];
|
|
915
|
-
const I = [];
|
|
916
|
-
for (let i = 0;i < pos.length; i += 3) {
|
|
917
|
-
const k = pos[i].toFixed(2) + "," + pos[i + 1].toFixed(2) + "," + pos[i + 2].toFixed(2);
|
|
918
|
-
let j = map.get(k);
|
|
919
|
-
if (j === undefined) {
|
|
920
|
-
j = P.length / 3;
|
|
921
|
-
map.set(k, j);
|
|
922
|
-
P.push(pos[i], pos[i + 1], pos[i + 2]);
|
|
923
|
-
}
|
|
924
|
-
I.push(j);
|
|
925
|
-
}
|
|
926
|
-
return { P: new Float32Array(P), I: P.length / 3 < 65536 ? new Uint16Array(I) : new Uint32Array(I) };
|
|
927
|
-
};
|
|
928
|
-
function createInstancedEdges(pos, im, material = sharedLineMat()) {
|
|
929
|
-
return sharedLines(pos, im, material);
|
|
930
|
-
}
|
|
931
|
-
function conditionalLines(pack, entry, which = "all") {
|
|
932
|
-
if (which === "all") {
|
|
933
|
-
const a = conditionalLines(pack, entry, "body"), b = conditionalLines(pack, entry, "under");
|
|
934
|
-
if (!a || !b)
|
|
935
|
-
return a ?? b;
|
|
936
|
-
const o = new Float32Array(a.length + b.length);
|
|
937
|
-
o.set(a);
|
|
938
|
-
o.set(b, a.length);
|
|
939
|
-
return o;
|
|
940
|
-
}
|
|
941
|
-
const c = which === "under" ? entry?.condlu : entry?.condl;
|
|
942
|
-
if (!c)
|
|
943
|
-
return null;
|
|
944
|
-
const { arr } = pack;
|
|
945
|
-
if (c.raw)
|
|
946
|
-
return arr(c.raw);
|
|
947
|
-
const pools = [entry.body ? arr(entry.body.pos) : [], entry.under ? arr(entry.under.pos) : [], entry.edges ? arr(entry.edges) : [], c.x ? arr(c.x) : []];
|
|
948
|
-
const idx = arr(c.idx);
|
|
949
|
-
const out = new Float32Array(idx.length * 3);
|
|
950
|
-
const starts = [];
|
|
951
|
-
let base = 0;
|
|
952
|
-
for (const p of pools) {
|
|
953
|
-
starts.push(base);
|
|
954
|
-
base += p.length / 3;
|
|
955
|
-
}
|
|
956
|
-
let prev = 0;
|
|
957
|
-
for (let i = 0;i < idx.length; i++) {
|
|
958
|
-
const z = idx[i];
|
|
959
|
-
const j = prev + (z & 1 ? -(z + 1) / 2 : z / 2);
|
|
960
|
-
prev = j;
|
|
961
|
-
let k = 3;
|
|
962
|
-
while (k > 0 && j < starts[k])
|
|
963
|
-
k--;
|
|
964
|
-
const p = pools[k], o = (j - starts[k]) * 3;
|
|
965
|
-
out[i * 3] = p[o];
|
|
966
|
-
out[i * 3 + 1] = p[o + 1];
|
|
967
|
-
out[i * 3 + 2] = p[o + 2];
|
|
968
|
-
}
|
|
969
|
-
return out;
|
|
970
|
-
}
|
|
971
|
-
var condLineMat = () => new THREE.ShaderMaterial({
|
|
972
|
-
uniforms: { ldrViewProj: { value: new THREE.Matrix4 } },
|
|
973
|
-
vertexShader: `uniform mat4 ldrViewProj; attribute mat4 instanceMatrix; attribute vec3 ldrP1; attribute vec3 ldrC0; attribute vec3 ldrC1; attribute float ldrSide;
|
|
974
|
-
void main(){
|
|
975
|
-
mat4 mvp = ldrViewProj * instanceMatrix;
|
|
976
|
-
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);
|
|
977
|
-
vec2 A = a.xy / a.w, B = b.xy / b.w, C0 = c0.xy / c0.w, C1 = c1.xy / c1.w, d = B - A;
|
|
978
|
-
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);
|
|
979
|
-
gl_Position = s0 * s1 >= 0.0 ? (ldrSide > 0.5 ? b : a) : vec4(2.0, 2.0, 2.0, 1.0);
|
|
980
|
-
}`,
|
|
981
|
-
fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
|
|
982
|
-
});
|
|
983
|
-
function conditionalLineVisible(cond, i, mvp) {
|
|
984
|
-
const e = mvp.elements;
|
|
985
|
-
const pr = (o) => {
|
|
986
|
-
const x = cond[o], y = cond[o + 1], z = cond[o + 2];
|
|
987
|
-
const w = e[3] * x + e[7] * y + e[11] * z + e[15];
|
|
988
|
-
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];
|
|
989
|
-
};
|
|
990
|
-
const o = i * 12;
|
|
991
|
-
const A = pr(o), B = pr(o + 3), C0 = pr(o + 6), C1 = pr(o + 9);
|
|
992
|
-
const dx = B[0] - A[0], dy = B[1] - A[1];
|
|
993
|
-
const s0 = dx * (C0[1] - A[1]) - dy * (C0[0] - A[0]), s1 = dx * (C1[1] - A[1]) - dy * (C1[0] - A[0]);
|
|
994
|
-
return s0 * s1 >= 0;
|
|
995
|
-
}
|
|
996
|
-
function createInstancedConditionalEdges(cond, im, material = condLineMat()) {
|
|
997
|
-
return condEdges(condBuffers(cond), im, material);
|
|
998
|
-
}
|
|
999
|
-
function condBuffers(cond) {
|
|
1000
|
-
const n = Math.floor(cond.length / 12);
|
|
1001
|
-
const buf = new Float32Array(n * 24), side = new Float32Array(n * 2);
|
|
1002
|
-
for (let l = 0;l < n; l++) {
|
|
1003
|
-
for (let k = 0;k < 12; k++) {
|
|
1004
|
-
const v = cond[l * 12 + k];
|
|
1005
|
-
buf[l * 24 + k] = v;
|
|
1006
|
-
buf[l * 24 + 12 + k] = v;
|
|
1007
|
-
}
|
|
1008
|
-
side[l * 2 + 1] = 1;
|
|
1009
|
-
}
|
|
1010
|
-
return { ib: new THREE.InterleavedBuffer(buf, 12), side: new THREE.BufferAttribute(side, 1) };
|
|
1011
|
-
}
|
|
1012
|
-
function condEdges({ ib, side }, im, material) {
|
|
1013
|
-
const g = new THREE.InstancedBufferGeometry;
|
|
1014
|
-
g.setAttribute("position", new THREE.InterleavedBufferAttribute(ib, 3, 0));
|
|
1015
|
-
g.setAttribute("ldrP1", new THREE.InterleavedBufferAttribute(ib, 3, 3));
|
|
1016
|
-
g.setAttribute("ldrC0", new THREE.InterleavedBufferAttribute(ib, 3, 6));
|
|
1017
|
-
g.setAttribute("ldrC1", new THREE.InterleavedBufferAttribute(ib, 3, 9));
|
|
1018
|
-
g.setAttribute("ldrSide", side);
|
|
1019
|
-
g.setAttribute("instanceMatrix", im.instanceMatrix);
|
|
1020
|
-
g.instanceCount = im.count;
|
|
1021
|
-
const l = new THREE.LineSegments(g, material);
|
|
1022
|
-
l.frustumCulled = false;
|
|
1023
|
-
l.name = "ldrCondLines";
|
|
1024
|
-
l.onBeforeRender = (_r, _s, cam, _g, mat) => {
|
|
1025
|
-
const u = mat.uniforms?.ldrViewProj;
|
|
1026
|
-
if (!u)
|
|
1027
|
-
return;
|
|
1028
|
-
l.modelViewMatrix.multiplyMatrices(cam.matrixWorldInverse, l.matrixWorld);
|
|
1029
|
-
u.value.multiplyMatrices(cam.projectionMatrix, l.modelViewMatrix);
|
|
1030
|
-
mat.uniformsNeedUpdate = true;
|
|
1031
|
-
};
|
|
1032
|
-
return l;
|
|
1033
|
-
}
|
|
1034
|
-
function sharedLines(pos, im, material = sharedLineMat()) {
|
|
1035
|
-
const { P, I } = weldLines(pos);
|
|
1036
|
-
const g = new THREE.InstancedBufferGeometry;
|
|
1037
|
-
g.setAttribute("position", new THREE.BufferAttribute(P, 3));
|
|
1038
|
-
g.setIndex(new THREE.BufferAttribute(I, 1));
|
|
1039
|
-
g.setAttribute("instanceMatrix", im.instanceMatrix);
|
|
1040
|
-
g.instanceCount = im.count;
|
|
1041
|
-
const l = new THREE.LineSegments(g, material);
|
|
1042
|
-
l.frustumCulled = false;
|
|
1043
|
-
return l;
|
|
1044
|
-
}
|
|
1045
|
-
function instancedLines(pos, mats, count) {
|
|
1046
|
-
const g = new THREE.InstancedBufferGeometry;
|
|
1047
|
-
g.setAttribute("position", new THREE.BufferAttribute(pos, 3));
|
|
1048
|
-
const ib = new THREE.InstancedInterleavedBuffer(mats, 16);
|
|
1049
|
-
for (let i = 0;i < 4; i++)
|
|
1050
|
-
g.setAttribute("im" + i, new THREE.InterleavedBufferAttribute(ib, 4, i * 4));
|
|
1051
|
-
g.instanceCount = count;
|
|
1052
|
-
const l = new THREE.LineSegments(g, lineMat());
|
|
1053
|
-
l.frustumCulled = false;
|
|
1054
|
-
return l;
|
|
1055
|
-
}
|
|
1056
|
-
function writeM4(t, o, m, mo = 0) {
|
|
1057
|
-
t[o] = m[mo + 3];
|
|
1058
|
-
t[o + 1] = m[mo + 6];
|
|
1059
|
-
t[o + 2] = m[mo + 9];
|
|
1060
|
-
t[o + 3] = 0;
|
|
1061
|
-
t[o + 4] = m[mo + 4];
|
|
1062
|
-
t[o + 5] = m[mo + 7];
|
|
1063
|
-
t[o + 6] = m[mo + 10];
|
|
1064
|
-
t[o + 7] = 0;
|
|
1065
|
-
t[o + 8] = m[mo + 5];
|
|
1066
|
-
t[o + 9] = m[mo + 8];
|
|
1067
|
-
t[o + 10] = m[mo + 11];
|
|
1068
|
-
t[o + 11] = 0;
|
|
1069
|
-
t[o + 12] = m[mo];
|
|
1070
|
-
t[o + 13] = m[mo + 1];
|
|
1071
|
-
t[o + 14] = m[mo + 2];
|
|
1072
|
-
t[o + 15] = 1;
|
|
1073
|
-
}
|
|
1074
|
-
function newIM(g, mat, n) {
|
|
1075
|
-
const im = new THREE.InstancedMesh(g, mat, 0);
|
|
1076
|
-
im.instanceMatrix = new THREE.InstancedBufferAttribute(new Float32Array(n * 16), 16);
|
|
1077
|
-
im.count = n;
|
|
1078
|
-
return im;
|
|
1079
|
-
}
|
|
1080
|
-
function fillInstances(im, ids, insts, color) {
|
|
1081
|
-
const M = im.instanceMatrix.array;
|
|
1082
|
-
const C = new Float32Array(ids.length * 3);
|
|
1083
|
-
for (let k = 0;k < ids.length; k++) {
|
|
1084
|
-
const it = insts[ids[k]];
|
|
1085
|
-
writeM4(M, k * 16, it.m);
|
|
1086
|
-
color(it.color).toArray(C, k * 3);
|
|
1087
|
-
}
|
|
1088
|
-
im.instanceColor = new THREE.InstancedBufferAttribute(C, 3);
|
|
1089
|
-
}
|
|
834
|
+
|
|
835
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/cull.ts
|
|
1090
836
|
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;
|
|
1091
837
|
var prepCache = new WeakMap;
|
|
1092
838
|
function prepPart(H, part) {
|
|
@@ -1132,76 +878,84 @@ function mul12To(a, b, bo, w, ao = 0) {
|
|
|
1132
878
|
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];
|
|
1133
879
|
}
|
|
1134
880
|
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]);
|
|
1135
|
-
var
|
|
1136
|
-
var topKey = (x, y, z) => {
|
|
1137
|
-
const rx = Math.round(x), ry = Math.round(y), rz = Math.round(z);
|
|
1138
|
-
return rx < -131072 || rx >= 131072 || ry < -65536 || ry >= 65536 || rz < -131072 || rz >= 131072 ? -1 : (rx + 131072) * 34359738368 + (ry + 65536) * 262144 + (rz + 131072);
|
|
1139
|
-
};
|
|
881
|
+
var BIG = 1073741824;
|
|
1140
882
|
|
|
1141
|
-
class
|
|
1142
|
-
|
|
883
|
+
class Int3Table {
|
|
884
|
+
a;
|
|
885
|
+
b;
|
|
886
|
+
c;
|
|
1143
887
|
vals;
|
|
888
|
+
used;
|
|
1144
889
|
mask;
|
|
1145
890
|
size = 0;
|
|
1146
891
|
constructor(cap = 1024) {
|
|
1147
892
|
let n = 1024;
|
|
1148
893
|
while (n < cap * 2)
|
|
1149
894
|
n *= 2;
|
|
1150
|
-
this.
|
|
895
|
+
this.a = new Int32Array(n);
|
|
896
|
+
this.b = new Int32Array(n);
|
|
897
|
+
this.c = new Int32Array(n);
|
|
1151
898
|
this.vals = new Int32Array(n);
|
|
899
|
+
this.used = new Uint8Array(n);
|
|
1152
900
|
this.mask = n - 1;
|
|
1153
901
|
}
|
|
1154
|
-
slot(
|
|
1155
|
-
|
|
1156
|
-
let h = Math.imul(lo ^ Math.imul(hi, 2654435761), 2246822507);
|
|
902
|
+
slot(x, y, z) {
|
|
903
|
+
let h = Math.imul(x, 2654435761) ^ Math.imul(y, 2246822507) ^ Math.imul(z, 3266489909);
|
|
1157
904
|
h ^= h >>> 15;
|
|
905
|
+
h = Math.imul(h, 739982445);
|
|
906
|
+
h ^= h >>> 12;
|
|
1158
907
|
return h & this.mask;
|
|
1159
908
|
}
|
|
1160
|
-
get(
|
|
1161
|
-
|
|
1162
|
-
|
|
909
|
+
get(x, y, z) {
|
|
910
|
+
let i = this.slot(x, y, z);
|
|
911
|
+
const U = this.used, A = this.a, B = this.b, C = this.c;
|
|
1163
912
|
for (;; ) {
|
|
1164
|
-
|
|
1165
|
-
if (x === k)
|
|
1166
|
-
return this.vals[i];
|
|
1167
|
-
if (x === -1)
|
|
913
|
+
if (!U[i])
|
|
1168
914
|
return -1;
|
|
915
|
+
if (A[i] === x && B[i] === y && C[i] === z)
|
|
916
|
+
return this.vals[i];
|
|
1169
917
|
i = i + 1 & this.mask;
|
|
1170
918
|
}
|
|
1171
919
|
}
|
|
1172
|
-
put(
|
|
1173
|
-
if ((this.size + 1) * 2 > this.
|
|
920
|
+
put(x, y, z, v) {
|
|
921
|
+
if ((this.size + 1) * 2 > this.used.length)
|
|
1174
922
|
this.grow();
|
|
1175
|
-
|
|
1176
|
-
|
|
923
|
+
let i = this.slot(x, y, z);
|
|
924
|
+
const U = this.used, A = this.a, B = this.b, C = this.c;
|
|
1177
925
|
for (;; ) {
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
}
|
|
1184
|
-
if (x === -1) {
|
|
1185
|
-
K[i] = k;
|
|
926
|
+
if (!U[i]) {
|
|
927
|
+
U[i] = 1;
|
|
928
|
+
A[i] = x;
|
|
929
|
+
B[i] = y;
|
|
930
|
+
C[i] = z;
|
|
1186
931
|
this.vals[i] = v;
|
|
1187
932
|
this.size++;
|
|
1188
933
|
return -1;
|
|
1189
934
|
}
|
|
935
|
+
if (A[i] === x && B[i] === y && C[i] === z) {
|
|
936
|
+
const o = this.vals[i];
|
|
937
|
+
this.vals[i] = v;
|
|
938
|
+
return o;
|
|
939
|
+
}
|
|
1190
940
|
i = i + 1 & this.mask;
|
|
1191
941
|
}
|
|
1192
942
|
}
|
|
1193
943
|
grow() {
|
|
1194
|
-
const
|
|
1195
|
-
const n =
|
|
1196
|
-
this.
|
|
944
|
+
const { a, b, c, vals, used } = this;
|
|
945
|
+
const n = used.length * 2;
|
|
946
|
+
this.a = new Int32Array(n);
|
|
947
|
+
this.b = new Int32Array(n);
|
|
948
|
+
this.c = new Int32Array(n);
|
|
1197
949
|
this.vals = new Int32Array(n);
|
|
950
|
+
this.used = new Uint8Array(n);
|
|
1198
951
|
this.mask = n - 1;
|
|
1199
952
|
this.size = 0;
|
|
1200
|
-
for (let i = 0;i <
|
|
1201
|
-
if (
|
|
1202
|
-
this.put(
|
|
953
|
+
for (let i = 0;i < used.length; i++)
|
|
954
|
+
if (used[i])
|
|
955
|
+
this.put(a[i], b[i], c[i], vals[i]);
|
|
1203
956
|
}
|
|
1204
957
|
}
|
|
958
|
+
var inRange = (x, y, z) => x > -BIG && x < BIG && y > -BIG && y < BIG && z > -BIG && z < BIG;
|
|
1205
959
|
var STEP_NEVER = 2147483647;
|
|
1206
960
|
function forEachStud(insts, H, fn) {
|
|
1207
961
|
const w = new Float64Array(12);
|
|
@@ -1221,7 +975,7 @@ function forEachStud(insts, H, fn) {
|
|
|
1221
975
|
function cullCore(insts, H, steps) {
|
|
1222
976
|
const CELL = 40;
|
|
1223
977
|
const rx0 = [], rx1 = [], rz0 = [], rz1 = [], rInst = [], rPrep = [], rBx = [], rBz = [];
|
|
1224
|
-
const cells = new
|
|
978
|
+
const cells = new Int3Table(insts.length * 2);
|
|
1225
979
|
const nextE = [], rectE = [];
|
|
1226
980
|
for (let idx = 0;idx < insts.length; idx++) {
|
|
1227
981
|
const it = insts[idx];
|
|
@@ -1256,21 +1010,27 @@ function cullCore(insts, H, steps) {
|
|
|
1256
1010
|
const lv2 = Math.round((m[1] + b[4]) * 2);
|
|
1257
1011
|
for (let cx = Math.floor(x0 / CELL);cx <= Math.floor(x1 / CELL); cx++)
|
|
1258
1012
|
for (let cz = Math.floor(z0 / CELL);cz <= Math.floor(z1 / CELL); cz++) {
|
|
1259
|
-
|
|
1260
|
-
if (k < 0)
|
|
1013
|
+
if (!inRange(lv2, cx, cz))
|
|
1261
1014
|
continue;
|
|
1262
1015
|
const e = rectE.length;
|
|
1263
1016
|
rectE.push(ri);
|
|
1264
|
-
nextE.push(cells.put(
|
|
1017
|
+
nextE.push(cells.put(lv2, cx, cz, e));
|
|
1265
1018
|
}
|
|
1266
1019
|
}
|
|
1267
1020
|
const SX = [0, 5, -5, 5, -5], SZ = [0, 5, 5, -5, -5];
|
|
1021
|
+
let kl = NaN, kx = NaN, kz = NaN, ke = -1;
|
|
1268
1022
|
const coverStep = (x, y, z, self) => {
|
|
1269
|
-
const
|
|
1270
|
-
if (
|
|
1023
|
+
const l2 = Math.round(y * 2), gx = Math.floor(x / CELL), gz = Math.floor(z / CELL);
|
|
1024
|
+
if (!inRange(l2, gx, gz))
|
|
1271
1025
|
return STEP_NEVER;
|
|
1272
1026
|
let best = STEP_NEVER;
|
|
1273
|
-
|
|
1027
|
+
if (l2 !== kl || gx !== kx || gz !== kz) {
|
|
1028
|
+
kl = l2;
|
|
1029
|
+
kx = gx;
|
|
1030
|
+
kz = gz;
|
|
1031
|
+
ke = cells.get(l2, gx, gz);
|
|
1032
|
+
}
|
|
1033
|
+
for (let e = ke;e >= 0; e = nextE[e]) {
|
|
1274
1034
|
const ri = rectE[e];
|
|
1275
1035
|
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))
|
|
1276
1036
|
continue;
|
|
@@ -1298,71 +1058,448 @@ function cullCore(insts, H, steps) {
|
|
|
1298
1058
|
}
|
|
1299
1059
|
return best;
|
|
1300
1060
|
};
|
|
1301
|
-
let nStuds = 0;
|
|
1302
|
-
for (const it of insts) {
|
|
1303
|
-
const pp = prepPart(H, it.part);
|
|
1304
|
-
if (pp)
|
|
1305
|
-
nStuds += pp.nStuds;
|
|
1061
|
+
let nStuds = 0;
|
|
1062
|
+
for (const it of insts) {
|
|
1063
|
+
const pp = prepPart(H, it.part);
|
|
1064
|
+
if (pp)
|
|
1065
|
+
nStuds += pp.nStuds;
|
|
1066
|
+
}
|
|
1067
|
+
const studHidden = new Uint8Array(nStuds), studUp = new Uint8Array(nStuds);
|
|
1068
|
+
const tops = new Int3Table(nStuds);
|
|
1069
|
+
let studsHidden = 0;
|
|
1070
|
+
const studHideStep = steps ? new Int32Array(nStuds).fill(STEP_NEVER) : undefined;
|
|
1071
|
+
for (let idx = 0, j = 0;idx < insts.length; idx++) {
|
|
1072
|
+
const it = insts[idx];
|
|
1073
|
+
const pp = prepPart(H, it.part);
|
|
1074
|
+
if (!pp)
|
|
1075
|
+
continue;
|
|
1076
|
+
const m = it.m, S = pp.studM;
|
|
1077
|
+
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];
|
|
1078
|
+
for (let s = 0;s < pp.nStuds; s++, j++) {
|
|
1079
|
+
const o = s * 12;
|
|
1080
|
+
const b4 = S[o + 4], b7 = S[o + 7], b10 = S[o + 10];
|
|
1081
|
+
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))
|
|
1082
|
+
continue;
|
|
1083
|
+
studUp[j] = 1;
|
|
1084
|
+
const b0 = S[o], b1 = S[o + 1], b2 = S[o + 2];
|
|
1085
|
+
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;
|
|
1086
|
+
const cs = coverStep(x, y, z, idx);
|
|
1087
|
+
if (cs !== STEP_NEVER) {
|
|
1088
|
+
studHidden[j] = 1;
|
|
1089
|
+
studsHidden++;
|
|
1090
|
+
if (studHideStep)
|
|
1091
|
+
studHideStep[j] = cs;
|
|
1092
|
+
}
|
|
1093
|
+
const rx = Math.round(x), ry = Math.round(y), rz = Math.round(z);
|
|
1094
|
+
if (!inRange(rx, ry, rz))
|
|
1095
|
+
continue;
|
|
1096
|
+
if (!steps) {
|
|
1097
|
+
tops.put(rx, ry, rz, 1);
|
|
1098
|
+
continue;
|
|
1099
|
+
}
|
|
1100
|
+
const st = steps[idx], t = tops.get(rx, ry, rz);
|
|
1101
|
+
if (t < 0 || st < t)
|
|
1102
|
+
tops.put(rx, ry, rz, st);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
const underHidden = new Uint8Array(insts.length);
|
|
1106
|
+
const underHideStep = steps ? new Int32Array(insts.length).fill(STEP_NEVER) : undefined;
|
|
1107
|
+
for (let idx = 0;idx < insts.length; idx++) {
|
|
1108
|
+
const it = insts[idx];
|
|
1109
|
+
const p = H.parts[it.part];
|
|
1110
|
+
if (!p || !p.under || !upright(it.m))
|
|
1111
|
+
continue;
|
|
1112
|
+
const b = p.bbox;
|
|
1113
|
+
const nx = Math.round((b[3] - b[0]) / 20), nz = Math.round((b[5] - b[2]) / 20);
|
|
1114
|
+
if (!nx || !nz || nx * nz > 4096)
|
|
1115
|
+
continue;
|
|
1116
|
+
const m = it.m;
|
|
1117
|
+
let all = true, at = 0;
|
|
1118
|
+
for (let a = 0;a < nx && all; a++)
|
|
1119
|
+
for (let c = 0;c < nz; c++) {
|
|
1120
|
+
const lx = b[0] + 10 + 20 * a, lz = b[2] + 10 + 20 * c;
|
|
1121
|
+
const x = m[0] + m[3] * lx + m[5] * lz, z = m[2] + m[9] * lx + m[11] * lz;
|
|
1122
|
+
const rx = Math.round(x), ry = Math.round(m[1] + b[4]), rz = Math.round(z);
|
|
1123
|
+
const t = inRange(rx, ry, rz) ? tops.get(rx, ry, rz) : -1;
|
|
1124
|
+
if (t < 0) {
|
|
1125
|
+
all = false;
|
|
1126
|
+
break;
|
|
1127
|
+
}
|
|
1128
|
+
if (t > at)
|
|
1129
|
+
at = t;
|
|
1130
|
+
}
|
|
1131
|
+
if (all) {
|
|
1132
|
+
underHidden[idx] = 1;
|
|
1133
|
+
if (underHideStep)
|
|
1134
|
+
underHideStep[idx] = at;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
return { nStuds, studHidden, studUp, underHidden, studsHidden, studHideStep, underHideStep };
|
|
1138
|
+
}
|
|
1139
|
+
function sceneInstances(instances, H, useTex) {
|
|
1140
|
+
const pick = (i) => useTex && i.texPart && H.parts[i.texPart] ? i.texPart : i.part;
|
|
1141
|
+
const all = instances.map((i) => ({ part: pick(i), color: String(i.color), m: i.m, steps: i.steps }));
|
|
1142
|
+
const keys = all.map((i) => i.steps.map((x) => String(x).padStart(6, "0")).join("."));
|
|
1143
|
+
const uniq = [...new Set(keys)].sort();
|
|
1144
|
+
const rank = new Map(uniq.map((k, j) => [k, j]));
|
|
1145
|
+
return { all, stepOf: keys.map((k) => rank.get(k)), nSteps: uniq.length };
|
|
1146
|
+
}
|
|
1147
|
+
function precomputeCull(instances, H, useTex = true) {
|
|
1148
|
+
const s = sceneInstances(instances, H, useTex);
|
|
1149
|
+
return cullCore(s.all, H, s.nSteps > 1 ? s.stepOf : undefined);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/render.ts
|
|
1153
|
+
async function loadPack(url) {
|
|
1154
|
+
const res = await fetch(url);
|
|
1155
|
+
if (!res.ok)
|
|
1156
|
+
throw new Error(`ldr: ${res.status} fetching ${url}`);
|
|
1157
|
+
return decodePack(await decompressPack(await res.arrayBuffer()));
|
|
1158
|
+
}
|
|
1159
|
+
var toI8 = (a) => {
|
|
1160
|
+
const o = new Int8Array(a.length);
|
|
1161
|
+
for (let i = 0;i < a.length; i++)
|
|
1162
|
+
o[i] = Math.round(Math.max(-1, Math.min(1, a[i])) * 127);
|
|
1163
|
+
return o;
|
|
1164
|
+
};
|
|
1165
|
+
var toU8 = (a) => {
|
|
1166
|
+
const o = new Uint8Array(a.length);
|
|
1167
|
+
for (let i = 0;i < a.length; i++)
|
|
1168
|
+
o[i] = Math.round(Math.max(0, Math.min(1, a[i])) * 255);
|
|
1169
|
+
return o;
|
|
1170
|
+
};
|
|
1171
|
+
function flatNormals(pos, idx) {
|
|
1172
|
+
const n = new Float32Array(pos.length);
|
|
1173
|
+
for (let t = 0;t < idx.length; t += 3) {
|
|
1174
|
+
const a = idx[t] * 3, b = idx[t + 1] * 3, c = idx[t + 2] * 3;
|
|
1175
|
+
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];
|
|
1176
|
+
let nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;
|
|
1177
|
+
const l = Math.hypot(nx, ny, nz) || 1;
|
|
1178
|
+
nx /= l;
|
|
1179
|
+
ny /= l;
|
|
1180
|
+
nz /= l;
|
|
1181
|
+
for (const o of [a, b, c]) {
|
|
1182
|
+
n[o] = nx;
|
|
1183
|
+
n[o + 1] = ny;
|
|
1184
|
+
n[o + 2] = nz;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
return n;
|
|
1188
|
+
}
|
|
1189
|
+
var geomCache = new WeakMap;
|
|
1190
|
+
function geom(b, arr) {
|
|
1191
|
+
if (!b)
|
|
1192
|
+
return null;
|
|
1193
|
+
let c = geomCache.get(arr);
|
|
1194
|
+
if (!c)
|
|
1195
|
+
geomCache.set(arr, c = new Map);
|
|
1196
|
+
let g = c.get(b);
|
|
1197
|
+
if (g)
|
|
1198
|
+
return g;
|
|
1199
|
+
g = new THREE.BufferGeometry;
|
|
1200
|
+
g.setAttribute("position", new THREE.BufferAttribute(arr(b.pos), 3));
|
|
1201
|
+
const nrm = b.nrm ? arr(b.nrm) : flatNormals(arr(b.pos), arr(b.idx));
|
|
1202
|
+
const col = arr(b.col);
|
|
1203
|
+
g.setAttribute("normal", new THREE.BufferAttribute(toI8(nrm), 3, true));
|
|
1204
|
+
g.setAttribute("ldrColor", new THREE.BufferAttribute(col instanceof Uint8Array ? col : toU8(col), 4, true));
|
|
1205
|
+
if (b.idx)
|
|
1206
|
+
g.setIndex(new THREE.BufferAttribute(arr(b.idx), 1));
|
|
1207
|
+
if (b.uv)
|
|
1208
|
+
g.setAttribute("ldrUV", new THREE.BufferAttribute(arr(b.uv), 2));
|
|
1209
|
+
c.set(b, g);
|
|
1210
|
+
return g;
|
|
1211
|
+
}
|
|
1212
|
+
function makeMaterial(side) {
|
|
1213
|
+
const m = new THREE.MeshStandardMaterial({ vertexColors: true, roughness: 0.45, side });
|
|
1214
|
+
m.onBeforeCompile = (s) => {
|
|
1215
|
+
s.vertexShader = `attribute vec4 ldrColor;
|
|
1216
|
+
` + s.vertexShader.replace("#include <color_vertex>", `#include <color_vertex>
|
|
1217
|
+
#ifdef USE_INSTANCING_COLOR
|
|
1218
|
+
vColor.rgb = ldrColor.a > 0.5 ? pow(ldrColor.rgb, vec3(2.2)) : instanceColor.rgb; // baked LDConfig colours are sRGB
|
|
1219
|
+
#else
|
|
1220
|
+
vColor.rgb = pow(ldrColor.rgb, vec3(2.2));
|
|
1221
|
+
#endif`);
|
|
1222
|
+
};
|
|
1223
|
+
m.customProgramCacheKey = () => "ldrColor";
|
|
1224
|
+
return m;
|
|
1225
|
+
}
|
|
1226
|
+
function makeTexturedMaterial(side, map, wrapU = false) {
|
|
1227
|
+
const m = makeMaterial(side);
|
|
1228
|
+
const base = m.onBeforeCompile;
|
|
1229
|
+
m.onBeforeCompile = (sh, r) => {
|
|
1230
|
+
base.call(m, sh, r);
|
|
1231
|
+
sh.uniforms.ldrMap = { value: map };
|
|
1232
|
+
sh.uniforms.ldrWrapU = { value: wrapU ? 1 : 0 };
|
|
1233
|
+
sh.vertexShader = `attribute vec2 ldrUV; varying vec2 vLdrUV;
|
|
1234
|
+
` + sh.vertexShader.replace("#include <uv_vertex>", `#include <uv_vertex>
|
|
1235
|
+
vLdrUV = ldrUV;`);
|
|
1236
|
+
sh.fragmentShader = `uniform sampler2D ldrMap; uniform int ldrWrapU; varying vec2 vLdrUV;
|
|
1237
|
+
` + sh.fragmentShader.replace("#include <color_fragment>", `#include <color_fragment>
|
|
1238
|
+
{ vec2 uv = vec2(ldrWrapU == 1 ? fract(vLdrUV.x) : vLdrUV.x, vLdrUV.y); vec4 t = texture2D(ldrMap, uv);
|
|
1239
|
+
float inside = step(0.0, uv.x) * step(uv.x, 1.0) * step(0.0, uv.y) * step(uv.y, 1.0);
|
|
1240
|
+
diffuseColor.rgb = mix(diffuseColor.rgb, t.rgb, t.a * inside); }`);
|
|
1241
|
+
};
|
|
1242
|
+
m.customProgramCacheKey = () => "ldrColorTex";
|
|
1243
|
+
m.userData.ldrMap = map;
|
|
1244
|
+
return m;
|
|
1245
|
+
}
|
|
1246
|
+
function packTexture(pack, i) {
|
|
1247
|
+
const t = new THREE.Texture;
|
|
1248
|
+
t.flipY = false;
|
|
1249
|
+
t.colorSpace = THREE.SRGBColorSpace;
|
|
1250
|
+
t.wrapS = t.wrapT = THREE.ClampToEdgeWrapping;
|
|
1251
|
+
const e = pack.header.textures?.[i];
|
|
1252
|
+
const bytes = e?.data ? pack.arr(e.data) : null;
|
|
1253
|
+
if (!bytes || typeof createImageBitmap === "undefined")
|
|
1254
|
+
return { texture: t, ready: Promise.resolve() };
|
|
1255
|
+
const ready = createImageBitmap(new Blob([bytes], { type: e.mime || "image/png" }), { premultiplyAlpha: "none", colorSpaceConversion: "none" }).then((img) => {
|
|
1256
|
+
t.image = img;
|
|
1257
|
+
t.needsUpdate = true;
|
|
1258
|
+
}).catch(() => {});
|
|
1259
|
+
return { texture: t, ready };
|
|
1260
|
+
}
|
|
1261
|
+
var sharedLineMat = () => new THREE.ShaderMaterial({
|
|
1262
|
+
vertexShader: `attribute mat4 instanceMatrix; void main(){ gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position,1.0); }`,
|
|
1263
|
+
fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
|
|
1264
|
+
});
|
|
1265
|
+
var weldLines = (pos, byLength = false) => {
|
|
1266
|
+
const map = new Map;
|
|
1267
|
+
const P = [];
|
|
1268
|
+
const I = [];
|
|
1269
|
+
const n = Math.floor(pos.length / 6);
|
|
1270
|
+
const len = new Float32Array(n);
|
|
1271
|
+
for (let s = 0;s < n; s++) {
|
|
1272
|
+
const o = s * 6;
|
|
1273
|
+
len[s] = Math.hypot(pos[o + 3] - pos[o], pos[o + 4] - pos[o + 1], pos[o + 5] - pos[o + 2]);
|
|
1274
|
+
}
|
|
1275
|
+
const order = Array.from({ length: n }, (_, s) => s);
|
|
1276
|
+
if (byLength)
|
|
1277
|
+
order.sort((a, b) => len[b] - len[a]);
|
|
1278
|
+
for (const sg of order)
|
|
1279
|
+
for (let e = 0;e < 2; e++) {
|
|
1280
|
+
const i = sg * 6 + e * 3;
|
|
1281
|
+
const k = pos[i].toFixed(2) + "," + pos[i + 1].toFixed(2) + "," + pos[i + 2].toFixed(2);
|
|
1282
|
+
let j = map.get(k);
|
|
1283
|
+
if (j === undefined) {
|
|
1284
|
+
j = P.length / 3;
|
|
1285
|
+
map.set(k, j);
|
|
1286
|
+
P.push(pos[i], pos[i + 1], pos[i + 2]);
|
|
1287
|
+
}
|
|
1288
|
+
I.push(j);
|
|
1289
|
+
}
|
|
1290
|
+
return { P: new Float32Array(P), I: P.length / 3 < 65536 ? new Uint16Array(I) : new Uint32Array(I), lens: Float32Array.from(order, (sg) => len[sg]) };
|
|
1291
|
+
};
|
|
1292
|
+
function createInstancedEdges(pos, im, material = sharedLineMat()) {
|
|
1293
|
+
return sharedLines(pos, im, material);
|
|
1294
|
+
}
|
|
1295
|
+
function conditionalLines(pack, entry, which = "all") {
|
|
1296
|
+
if (which === "all") {
|
|
1297
|
+
const a = conditionalLines(pack, entry, "body"), b = conditionalLines(pack, entry, "under");
|
|
1298
|
+
if (!a || !b)
|
|
1299
|
+
return a ?? b;
|
|
1300
|
+
const o = new Float32Array(a.length + b.length);
|
|
1301
|
+
o.set(a);
|
|
1302
|
+
o.set(b, a.length);
|
|
1303
|
+
return o;
|
|
1304
|
+
}
|
|
1305
|
+
const c = which === "under" ? entry?.condlu : entry?.condl;
|
|
1306
|
+
if (!c)
|
|
1307
|
+
return null;
|
|
1308
|
+
const { arr } = pack;
|
|
1309
|
+
if (c.raw)
|
|
1310
|
+
return arr(c.raw);
|
|
1311
|
+
const pools = [entry.body ? arr(entry.body.pos) : [], entry.under ? arr(entry.under.pos) : [], entry.edges ? arr(entry.edges) : [], c.x ? arr(c.x) : []];
|
|
1312
|
+
const idx = arr(c.idx);
|
|
1313
|
+
const out = new Float32Array(idx.length * 3);
|
|
1314
|
+
const starts = [];
|
|
1315
|
+
let base = 0;
|
|
1316
|
+
for (const p of pools) {
|
|
1317
|
+
starts.push(base);
|
|
1318
|
+
base += p.length / 3;
|
|
1319
|
+
}
|
|
1320
|
+
let prev = 0;
|
|
1321
|
+
for (let i = 0;i < idx.length; i++) {
|
|
1322
|
+
const z = idx[i];
|
|
1323
|
+
const j = prev + (z & 1 ? -(z + 1) / 2 : z / 2);
|
|
1324
|
+
prev = j;
|
|
1325
|
+
let k = 3;
|
|
1326
|
+
while (k > 0 && j < starts[k])
|
|
1327
|
+
k--;
|
|
1328
|
+
const p = pools[k], o = (j - starts[k]) * 3;
|
|
1329
|
+
out[i * 3] = p[o];
|
|
1330
|
+
out[i * 3 + 1] = p[o + 1];
|
|
1331
|
+
out[i * 3 + 2] = p[o + 2];
|
|
1332
|
+
}
|
|
1333
|
+
return out;
|
|
1334
|
+
}
|
|
1335
|
+
var condLineMat = () => new THREE.ShaderMaterial({
|
|
1336
|
+
uniforms: { ldrViewProj: { value: new THREE.Matrix4 } },
|
|
1337
|
+
vertexShader: `uniform mat4 ldrViewProj; attribute mat4 instanceMatrix; attribute vec3 ldrP1; attribute vec3 ldrC0; attribute vec3 ldrC1; attribute float ldrSide;
|
|
1338
|
+
void main(){
|
|
1339
|
+
mat4 mvp = ldrViewProj * instanceMatrix;
|
|
1340
|
+
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);
|
|
1341
|
+
vec2 A = a.xy / a.w, B = b.xy / b.w, C0 = c0.xy / c0.w, C1 = c1.xy / c1.w, d = B - A;
|
|
1342
|
+
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);
|
|
1343
|
+
gl_Position = s0 * s1 >= 0.0 ? (ldrSide > 0.5 ? b : a) : vec4(2.0, 2.0, 2.0, 1.0);
|
|
1344
|
+
}`,
|
|
1345
|
+
fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
|
|
1346
|
+
});
|
|
1347
|
+
function conditionalLineVisible(cond, i, mvp) {
|
|
1348
|
+
const e = mvp.elements;
|
|
1349
|
+
const pr = (o) => {
|
|
1350
|
+
const x = cond[o], y = cond[o + 1], z = cond[o + 2];
|
|
1351
|
+
const w = e[3] * x + e[7] * y + e[11] * z + e[15];
|
|
1352
|
+
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];
|
|
1353
|
+
};
|
|
1354
|
+
const o = i * 12;
|
|
1355
|
+
const A = pr(o), B = pr(o + 3), C0 = pr(o + 6), C1 = pr(o + 9);
|
|
1356
|
+
const dx = B[0] - A[0], dy = B[1] - A[1];
|
|
1357
|
+
const s0 = dx * (C0[1] - A[1]) - dy * (C0[0] - A[0]), s1 = dx * (C1[1] - A[1]) - dy * (C1[0] - A[0]);
|
|
1358
|
+
return s0 * s1 >= 0;
|
|
1359
|
+
}
|
|
1360
|
+
function createInstancedConditionalEdges(cond, im, material = condLineMat()) {
|
|
1361
|
+
return condEdges(condBuffers(cond), im, material);
|
|
1362
|
+
}
|
|
1363
|
+
function condBuffers(cond) {
|
|
1364
|
+
const n = Math.floor(cond.length / 12);
|
|
1365
|
+
const buf = new Float32Array(n * 24), side = new Float32Array(n * 2);
|
|
1366
|
+
for (let l = 0;l < n; l++) {
|
|
1367
|
+
for (let k = 0;k < 12; k++) {
|
|
1368
|
+
const v = cond[l * 12 + k];
|
|
1369
|
+
buf[l * 24 + k] = v;
|
|
1370
|
+
buf[l * 24 + 12 + k] = v;
|
|
1371
|
+
}
|
|
1372
|
+
side[l * 2 + 1] = 1;
|
|
1306
1373
|
}
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
const
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
const
|
|
1323
|
-
if (
|
|
1374
|
+
return { ib: new THREE.InterleavedBuffer(buf, 12), side: new THREE.BufferAttribute(side, 1) };
|
|
1375
|
+
}
|
|
1376
|
+
function condEdges({ ib, side }, im, material) {
|
|
1377
|
+
const g = new THREE.InstancedBufferGeometry;
|
|
1378
|
+
g.setAttribute("position", new THREE.InterleavedBufferAttribute(ib, 3, 0));
|
|
1379
|
+
g.setAttribute("ldrP1", new THREE.InterleavedBufferAttribute(ib, 3, 3));
|
|
1380
|
+
g.setAttribute("ldrC0", new THREE.InterleavedBufferAttribute(ib, 3, 6));
|
|
1381
|
+
g.setAttribute("ldrC1", new THREE.InterleavedBufferAttribute(ib, 3, 9));
|
|
1382
|
+
g.setAttribute("ldrSide", side);
|
|
1383
|
+
g.setAttribute("instanceMatrix", im.instanceMatrix);
|
|
1384
|
+
g.instanceCount = im.count;
|
|
1385
|
+
const l = new THREE.LineSegments(g, material);
|
|
1386
|
+
l.frustumCulled = false;
|
|
1387
|
+
l.name = "ldrCondLines";
|
|
1388
|
+
l.onBeforeRender = (_r, _s, cam, _g, mat) => {
|
|
1389
|
+
const u = mat.uniforms?.ldrViewProj;
|
|
1390
|
+
if (!u)
|
|
1324
1391
|
return;
|
|
1325
|
-
|
|
1326
|
-
|
|
1392
|
+
l.modelViewMatrix.multiplyMatrices(cam.matrixWorldInverse, l.matrixWorld);
|
|
1393
|
+
u.value.multiplyMatrices(cam.projectionMatrix, l.modelViewMatrix);
|
|
1394
|
+
mat.uniformsNeedUpdate = true;
|
|
1395
|
+
};
|
|
1396
|
+
return l;
|
|
1397
|
+
}
|
|
1398
|
+
function sharedLines(pos, im, material = sharedLineMat()) {
|
|
1399
|
+
const { P, I } = weldLines(pos);
|
|
1400
|
+
const g = new THREE.InstancedBufferGeometry;
|
|
1401
|
+
g.setAttribute("position", new THREE.BufferAttribute(P, 3));
|
|
1402
|
+
g.setIndex(new THREE.BufferAttribute(I, 1));
|
|
1403
|
+
g.setAttribute("instanceMatrix", im.instanceMatrix);
|
|
1404
|
+
g.instanceCount = im.count;
|
|
1405
|
+
const l = new THREE.LineSegments(g, material);
|
|
1406
|
+
l.frustumCulled = false;
|
|
1407
|
+
return l;
|
|
1408
|
+
}
|
|
1409
|
+
function writeM4(t, o, m, mo = 0) {
|
|
1410
|
+
t[o] = m[mo + 3];
|
|
1411
|
+
t[o + 1] = m[mo + 6];
|
|
1412
|
+
t[o + 2] = m[mo + 9];
|
|
1413
|
+
t[o + 3] = 0;
|
|
1414
|
+
t[o + 4] = m[mo + 4];
|
|
1415
|
+
t[o + 5] = m[mo + 7];
|
|
1416
|
+
t[o + 6] = m[mo + 10];
|
|
1417
|
+
t[o + 7] = 0;
|
|
1418
|
+
t[o + 8] = m[mo + 5];
|
|
1419
|
+
t[o + 9] = m[mo + 8];
|
|
1420
|
+
t[o + 10] = m[mo + 11];
|
|
1421
|
+
t[o + 11] = 0;
|
|
1422
|
+
t[o + 12] = m[mo];
|
|
1423
|
+
t[o + 13] = m[mo + 1];
|
|
1424
|
+
t[o + 14] = m[mo + 2];
|
|
1425
|
+
t[o + 15] = 1;
|
|
1426
|
+
}
|
|
1427
|
+
function newIM(g, mat, n) {
|
|
1428
|
+
const im = new THREE.InstancedMesh(g, mat, 0);
|
|
1429
|
+
im.instanceMatrix = new THREE.InstancedBufferAttribute(new Float32Array(n * 16), 16);
|
|
1430
|
+
im.count = n;
|
|
1431
|
+
return im;
|
|
1432
|
+
}
|
|
1433
|
+
function instancedBoundingSphere(im) {
|
|
1434
|
+
const g = im.geometry;
|
|
1435
|
+
if (!g.boundingSphere)
|
|
1436
|
+
g.computeBoundingSphere();
|
|
1437
|
+
const gs = g.boundingSphere;
|
|
1438
|
+
const gx = gs.center.x, gy = gs.center.y, gz = gs.center.z, gr = gs.radius;
|
|
1439
|
+
const A = im.instanceMatrix.array;
|
|
1440
|
+
let cx = 0, cy = 0, cz = 0, r = -1;
|
|
1441
|
+
const expand = (px, py, pz) => {
|
|
1442
|
+
if (r < 0) {
|
|
1443
|
+
cx = px;
|
|
1444
|
+
cy = py;
|
|
1445
|
+
cz = pz;
|
|
1446
|
+
r = 0;
|
|
1327
1447
|
return;
|
|
1328
1448
|
}
|
|
1329
|
-
const
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1449
|
+
const vx = px - cx, vy = py - cy, vz = pz - cz;
|
|
1450
|
+
const l2 = vx * vx + vy * vy + vz * vz;
|
|
1451
|
+
if (l2 > r * r) {
|
|
1452
|
+
const l = Math.sqrt(l2);
|
|
1453
|
+
const d = (l - r) * 0.5;
|
|
1454
|
+
const f = d / l;
|
|
1455
|
+
cx += vx * f;
|
|
1456
|
+
cy += vy * f;
|
|
1457
|
+
cz += vz * f;
|
|
1458
|
+
r += d;
|
|
1459
|
+
}
|
|
1460
|
+
};
|
|
1461
|
+
for (let i = 0, n = im.count;i < n; i++) {
|
|
1462
|
+
const o = i * 16;
|
|
1463
|
+
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];
|
|
1464
|
+
const w = 1 / (e3 * gx + e7 * gy + e11 * gz + A[o + 15]);
|
|
1465
|
+
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;
|
|
1466
|
+
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));
|
|
1467
|
+
if (r < 0) {
|
|
1468
|
+
cx = x;
|
|
1469
|
+
cy = y;
|
|
1470
|
+
cz = z;
|
|
1471
|
+
r = sr;
|
|
1339
1472
|
continue;
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1473
|
+
}
|
|
1474
|
+
if (x === cx && y === cy && z === cz) {
|
|
1475
|
+
r = Math.max(r, sr);
|
|
1343
1476
|
continue;
|
|
1344
|
-
const m = it.m;
|
|
1345
|
-
let all = true, at = 0;
|
|
1346
|
-
for (let a = 0;a < nx && all; a++)
|
|
1347
|
-
for (let c = 0;c < nz; c++) {
|
|
1348
|
-
const lx = b[0] + 10 + 20 * a, lz = b[2] + 10 + 20 * c;
|
|
1349
|
-
const x = m[0] + m[3] * lx + m[5] * lz, z = m[2] + m[9] * lx + m[11] * lz;
|
|
1350
|
-
const k = topKey(x, m[1] + b[4], z);
|
|
1351
|
-
const t = k < 0 ? -1 : tops.get(k);
|
|
1352
|
-
if (t < 0) {
|
|
1353
|
-
all = false;
|
|
1354
|
-
break;
|
|
1355
|
-
}
|
|
1356
|
-
if (t > at)
|
|
1357
|
-
at = t;
|
|
1358
|
-
}
|
|
1359
|
-
if (all) {
|
|
1360
|
-
underHidden[idx] = 1;
|
|
1361
|
-
if (underHideStep)
|
|
1362
|
-
underHideStep[idx] = at;
|
|
1363
1477
|
}
|
|
1478
|
+
let dx = x - cx, dy = y - cy, dz = z - cz;
|
|
1479
|
+
const inv = 1 / (Math.sqrt(dx * dx + dy * dy + dz * dz) || 1);
|
|
1480
|
+
dx = dx * inv * sr;
|
|
1481
|
+
dy = dy * inv * sr;
|
|
1482
|
+
dz = dz * inv * sr;
|
|
1483
|
+
expand(x + dx, y + dy, z + dz);
|
|
1484
|
+
expand(x - dx, y - dy, z - dz);
|
|
1485
|
+
}
|
|
1486
|
+
const sph = im.boundingSphere ?? new THREE.Sphere;
|
|
1487
|
+
sph.center.set(cx, cy, cz);
|
|
1488
|
+
sph.radius = r;
|
|
1489
|
+
if (r < 0)
|
|
1490
|
+
sph.makeEmpty();
|
|
1491
|
+
im.boundingSphere = sph;
|
|
1492
|
+
return sph;
|
|
1493
|
+
}
|
|
1494
|
+
function fillInstances(im, ids, insts, color) {
|
|
1495
|
+
const M = im.instanceMatrix.array;
|
|
1496
|
+
const C = new Float32Array(ids.length * 3);
|
|
1497
|
+
for (let k = 0;k < ids.length; k++) {
|
|
1498
|
+
const it = insts[ids[k]];
|
|
1499
|
+
writeM4(M, k * 16, it.m);
|
|
1500
|
+
color(it.color).toArray(C, k * 3);
|
|
1364
1501
|
}
|
|
1365
|
-
|
|
1502
|
+
im.instanceColor = new THREE.InstancedBufferAttribute(C, 3);
|
|
1366
1503
|
}
|
|
1367
1504
|
function computeCulling(insts, H) {
|
|
1368
1505
|
const c = cullCore(insts, H);
|
|
@@ -1418,7 +1555,8 @@ class LdrLodRoot extends THREE.LOD {
|
|
|
1418
1555
|
clusters = [];
|
|
1419
1556
|
vpH = 1080;
|
|
1420
1557
|
px = 0.5;
|
|
1421
|
-
edgePpl = 0.
|
|
1558
|
+
edgePpl = 0.5 / 20;
|
|
1559
|
+
edgeMinPx = 0.15;
|
|
1422
1560
|
enabled = true;
|
|
1423
1561
|
apply = () => {};
|
|
1424
1562
|
inv = new THREE.Matrix4;
|
|
@@ -1448,37 +1586,90 @@ class LdrLodRoot extends THREE.LOD {
|
|
|
1448
1586
|
L = i;
|
|
1449
1587
|
break;
|
|
1450
1588
|
}
|
|
1589
|
+
if (c.below !== undefined && x * c.ax[0] + y * c.ax[1] + z * c.ax[2] < c.below - 1 && ppl * 20 < 4)
|
|
1590
|
+
L = -1;
|
|
1591
|
+
if (c.boxErr !== undefined && c.boxErr * ppl <= tau)
|
|
1592
|
+
L = -1;
|
|
1451
1593
|
const e = ppl >= eppl;
|
|
1452
1594
|
if (L !== c.cur || e !== c.edgeOk) {
|
|
1453
1595
|
c.cur = L;
|
|
1454
1596
|
c.edgeOk = e;
|
|
1455
1597
|
this.apply(c);
|
|
1456
1598
|
}
|
|
1599
|
+
if (e && c.lines.length) {
|
|
1600
|
+
const minLen = this.edgeMinPx / ppl;
|
|
1601
|
+
for (const l of c.lines) {
|
|
1602
|
+
const lens = l.userData.ldrLens;
|
|
1603
|
+
if (!lens)
|
|
1604
|
+
continue;
|
|
1605
|
+
let lo = 0, hi = lens.length;
|
|
1606
|
+
while (lo < hi) {
|
|
1607
|
+
const mid = lo + hi >> 1;
|
|
1608
|
+
if (lens[mid] >= minLen)
|
|
1609
|
+
lo = mid + 1;
|
|
1610
|
+
else
|
|
1611
|
+
hi = mid;
|
|
1612
|
+
}
|
|
1613
|
+
l.geometry.drawRange.count = lo * 2;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1457
1616
|
}
|
|
1458
1617
|
}
|
|
1459
1618
|
}
|
|
1460
|
-
function buildStudMeshes(insts, H, cull, arr,
|
|
1619
|
+
function buildStudMeshes(insts, H, cull, arr, LOD, color, matF, matB, steps, colorIndex) {
|
|
1461
1620
|
const bucketOf = new Map;
|
|
1462
1621
|
const bKind = [], bMirror = [];
|
|
1463
1622
|
const bAll = [];
|
|
1464
1623
|
const studBucket = new Uint16Array(cull.nStuds);
|
|
1465
1624
|
const sx = new Float32Array(cull.nStuds), sz = new Float32Array(cull.nStuds);
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1625
|
+
const kindIds = new Map;
|
|
1626
|
+
const kindNames = [];
|
|
1627
|
+
const bucketOfKM = [];
|
|
1628
|
+
const partStud = new Map;
|
|
1629
|
+
for (let idx = 0, j = 0;idx < insts.length; idx++) {
|
|
1630
|
+
const it = insts[idx];
|
|
1631
|
+
const pp = prepPart(H, it.part);
|
|
1632
|
+
if (!pp || !pp.nStuds)
|
|
1633
|
+
continue;
|
|
1634
|
+
const a = it.m;
|
|
1635
|
+
let ps = partStud.get(pp);
|
|
1636
|
+
if (!ps) {
|
|
1637
|
+
const kid = new Int32Array(pp.nStuds), neg = new Uint8Array(pp.nStuds);
|
|
1638
|
+
for (let si = 0;si < pp.nStuds; si++) {
|
|
1639
|
+
const kn = pp.kind[si];
|
|
1640
|
+
let id = kindIds.get(kn);
|
|
1641
|
+
if (id === undefined) {
|
|
1642
|
+
id = kindNames.length;
|
|
1643
|
+
kindIds.set(kn, id);
|
|
1644
|
+
kindNames.push(kn);
|
|
1645
|
+
}
|
|
1646
|
+
kid[si] = id;
|
|
1647
|
+
neg[si] = det12(pp.studM.subarray(si * 12, si * 12 + 12)) < 0 ? 1 : 0;
|
|
1648
|
+
}
|
|
1649
|
+
partStud.set(pp, ps = { kid, neg });
|
|
1650
|
+
}
|
|
1651
|
+
const instNeg = det12(a) < 0 ? 1 : 0;
|
|
1652
|
+
const B = pp.studM;
|
|
1653
|
+
for (let si = 0;si < pp.nStuds; si++, j++) {
|
|
1654
|
+
const o = si * 12, b0 = B[o], b1 = B[o + 1], b2 = B[o + 2];
|
|
1655
|
+
const neg = (instNeg ^ ps.neg[si]) === 1;
|
|
1656
|
+
const km = ps.kid[si] * 2 + (neg ? 1 : 0);
|
|
1657
|
+
let b = bucketOfKM[km];
|
|
1658
|
+
if (b === undefined) {
|
|
1659
|
+
const kn = kindNames[ps.kid[si]];
|
|
1660
|
+
b = bKind.length;
|
|
1661
|
+
bucketOfKM[km] = b;
|
|
1662
|
+
bucketOf.set(neg ? kn + "#m" : kn, b);
|
|
1663
|
+
bKind.push(kn);
|
|
1664
|
+
bMirror.push(neg);
|
|
1665
|
+
bAll.push(0);
|
|
1666
|
+
}
|
|
1667
|
+
studBucket[j] = b;
|
|
1668
|
+
bAll[b]++;
|
|
1669
|
+
sx[j] = a[0] + a[3] * b0 + a[4] * b1 + a[5] * b2;
|
|
1670
|
+
sz[j] = a[2] + a[9] * b0 + a[10] * b1 + a[11] * b2;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1482
1673
|
const bIds = bAll.map((n) => new Int32Array(n));
|
|
1483
1674
|
{
|
|
1484
1675
|
const f = bAll.map(() => 0);
|
|
@@ -1490,7 +1681,7 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
|
|
|
1490
1681
|
const studCl = new Int32Array(cull.nStuds), studSlot = new Int32Array(cull.nStuds);
|
|
1491
1682
|
const sMesh = [];
|
|
1492
1683
|
bKind.forEach((kind, b) => {
|
|
1493
|
-
const g = geom(H.studKinds[kind].body, arr
|
|
1684
|
+
const g = geom(H.studKinds[kind].body, arr);
|
|
1494
1685
|
const ids = bIds[b];
|
|
1495
1686
|
for (const c of gridClusters(ids.length, (i) => sx[ids[i]], (i) => sz[ids[i]], LOD ? 16384 : Infinity)) {
|
|
1496
1687
|
const ci = sMesh.length;
|
|
@@ -1514,6 +1705,13 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
|
|
|
1514
1705
|
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) } } : {} });
|
|
1515
1706
|
}
|
|
1516
1707
|
});
|
|
1708
|
+
const colCache = new Map;
|
|
1709
|
+
const colorOf = (c) => {
|
|
1710
|
+
let x = colCache.get(c);
|
|
1711
|
+
if (!x)
|
|
1712
|
+
colCache.set(c, x = color(c));
|
|
1713
|
+
return x;
|
|
1714
|
+
};
|
|
1517
1715
|
forEachStud(insts, H, (j, owner, w, _kind, col, si) => {
|
|
1518
1716
|
const sm = sMesh[studCl[j]];
|
|
1519
1717
|
if (!sm)
|
|
@@ -1529,18 +1727,46 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
|
|
|
1529
1727
|
t.col[slot] = colorIndex(col);
|
|
1530
1728
|
}
|
|
1531
1729
|
writeM4(im.instanceMatrix.array, slot * 16, w);
|
|
1532
|
-
|
|
1730
|
+
colorOf(col).toArray(im.instanceColor.array, slot * 3);
|
|
1533
1731
|
});
|
|
1534
1732
|
return sMesh;
|
|
1535
1733
|
}
|
|
1734
|
+
function undersideGroups(ids, insts) {
|
|
1735
|
+
const by = new Map;
|
|
1736
|
+
const rest = [];
|
|
1737
|
+
for (const id of ids) {
|
|
1738
|
+
const m = insts[id].m;
|
|
1739
|
+
const l = Math.hypot(m[4], m[7], m[10]);
|
|
1740
|
+
if (!(l > 0.000001)) {
|
|
1741
|
+
rest.push(id);
|
|
1742
|
+
continue;
|
|
1743
|
+
}
|
|
1744
|
+
const ax = [m[4] / l, m[7] / l, m[10] / l, l];
|
|
1745
|
+
const k = ax.map((v) => Math.round(v * 1000)).join();
|
|
1746
|
+
let g = by.get(k);
|
|
1747
|
+
if (!g) {
|
|
1748
|
+
if (by.size >= 12) {
|
|
1749
|
+
rest.push(id);
|
|
1750
|
+
continue;
|
|
1751
|
+
}
|
|
1752
|
+
by.set(k, g = { ids: [], ax });
|
|
1753
|
+
}
|
|
1754
|
+
g.ids.push(id);
|
|
1755
|
+
}
|
|
1756
|
+
const out = [...by.values()];
|
|
1757
|
+
if (rest.length)
|
|
1758
|
+
out.push({ ids: rest, ax: null });
|
|
1759
|
+
return out;
|
|
1760
|
+
}
|
|
1536
1761
|
function buildLdrScene(insts, pack, P, color, mark) {
|
|
1537
1762
|
const { header: H, arr } = pack;
|
|
1538
|
-
const Q = P.quant !== false;
|
|
1539
1763
|
const LOD = P.lod !== false;
|
|
1764
|
+
const EDGES = !!P.edges;
|
|
1540
1765
|
const root = new LdrLodRoot;
|
|
1541
1766
|
root.enabled = LOD;
|
|
1542
1767
|
root.px = P.lodPx ?? 0.5;
|
|
1543
1768
|
root.edgePpl = (P.lodEdgePx ?? 0.5) / 20;
|
|
1769
|
+
root.edgeMinPx = P.lodEdgeMinPx ?? 0.15;
|
|
1544
1770
|
const trackVp = (r) => {
|
|
1545
1771
|
const rt = r.getRenderTarget();
|
|
1546
1772
|
const h = rt ? rt.height : r.getContext().drawingBufferHeight;
|
|
@@ -1558,7 +1784,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1558
1784
|
}
|
|
1559
1785
|
});
|
|
1560
1786
|
const steps = P.steps;
|
|
1561
|
-
let cull = cullCore(insts, H, steps);
|
|
1787
|
+
let cull = P.cull ?? cullCore(insts, H, steps);
|
|
1562
1788
|
mark("culling");
|
|
1563
1789
|
const stepBatches = [];
|
|
1564
1790
|
const instM = steps ? new Float64Array(insts.length * 12) : null;
|
|
@@ -1584,7 +1810,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1584
1810
|
});
|
|
1585
1811
|
const edgeObjs = [];
|
|
1586
1812
|
const condObjs = [];
|
|
1587
|
-
const wantCond = P.cond !== false &&
|
|
1813
|
+
const wantCond = P.cond !== false && EDGES;
|
|
1588
1814
|
let condMat = null;
|
|
1589
1815
|
const cmat = () => condMat ??= condLineMat();
|
|
1590
1816
|
let lineMatShared = null;
|
|
@@ -1615,8 +1841,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1615
1841
|
const addLines = (ref, im, cl) => {
|
|
1616
1842
|
let w = lineCache.get(ref);
|
|
1617
1843
|
if (!w) {
|
|
1618
|
-
const r = weldLines(arr(ref));
|
|
1619
|
-
lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1) });
|
|
1844
|
+
const r = weldLines(arr(ref), LOD);
|
|
1845
|
+
lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1), lens: r.lens });
|
|
1620
1846
|
}
|
|
1621
1847
|
const g = new THREE.InstancedBufferGeometry;
|
|
1622
1848
|
g.setAttribute("position", w.P);
|
|
@@ -1625,6 +1851,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1625
1851
|
g.instanceCount = im.count;
|
|
1626
1852
|
const l = new THREE.LineSegments(g, lmat());
|
|
1627
1853
|
l.frustumCulled = false;
|
|
1854
|
+
if (LOD)
|
|
1855
|
+
l.userData.ldrLens = w.lens;
|
|
1628
1856
|
edgeObjs.push(l);
|
|
1629
1857
|
cl.lines.push(l);
|
|
1630
1858
|
root.add(l);
|
|
@@ -1632,7 +1860,6 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1632
1860
|
};
|
|
1633
1861
|
const stats = { studsTotal: cull.nStuds, studsHidden: cull.studsHidden, undersTotal: 0, undersHidden: 0 };
|
|
1634
1862
|
const toggles = [];
|
|
1635
|
-
const studMeshes = [];
|
|
1636
1863
|
const countTo = (objs) => ({ set count(n) {
|
|
1637
1864
|
for (const o of objs()) {
|
|
1638
1865
|
if (o.isInstancedMesh)
|
|
@@ -1667,8 +1894,9 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1667
1894
|
root.clusters.push(c);
|
|
1668
1895
|
return c;
|
|
1669
1896
|
};
|
|
1670
|
-
const lodLevels = (b, base, mat) => !LOD ||
|
|
1671
|
-
const im = new THREE.InstancedMesh(geom(l, arr
|
|
1897
|
+
const lodLevels = (b, base, mat) => !LOD || !b?.lod ? [] : b.lod.map((l) => {
|
|
1898
|
+
const im = new THREE.InstancedMesh(geom(l, arr), mat, 0);
|
|
1899
|
+
im.userData = { ...base.userData };
|
|
1672
1900
|
im.instanceMatrix = base.instanceMatrix;
|
|
1673
1901
|
im.count = base.count;
|
|
1674
1902
|
im.instanceColor = base.instanceColor;
|
|
@@ -1684,10 +1912,10 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1684
1912
|
for (const [pk, idsAll] of byPart) {
|
|
1685
1913
|
const part = pk.replace(/#m$/, "");
|
|
1686
1914
|
const p = H.parts[part];
|
|
1687
|
-
const mat =
|
|
1915
|
+
const mat = p.uncert ? (nUncert++, matD) : pk.endsWith("#m") ? matB : matF;
|
|
1688
1916
|
const textured = wantTex && !!p.tex;
|
|
1689
1917
|
const bodyB = textured ? p.tbody : p.body;
|
|
1690
|
-
const body = geom(bodyB, arr
|
|
1918
|
+
const body = geom(bodyB, arr);
|
|
1691
1919
|
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)));
|
|
1692
1920
|
for (const g of groups) {
|
|
1693
1921
|
const ids = Array.from(g, (i) => idsAll[i]);
|
|
@@ -1695,7 +1923,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1695
1923
|
const lv0 = [];
|
|
1696
1924
|
const place = (im) => {
|
|
1697
1925
|
fillInstances(im, ids, insts, color);
|
|
1698
|
-
im
|
|
1926
|
+
instancedBoundingSphere(im);
|
|
1927
|
+
im.userData.ldrPart = part;
|
|
1699
1928
|
root.add(im);
|
|
1700
1929
|
};
|
|
1701
1930
|
if (body) {
|
|
@@ -1705,7 +1934,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1705
1934
|
}
|
|
1706
1935
|
if (textured)
|
|
1707
1936
|
for (const tb of p.tex) {
|
|
1708
|
-
const gg = geom(tb, arr
|
|
1937
|
+
const gg = geom(tb, arr);
|
|
1709
1938
|
const im = newIM(gg, texMat(tb.t, mat, !!tb.wrapU), ids.length);
|
|
1710
1939
|
texBatches++;
|
|
1711
1940
|
lv0.push(im);
|
|
@@ -1723,49 +1952,57 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1723
1952
|
const cl = newCluster(bodyIm.boundingSphere);
|
|
1724
1953
|
lv0.forEach((o) => o.onBeforeRender = trackVp);
|
|
1725
1954
|
cl.lv.push({ objs: lv0, err: 0 }, ...textured ? [] : lodLevels(p.body, bodyIm, mat));
|
|
1726
|
-
if (
|
|
1955
|
+
if (EDGES && p.edges)
|
|
1727
1956
|
addLines(p.edges, bodyIm, cl);
|
|
1728
1957
|
addCond(p, bodyIm, cl);
|
|
1729
1958
|
if (steps)
|
|
1730
1959
|
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]) });
|
|
1731
|
-
if (P.edges === true && p.edges) {
|
|
1732
|
-
const mats = new Float32Array(ids.length * 16);
|
|
1733
|
-
ids.forEach((id, k) => writeM4(mats, k * 16, insts[id].m));
|
|
1734
|
-
{
|
|
1735
|
-
const l = instancedLines(arr(p.edges), mats, ids.length);
|
|
1736
|
-
edgeObjs.push(l);
|
|
1737
|
-
cl.lines.push(l);
|
|
1738
|
-
root.add(l);
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1741
1960
|
}
|
|
1742
|
-
const under = geom(p.under, arr
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
const
|
|
1746
|
-
|
|
1747
|
-
stats.
|
|
1748
|
-
|
|
1961
|
+
const under = geom(p.under, arr);
|
|
1962
|
+
const uGroups = !under ? [] : LOD && P.lodUnder !== false ? undersideGroups(ids, insts) : [{ ids, ax: null }];
|
|
1963
|
+
for (const { ids: uids, ax } of uGroups) {
|
|
1964
|
+
const ord = [...uids.filter((i) => !cull.underHidden[i]), ...uids.filter((i) => cull.underHidden[i])];
|
|
1965
|
+
const vis = uids.length - uids.reduce((a, i) => a + cull.underHidden[i], 0);
|
|
1966
|
+
stats.undersTotal += uids.length;
|
|
1967
|
+
stats.undersHidden += uids.length - vis;
|
|
1968
|
+
const im = newIM(under, mat, uids.length);
|
|
1749
1969
|
fillInstances(im, ord, insts, color);
|
|
1750
1970
|
im.onBeforeRender = trackVp;
|
|
1751
|
-
im.
|
|
1752
|
-
im.
|
|
1971
|
+
im.userData.ldrUnder = true;
|
|
1972
|
+
im.userData.ldrPart = part;
|
|
1973
|
+
instancedBoundingSphere(im);
|
|
1974
|
+
im.count = P.cullUnder ? vis : uids.length;
|
|
1753
1975
|
root.add(im);
|
|
1754
1976
|
const cl = newCluster(im.boundingSphere);
|
|
1755
1977
|
cl.lv.push({ objs: [im], err: 0 }, ...lodLevels(p.under, im, mat));
|
|
1978
|
+
{
|
|
1979
|
+
const bl = p.body?.lod;
|
|
1980
|
+
const last = bl?.[bl.length - 1];
|
|
1981
|
+
if (LOD && P.lodUnder !== false && last && last.tris === 12)
|
|
1982
|
+
cl.boxErr = last.err;
|
|
1983
|
+
}
|
|
1984
|
+
if (ax) {
|
|
1985
|
+
let below = Infinity;
|
|
1986
|
+
for (const id of uids) {
|
|
1987
|
+
const m = insts[id].m;
|
|
1988
|
+
below = Math.min(below, m[0] * ax[0] + m[1] * ax[1] + m[2] * ax[2] + p.bbox[4] * ax[3]);
|
|
1989
|
+
}
|
|
1990
|
+
cl.below = below;
|
|
1991
|
+
cl.ax = ax.slice(0, 3);
|
|
1992
|
+
}
|
|
1756
1993
|
addCond(p, im, cl, "under");
|
|
1757
1994
|
const objs = [...cl.lv.flatMap((l) => l.objs), ...cl.cond];
|
|
1758
1995
|
objs.forEach((o) => {
|
|
1759
1996
|
if (!o.isInstancedMesh)
|
|
1760
1997
|
o.geometry.instanceCount = im.count;
|
|
1761
1998
|
});
|
|
1762
|
-
toggles.push({ mesh: countTo(() => objs), all:
|
|
1999
|
+
toggles.push({ mesh: countTo(() => objs), all: uids.length, visible: vis, flag: "under" });
|
|
1763
2000
|
if (steps)
|
|
1764
2001
|
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]) });
|
|
1765
2002
|
}
|
|
1766
2003
|
}
|
|
1767
2004
|
}
|
|
1768
|
-
const sMesh = buildStudMeshes(insts, H, cull, arr,
|
|
2005
|
+
const sMesh = buildStudMeshes(insts, H, cull, arr, LOD, color, matF, matB, steps, steps && colorIndex);
|
|
1769
2006
|
const sKind = sMesh.map((x) => x?.kind ?? "");
|
|
1770
2007
|
const sVis = sMesh.map((x) => x?.vis ?? 0);
|
|
1771
2008
|
const STUD_ERR = 12;
|
|
@@ -1776,26 +2013,19 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1776
2013
|
const kind = sKind[ci];
|
|
1777
2014
|
const k = H.studKinds[kind];
|
|
1778
2015
|
const vis = sVis[ci], all = im.instanceMatrix.count;
|
|
1779
|
-
im
|
|
2016
|
+
instancedBoundingSphere(im);
|
|
1780
2017
|
im.count = P.cullStuds ? vis : all;
|
|
1781
2018
|
im.onBeforeRender = trackVp;
|
|
1782
2019
|
im.userData.ldrStud = true;
|
|
1783
2020
|
root.add(im);
|
|
1784
|
-
studMeshes.push({ im, kind });
|
|
1785
2021
|
const cl = newCluster(im.boundingSphere);
|
|
1786
2022
|
cl.lv.push({ objs: [im], err: 0 });
|
|
1787
|
-
if (LOD
|
|
2023
|
+
if (LOD)
|
|
1788
2024
|
cl.lv.push({ objs: [], err: STUD_ERR });
|
|
1789
|
-
if (
|
|
2025
|
+
if (EDGES && k.edges)
|
|
1790
2026
|
addLines(k.edges, im, cl);
|
|
1791
2027
|
if (P.condStuds !== false)
|
|
1792
2028
|
addCond(k, im, cl);
|
|
1793
|
-
if (P.edges === true && k.edges) {
|
|
1794
|
-
const l = instancedLines(arr(k.edges), im.instanceMatrix.array.slice(), im.count);
|
|
1795
|
-
edgeObjs.push(l);
|
|
1796
|
-
cl.lines.push(l);
|
|
1797
|
-
root.add(l);
|
|
1798
|
-
}
|
|
1799
2029
|
const objs = [im, ...cl.lines, ...cl.cond];
|
|
1800
2030
|
objs.forEach((o) => {
|
|
1801
2031
|
if (!o.isInstancedMesh)
|
|
@@ -1813,7 +2043,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1813
2043
|
for (const o of l.objs)
|
|
1814
2044
|
o.visible = i === c.cur;
|
|
1815
2045
|
});
|
|
1816
|
-
const lineVis = edgesOn && c.edgeOk && (c.cur === 0 || !LOD || c.lv[c.cur].objs.length > 0);
|
|
2046
|
+
const lineVis = edgesOn && c.edgeOk && c.cur >= 0 && (c.cur === 0 || !LOD || c.lv[c.cur].objs.length > 0);
|
|
1817
2047
|
for (const o of c.lines)
|
|
1818
2048
|
o.visible = lineVis;
|
|
1819
2049
|
for (const o of c.cond)
|
|
@@ -1923,21 +2153,14 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1923
2153
|
m.needsUpdate = true;
|
|
1924
2154
|
}
|
|
1925
2155
|
};
|
|
1926
|
-
const swapStuds = (alt) => {
|
|
1927
|
-
const saved = studMeshes.map((s) => s.im.geometry);
|
|
1928
|
-
for (const s of studMeshes) {
|
|
1929
|
-
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/"));
|
|
1930
|
-
if (k2)
|
|
1931
|
-
s.im.geometry = geom(alt.header.studKinds[k2].body, alt.arr, Q);
|
|
1932
|
-
}
|
|
1933
|
-
return () => studMeshes.forEach((s, i) => s.im.geometry = saved[i]);
|
|
1934
|
-
};
|
|
1935
2156
|
const setLod = (on) => {
|
|
1936
2157
|
root.enabled = on && LOD;
|
|
1937
2158
|
if (!root.enabled) {
|
|
1938
2159
|
for (const c of root.clusters) {
|
|
1939
2160
|
c.cur = 0;
|
|
1940
2161
|
c.edgeOk = true;
|
|
2162
|
+
for (const l of c.lines)
|
|
2163
|
+
l.geometry.drawRange.count = Infinity;
|
|
1941
2164
|
}
|
|
1942
2165
|
refresh();
|
|
1943
2166
|
}
|
|
@@ -1945,9 +2168,31 @@ function buildLdrScene(insts, pack, P, color, mark) {
|
|
|
1945
2168
|
insts = null;
|
|
1946
2169
|
cull = null;
|
|
1947
2170
|
byPart.clear();
|
|
1948
|
-
return { root, stats, setCull, setSide, setEdges, setCond,
|
|
2171
|
+
return { root, stats, setCull, setSide, setEdges, setCond, setLod, setStep, box, texturesReady };
|
|
2172
|
+
}
|
|
2173
|
+
async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
|
|
2174
|
+
const { header: H, arr } = pack;
|
|
2175
|
+
const list = [];
|
|
2176
|
+
for (const p of Object.values(H.parts ?? {}))
|
|
2177
|
+
for (const b of [p.body, p.under])
|
|
2178
|
+
if (b) {
|
|
2179
|
+
list.push(b);
|
|
2180
|
+
for (const l of b.lod ?? [])
|
|
2181
|
+
list.push(l);
|
|
2182
|
+
}
|
|
2183
|
+
for (const k of Object.values(H.studKinds ?? {}))
|
|
2184
|
+
if (k?.body)
|
|
2185
|
+
list.push(k.body);
|
|
2186
|
+
let i = 0;
|
|
2187
|
+
while (i < list.length && !stop()) {
|
|
2188
|
+
const t = performance.now();
|
|
2189
|
+
while (i < list.length && performance.now() - t < sliceMs)
|
|
2190
|
+
geom(list[i++], arr);
|
|
2191
|
+
if (i < list.length)
|
|
2192
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
2193
|
+
}
|
|
1949
2194
|
}
|
|
1950
|
-
// ../../../../../../../tmp/ldr-build-
|
|
2195
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/scene.ts
|
|
1951
2196
|
import * as THREE2 from "three";
|
|
1952
2197
|
function colorFn(src, pack, fallback) {
|
|
1953
2198
|
const table = new Map;
|
|
@@ -1992,12 +2237,8 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
1992
2237
|
const o = { edges: true, conditionalLines: true, cullStuds: true, cullUndersides: true, side: "front", material: "plastic", ...options };
|
|
1993
2238
|
const color = colorFn(o.colors, pack, new THREE2.Color(o.fallbackColor ?? 10528169));
|
|
1994
2239
|
const useTex = o.textures !== false;
|
|
1995
|
-
const
|
|
1996
|
-
const
|
|
1997
|
-
const key = (i) => i.steps.map((x) => String(x).padStart(6, "0")).join(".");
|
|
1998
|
-
const uniq = [...new Set(all.map(key))].sort();
|
|
1999
|
-
const rank = new Map(uniq.map((k, j) => [k, j]));
|
|
2000
|
-
const stepOf = all.map((i) => rank.get(key(i)));
|
|
2240
|
+
const { all, stepOf, nSteps } = sceneInstances(instances, pack.header, useTex);
|
|
2241
|
+
const uniq = { length: nSteps };
|
|
2001
2242
|
const stepViews = new Array(uniq.length).fill(null);
|
|
2002
2243
|
instances.forEach((i, k) => {
|
|
2003
2244
|
if (i.view)
|
|
@@ -2036,7 +2277,7 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
2036
2277
|
const drawnAt = (step) => all.filter((i, k) => (step == null || stepOf[k] <= step) && pack.header.parts[i.part]).length;
|
|
2037
2278
|
const build = () => {
|
|
2038
2279
|
const t0 = performance.now();
|
|
2039
|
-
cur = buildLdrScene(all, pack, {
|
|
2280
|
+
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, () => {});
|
|
2040
2281
|
pairs.clear();
|
|
2041
2282
|
if (o.material === "plastic")
|
|
2042
2283
|
cur.root.traverse((x) => {
|
|
@@ -2107,18 +2348,7 @@ function createLdrObject(instances, pack, options = {}) {
|
|
|
2107
2348
|
dispose: disposeCur
|
|
2108
2349
|
});
|
|
2109
2350
|
}
|
|
2110
|
-
// ../../../../../../../tmp/ldr-build-
|
|
2111
|
-
import { decompress } from "fzstd";
|
|
2112
|
-
async function decompressPack(data) {
|
|
2113
|
-
const u = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
2114
|
-
const own = (o) => o.buffer.slice(o.byteOffset, o.byteOffset + o.byteLength);
|
|
2115
|
-
if (u[0] === 40 && u[1] === 181 && u[2] === 47 && u[3] === 253)
|
|
2116
|
-
return own(decompress(u));
|
|
2117
|
-
if (u[0] === 31 && u[1] === 139)
|
|
2118
|
-
return new Response(new Blob([u]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();
|
|
2119
|
-
return own(u);
|
|
2120
|
-
}
|
|
2121
|
-
// ../../../../../../../tmp/ldr-build-qIdKSv/src/cdn.ts
|
|
2351
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/parts-cdn.ts
|
|
2122
2352
|
import { decompress as decompress2 } from "fzstd";
|
|
2123
2353
|
var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
|
|
2124
2354
|
var indexCache = new Map;
|
|
@@ -2179,7 +2409,7 @@ function mergePacks(packs, extra = {}) {
|
|
|
2179
2409
|
return decodePack(out.buffer);
|
|
2180
2410
|
}
|
|
2181
2411
|
async function loadParts(names, o = {}) {
|
|
2182
|
-
const cdn = o.cdn ?? DEFAULT_PARTS_CDN, f = o.fetch ?? fetch, gap = o.gap ??
|
|
2412
|
+
const cdn = o.cdn ?? DEFAULT_PARTS_CDN, f = o.fetch ?? fetch, gap = o.gap ?? 16384;
|
|
2183
2413
|
const idx = await loadPartsIndex(cdn, f);
|
|
2184
2414
|
const want = [...new Set([...names].map(norm))];
|
|
2185
2415
|
const missing = [];
|
|
@@ -2222,7 +2452,7 @@ async function loadParts(names, o = {}) {
|
|
|
2222
2452
|
}
|
|
2223
2453
|
}
|
|
2224
2454
|
};
|
|
2225
|
-
await Promise.all(Array.from({ length: Math.min(o.concurrency ??
|
|
2455
|
+
await Promise.all(Array.from({ length: Math.min(o.concurrency ?? 24, groups.length) }, worker));
|
|
2226
2456
|
const shards = want.filter((n) => shardCache.has(cdn + n)).map((n) => shardCache.get(cdn + n));
|
|
2227
2457
|
const pack = shards.length ? mergePacks(shards, { colors: idx.colors }) : decodePack(emptyPack(idx.colors));
|
|
2228
2458
|
return { pack, missing, requests: groups.length, bytes };
|
|
@@ -2235,10 +2465,11 @@ function emptyPack(colors) {
|
|
|
2235
2465
|
b.set(h, 4);
|
|
2236
2466
|
return b.buffer;
|
|
2237
2467
|
}
|
|
2238
|
-
async function
|
|
2468
|
+
async function prepareModel(source, o = {}) {
|
|
2239
2469
|
const t0 = performance.now();
|
|
2240
2470
|
const f = o.fetch ?? fetch;
|
|
2241
2471
|
const idxP = loadPartsIndex(o.cdn ?? DEFAULT_PARTS_CDN, f);
|
|
2472
|
+
idxP.catch(() => {});
|
|
2242
2473
|
const text = o.text ? source : await f(source).then((r) => {
|
|
2243
2474
|
if (!r.ok)
|
|
2244
2475
|
throw new Error(`ldr: ${r.status} fetching ${source}`);
|
|
@@ -2248,17 +2479,127 @@ async function loadModel(source, o = {}) {
|
|
|
2248
2479
|
const name = o.name ?? (o.text ? "main.ldr" : decodeURIComponent(source.split(/[?#]/)[0].split("/").pop() || "main.ldr"));
|
|
2249
2480
|
const insts = parseModel(text, name, { looseGeometry: false });
|
|
2250
2481
|
const t2 = performance.now();
|
|
2482
|
+
o.onParsed?.(insts);
|
|
2251
2483
|
await idxP;
|
|
2252
2484
|
const { pack, missing, requests, bytes } = await loadParts(insts.filter((i) => !i.embedded).map((i) => i.part), o);
|
|
2253
2485
|
const t3 = performance.now();
|
|
2254
|
-
const
|
|
2255
|
-
|
|
2486
|
+
const cull = o.cull ? precomputeCull(insts, pack.header, o.textures !== false) : undefined;
|
|
2487
|
+
return { insts, pack, missing, requests, bytes, cull, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, ...cull ? { cull: performance.now() - t3 } : {} } };
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/load-worker.gen.ts
|
|
2491
|
+
var load_worker_gen_default = 'var ut=ArrayBuffer,j=Uint8Array,ge=Uint16Array,ft=Int16Array;var be=Int32Array,Ae=function(e,t,n){if(j.prototype.slice)return j.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 j(n-t);return r.set(e.subarray(t,n)),r},ce=function(e,t,n,r){if(j.prototype.fill)return j.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},pt=function(e,t,n,r){if(j.prototype.copyWithin)return j.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 mt=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],V=function(e,t,n){var r=Error(t||mt[e]);if(r.code=e,Error.captureStackTrace)Error.captureStackTrace(r,V);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},ht=function(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0},gt=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)V(0);var a=6-o,l=i==3?4:i,f=Ne(e,a,l);a+=l;var g=c?1<<c:o,p=Ne(e,a,g)+(c==1&&256),y=p;if(!o){var C=1<<10+(e[5]>>3);y=C+(C>>3)*(e[5]&7)}if(y>2145386496)V(1);var u=new j((t==1?p||y:t?0:y)+12);return u[0]=1,u[4]=4,u[8]=8,{b:a+g,y:0,l:0,d:f,w:t&&t!=1?t:u.subarray(12),e:y,o:new be(u.buffer,0,3),u:p,c:s,m:Math.min(131072,y)}}else if((n>>4|e[3]<<20)==25481893)return ht(e,4)+8;V(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)V(3);var s=1<<o,i=s,c=-1,a=-1,l=-1,f=s,g=new ut(512+(s<<2)),p=new ft(g,0,256),y=new ge(g,0,256),C=new ge(g,512,s),u=512+(s<<1),m=new j(g,u,s),P=new j(g,u+s);while(c<255&&i>0){var b=re(i+1),d=r>>3,S=(1<<b+1)-1,k=(e[d]|e[d+1]<<8|e[d+2]<<16)>>(r&7)&S,w=(1<<b)-1,E=S-i-1,M=k&w;if(M<E)r+=b,k=M;else if(r+=b+1,k>w)k-=E;if(p[++c]=--k,k==-1)i+=k,m[--f]=c;else i-=k;if(!k)do{var x=r>>3;a=(e[x]|e[x+1]<<8)>>(r&7)&3,r+=2,c+=a}while(a==3)}if(c>255||i)V(0);var A=0,L=(s>>1)+(s>>3)+3,D=s-1;for(var F=0;F<=c;++F){var v=p[F];if(v<1){y[F]=-v;continue}for(l=0;l<v;++l){m[A]=F;do A=A+L&D;while(A>=f)}}if(A)V(0);for(l=0;l<s;++l){var h=y[m[l]]++,T=P[l]=o-re(h);C[l]=(h<<T)-s}return[r+7>>3,{b:o,s:m,n:P,t:C}]},bt=function(e,t){var n=0,r=-1,o=new j(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],g=l[1];t+=s;var p=f<<3,y=e[t];if(!y)V(0);var C=0,u=0,m=g.b,P=m,b=(++t<<3)-8+re(y);for(;;){if(b-=m,b<p)break;var d=b>>3;if(C+=(e[d]|e[d+1]<<8)>>(b&7)&(1<<m)-1,i[++r]=g.s[C],b-=P,b<p)break;d=b>>3,u+=(e[d]|e[d+1]<<8)>>(b&7)&(1<<P)-1,i[++r]=g.s[u],m=g.n[C],C=g.t[C],P=g.n[u],u=g.t[u]}if(++r>255)V(0)}else{r=s-127;for(;n<r;n+=2){var S=e[++t];i[n]=S>>4,i[n+1]=S&15}++t}var k=0;for(n=0;n<r;++n){var w=i[n];if(w>11)V(0);k+=w&&1<<w-1}var E=re(k)+1,M=1<<E,x=M-k;if(x&x-1)V(0);i[r++]=re(x)+1;for(n=0;n<r;++n){var w=i[n];++c[i[n]=w&&E+1-w]}var A=new j(M<<1),L=A.subarray(0,M),D=A.subarray(M);a[E]=0;for(n=E;n>0;--n){var F=a[n];ce(D,n,F,a[n-1]=F+c[n]*(1<<E-n))}if(a[0]!=M)V(0);for(n=0;n<r;++n){var v=i[n];if(v){var h=a[v];ce(L,n,h,a[v]=h+(1<<E-v))}}return[t,{n:D,b:E,s:L}]},dt=ue(new j([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],yt=ue(new j([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],xt=ue(new j([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},Me=new j(new be([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),wt=$e(Me,0),Se=new j(new be([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),vt=$e(Se,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)V(0);var a=0,l=n.b,f=(r<<3)-8+re(s)-l,g=-1;for(;f>c&&g<o;){var p=f>>3,y=(e[p]|e[p+1]<<8|e[p+2]<<16)>>(f&7);a=(a<<l|y)&i,t[++g]=n.s[a],f-=l=n.n[a]}if(f!=c||g+1!=o)V(0)},At=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)},Mt=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 j(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 Ae(e,o,a)}if(i==2){var l=e[o],f=l&3,g=l>>2&3,p=l>>4,y=0,C=0;if(f<2)if(g&1)p|=e[++o]<<4|(g&2&&e[++o]<<12);else p=l>>3;else if(C=g,g<2)p|=(e[++o]&63)<<4,y=e[o]>>6|e[++o]<<2;else if(g==2)p|=e[++o]<<4|(e[++o]&3)<<12,y=e[o]>>2|e[++o]<<6;else p|=e[++o]<<4|(e[++o]&63)<<12,y=e[o]>>6|e[++o]<<2|e[++o]<<10;++o;var u=n?n.subarray(t.y,t.y+t.m):new j(t.m),m=u.length-p;if(f==0)u.set(e.subarray(o,o+=p),m);else if(f==1)ce(u,e[o++],m);else{var P=t.h;if(f==2){var b=bt(e,o);y+=o-(o=b[0]),t.h=P=b[1]}else if(!P)V(0);(C?At:le)(e.subarray(o,o+=y),u.subarray(m),P)}var d=e[o++];if(d){if(d==255)d=(e[o++]|e[o++]<<8)+32512;else if(d>127)d=d-128<<8|e[o++];var S=e[o++];if(S&3)V(0);var k=[yt,xt,dt];for(var w=2;w>-1;--w){var E=S>>(w<<1)+2&3;if(E==1){var M=new j([0,0,e[o++]]);k[w]={s:M.subarray(2,3),n:M.subarray(0,1),t:new ge(M.buffer,0,1),b:0}}else if(E==2)r=ue(e,o,9-(w&1)),o=r[0],k[w]=r[1];else if(E==3){if(!t.t)V(0);k[w]=t.t[w]}}var x=t.t=k,A=x[0],L=x[1],D=x[2],F=e[a-1];if(!F)V(0);var v=(a<<3)-8+re(F)-D.b,h=v>>3,T=0,R=(e[h]|e[h+1]<<8)>>(v&7)&(1<<D.b)-1;h=(v-=L.b)>>3;var I=(e[h]|e[h+1]<<8)>>(v&7)&(1<<L.b)-1;h=(v-=A.b)>>3;var U=(e[h]|e[h+1]<<8)>>(v&7)&(1<<A.b)-1;for(++d;--d;){var O=D.s[R],K=D.n[R],H=A.s[U],z=A.n[U],B=L.s[I],N=L.n[I];h=(v-=B)>>3;var G=1<<B,X=G+((e[h]|e[h+1]<<8|e[h+2]<<16|e[h+3]<<24)>>>(v&7)&G-1);h=(v-=Se[H])>>3;var Y=vt[H]+((e[h]|e[h+1]<<8|e[h+2]<<16)>>(v&7)&(1<<Se[H])-1);h=(v-=Me[O])>>3;var W=wt[O]+((e[h]|e[h+1]<<8|e[h+2]<<16)>>(v&7)&(1<<Me[O])-1);if(h=(v-=K)>>3,R=D.t[R]+((e[h]|e[h+1]<<8)>>(v&7)&(1<<K)-1),h=(v-=z)>>3,U=A.t[U]+((e[h]|e[h+1]<<8)>>(v&7)&(1<<z)-1),h=(v-=N)>>3,I=L.t[I]+((e[h]|e[h+1]<<8)>>(v&7)&(1<<N)-1),X>3)t.o[2]=t.o[1],t.o[1]=t.o[0],t.o[0]=X-=3;else{var _=X-(W!=0);if(_){if(X=_==3?t.o[0]-1:t.o[_],_>1)t.o[2]=t.o[1];t.o[1]=t.o[0],t.o[0]=X}else X=t.o[0]}for(var w=0;w<W;++w)u[T+w]=u[m+w];T+=W,m+=W;var Z=T-X;if(Z<0){var J=-Z,ee=t.e+Z;if(J>Y)J=Y;for(var w=0;w<J;++w)u[T+w]=t.w[ee+w];T+=J,Y-=J,Z=0}for(var w=0;w<Y;++w)u[T+w]=u[Z+w];T+=Y}if(T!=m)while(m<u.length)u[T++]=u[m++];else T=u.length;if(n)t.y+=T;else u=Ae(u,0,T)}else if(n){if(t.y+=p,m)for(var w=0;w<p;++w)u[w]=u[m+w]}else if(m)u=Ae(u,m);return t.b=a,u}V(2)},St=function(e,t){if(e.length==1)return e[0];var n=new j(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=gt(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=Mt(e,i,t);if(!c)V(5);if(t)i.e=i.y;else n.push(c),s+=c.length,pt(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 St(n,s)}function de(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 Ce(e){if(/^0x/i.test(e))return parseInt(e,16);return+e}var Ve=/^~?\\s*moved\\s+to\\s+(.+)$/i,Ct=new Set(["FILE","NOFILE","!DATA","!:","STEP","BFC","ROTSTEP","BUFEXCHG","!TEXMAP"]),Je=new Set(["part","subpart","primitive","8_primitive","48_primitive","shortcut","helper"]),Pt=new Set(["model","submodel","configuration"]),Et=/^(?:!?LDRAW_ORG|Unofficial|Official\\s+LCAD)\\s+(\\S+)/i;function He(e){let t=Et.exec(e);if(!t)return;let n=t[1].toLowerCase().replace(/^unofficial_/,"");return Je.has(n)||Pt.has(n)?n:void 0}function Tt(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 Lt(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 g=0;g<o;g++)c=c.replace(/^\\S+\\s*/,"");let a=Tt(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((g,p)=>p>0&&g.toUpperCase()==="GLOSSMAP");if(f>0&&a[f+1])l.glossmap=a[f+1];if(t)l.next=!0;return l}var It=(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 kt(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:Ce(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=Ce(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,g=()=>{if(!a)return;let b=It(a.chunks.join("")),d=b[0]===137&&b[1]===80&&b[2]===78&&b[3]===71;(c??=new Map).set(q(a.name),{name:a.name,bytes:b,...d?{mime:"image/png"}:{}}),a=null},p=!0,y=(b)=>{if(g(),s={name:q(b),cmds:[]},o.set(s.name,s),!i)i=s.name;l=[],f=null,p=!0},C=!1,u=!1,m=()=>{if(u)return;u=!0,o.clear(),s=null,i=""},P=(b,d)=>{if(f){b.tex=f,f=null;return}let S=l[l.length-1];if(!S)return;if(S.fallback){if(!d)b.fallback=!0}else b.tex=S.map};for(let b of e.split(`\n`)){let d=b.trim();if(!d)continue;if(r&&d.charCodeAt(0)>=50&&d.charCodeAt(0)<=53&&(d.charCodeAt(1)===32||d.charCodeAt(1)===9)){if(a||C)continue;if(!s)y(t);let E=d.slice(2).trimStart(),M=E.search(/\\s/),x={t:d.charCodeAt(0)-48,color:Ce(M<0?E:E.slice(0,M)),p:[],src:d};P(x,!1),s.cmds.push(x),p=!1;continue}if(d.charCodeAt(0)===48&&(d.charCodeAt(1)===32||d.charCodeAt(1)===9)){let E=2;while(d.charCodeAt(E)===32||d.charCodeAt(E)===9)E++;let M=E;while(M<d.length&&d.charCodeAt(M)!==32&&d.charCodeAt(M)!==9)M++;let x=d.slice(E,M);if(!Ct.has(x)){if(C||a)continue;if(!s)y(t);let A=d.slice(E),L={t:0,text:A};if(x.charCodeAt(0)===33)L.meta=x;if(f=null,p&&!s.org){let F=He(A);if(F)s.org=F}let D=A.match(Ve);if(D&&!s.movedTo){let F=D[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(F))F+=".dat";s.movedTo=q(F)}s.cmds.push(L);continue}}if(d.charCodeAt(0)===49&&(d.charCodeAt(1)===32||d.charCodeAt(1)===9)&&!a&&!C){let E=kt(d);if(E){if(!s)y(t);P(E,!1),s.cmds.push(E),p=!1;continue}}let S=d.split(/\\s+/);if(+S[0]===0){let E=d.slice(1).trim();if(S[1]==="FILE"){m(),C=!1,y(E.slice(5));continue}if(S[1]==="NOFILE"){g(),s=null,C=!0;continue}if(S[1]==="!DATA"){m(),g(),s=null,C=!1,a={name:E.slice(5).trim(),chunks:[]};continue}if(C)continue;if(a){if(S[1]==="!:")a.chunks.push(S.slice(2).join(""));continue}if(!s)y(t);let M={t:0,text:E};if(S[1]==="STEP")M.step=!0,l=[],f=null;else if(S[1]==="BFC")M.bfc=S.slice(2).join(" ");else if(S[1]==="ROTSTEP")if(M.meta="ROTSTEP",M.step=!0,l=[],f=null,(S[2]??"").toUpperCase()==="END")M.rotstep={x:0,y:0,z:0,mode:"END"};else{let A=(S[5]??"REL").toUpperCase();M.rotstep={x:+S[2]||0,y:+S[3]||0,z:+S[4]||0,mode:["REL","ABS","ADD"].includes(A)?A:"REL"}}else if(S[1]==="BUFEXCHG"){M.meta="BUFEXCHG";let A=(S[2]??"").toUpperCase();M.bufexchg={op:A==="RETRIEVE"?"RETRIEVE":"STORE",buf:S[3]??"A"}}else if(S[1]?.startsWith("!"))M.meta=S[1];if(p&&!s.org){let A=He(E);if(A)s.org=A}if(S[1]==="!TEXMAP"){let A=(S[2]??"").toUpperCase();if(f=null,A==="START"||A==="NEXT"){let L=Lt(E.replace(/^!TEXMAP\\s+\\S+/i,""),A==="NEXT");if(M.texmap={op:A,...L?{map:L}:{}},L)if((s.texmaps??=[]).push(L),A==="START")l.push({map:L,fallback:!1});else f=L}else if(A==="FALLBACK"){M.texmap={op:A};let L=l[l.length-1];if(L)L.fallback=!0}else if(A==="END")M.texmap={op:A},l.pop()}else if(S[1]==="!:"){f=null;let A=Ge(S.slice(2));if(A)P(A,!0),M.geom=A}else f=null;let x=E.match(Ve);if(x&&!s.movedTo){let A=x[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(A))A+=".dat";s.movedTo=q(A)}s.cmds.push(M);continue}if(a||C)continue;if(!s)y(t);let w=Ge(S);if(!w)continue;P(w,!1),s.cmds.push(w),p=!1}return g(),c?{main:i,files:o,data:c}:{main:i,files:o}}var Kt=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,g,p,y]=e,[C,u,m,P,b,d,S,k,w,E,M,x]=t;return[s*C+i*u+c*m+n,a*C+l*u+f*m+r,g*C+p*u+y*m+o,s*P+i*S+c*E,s*b+i*k+c*M,s*d+i*w+c*x,a*P+l*S+f*E,a*b+l*k+f*M,a*d+l*w+f*x,g*P+p*S+y*E,g*b+p*k+y*M,g*d+p*w+y*x]}var Pe=[0,0,0,1,0,0,0,1,0,0,0,1];var Xe=new WeakMap,Ft=/^(s|8|48)\\//;function Ee(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&&Ft.test(o.file))?"part":"model";return Xe.set(n,r),r}var We=new WeakMap;function et(e){let t=We.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 We.set(e,t),t}var _e=(e)=>e>16777215?"0x"+e.toString(16).toUpperCase():String(e),Rt=(e)=>e.t===0?"0 "+e.text:e.t===1?`1 ${_e(e.color)} ${e.m.join(" ")} ${e.file}`:e.src?e.src:`${e.t} ${_e(e.color)} ${e.p.join(" ")}`,Te=(e,t)=>`${q(e)}#${t}`;function Ut(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:Te(e.name,t),cmds:n}}function tt(e,t){return[`0 ldr: own geometry of ${e.name}, step ${t}`,...Ut(e,t).cmds.map(Rt)].join(`\n`)+`\n`}function Dt(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,g,p]=e,y=a*p-l*g,C=-(c*p-l*f),u=c*g-a*f,m=o*y+s*C+i*u;if(!Number.isFinite(m)||Math.abs(m)<0.000000000001)return null;let P=1/m,b=[y*P,-(s*p-i*g)*P,(s*l-i*a)*P,C*P,(o*p-i*f)*P,-(o*l-i*c)*P,u*P,-(o*g-s*f)*P,(o*a-s*c)*P];return[-(b[0]*t+b[1]*n+b[2]*r),-(b[3]*t+b[4]*n+b[5]*r),-(b[6]*t+b[7]*n+b[8]*r),...b]}var Ot=(e)=>String(+e.toFixed(6)||0),Ke=(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(Ot).join(" "),r=`0 ldr: ${e} with a model-level !TEXMAP\n0 BFC CERTIFY CCW\n0 !TEXMAP START ${t.method} ${n} ${Ke(t.texture)}${t.glossmap?" GLOSSMAP "+Ke(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-${Dt(r)}`,source:r}}var zt=(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 Bt(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=Bt(s.x,s.y,s.z);r=s.mode==="ABS"?{abs:!0,m:i,rotstep:s}:s.mode==="ADD"&&r?{abs:r.abs,m:zt(r.m,i),rotstep:s}:{abs:!1,m:i,rotstep:s}}n.push(r)}return n.push(r),Ye.set(e,n),n}function Nt(e,t={}){let n=[],r=t.maxDepth??64,o=t.looseGeometry!==!1,s=!!t.textures,i=new Map,c=(l,f)=>{let g=l.name+"#"+f,p=i.get(g);if(!p){let y;p=Object.assign(()=>y??=tt(l,f),{file:l,step:f}),i.set(g,p)}return p},a=(l,f,g,p,y,C,u,m)=>{let P=l.files.get(f);if(!P||u>r)return;let b=0,d=ot(P),S=o?et(P):[],k=0,w=(M,x,A,L,D,F,v)=>{let h={part:M,color:x,m:A,step:L[0],steps:L,localStep:D,path:y};if(F)h.embedded=!0;if(v){let R=rt(M,v);h.texPart=R.name,h.texSource=R.source}let T=d[D];if(T)h.view=T;return n.push(h),h},E=(M)=>{while(k<S.length&&S[k]<=M){let x=S[k++];w(Te(P.name,x),p,g,[...C,x],x,!1,null).source=c(P,x)}};for(let M of P.cmds){if(M.t===0&&M.step){b++;continue}let x=M;if(x.t>=2||x.t===0&&x.geom&&x.geom.t>=2){E(b);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 A=x.color===16?p:x.color,L=Qe(g,x.m),D=[...C,b],F=s?x.tex??m:null,v=F?nt(x.m):null,h=F&&v?qe(F,v):null;if(l.files.has(x.file)){if(Ee(l,x.file)==="model"){a(l,x.file,L,A,y+"/"+x.file,D,u+1,h);continue}w(x.file,A,L,D,b,!0,h);continue}let T=t.resolveModel?.(x.file);if(T){a(T,T.main,L,A,y+"/"+x.file,D,u+1,h);continue}w(x.file,A,L,D,b,!1,h)}E(1/0)};if(Ee(e,e.main)==="part"){if(e.files.get(e.main))n.push({part:e.main,color:16,m:[...Pe],step:0,steps:[0],localStep:0,path:e.main,embedded:!0});return n}return a(e,e.main,Pe,16,e.main,[],0,null),n}function st(e,t="main.ldr",n){return Nt(Ze(e,t,{geometryText:!0}),n)}var it=(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,at=new WeakMap;function Le(e,t){let n=at.get(e);if(!n)at.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((p,y)=>{c.push(p[0]),a.push(p[1]);for(let C=0;C<12;C++)i[y*12+C]=p[2+C]});let l=null,f=0,g=0;if(o.mask){f=o.mask[0],g=o.mask[1];let p=o.mask[2];l=new Uint8Array(p.length);for(let y=0;y<p.length;y++)l[y]=p.charCodeAt(y)===49?1:0}return n.set(t,r={nStuds:s,studM:i,kind:c,color:a,mask:l,nx:f,nz:g}),r}var ie=1073741824;class Ie{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 ye=(e,t,n)=>e>-ie&&e<ie&&t>-ie&&t<ie&&n>-ie&&n<ie,fe=2147483647;function $t(e,t,n){let o=[],s=[],i=[],c=[],a=[],l=[],f=[],g=[],p=new Ie(e.length*2),y=[],C=[];for(let v=0;v<e.length;v++){let h=e[v],T=h.m,R=t.parts[h.part];if(!R||!R.mask||!it(T))continue;let I=R.bbox,U=1/0,O=-1/0,K=1/0,H=-1/0;for(let N=0;N<2;N++)for(let G=0;G<2;G++){let X=N?I[3]:I[0],Y=G?I[5]:I[2],W=T[0]+T[3]*X+T[5]*Y,_=T[2]+T[9]*X+T[11]*Y;if(W<U)U=W;if(W>O)O=W;if(_<K)K=_;if(_>H)H=_}let z=a.length;o.push(U),s.push(O),i.push(K),c.push(H),a.push(v),l.push(Le(t,h.part)),f.push(I[0]),g.push(I[2]);let B=Math.round((T[1]+I[4])*2);for(let N=Math.floor(U/40);N<=Math.floor(O/40);N++)for(let G=Math.floor(K/40);G<=Math.floor(H/40);G++){if(!ye(B,N,G))continue;let X=C.length;C.push(z),y.push(p.put(B,N,G,X))}}let u=[0,5,-5,5,-5],m=[0,5,5,-5,-5],P=NaN,b=NaN,d=NaN,S=-1,k=(v,h,T,R)=>{let I=Math.round(h*2),U=Math.floor(v/40),O=Math.floor(T/40);if(!ye(I,U,O))return fe;let K=fe;if(I!==P||U!==b||O!==d)P=I,b=U,d=O,S=p.get(I,U,O);for(let H=S;H>=0;H=y[H]){let z=C[H];if(a[z]===R||!(v-6>=o[z]-0.5&&v+6<=s[z]+0.5&&T-6>=i[z]-0.5&&T+6<=c[z]+0.5))continue;let B=e[a[z]].m,N=l[z],G=f[z],X=g[z],Y=v-B[0],W=h-B[1],_=T-B[2],Z=B[3]*Y+B[6]*W+B[9]*_,J=B[5]*Y+B[8]*W+B[11]*_,{nx:ee,nz:oe,mask:ae}=N,se=!0;for(let Q=0;Q<5;Q++){let te=Math.floor((Z+u[Q]-G)/20),ne=Math.floor((J+m[Q]-X)/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[z]];if(Q<K)K=Q}}return K},w=0;for(let v of e){let h=Le(t,v.part);if(h)w+=h.nStuds}let E=new Uint8Array(w),M=new Uint8Array(w),x=new Ie(w),A=0,L=n?new Int32Array(w).fill(fe):void 0;for(let v=0,h=0;v<e.length;v++){let T=e[v],R=Le(t,T.part);if(!R)continue;let I=T.m,U=R.studM,O=I[0],K=I[1],H=I[2],z=I[3],B=I[4],N=I[5],G=I[6],X=I[7],Y=I[8],W=I[9],_=I[10],Z=I[11];for(let J=0;J<R.nStuds;J++,h++){let ee=J*12,oe=U[ee+4],ae=U[ee+7],se=U[ee+10];if(!(Math.abs(G*oe+X*ae+Y*se-1)<0.001&&Math.abs(z*oe+B*ae+N*se)<0.001&&Math.abs(W*oe+_*ae+Z*se)<0.001))continue;M[h]=1;let Q=U[ee],te=U[ee+1],ne=U[ee+2],Re=O+z*Q+B*te+N*ne,Ue=K+G*Q+X*te+Y*ne,De=H+W*Q+_*te+Z*ne,Oe=k(Re,Ue,De,v);if(Oe!==fe){if(E[h]=1,A++,L)L[h]=Oe}let pe=Math.round(Re),me=Math.round(Ue),he=Math.round(De);if(!ye(pe,me,he))continue;if(!n){x.put(pe,me,he,1);continue}let ze=n[v],Be=x.get(pe,me,he);if(Be<0||ze<Be)x.put(pe,me,he,ze)}}let D=new Uint8Array(e.length),F=n?new Int32Array(e.length).fill(fe):void 0;for(let v=0;v<e.length;v++){let h=e[v],T=t.parts[h.part];if(!T||!T.under||!it(h.m))continue;let R=T.bbox,I=Math.round((R[3]-R[0])/20),U=Math.round((R[5]-R[2])/20);if(!I||!U||I*U>4096)continue;let O=h.m,K=!0,H=0;for(let z=0;z<I&&K;z++)for(let B=0;B<U;B++){let N=R[0]+10+20*z,G=R[2]+10+20*B,X=O[0]+O[3]*N+O[5]*G,Y=O[2]+O[9]*N+O[11]*G,W=Math.round(X),_=Math.round(O[1]+R[4]),Z=Math.round(Y),J=ye(W,_,Z)?x.get(W,_,Z):-1;if(J<0){K=!1;break}if(J>H)H=J}if(K){if(D[v]=1,F)F[v]=H}}return{nStuds:w,studHidden:E,studUp:M,underHidden:D,studsHidden:A,studHideStep:L,underHideStep:F}}function jt(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)=>a.steps.map((l)=>String(l).padStart(6,"0")).join(".")),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=jt(e,t,n);return $t(r.all,t,r.nSteps>1?r.stepOf:void 0)}var Fe="https://ldr-demo.vercel.app/cdn/v1/",ke=new Map,we=new Map;function lt(e=Fe,t=fetch){let n=ke.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(()=>ke.delete(e)),ke.set(e,n);return n}var Vt=(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"),ve=(e,t)=>Vt(e)?[e[0]+t,e[1],e[2]]:Array.isArray(e)?e.map((n)=>ve(n,t)):e&&typeof e==="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,ve(r,t)])):e;function Ht(e,t={}){let n=[],r=0,o={},s={};for(let p of e){let y=p.buffer;if(!y)throw Error("ldr: mergePacks needs packs from decodePack/loadPack");let C=new DataView(y).getUint32(0,!0),u=new Uint8Array(y,4+C),m=r;n.push(u),r+=u.byteLength;let P=(4-r%4)%4;if(P)n.push(new Uint8Array(P)),r+=P;for(let[b,d]of Object.entries(p.header.parts??{}))if(!(b in o))o[b]=ve(d,m);for(let[b,d]of Object.entries(p.header.studKinds??{}))if(!(b in s))s[b]=ve(d,m)}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 g=l;for(let p of n)f.set(p,g),g+=p.byteLength;return de(f.buffer)}async function Gt(e,t={}){let n=t.cdn??Fe,r=t.fetch??fetch,o=t.gap??16384,s=await lt(n,r),i=[...new Set([...e].map(q))],c=[],a=[];for(let u of i){if(we.has(n+u))continue;let m=s.parts[u];if(m)a.push({name:u,off:m[0],len:m[1],file:m[2]??0});else c.push(u)}a.sort((u,m)=>u.file-m.file||u.off-m.off);let l=[];for(let u of a){let m=l[l.length-1];if(m&&m.file===u.file&&u.off-m.end<=o)m.end=Math.max(m.end,u.off+u.len),m.items.push(u);else l.push({file:u.file,start:u.off,end:u.off+u.len,items:[u]})}let f=0,g=0,p=async()=>{while(g<l.length){let u=l[g++],m=await r(new URL(s.archives[u.file],n).href,{headers:{Range:`bytes=${u.start}-${u.end-1}`}});if(!m.ok)throw Error(`ldr: parts CDN ${m.status}`);let P=new Uint8Array(await m.arrayBuffer());if(m.status===200)P=P.subarray(u.start,u.end);f+=P.byteLength;for(let b of u.items){let d=je(P.subarray(b.off-u.start,b.off-u.start+b.len)),S=d.buffer.slice(d.byteOffset,d.byteOffset+d.byteLength);we.set(n+b.name,de(S))}}};await Promise.all(Array.from({length:Math.min(t.concurrency??24,l.length)},p));let y=i.filter((u)=>we.has(n+u)).map((u)=>we.get(n+u));return{pack:y.length?Ht(y,{colors:s.colors}):de(Xt(s.colors)),missing:c,requests:l.length,bytes:f}}function Xt(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 ct(e,t={}){let n=performance.now(),r=t.fetch??fetch,o=lt(t.cdn??Fe,r);o.catch(()=>{});let s=t.text?e:await r(e).then((m)=>{if(!m.ok)throw Error(`ldr: ${m.status} fetching ${e}`);return m.text()}),i=performance.now(),c=t.name??(t.text?"main.ldr":decodeURIComponent(e.split(/[?#]/)[0].split("/").pop()||"main.ldr")),a=st(s,c,{looseGeometry:!1}),l=performance.now();t.onParsed?.(a),await o;let{pack:f,missing:g,requests:p,bytes:y}=await Gt(a.filter((m)=>!m.embedded).map((m)=>m.part),t),C=performance.now(),u=t.cull?xe(a,f.header,t.textures!==!1):void 0;return{insts:a,pack:f,missing:g,requests:p,bytes:y,cull:u,timings:{fetchModel:i-n,parse:l-i,parts:C-l,...u?{cull:performance.now()-C}:{}}}}self.onmessage=async(e)=>{let{id:t,source:n,opts:r}=e.data;try{let o=await ct(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';
|
|
2492
|
+
|
|
2493
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/cdn.ts
|
|
2494
|
+
var worker;
|
|
2495
|
+
var seq = 0;
|
|
2496
|
+
var pending = new Map;
|
|
2497
|
+
var pendingInsts = new Map;
|
|
2498
|
+
var pendingCull = new Map;
|
|
2499
|
+
function getWorker() {
|
|
2500
|
+
if (worker !== undefined)
|
|
2501
|
+
return worker;
|
|
2502
|
+
try {
|
|
2503
|
+
if (typeof Worker === "undefined" || typeof Blob === "undefined" || typeof URL?.createObjectURL !== "function" || !load_worker_gen_default)
|
|
2504
|
+
return worker = null;
|
|
2505
|
+
const url = URL.createObjectURL(new Blob([load_worker_gen_default], { type: "text/javascript" }));
|
|
2506
|
+
const w = new Worker(url, { type: "module", name: "ldr-load" });
|
|
2507
|
+
w.onmessage = (e) => {
|
|
2508
|
+
const d = e.data;
|
|
2509
|
+
if (d.insts) {
|
|
2510
|
+
pendingInsts.get(d.id)?.(d.insts);
|
|
2511
|
+
pendingInsts.delete(d.id);
|
|
2512
|
+
return;
|
|
2513
|
+
}
|
|
2514
|
+
const map = d.cull || d.error && !pending.has(d.id) ? pendingCull : pending;
|
|
2515
|
+
const p = map.get(d.id);
|
|
2516
|
+
if (!p)
|
|
2517
|
+
return;
|
|
2518
|
+
map.delete(d.id);
|
|
2519
|
+
d.error ? p.rej(new Error(d.error)) : p.res(d);
|
|
2520
|
+
};
|
|
2521
|
+
w.onerror = (e) => {
|
|
2522
|
+
e.preventDefault?.();
|
|
2523
|
+
worker = null;
|
|
2524
|
+
w.terminate();
|
|
2525
|
+
const err = new Error("ldr: load worker failed: " + (e.message || "error"));
|
|
2526
|
+
err.workerFailed = true;
|
|
2527
|
+
for (const m of [pending, pendingCull]) {
|
|
2528
|
+
for (const p of m.values())
|
|
2529
|
+
p.rej(err);
|
|
2530
|
+
m.clear();
|
|
2531
|
+
}
|
|
2532
|
+
};
|
|
2533
|
+
return worker = w;
|
|
2534
|
+
} catch {
|
|
2535
|
+
return worker = null;
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
var abs = (u) => {
|
|
2539
|
+
try {
|
|
2540
|
+
return new URL(u, globalThis.location?.href).href;
|
|
2541
|
+
} catch {
|
|
2542
|
+
return u;
|
|
2543
|
+
}
|
|
2544
|
+
};
|
|
2545
|
+
function prepareInWorker(w, source, o) {
|
|
2546
|
+
const id = ++seq;
|
|
2547
|
+
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 };
|
|
2548
|
+
const name = o.name ?? (o.text ? undefined : decodeURIComponent(source.split(/[?#]/)[0].split("/").pop() || "main.ldr"));
|
|
2549
|
+
let insts;
|
|
2550
|
+
pendingInsts.set(id, (v) => {
|
|
2551
|
+
insts = v;
|
|
2552
|
+
});
|
|
2553
|
+
const cull = new Promise((res, rej) => pendingCull.set(id, { res, rej }));
|
|
2554
|
+
cull.catch(() => {});
|
|
2555
|
+
return new Promise((res, rej) => {
|
|
2556
|
+
pending.set(id, { res, rej });
|
|
2557
|
+
w.postMessage({ id, source: o.text ? source : abs(source), opts: { ...opts, name } });
|
|
2558
|
+
}).then(async (d) => {
|
|
2559
|
+
const pack = decodePack(d.buffer);
|
|
2560
|
+
let done = false;
|
|
2561
|
+
cull.then(() => done = true, () => done = true);
|
|
2562
|
+
await warmPackGeometry(pack, () => done);
|
|
2563
|
+
const c = await cull;
|
|
2564
|
+
pendingInsts.delete(id);
|
|
2565
|
+
return { insts, pack, missing: d.missing, requests: d.requests, bytes: d.bytes, timings: { ...d.timings, cull: c.ms }, cull: c.cull };
|
|
2566
|
+
}, (e) => {
|
|
2567
|
+
pendingCull.delete(id);
|
|
2568
|
+
pendingInsts.delete(id);
|
|
2569
|
+
throw e;
|
|
2570
|
+
});
|
|
2571
|
+
}
|
|
2572
|
+
async function loadModel(source, o = {}) {
|
|
2573
|
+
const t0 = performance.now();
|
|
2574
|
+
const w = o.worker !== false && !o.fetch ? getWorker() : null;
|
|
2575
|
+
let prep, ranIn = "main";
|
|
2576
|
+
if (w) {
|
|
2577
|
+
try {
|
|
2578
|
+
prep = await prepareInWorker(w, source, o);
|
|
2579
|
+
ranIn = "worker";
|
|
2580
|
+
} catch (e) {
|
|
2581
|
+
if (!e?.workerFailed)
|
|
2582
|
+
throw e;
|
|
2583
|
+
prep = await prepareModel(source, o);
|
|
2584
|
+
}
|
|
2585
|
+
} else
|
|
2586
|
+
prep = await prepareModel(source, o);
|
|
2587
|
+
const t3 = performance.now();
|
|
2588
|
+
const obj = createLdrObject(prep.insts, prep.pack, prep.cull ? { ...o, precomputedCull: prep.cull } : o);
|
|
2589
|
+
for (const m of prep.missing)
|
|
2256
2590
|
if (!obj.stats.missing.includes(m))
|
|
2257
2591
|
obj.stats.missing.push(m);
|
|
2258
2592
|
const t4 = performance.now();
|
|
2259
|
-
return Object.assign(obj, {
|
|
2593
|
+
return Object.assign(obj, {
|
|
2594
|
+
pack: prep.pack,
|
|
2595
|
+
instances: prep.insts,
|
|
2596
|
+
requests: prep.requests,
|
|
2597
|
+
bytes: prep.bytes,
|
|
2598
|
+
ranIn,
|
|
2599
|
+
timings: { ...prep.timings, parts: t3 - t0 - prep.timings.fetchModel - prep.timings.parse, build: t4 - t3, total: t4 - t0 }
|
|
2600
|
+
});
|
|
2260
2601
|
}
|
|
2261
|
-
// ../../../../../../../tmp/ldr-build-
|
|
2602
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/node/library.ts
|
|
2262
2603
|
import { existsSync, readFileSync } from "fs";
|
|
2263
2604
|
import { join } from "path";
|
|
2264
2605
|
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]];
|
|
@@ -2510,11 +2851,11 @@ class Library {
|
|
|
2510
2851
|
return insts;
|
|
2511
2852
|
}
|
|
2512
2853
|
}
|
|
2513
|
-
// ../../../../../../../tmp/ldr-build-
|
|
2854
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/node/build-pack.ts
|
|
2514
2855
|
import fs3 from "node:fs";
|
|
2515
2856
|
import path3 from "node:path";
|
|
2516
2857
|
|
|
2517
|
-
// ../../../../../../../tmp/ldr-build-
|
|
2858
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/node/resolver.ts
|
|
2518
2859
|
import fs from "node:fs";
|
|
2519
2860
|
import path from "node:path";
|
|
2520
2861
|
var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
|
|
@@ -2786,11 +3127,11 @@ function collectDeps(lib, refs) {
|
|
|
2786
3127
|
return out;
|
|
2787
3128
|
}
|
|
2788
3129
|
|
|
2789
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3130
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/node/compile.ts
|
|
2790
3131
|
import fs2 from "node:fs";
|
|
2791
3132
|
import path2 from "node:path";
|
|
2792
3133
|
|
|
2793
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3134
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/node/lod.ts
|
|
2794
3135
|
import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
|
|
2795
3136
|
await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
|
|
2796
3137
|
function reorderMesh(P, N, C, I) {
|
|
@@ -2813,8 +3154,10 @@ function reorderMesh(P, N, C, I) {
|
|
|
2813
3154
|
}
|
|
2814
3155
|
return { P: P2, N: N2, C: C2, I: idx };
|
|
2815
3156
|
}
|
|
2816
|
-
var TARGETS = [0.25, 0.08];
|
|
3157
|
+
var TARGETS = [0.25, 0.08, 0.025];
|
|
2817
3158
|
var MIN_TRIS = 64;
|
|
3159
|
+
var MIN_BOX_TRIS = 24;
|
|
3160
|
+
var COVERAGE_WEIGHT = Number(process.env.LDR_LOD_COVERAGE ?? 0.5);
|
|
2818
3161
|
function flatMesh(tris) {
|
|
2819
3162
|
const map = new Map;
|
|
2820
3163
|
const P = [], N = [], C = [], I = [];
|
|
@@ -2844,9 +3187,62 @@ function flatMesh(tris) {
|
|
|
2844
3187
|
}
|
|
2845
3188
|
return { P: new Float32Array(P), N: new Float32Array(N), C: new Float32Array(C), I: new Uint32Array(I) };
|
|
2846
3189
|
}
|
|
3190
|
+
var G = 64;
|
|
3191
|
+
function silhouettes(P, I, box) {
|
|
3192
|
+
const masks = [0, 1, 2].map(() => new Uint8Array(G * G));
|
|
3193
|
+
for (let ax = 0;ax < 3; ax++) {
|
|
3194
|
+
const u = (ax + 1) % 3, v = (ax + 2) % 3;
|
|
3195
|
+
const m = masks[ax];
|
|
3196
|
+
const su = (box.hi[u] - box.lo[u]) / G || 1, sv = (box.hi[v] - box.lo[v]) / G || 1;
|
|
3197
|
+
for (let t = 0;t < I.length; t += 3) {
|
|
3198
|
+
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]);
|
|
3199
|
+
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]);
|
|
3200
|
+
if (Math.abs(area) < 0.000000000001)
|
|
3201
|
+
continue;
|
|
3202
|
+
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])));
|
|
3203
|
+
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])));
|
|
3204
|
+
for (let y = y0;y <= y1; y++)
|
|
3205
|
+
for (let x = x0;x <= x1; x++) {
|
|
3206
|
+
if (m[y * G + x])
|
|
3207
|
+
continue;
|
|
3208
|
+
const cx = x + 0.5, cy = y + 0.5;
|
|
3209
|
+
let inside = true;
|
|
3210
|
+
for (let e = 0;e < 3 && inside; e++) {
|
|
3211
|
+
const a0 = p[e], a1 = p[(e + 1) % 3];
|
|
3212
|
+
const w = (a1[0] - a0[0]) * (cy - a0[1]) - (cx - a0[0]) * (a1[1] - a0[1]);
|
|
3213
|
+
if (w * area < 0)
|
|
3214
|
+
inside = false;
|
|
3215
|
+
}
|
|
3216
|
+
if (inside)
|
|
3217
|
+
m[y * G + x] = 1;
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
return masks;
|
|
3222
|
+
}
|
|
3223
|
+
function silhouetteDiff(a, b) {
|
|
3224
|
+
let worst = 0;
|
|
3225
|
+
for (let ax = 0;ax < 3; ax++) {
|
|
3226
|
+
let d = 0;
|
|
3227
|
+
for (let i = 0;i < G * G; i++)
|
|
3228
|
+
d += a[ax][i] ^ b[ax][i];
|
|
3229
|
+
worst = Math.max(worst, d / (G * G));
|
|
3230
|
+
}
|
|
3231
|
+
return worst;
|
|
3232
|
+
}
|
|
3233
|
+
function boxMesh(box, col) {
|
|
3234
|
+
const [x0, y0, z0] = box.lo, [x1, y1, z1] = box.hi;
|
|
3235
|
+
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]];
|
|
3236
|
+
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]];
|
|
3237
|
+
const p = new Float32Array(c.flat());
|
|
3238
|
+
const idx = [];
|
|
3239
|
+
for (const q of quads)
|
|
3240
|
+
idx.push(q[0], q[1], q[2], q[0], q[2], q[3]);
|
|
3241
|
+
return flatMesh([{ p, i: Uint32Array.from(idx), col }]);
|
|
3242
|
+
}
|
|
2847
3243
|
function lodChain(P, C, I) {
|
|
2848
3244
|
const nTris = I.length / 3;
|
|
2849
|
-
if (nTris <
|
|
3245
|
+
if (nTris < MIN_BOX_TRIS)
|
|
2850
3246
|
return [];
|
|
2851
3247
|
const groups = new Map;
|
|
2852
3248
|
for (let t = 0;t < I.length; t += 3) {
|
|
@@ -2877,27 +3273,57 @@ function lodChain(P, C, I) {
|
|
|
2877
3273
|
});
|
|
2878
3274
|
const out = [];
|
|
2879
3275
|
let prevTris = nTris;
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
3276
|
+
const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
|
|
3277
|
+
for (let v = 0;v < P.length; v += 3)
|
|
3278
|
+
for (let k = 0;k < 3; k++) {
|
|
3279
|
+
lo[k] = Math.min(lo[k], P[v + k]);
|
|
3280
|
+
hi[k] = Math.max(hi[k], P[v + k]);
|
|
3281
|
+
}
|
|
3282
|
+
const box = { lo, hi };
|
|
3283
|
+
const diag = Math.hypot(hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]);
|
|
3284
|
+
const S0 = silhouettes(P, I, box);
|
|
3285
|
+
const coverageErr = (m) => COVERAGE_WEIGHT * silhouetteDiff(S0, silhouettes(m.P, m.I, box)) * diag;
|
|
3286
|
+
for (let li = 0;li < (nTris >= MIN_TRIS ? TARGETS.length : 0); li++) {
|
|
3287
|
+
let best = null;
|
|
3288
|
+
for (const sloppy of [false, true]) {
|
|
3289
|
+
let err = 0;
|
|
3290
|
+
const parts = [];
|
|
3291
|
+
for (const g of welded) {
|
|
3292
|
+
const target = Math.max(3, Math.floor(g.i.length * TARGETS[li] / 3) * 3);
|
|
3293
|
+
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"]);
|
|
3294
|
+
err = Math.max(err, sloppy ? e * MeshoptSimplifier.getScale(g.p, 3) : e);
|
|
3295
|
+
if (idx.length)
|
|
3296
|
+
parts.push({ p: g.p, i: idx, col: g.col });
|
|
3297
|
+
}
|
|
3298
|
+
const m = flatMesh(parts);
|
|
3299
|
+
const t = m.I.length / 3;
|
|
3300
|
+
if (!t || t > prevTris * 0.7)
|
|
3301
|
+
continue;
|
|
3302
|
+
const e = +Math.max(err, coverageErr(m), 0.001).toFixed(3);
|
|
3303
|
+
if (!best || e < best.err)
|
|
3304
|
+
best = { ...m, err: e };
|
|
3305
|
+
}
|
|
3306
|
+
if (best) {
|
|
3307
|
+
out.push(best);
|
|
3308
|
+
prevTris = best.I.length / 3;
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
if (prevTris * 0.7 >= 12) {
|
|
3312
|
+
const main = welded.reduce((a, g) => g.i.length > a.i.length ? g : a);
|
|
3313
|
+
const m = boxMesh(box, main.col);
|
|
3314
|
+
let inner = 0;
|
|
3315
|
+
for (let v = 0;v < P.length; v += 3) {
|
|
3316
|
+
let d = Infinity;
|
|
3317
|
+
for (let k = 0;k < 3; k++)
|
|
3318
|
+
d = Math.min(d, P[v + k] - lo[k], hi[k] - P[v + k]);
|
|
3319
|
+
inner = Math.max(inner, d);
|
|
3320
|
+
}
|
|
3321
|
+
out.push({ ...m, err: +Math.max(inner, coverageErr(m) / COVERAGE_WEIGHT, out.length ? out[out.length - 1].err : 0, 0.001).toFixed(3) });
|
|
2896
3322
|
}
|
|
2897
3323
|
return out;
|
|
2898
3324
|
}
|
|
2899
3325
|
|
|
2900
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3326
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/node/compile.ts
|
|
2901
3327
|
function loadColors(root) {
|
|
2902
3328
|
const map = new Map;
|
|
2903
3329
|
for (const l of fs2.readFileSync(path2.join(root, "LDConfig.ldr"), "latin1").split(/\r?\n/)) {
|
|
@@ -3480,7 +3906,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
3480
3906
|
return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
|
|
3481
3907
|
}
|
|
3482
3908
|
|
|
3483
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3909
|
+
// ../../../../../../../tmp/ldr-build-NB5kkP/src/node/build-pack.ts
|
|
3484
3910
|
function buildPack(o) {
|
|
3485
3911
|
const lib = new Library2(o.ldrawRoot);
|
|
3486
3912
|
const refs = new Map;
|
|
@@ -3588,8 +4014,11 @@ export {
|
|
|
3588
4014
|
parseLDConfig,
|
|
3589
4015
|
parseModel,
|
|
3590
4016
|
parseTexMap,
|
|
4017
|
+
precomputeCull,
|
|
4018
|
+
prepareModel,
|
|
3591
4019
|
resolveTexture,
|
|
3592
4020
|
rotStepMatrix,
|
|
4021
|
+
sceneInstances,
|
|
3593
4022
|
sequenceSteps,
|
|
3594
4023
|
smoothNormals,
|
|
3595
4024
|
splitModel,
|
|
@@ -3598,5 +4027,6 @@ export {
|
|
|
3598
4027
|
texmapTriangleUV,
|
|
3599
4028
|
texmapUV,
|
|
3600
4029
|
transformTexMap,
|
|
4030
|
+
warmPackGeometry,
|
|
3601
4031
|
writePack
|
|
3602
4032
|
};
|