ldr 0.5.1 → 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.
@@ -1,4 +1,4 @@
1
- // ../../../../../../../tmp/ldr-build-pIke9r/src/spec.ts
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(/\r?\n/)) {
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-pIke9r/src/model.ts
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-pIke9r/src/render.ts
813
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/render.ts
772
814
  import * as THREE from "three";
773
- async function loadPack(url) {
774
- const res = await fetch(url);
775
- const t0 = performance.now();
776
- let buf;
777
- if (url.endsWith(".gz"))
778
- buf = await new Response(res.body.pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();
779
- else if (url.endsWith(".br"))
780
- buf = await new Response(res.body.pipeThrough(new DecompressionStream("brotli"))).arrayBuffer();
781
- else if (url.endsWith(".zst")) {
782
- const raw = new Uint8Array(await res.arrayBuffer());
783
- const t1 = performance.now();
784
- const { decompress } = await import("fzstd");
785
- const o = decompress(raw);
786
- buf = o.buffer.slice(o.byteOffset, o.byteOffset + o.byteLength);
787
- globalThis.__decodeMs = performance.now() - t1;
788
- } else
789
- buf = await res.arrayBuffer();
790
- if (!url.endsWith(".zst"))
791
- globalThis.__decodeMs = performance.now() - t0;
792
- return decodePack(buf);
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,296 +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
- var toI8 = (a) => {
802
- const o = new Int8Array(a.length);
803
- for (let i = 0;i < a.length; i++)
804
- o[i] = Math.round(Math.max(-1, Math.min(1, a[i])) * 127);
805
- return o;
806
- };
807
- var toU8 = (a) => {
808
- const o = new Uint8Array(a.length);
809
- for (let i = 0;i < a.length; i++)
810
- o[i] = Math.round(Math.max(0, Math.min(1, a[i])) * 255);
811
- return o;
812
- };
813
- function flatNormals(pos, idx) {
814
- const n = new Float32Array(pos.length);
815
- for (let t = 0;t < idx.length; t += 3) {
816
- const a = idx[t] * 3, b = idx[t + 1] * 3, c = idx[t + 2] * 3;
817
- const ux = pos[b] - pos[a], uy = pos[b + 1] - pos[a + 1], uz = pos[b + 2] - pos[a + 2], vx = pos[c] - pos[a], vy = pos[c + 1] - pos[a + 1], vz = pos[c + 2] - pos[a + 2];
818
- let nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;
819
- const l = Math.hypot(nx, ny, nz) || 1;
820
- nx /= l;
821
- ny /= l;
822
- nz /= l;
823
- for (const o of [a, b, c]) {
824
- n[o] = nx;
825
- n[o + 1] = ny;
826
- n[o + 2] = nz;
827
- }
828
- }
829
- return n;
830
- }
831
- var geomCache = new WeakMap;
832
- function geom(b, arr, quant = true) {
833
- if (!b)
834
- return null;
835
- let c = geomCache.get(arr);
836
- if (!c)
837
- geomCache.set(arr, c = new Map);
838
- const ck = quant ? b : b.pos;
839
- let g = c.get(ck);
840
- if (g)
841
- return g;
842
- g = new THREE.BufferGeometry;
843
- g.setAttribute("position", new THREE.BufferAttribute(arr(b.pos), 3));
844
- const nrm = b.nrm ? arr(b.nrm) : flatNormals(arr(b.pos), arr(b.idx));
845
- const col = arr(b.col);
846
- g.setAttribute("normal", quant ? new THREE.BufferAttribute(toI8(nrm), 3, true) : new THREE.BufferAttribute(nrm, 3));
847
- g.setAttribute("ldrColor", col instanceof Uint8Array ? new THREE.BufferAttribute(col, 4, true) : quant ? new THREE.BufferAttribute(toU8(col), 4, true) : new THREE.BufferAttribute(col, 4));
848
- if (b.idx)
849
- g.setIndex(new THREE.BufferAttribute(arr(b.idx), 1));
850
- if (b.uv)
851
- g.setAttribute("ldrUV", new THREE.BufferAttribute(arr(b.uv), 2));
852
- c.set(ck, g);
853
- return g;
854
- }
855
- function makeMaterial(side) {
856
- const m = new THREE.MeshStandardMaterial({ vertexColors: true, roughness: 0.45, side });
857
- m.onBeforeCompile = (s) => {
858
- s.vertexShader = `attribute vec4 ldrColor;
859
- ` + s.vertexShader.replace("#include <color_vertex>", `#include <color_vertex>
860
- #ifdef USE_INSTANCING_COLOR
861
- vColor.rgb = ldrColor.a > 0.5 ? pow(ldrColor.rgb, vec3(2.2)) : instanceColor.rgb; // baked LDConfig colours are sRGB
862
- #else
863
- vColor.rgb = pow(ldrColor.rgb, vec3(2.2));
864
- #endif`);
865
- };
866
- m.customProgramCacheKey = () => "ldrColor";
867
- return m;
868
- }
869
- function makeTexturedMaterial(side, map, wrapU = false) {
870
- const m = makeMaterial(side);
871
- const base = m.onBeforeCompile;
872
- m.onBeforeCompile = (sh, r) => {
873
- base.call(m, sh, r);
874
- sh.uniforms.ldrMap = { value: map };
875
- sh.uniforms.ldrWrapU = { value: wrapU ? 1 : 0 };
876
- sh.vertexShader = `attribute vec2 ldrUV; varying vec2 vLdrUV;
877
- ` + sh.vertexShader.replace("#include <uv_vertex>", `#include <uv_vertex>
878
- vLdrUV = ldrUV;`);
879
- sh.fragmentShader = `uniform sampler2D ldrMap; uniform int ldrWrapU; varying vec2 vLdrUV;
880
- ` + sh.fragmentShader.replace("#include <color_fragment>", `#include <color_fragment>
881
- { vec2 uv = vec2(ldrWrapU == 1 ? fract(vLdrUV.x) : vLdrUV.x, vLdrUV.y); vec4 t = texture2D(ldrMap, uv);
882
- float inside = step(0.0, uv.x) * step(uv.x, 1.0) * step(0.0, uv.y) * step(uv.y, 1.0);
883
- diffuseColor.rgb = mix(diffuseColor.rgb, t.rgb, t.a * inside); }`);
884
- };
885
- m.customProgramCacheKey = () => "ldrColorTex";
886
- m.userData.ldrMap = map;
887
- return m;
888
- }
889
- function packTexture(pack, i) {
890
- const t = new THREE.Texture;
891
- t.flipY = false;
892
- t.colorSpace = THREE.SRGBColorSpace;
893
- t.wrapS = t.wrapT = THREE.ClampToEdgeWrapping;
894
- const e = pack.header.textures?.[i];
895
- const bytes = e?.data ? pack.arr(e.data) : null;
896
- if (!bytes || typeof createImageBitmap === "undefined")
897
- return { texture: t, ready: Promise.resolve() };
898
- const ready = createImageBitmap(new Blob([bytes], { type: e.mime || "image/png" }), { premultiplyAlpha: "none", colorSpaceConversion: "none" }).then((img) => {
899
- t.image = img;
900
- t.needsUpdate = true;
901
- }).catch(() => {});
902
- return { texture: t, ready };
903
- }
904
- var lineMat = () => new THREE.ShaderMaterial({
905
- vertexShader: `attribute vec4 im0; attribute vec4 im1; attribute vec4 im2; attribute vec4 im3;
906
- void main(){ gl_Position = projectionMatrix * modelViewMatrix * mat4(im0,im1,im2,im3) * vec4(position,1.0); }`,
907
- fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
908
- });
909
- var sharedLineMat = () => new THREE.ShaderMaterial({
910
- vertexShader: `attribute mat4 instanceMatrix; void main(){ gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position,1.0); }`,
911
- fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
912
- });
913
- var weldLines = (pos) => {
914
- const map = new Map;
915
- const P = [];
916
- const I = [];
917
- for (let i = 0;i < pos.length; i += 3) {
918
- const k = pos[i].toFixed(2) + "," + pos[i + 1].toFixed(2) + "," + pos[i + 2].toFixed(2);
919
- let j = map.get(k);
920
- if (j === undefined) {
921
- j = P.length / 3;
922
- map.set(k, j);
923
- P.push(pos[i], pos[i + 1], pos[i + 2]);
924
- }
925
- I.push(j);
926
- }
927
- return { P: new Float32Array(P), I: P.length / 3 < 65536 ? new Uint16Array(I) : new Uint32Array(I) };
928
- };
929
- function createInstancedEdges(pos, im, material = sharedLineMat()) {
930
- return sharedLines(pos, im, material);
931
- }
932
- function conditionalLines(pack, entry, which = "all") {
933
- if (which === "all") {
934
- const a = conditionalLines(pack, entry, "body"), b = conditionalLines(pack, entry, "under");
935
- if (!a || !b)
936
- return a ?? b;
937
- const o = new Float32Array(a.length + b.length);
938
- o.set(a);
939
- o.set(b, a.length);
940
- return o;
941
- }
942
- const c = which === "under" ? entry?.condlu : entry?.condl;
943
- if (!c)
944
- return null;
945
- const { arr } = pack;
946
- if (c.raw)
947
- return arr(c.raw);
948
- const pools = [entry.body ? arr(entry.body.pos) : [], entry.under ? arr(entry.under.pos) : [], entry.edges ? arr(entry.edges) : [], c.x ? arr(c.x) : []];
949
- const idx = arr(c.idx);
950
- const out = new Float32Array(idx.length * 3);
951
- const starts = [];
952
- let base = 0;
953
- for (const p of pools) {
954
- starts.push(base);
955
- base += p.length / 3;
956
- }
957
- let prev = 0;
958
- for (let i = 0;i < idx.length; i++) {
959
- const z = idx[i];
960
- const j = prev + (z & 1 ? -(z + 1) / 2 : z / 2);
961
- prev = j;
962
- let k = 3;
963
- while (k > 0 && j < starts[k])
964
- k--;
965
- const p = pools[k], o = (j - starts[k]) * 3;
966
- out[i * 3] = p[o];
967
- out[i * 3 + 1] = p[o + 1];
968
- out[i * 3 + 2] = p[o + 2];
969
- }
970
- return out;
971
- }
972
- var condLineMat = () => new THREE.ShaderMaterial({
973
- uniforms: { ldrViewProj: { value: new THREE.Matrix4 } },
974
- vertexShader: `uniform mat4 ldrViewProj; attribute mat4 instanceMatrix; attribute vec3 ldrP1; attribute vec3 ldrC0; attribute vec3 ldrC1; attribute float ldrSide;
975
- void main(){
976
- mat4 mvp = ldrViewProj * instanceMatrix;
977
- 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);
978
- vec2 A = a.xy / a.w, B = b.xy / b.w, C0 = c0.xy / c0.w, C1 = c1.xy / c1.w, d = B - A;
979
- 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);
980
- gl_Position = s0 * s1 >= 0.0 ? (ldrSide > 0.5 ? b : a) : vec4(2.0, 2.0, 2.0, 1.0);
981
- }`,
982
- fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
983
- });
984
- function conditionalLineVisible(cond, i, mvp) {
985
- const e = mvp.elements;
986
- const pr = (o) => {
987
- const x = cond[o], y = cond[o + 1], z = cond[o + 2];
988
- const w = e[3] * x + e[7] * y + e[11] * z + e[15];
989
- 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];
990
- };
991
- const o = i * 12;
992
- const A = pr(o), B = pr(o + 3), C0 = pr(o + 6), C1 = pr(o + 9);
993
- const dx = B[0] - A[0], dy = B[1] - A[1];
994
- const s0 = dx * (C0[1] - A[1]) - dy * (C0[0] - A[0]), s1 = dx * (C1[1] - A[1]) - dy * (C1[0] - A[0]);
995
- return s0 * s1 >= 0;
996
- }
997
- function createInstancedConditionalEdges(cond, im, material = condLineMat()) {
998
- return condEdges(condBuffers(cond), im, material);
999
- }
1000
- function condBuffers(cond) {
1001
- const n = Math.floor(cond.length / 12);
1002
- const buf = new Float32Array(n * 24), side = new Float32Array(n * 2);
1003
- for (let l = 0;l < n; l++) {
1004
- for (let k = 0;k < 12; k++) {
1005
- const v = cond[l * 12 + k];
1006
- buf[l * 24 + k] = v;
1007
- buf[l * 24 + 12 + k] = v;
1008
- }
1009
- side[l * 2 + 1] = 1;
1010
- }
1011
- return { ib: new THREE.InterleavedBuffer(buf, 12), side: new THREE.BufferAttribute(side, 1) };
1012
- }
1013
- function condEdges({ ib, side }, im, material) {
1014
- const g = new THREE.InstancedBufferGeometry;
1015
- g.setAttribute("position", new THREE.InterleavedBufferAttribute(ib, 3, 0));
1016
- g.setAttribute("ldrP1", new THREE.InterleavedBufferAttribute(ib, 3, 3));
1017
- g.setAttribute("ldrC0", new THREE.InterleavedBufferAttribute(ib, 3, 6));
1018
- g.setAttribute("ldrC1", new THREE.InterleavedBufferAttribute(ib, 3, 9));
1019
- g.setAttribute("ldrSide", side);
1020
- g.setAttribute("instanceMatrix", im.instanceMatrix);
1021
- g.instanceCount = im.count;
1022
- const l = new THREE.LineSegments(g, material);
1023
- l.frustumCulled = false;
1024
- l.name = "ldrCondLines";
1025
- l.onBeforeRender = (_r, _s, cam, _g, mat) => {
1026
- const u = mat.uniforms?.ldrViewProj;
1027
- if (!u)
1028
- return;
1029
- l.modelViewMatrix.multiplyMatrices(cam.matrixWorldInverse, l.matrixWorld);
1030
- u.value.multiplyMatrices(cam.projectionMatrix, l.modelViewMatrix);
1031
- mat.uniformsNeedUpdate = true;
1032
- };
1033
- return l;
1034
- }
1035
- function sharedLines(pos, im, material = sharedLineMat()) {
1036
- const { P, I } = weldLines(pos);
1037
- const g = new THREE.InstancedBufferGeometry;
1038
- g.setAttribute("position", new THREE.BufferAttribute(P, 3));
1039
- g.setIndex(new THREE.BufferAttribute(I, 1));
1040
- g.setAttribute("instanceMatrix", im.instanceMatrix);
1041
- g.instanceCount = im.count;
1042
- const l = new THREE.LineSegments(g, material);
1043
- l.frustumCulled = false;
1044
- return l;
1045
- }
1046
- function instancedLines(pos, mats, count) {
1047
- const g = new THREE.InstancedBufferGeometry;
1048
- g.setAttribute("position", new THREE.BufferAttribute(pos, 3));
1049
- const ib = new THREE.InstancedInterleavedBuffer(mats, 16);
1050
- for (let i = 0;i < 4; i++)
1051
- g.setAttribute("im" + i, new THREE.InterleavedBufferAttribute(ib, 4, i * 4));
1052
- g.instanceCount = count;
1053
- const l = new THREE.LineSegments(g, lineMat());
1054
- l.frustumCulled = false;
1055
- return l;
1056
- }
1057
- function writeM4(t, o, m, mo = 0) {
1058
- t[o] = m[mo + 3];
1059
- t[o + 1] = m[mo + 6];
1060
- t[o + 2] = m[mo + 9];
1061
- t[o + 3] = 0;
1062
- t[o + 4] = m[mo + 4];
1063
- t[o + 5] = m[mo + 7];
1064
- t[o + 6] = m[mo + 10];
1065
- t[o + 7] = 0;
1066
- t[o + 8] = m[mo + 5];
1067
- t[o + 9] = m[mo + 8];
1068
- t[o + 10] = m[mo + 11];
1069
- t[o + 11] = 0;
1070
- t[o + 12] = m[mo];
1071
- t[o + 13] = m[mo + 1];
1072
- t[o + 14] = m[mo + 2];
1073
- t[o + 15] = 1;
1074
- }
1075
- function newIM(g, mat, n) {
1076
- const im = new THREE.InstancedMesh(g, mat, 0);
1077
- im.instanceMatrix = new THREE.InstancedBufferAttribute(new Float32Array(n * 16), 16);
1078
- im.count = n;
1079
- return im;
1080
- }
1081
- function fillInstances(im, ids, insts, color) {
1082
- const M = im.instanceMatrix.array;
1083
- const C = new Float32Array(ids.length * 3);
1084
- for (let k = 0;k < ids.length; k++) {
1085
- const it = insts[ids[k]];
1086
- writeM4(M, k * 16, it.m);
1087
- color(it.color).toArray(C, k * 3);
1088
- }
1089
- im.instanceColor = new THREE.InstancedBufferAttribute(C, 3);
1090
- }
834
+
835
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/cull.ts
1091
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;
1092
837
  var prepCache = new WeakMap;
1093
838
  function prepPart(H, part) {
@@ -1133,76 +878,84 @@ function mul12To(a, b, bo, w, ao = 0) {
1133
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];
1134
879
  }
1135
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]);
1136
- var cellKey = (lv2, cx, cz) => lv2 < -1048576 || lv2 >= 1048576 || cx < -32768 || cx >= 32768 || cz < -32768 || cz >= 32768 ? -1 : (lv2 + 1048576) * 4294967296 + (cx + 32768) * 65536 + (cz + 32768);
1137
- var topKey = (x, y, z) => {
1138
- const rx = Math.round(x), ry = Math.round(y), rz = Math.round(z);
1139
- return rx < -131072 || rx >= 131072 || ry < -65536 || ry >= 65536 || rz < -131072 || rz >= 131072 ? -1 : (rx + 131072) * 34359738368 + (ry + 65536) * 262144 + (rz + 131072);
1140
- };
881
+ var BIG = 1073741824;
1141
882
 
1142
- class NumTable {
1143
- keys;
883
+ class Int3Table {
884
+ a;
885
+ b;
886
+ c;
1144
887
  vals;
888
+ used;
1145
889
  mask;
1146
890
  size = 0;
1147
891
  constructor(cap = 1024) {
1148
892
  let n = 1024;
1149
893
  while (n < cap * 2)
1150
894
  n *= 2;
1151
- this.keys = new Float64Array(n).fill(-1);
895
+ this.a = new Int32Array(n);
896
+ this.b = new Int32Array(n);
897
+ this.c = new Int32Array(n);
1152
898
  this.vals = new Int32Array(n);
899
+ this.used = new Uint8Array(n);
1153
900
  this.mask = n - 1;
1154
901
  }
1155
- slot(k) {
1156
- const lo = k >>> 0, hi = k / 4294967296 >>> 0;
1157
- 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);
1158
904
  h ^= h >>> 15;
905
+ h = Math.imul(h, 739982445);
906
+ h ^= h >>> 12;
1159
907
  return h & this.mask;
1160
908
  }
1161
- get(k) {
1162
- const K = this.keys;
1163
- let i = this.slot(k);
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;
1164
912
  for (;; ) {
1165
- const x = K[i];
1166
- if (x === k)
1167
- return this.vals[i];
1168
- if (x === -1)
913
+ if (!U[i])
1169
914
  return -1;
915
+ if (A[i] === x && B[i] === y && C[i] === z)
916
+ return this.vals[i];
1170
917
  i = i + 1 & this.mask;
1171
918
  }
1172
919
  }
1173
- put(k, v) {
1174
- if ((this.size + 1) * 2 > this.keys.length)
920
+ put(x, y, z, v) {
921
+ if ((this.size + 1) * 2 > this.used.length)
1175
922
  this.grow();
1176
- const K = this.keys;
1177
- let i = this.slot(k);
923
+ let i = this.slot(x, y, z);
924
+ const U = this.used, A = this.a, B = this.b, C = this.c;
1178
925
  for (;; ) {
1179
- const x = K[i];
1180
- if (x === k) {
1181
- const o = this.vals[i];
1182
- this.vals[i] = v;
1183
- return o;
1184
- }
1185
- if (x === -1) {
1186
- K[i] = k;
926
+ if (!U[i]) {
927
+ U[i] = 1;
928
+ A[i] = x;
929
+ B[i] = y;
930
+ C[i] = z;
1187
931
  this.vals[i] = v;
1188
932
  this.size++;
1189
933
  return -1;
1190
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
+ }
1191
940
  i = i + 1 & this.mask;
1192
941
  }
1193
942
  }
1194
943
  grow() {
1195
- const ok = this.keys, ov = this.vals;
1196
- const n = ok.length * 2;
1197
- this.keys = new Float64Array(n).fill(-1);
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);
1198
949
  this.vals = new Int32Array(n);
950
+ this.used = new Uint8Array(n);
1199
951
  this.mask = n - 1;
1200
952
  this.size = 0;
1201
- for (let i = 0;i < ok.length; i++)
1202
- if (ok[i] !== -1)
1203
- this.put(ok[i], ov[i]);
953
+ for (let i = 0;i < used.length; i++)
954
+ if (used[i])
955
+ this.put(a[i], b[i], c[i], vals[i]);
1204
956
  }
1205
957
  }
958
+ var inRange = (x, y, z) => x > -BIG && x < BIG && y > -BIG && y < BIG && z > -BIG && z < BIG;
1206
959
  var STEP_NEVER = 2147483647;
1207
960
  function forEachStud(insts, H, fn) {
1208
961
  const w = new Float64Array(12);
@@ -1222,7 +975,7 @@ function forEachStud(insts, H, fn) {
1222
975
  function cullCore(insts, H, steps) {
1223
976
  const CELL = 40;
1224
977
  const rx0 = [], rx1 = [], rz0 = [], rz1 = [], rInst = [], rPrep = [], rBx = [], rBz = [];
1225
- const cells = new NumTable(insts.length * 2);
978
+ const cells = new Int3Table(insts.length * 2);
1226
979
  const nextE = [], rectE = [];
1227
980
  for (let idx = 0;idx < insts.length; idx++) {
1228
981
  const it = insts[idx];
@@ -1257,21 +1010,27 @@ function cullCore(insts, H, steps) {
1257
1010
  const lv2 = Math.round((m[1] + b[4]) * 2);
1258
1011
  for (let cx = Math.floor(x0 / CELL);cx <= Math.floor(x1 / CELL); cx++)
1259
1012
  for (let cz = Math.floor(z0 / CELL);cz <= Math.floor(z1 / CELL); cz++) {
1260
- const k = cellKey(lv2, cx, cz);
1261
- if (k < 0)
1013
+ if (!inRange(lv2, cx, cz))
1262
1014
  continue;
1263
1015
  const e = rectE.length;
1264
1016
  rectE.push(ri);
1265
- nextE.push(cells.put(k, e));
1017
+ nextE.push(cells.put(lv2, cx, cz, e));
1266
1018
  }
1267
1019
  }
1268
1020
  const SX = [0, 5, -5, 5, -5], SZ = [0, 5, 5, -5, -5];
1021
+ let kl = NaN, kx = NaN, kz = NaN, ke = -1;
1269
1022
  const coverStep = (x, y, z, self) => {
1270
- const k = cellKey(Math.round(y * 2), Math.floor(x / CELL), Math.floor(z / CELL));
1271
- if (k < 0)
1023
+ const l2 = Math.round(y * 2), gx = Math.floor(x / CELL), gz = Math.floor(z / CELL);
1024
+ if (!inRange(l2, gx, gz))
1272
1025
  return STEP_NEVER;
1273
1026
  let best = STEP_NEVER;
1274
- for (let e = cells.get(k);e >= 0; e = nextE[e]) {
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]) {
1275
1034
  const ri = rectE[e];
1276
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))
1277
1036
  continue;
@@ -1299,71 +1058,448 @@ function cullCore(insts, H, steps) {
1299
1058
  }
1300
1059
  return best;
1301
1060
  };
1302
- let nStuds = 0;
1303
- for (const it of insts) {
1304
- const pp = prepPart(H, it.part);
1305
- if (pp)
1306
- 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;
1307
1373
  }
1308
- const studHidden = new Uint8Array(nStuds), studUp = new Uint8Array(nStuds);
1309
- const tops = new NumTable(nStuds);
1310
- let studsHidden = 0;
1311
- const studHideStep = steps ? new Int32Array(nStuds).fill(STEP_NEVER) : undefined;
1312
- forEachStud(insts, H, (j, idx, w) => {
1313
- if (!upright(w))
1314
- return;
1315
- studUp[j] = 1;
1316
- const cs = coverStep(w[0], w[1], w[2], idx);
1317
- if (cs !== STEP_NEVER) {
1318
- studHidden[j] = 1;
1319
- studsHidden++;
1320
- if (studHideStep)
1321
- studHideStep[j] = cs;
1322
- }
1323
- const k = topKey(w[0], w[1], w[2]);
1324
- if (k < 0)
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)
1325
1391
  return;
1326
- if (!steps) {
1327
- tops.put(k, 1);
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;
1328
1447
  return;
1329
1448
  }
1330
- const st = steps[idx], o = tops.get(k);
1331
- if (o < 0 || st < o)
1332
- tops.put(k, st);
1333
- });
1334
- const underHidden = new Uint8Array(insts.length);
1335
- const underHideStep = steps ? new Int32Array(insts.length).fill(STEP_NEVER) : undefined;
1336
- for (let idx = 0;idx < insts.length; idx++) {
1337
- const it = insts[idx];
1338
- const p = H.parts[it.part];
1339
- if (!p || !p.under || !upright(it.m))
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;
1340
1472
  continue;
1341
- const b = p.bbox;
1342
- const nx = Math.round((b[3] - b[0]) / 20), nz = Math.round((b[5] - b[2]) / 20);
1343
- if (!nx || !nz || nx * nz > 4096)
1473
+ }
1474
+ if (x === cx && y === cy && z === cz) {
1475
+ r = Math.max(r, sr);
1344
1476
  continue;
1345
- const m = it.m;
1346
- let all = true, at = 0;
1347
- for (let a = 0;a < nx && all; a++)
1348
- for (let c = 0;c < nz; c++) {
1349
- const lx = b[0] + 10 + 20 * a, lz = b[2] + 10 + 20 * c;
1350
- const x = m[0] + m[3] * lx + m[5] * lz, z = m[2] + m[9] * lx + m[11] * lz;
1351
- const k = topKey(x, m[1] + b[4], z);
1352
- const t = k < 0 ? -1 : tops.get(k);
1353
- if (t < 0) {
1354
- all = false;
1355
- break;
1356
- }
1357
- if (t > at)
1358
- at = t;
1359
- }
1360
- if (all) {
1361
- underHidden[idx] = 1;
1362
- if (underHideStep)
1363
- underHideStep[idx] = at;
1364
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);
1365
1501
  }
1366
- return { nStuds, studHidden, studUp, underHidden, studsHidden, studHideStep, underHideStep };
1502
+ im.instanceColor = new THREE.InstancedBufferAttribute(C, 3);
1367
1503
  }
1368
1504
  function computeCulling(insts, H) {
1369
1505
  const c = cullCore(insts, H);
@@ -1419,7 +1555,8 @@ class LdrLodRoot extends THREE.LOD {
1419
1555
  clusters = [];
1420
1556
  vpH = 1080;
1421
1557
  px = 0.5;
1422
- edgePpl = 0.025;
1558
+ edgePpl = 0.5 / 20;
1559
+ edgeMinPx = 0.15;
1423
1560
  enabled = true;
1424
1561
  apply = () => {};
1425
1562
  inv = new THREE.Matrix4;
@@ -1449,37 +1586,90 @@ class LdrLodRoot extends THREE.LOD {
1449
1586
  L = i;
1450
1587
  break;
1451
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;
1452
1593
  const e = ppl >= eppl;
1453
1594
  if (L !== c.cur || e !== c.edgeOk) {
1454
1595
  c.cur = L;
1455
1596
  c.edgeOk = e;
1456
1597
  this.apply(c);
1457
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
+ }
1458
1616
  }
1459
1617
  }
1460
1618
  }
1461
- function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps, colorIndex) {
1619
+ function buildStudMeshes(insts, H, cull, arr, LOD, color, matF, matB, steps, colorIndex) {
1462
1620
  const bucketOf = new Map;
1463
1621
  const bKind = [], bMirror = [];
1464
1622
  const bAll = [];
1465
1623
  const studBucket = new Uint16Array(cull.nStuds);
1466
1624
  const sx = new Float32Array(cull.nStuds), sz = new Float32Array(cull.nStuds);
1467
- forEachStud(insts, H, (j, _i, w, kind) => {
1468
- const neg = det12(w) < 0;
1469
- const k = neg ? kind + "#m" : kind;
1470
- let b = bucketOf.get(k);
1471
- if (b === undefined) {
1472
- b = bKind.length;
1473
- bucketOf.set(k, b);
1474
- bKind.push(kind);
1475
- bMirror.push(neg);
1476
- bAll.push(0);
1477
- }
1478
- studBucket[j] = b;
1479
- bAll[b]++;
1480
- sx[j] = w[0];
1481
- sz[j] = w[2];
1482
- });
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
+ }
1483
1673
  const bIds = bAll.map((n) => new Int32Array(n));
1484
1674
  {
1485
1675
  const f = bAll.map(() => 0);
@@ -1491,7 +1681,7 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
1491
1681
  const studCl = new Int32Array(cull.nStuds), studSlot = new Int32Array(cull.nStuds);
1492
1682
  const sMesh = [];
1493
1683
  bKind.forEach((kind, b) => {
1494
- const g = geom(H.studKinds[kind].body, arr, Q);
1684
+ const g = geom(H.studKinds[kind].body, arr);
1495
1685
  const ids = bIds[b];
1496
1686
  for (const c of gridClusters(ids.length, (i) => sx[ids[i]], (i) => sz[ids[i]], LOD ? 16384 : Infinity)) {
1497
1687
  const ci = sMesh.length;
@@ -1515,6 +1705,13 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
1515
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) } } : {} });
1516
1706
  }
1517
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
+ };
1518
1715
  forEachStud(insts, H, (j, owner, w, _kind, col, si) => {
1519
1716
  const sm = sMesh[studCl[j]];
1520
1717
  if (!sm)
@@ -1530,18 +1727,46 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
1530
1727
  t.col[slot] = colorIndex(col);
1531
1728
  }
1532
1729
  writeM4(im.instanceMatrix.array, slot * 16, w);
1533
- color(col).toArray(im.instanceColor.array, slot * 3);
1730
+ colorOf(col).toArray(im.instanceColor.array, slot * 3);
1534
1731
  });
1535
1732
  return sMesh;
1536
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
+ }
1537
1761
  function buildLdrScene(insts, pack, P, color, mark) {
1538
1762
  const { header: H, arr } = pack;
1539
- const Q = P.quant !== false;
1540
1763
  const LOD = P.lod !== false;
1764
+ const EDGES = !!P.edges;
1541
1765
  const root = new LdrLodRoot;
1542
1766
  root.enabled = LOD;
1543
1767
  root.px = P.lodPx ?? 0.5;
1544
1768
  root.edgePpl = (P.lodEdgePx ?? 0.5) / 20;
1769
+ root.edgeMinPx = P.lodEdgeMinPx ?? 0.15;
1545
1770
  const trackVp = (r) => {
1546
1771
  const rt = r.getRenderTarget();
1547
1772
  const h = rt ? rt.height : r.getContext().drawingBufferHeight;
@@ -1559,7 +1784,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
1559
1784
  }
1560
1785
  });
1561
1786
  const steps = P.steps;
1562
- let cull = cullCore(insts, H, steps);
1787
+ let cull = P.cull ?? cullCore(insts, H, steps);
1563
1788
  mark("culling");
1564
1789
  const stepBatches = [];
1565
1790
  const instM = steps ? new Float64Array(insts.length * 12) : null;
@@ -1585,7 +1810,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
1585
1810
  });
1586
1811
  const edgeObjs = [];
1587
1812
  const condObjs = [];
1588
- const wantCond = P.cond !== false && (P.edges === "idx" || P.edges === true);
1813
+ const wantCond = P.cond !== false && EDGES;
1589
1814
  let condMat = null;
1590
1815
  const cmat = () => condMat ??= condLineMat();
1591
1816
  let lineMatShared = null;
@@ -1616,8 +1841,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
1616
1841
  const addLines = (ref, im, cl) => {
1617
1842
  let w = lineCache.get(ref);
1618
1843
  if (!w) {
1619
- const r = weldLines(arr(ref));
1620
- lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1) });
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 });
1621
1846
  }
1622
1847
  const g = new THREE.InstancedBufferGeometry;
1623
1848
  g.setAttribute("position", w.P);
@@ -1626,6 +1851,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
1626
1851
  g.instanceCount = im.count;
1627
1852
  const l = new THREE.LineSegments(g, lmat());
1628
1853
  l.frustumCulled = false;
1854
+ if (LOD)
1855
+ l.userData.ldrLens = w.lens;
1629
1856
  edgeObjs.push(l);
1630
1857
  cl.lines.push(l);
1631
1858
  root.add(l);
@@ -1633,7 +1860,6 @@ function buildLdrScene(insts, pack, P, color, mark) {
1633
1860
  };
1634
1861
  const stats = { studsTotal: cull.nStuds, studsHidden: cull.studsHidden, undersTotal: 0, undersHidden: 0 };
1635
1862
  const toggles = [];
1636
- const studMeshes = [];
1637
1863
  const countTo = (objs) => ({ set count(n) {
1638
1864
  for (const o of objs()) {
1639
1865
  if (o.isInstancedMesh)
@@ -1668,8 +1894,9 @@ function buildLdrScene(insts, pack, P, color, mark) {
1668
1894
  root.clusters.push(c);
1669
1895
  return c;
1670
1896
  };
1671
- const lodLevels = (b, base, mat) => !LOD || P.lodMesh === false || !b?.lod ? [] : b.lod.map((l) => {
1672
- const im = new THREE.InstancedMesh(geom(l, arr, Q), mat, 0);
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 };
1673
1900
  im.instanceMatrix = base.instanceMatrix;
1674
1901
  im.count = base.count;
1675
1902
  im.instanceColor = base.instanceColor;
@@ -1685,10 +1912,10 @@ function buildLdrScene(insts, pack, P, color, mark) {
1685
1912
  for (const [pk, idsAll] of byPart) {
1686
1913
  const part = pk.replace(/#m$/, "");
1687
1914
  const p = H.parts[part];
1688
- const mat = P.uncertDouble !== false && p.uncert ? (nUncert++, matD) : pk.endsWith("#m") ? matB : matF;
1915
+ const mat = p.uncert ? (nUncert++, matD) : pk.endsWith("#m") ? matB : matF;
1689
1916
  const textured = wantTex && !!p.tex;
1690
1917
  const bodyB = textured ? p.tbody : p.body;
1691
- const body = geom(bodyB, arr, Q);
1918
+ const body = geom(bodyB, arr);
1692
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)));
1693
1920
  for (const g of groups) {
1694
1921
  const ids = Array.from(g, (i) => idsAll[i]);
@@ -1696,7 +1923,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
1696
1923
  const lv0 = [];
1697
1924
  const place = (im) => {
1698
1925
  fillInstances(im, ids, insts, color);
1699
- im.computeBoundingSphere();
1926
+ instancedBoundingSphere(im);
1927
+ im.userData.ldrPart = part;
1700
1928
  root.add(im);
1701
1929
  };
1702
1930
  if (body) {
@@ -1706,7 +1934,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
1706
1934
  }
1707
1935
  if (textured)
1708
1936
  for (const tb of p.tex) {
1709
- const gg = geom(tb, arr, Q);
1937
+ const gg = geom(tb, arr);
1710
1938
  const im = newIM(gg, texMat(tb.t, mat, !!tb.wrapU), ids.length);
1711
1939
  texBatches++;
1712
1940
  lv0.push(im);
@@ -1724,49 +1952,57 @@ function buildLdrScene(insts, pack, P, color, mark) {
1724
1952
  const cl = newCluster(bodyIm.boundingSphere);
1725
1953
  lv0.forEach((o) => o.onBeforeRender = trackVp);
1726
1954
  cl.lv.push({ objs: lv0, err: 0 }, ...textured ? [] : lodLevels(p.body, bodyIm, mat));
1727
- if (P.edges === "idx" && p.edges)
1955
+ if (EDGES && p.edges)
1728
1956
  addLines(p.edges, bodyIm, cl);
1729
1957
  addCond(p, bodyIm, cl);
1730
1958
  if (steps)
1731
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]) });
1732
- if (P.edges === true && p.edges) {
1733
- const mats = new Float32Array(ids.length * 16);
1734
- ids.forEach((id, k) => writeM4(mats, k * 16, insts[id].m));
1735
- {
1736
- const l = instancedLines(arr(p.edges), mats, ids.length);
1737
- edgeObjs.push(l);
1738
- cl.lines.push(l);
1739
- root.add(l);
1740
- }
1741
- }
1742
1960
  }
1743
- const under = geom(p.under, arr, Q);
1744
- if (under) {
1745
- const ord = [...ids.filter((i) => !cull.underHidden[i]), ...ids.filter((i) => cull.underHidden[i])];
1746
- const vis = ids.length - ids.reduce((a, i) => a + cull.underHidden[i], 0);
1747
- stats.undersTotal += ids.length;
1748
- stats.undersHidden += ids.length - vis;
1749
- const im = newIM(under, mat, ids.length);
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);
1750
1969
  fillInstances(im, ord, insts, color);
1751
1970
  im.onBeforeRender = trackVp;
1752
- im.computeBoundingSphere();
1753
- im.count = P.cullUnder ? vis : ids.length;
1971
+ im.userData.ldrUnder = true;
1972
+ im.userData.ldrPart = part;
1973
+ instancedBoundingSphere(im);
1974
+ im.count = P.cullUnder ? vis : uids.length;
1754
1975
  root.add(im);
1755
1976
  const cl = newCluster(im.boundingSphere);
1756
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
+ }
1757
1993
  addCond(p, im, cl, "under");
1758
1994
  const objs = [...cl.lv.flatMap((l) => l.objs), ...cl.cond];
1759
1995
  objs.forEach((o) => {
1760
1996
  if (!o.isInstancedMesh)
1761
1997
  o.geometry.instanceCount = im.count;
1762
1998
  });
1763
- toggles.push({ mesh: countTo(() => objs), all: ids.length, visible: vis, flag: "under" });
1999
+ toggles.push({ mesh: countTo(() => objs), all: uids.length, visible: vis, flag: "under" });
1764
2000
  if (steps)
1765
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]) });
1766
2002
  }
1767
2003
  }
1768
2004
  }
1769
- const sMesh = buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps, steps && colorIndex);
2005
+ const sMesh = buildStudMeshes(insts, H, cull, arr, LOD, color, matF, matB, steps, steps && colorIndex);
1770
2006
  const sKind = sMesh.map((x) => x?.kind ?? "");
1771
2007
  const sVis = sMesh.map((x) => x?.vis ?? 0);
1772
2008
  const STUD_ERR = 12;
@@ -1777,26 +2013,19 @@ function buildLdrScene(insts, pack, P, color, mark) {
1777
2013
  const kind = sKind[ci];
1778
2014
  const k = H.studKinds[kind];
1779
2015
  const vis = sVis[ci], all = im.instanceMatrix.count;
1780
- im.computeBoundingSphere();
2016
+ instancedBoundingSphere(im);
1781
2017
  im.count = P.cullStuds ? vis : all;
1782
2018
  im.onBeforeRender = trackVp;
1783
2019
  im.userData.ldrStud = true;
1784
2020
  root.add(im);
1785
- studMeshes.push({ im, kind });
1786
2021
  const cl = newCluster(im.boundingSphere);
1787
2022
  cl.lv.push({ objs: [im], err: 0 });
1788
- if (LOD && P.lodStuds !== false)
2023
+ if (LOD)
1789
2024
  cl.lv.push({ objs: [], err: STUD_ERR });
1790
- if (P.edges === "idx" && k.edges)
2025
+ if (EDGES && k.edges)
1791
2026
  addLines(k.edges, im, cl);
1792
2027
  if (P.condStuds !== false)
1793
2028
  addCond(k, im, cl);
1794
- if (P.edges === true && k.edges) {
1795
- const l = instancedLines(arr(k.edges), im.instanceMatrix.array.slice(), im.count);
1796
- edgeObjs.push(l);
1797
- cl.lines.push(l);
1798
- root.add(l);
1799
- }
1800
2029
  const objs = [im, ...cl.lines, ...cl.cond];
1801
2030
  objs.forEach((o) => {
1802
2031
  if (!o.isInstancedMesh)
@@ -1814,7 +2043,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
1814
2043
  for (const o of l.objs)
1815
2044
  o.visible = i === c.cur;
1816
2045
  });
1817
- 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);
1818
2047
  for (const o of c.lines)
1819
2048
  o.visible = lineVis;
1820
2049
  for (const o of c.cond)
@@ -1924,21 +2153,14 @@ function buildLdrScene(insts, pack, P, color, mark) {
1924
2153
  m.needsUpdate = true;
1925
2154
  }
1926
2155
  };
1927
- const swapStuds = (alt) => {
1928
- const saved = studMeshes.map((s) => s.im.geometry);
1929
- for (const s of studMeshes) {
1930
- const k2 = alt.header.studKinds[s.kind] ? s.kind : Object.keys(alt.header.studKinds).find((k) => k.replace("p/8/", "p/") === s.kind.replace("p/8/", "p/"));
1931
- if (k2)
1932
- s.im.geometry = geom(alt.header.studKinds[k2].body, alt.arr, Q);
1933
- }
1934
- return () => studMeshes.forEach((s, i) => s.im.geometry = saved[i]);
1935
- };
1936
2156
  const setLod = (on) => {
1937
2157
  root.enabled = on && LOD;
1938
2158
  if (!root.enabled) {
1939
2159
  for (const c of root.clusters) {
1940
2160
  c.cur = 0;
1941
2161
  c.edgeOk = true;
2162
+ for (const l of c.lines)
2163
+ l.geometry.drawRange.count = Infinity;
1942
2164
  }
1943
2165
  refresh();
1944
2166
  }
@@ -1946,9 +2168,31 @@ function buildLdrScene(insts, pack, P, color, mark) {
1946
2168
  insts = null;
1947
2169
  cull = null;
1948
2170
  byPart.clear();
1949
- return { root, stats, setCull, setSide, setEdges, setCond, swapStuds, setLod, setStep, box, texturesReady };
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
+ }
1950
2194
  }
1951
- // ../../../../../../../tmp/ldr-build-pIke9r/src/scene.ts
2195
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/scene.ts
1952
2196
  import * as THREE2 from "three";
1953
2197
  function colorFn(src, pack, fallback) {
1954
2198
  const table = new Map;
@@ -1993,12 +2237,8 @@ function createLdrObject(instances, pack, options = {}) {
1993
2237
  const o = { edges: true, conditionalLines: true, cullStuds: true, cullUndersides: true, side: "front", material: "plastic", ...options };
1994
2238
  const color = colorFn(o.colors, pack, new THREE2.Color(o.fallbackColor ?? 10528169));
1995
2239
  const useTex = o.textures !== false;
1996
- const pick = (i) => useTex && i.texPart && pack.header.parts[i.texPart] ? i.texPart : i.part;
1997
- const all = instances.map((i) => ({ part: pick(i), color: String(i.color), m: i.m, steps: i.steps }));
1998
- const key = (i) => i.steps.map((x) => String(x).padStart(6, "0")).join(".");
1999
- const uniq = [...new Set(all.map(key))].sort();
2000
- const rank = new Map(uniq.map((k, j) => [k, j]));
2001
- const stepOf = all.map((i) => rank.get(key(i)));
2240
+ const { all, stepOf, nSteps } = sceneInstances(instances, pack.header, useTex);
2241
+ const uniq = { length: nSteps };
2002
2242
  const stepViews = new Array(uniq.length).fill(null);
2003
2243
  instances.forEach((i, k) => {
2004
2244
  if (i.view)
@@ -2037,7 +2277,7 @@ function createLdrObject(instances, pack, options = {}) {
2037
2277
  const drawnAt = (step) => all.filter((i, k) => (step == null || stepOf[k] <= step) && pack.header.parts[i.part]).length;
2038
2278
  const build = () => {
2039
2279
  const t0 = performance.now();
2040
- cur = buildLdrScene(all, pack, { pack: "", cullStuds: cs, cullUnder: cu, edges: edges ? "idx" : false, side, cond, condStuds: o.conditionalStudLines !== false, tex: o.textures !== false, lod: o.lod !== false, lodPx: o.lodPx, lodEdgePx: o.lodEdgePx, steps: multiStep ? stepOf : undefined }, color, () => {});
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, () => {});
2041
2281
  pairs.clear();
2042
2282
  if (o.material === "plastic")
2043
2283
  cur.root.traverse((x) => {
@@ -2108,18 +2348,7 @@ function createLdrObject(instances, pack, options = {}) {
2108
2348
  dispose: disposeCur
2109
2349
  });
2110
2350
  }
2111
- // ../../../../../../../tmp/ldr-build-pIke9r/src/pack-io.ts
2112
- import { decompress } from "fzstd";
2113
- async function decompressPack(data) {
2114
- const u = data instanceof Uint8Array ? data : new Uint8Array(data);
2115
- const own = (o) => o.buffer.slice(o.byteOffset, o.byteOffset + o.byteLength);
2116
- if (u[0] === 40 && u[1] === 181 && u[2] === 47 && u[3] === 253)
2117
- return own(decompress(u));
2118
- if (u[0] === 31 && u[1] === 139)
2119
- return new Response(new Blob([u]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();
2120
- return own(u);
2121
- }
2122
- // ../../../../../../../tmp/ldr-build-pIke9r/src/cdn.ts
2351
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/parts-cdn.ts
2123
2352
  import { decompress as decompress2 } from "fzstd";
2124
2353
  var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
2125
2354
  var indexCache = new Map;
@@ -2180,7 +2409,7 @@ function mergePacks(packs, extra = {}) {
2180
2409
  return decodePack(out.buffer);
2181
2410
  }
2182
2411
  async function loadParts(names, o = {}) {
2183
- const cdn = o.cdn ?? DEFAULT_PARTS_CDN, f = o.fetch ?? fetch, gap = o.gap ?? 65536;
2412
+ const cdn = o.cdn ?? DEFAULT_PARTS_CDN, f = o.fetch ?? fetch, gap = o.gap ?? 16384;
2184
2413
  const idx = await loadPartsIndex(cdn, f);
2185
2414
  const want = [...new Set([...names].map(norm))];
2186
2415
  const missing = [];
@@ -2223,7 +2452,7 @@ async function loadParts(names, o = {}) {
2223
2452
  }
2224
2453
  }
2225
2454
  };
2226
- await Promise.all(Array.from({ length: Math.min(o.concurrency ?? 6, groups.length) }, worker));
2455
+ await Promise.all(Array.from({ length: Math.min(o.concurrency ?? 24, groups.length) }, worker));
2227
2456
  const shards = want.filter((n) => shardCache.has(cdn + n)).map((n) => shardCache.get(cdn + n));
2228
2457
  const pack = shards.length ? mergePacks(shards, { colors: idx.colors }) : decodePack(emptyPack(idx.colors));
2229
2458
  return { pack, missing, requests: groups.length, bytes };
@@ -2236,10 +2465,11 @@ function emptyPack(colors) {
2236
2465
  b.set(h, 4);
2237
2466
  return b.buffer;
2238
2467
  }
2239
- async function loadModel(source, o = {}) {
2468
+ async function prepareModel(source, o = {}) {
2240
2469
  const t0 = performance.now();
2241
2470
  const f = o.fetch ?? fetch;
2242
2471
  const idxP = loadPartsIndex(o.cdn ?? DEFAULT_PARTS_CDN, f);
2472
+ idxP.catch(() => {});
2243
2473
  const text = o.text ? source : await f(source).then((r) => {
2244
2474
  if (!r.ok)
2245
2475
  throw new Error(`ldr: ${r.status} fetching ${source}`);
@@ -2249,17 +2479,127 @@ async function loadModel(source, o = {}) {
2249
2479
  const name = o.name ?? (o.text ? "main.ldr" : decodeURIComponent(source.split(/[?#]/)[0].split("/").pop() || "main.ldr"));
2250
2480
  const insts = parseModel(text, name, { looseGeometry: false });
2251
2481
  const t2 = performance.now();
2482
+ o.onParsed?.(insts);
2252
2483
  await idxP;
2253
2484
  const { pack, missing, requests, bytes } = await loadParts(insts.filter((i) => !i.embedded).map((i) => i.part), o);
2254
2485
  const t3 = performance.now();
2255
- const obj = createLdrObject(insts, pack, o);
2256
- for (const m of missing)
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)
2257
2590
  if (!obj.stats.missing.includes(m))
2258
2591
  obj.stats.missing.push(m);
2259
2592
  const t4 = performance.now();
2260
- return Object.assign(obj, { pack, instances: insts, requests, bytes, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, build: t4 - t3, total: t4 - t0 } });
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
+ });
2261
2601
  }
2262
- // ../../../../../../../tmp/ldr-build-pIke9r/src/node/library.ts
2602
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/node/library.ts
2263
2603
  import { existsSync, readFileSync } from "fs";
2264
2604
  import { join } from "path";
2265
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]];
@@ -2511,11 +2851,11 @@ class Library {
2511
2851
  return insts;
2512
2852
  }
2513
2853
  }
2514
- // ../../../../../../../tmp/ldr-build-pIke9r/src/node/build-pack.ts
2854
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/node/build-pack.ts
2515
2855
  import fs3 from "node:fs";
2516
2856
  import path3 from "node:path";
2517
2857
 
2518
- // ../../../../../../../tmp/ldr-build-pIke9r/src/node/resolver.ts
2858
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/node/resolver.ts
2519
2859
  import fs from "node:fs";
2520
2860
  import path from "node:path";
2521
2861
  var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
@@ -2787,11 +3127,11 @@ function collectDeps(lib, refs) {
2787
3127
  return out;
2788
3128
  }
2789
3129
 
2790
- // ../../../../../../../tmp/ldr-build-pIke9r/src/node/compile.ts
3130
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/node/compile.ts
2791
3131
  import fs2 from "node:fs";
2792
3132
  import path2 from "node:path";
2793
3133
 
2794
- // ../../../../../../../tmp/ldr-build-pIke9r/src/node/lod.ts
3134
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/node/lod.ts
2795
3135
  import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
2796
3136
  await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
2797
3137
  function reorderMesh(P, N, C, I) {
@@ -2814,8 +3154,10 @@ function reorderMesh(P, N, C, I) {
2814
3154
  }
2815
3155
  return { P: P2, N: N2, C: C2, I: idx };
2816
3156
  }
2817
- var TARGETS = [0.25, 0.08];
3157
+ var TARGETS = [0.25, 0.08, 0.025];
2818
3158
  var MIN_TRIS = 64;
3159
+ var MIN_BOX_TRIS = 24;
3160
+ var COVERAGE_WEIGHT = Number(process.env.LDR_LOD_COVERAGE ?? 0.5);
2819
3161
  function flatMesh(tris) {
2820
3162
  const map = new Map;
2821
3163
  const P = [], N = [], C = [], I = [];
@@ -2845,9 +3187,62 @@ function flatMesh(tris) {
2845
3187
  }
2846
3188
  return { P: new Float32Array(P), N: new Float32Array(N), C: new Float32Array(C), I: new Uint32Array(I) };
2847
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
+ }
2848
3243
  function lodChain(P, C, I) {
2849
3244
  const nTris = I.length / 3;
2850
- if (nTris < MIN_TRIS)
3245
+ if (nTris < MIN_BOX_TRIS)
2851
3246
  return [];
2852
3247
  const groups = new Map;
2853
3248
  for (let t = 0;t < I.length; t += 3) {
@@ -2878,27 +3273,57 @@ function lodChain(P, C, I) {
2878
3273
  });
2879
3274
  const out = [];
2880
3275
  let prevTris = nTris;
2881
- for (let li = 0;li < TARGETS.length; li++) {
2882
- let err = 0;
2883
- const parts = [];
2884
- for (const g of welded) {
2885
- const target = Math.max(3, Math.floor(g.i.length * TARGETS[li] / 3) * 3);
2886
- const [idx, e] = MeshoptSimplifier.simplify(g.i, g.p, 3, target, 1e9, li ? ["ErrorAbsolute", "Prune"] : ["ErrorAbsolute"]);
2887
- err = Math.max(err, e);
2888
- if (idx.length)
2889
- parts.push({ p: g.p, i: idx, col: g.col });
2890
- }
2891
- const m = flatMesh(parts);
2892
- const t = m.I.length / 3;
2893
- if (t > prevTris * 0.7 || !t)
2894
- continue;
2895
- out.push({ ...m, err: +Math.max(err, 0.001).toFixed(3) });
2896
- prevTris = t;
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) });
2897
3322
  }
2898
3323
  return out;
2899
3324
  }
2900
3325
 
2901
- // ../../../../../../../tmp/ldr-build-pIke9r/src/node/compile.ts
3326
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/node/compile.ts
2902
3327
  function loadColors(root) {
2903
3328
  const map = new Map;
2904
3329
  for (const l of fs2.readFileSync(path2.join(root, "LDConfig.ldr"), "latin1").split(/\r?\n/)) {
@@ -3481,7 +3906,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
3481
3906
  return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
3482
3907
  }
3483
3908
 
3484
- // ../../../../../../../tmp/ldr-build-pIke9r/src/node/build-pack.ts
3909
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/node/build-pack.ts
3485
3910
  function buildPack(o) {
3486
3911
  const lib = new Library2(o.ldrawRoot);
3487
3912
  const refs = new Map;
@@ -3589,8 +4014,11 @@ export {
3589
4014
  parseLDConfig,
3590
4015
  parseModel,
3591
4016
  parseTexMap,
4017
+ precomputeCull,
4018
+ prepareModel,
3592
4019
  resolveTexture,
3593
4020
  rotStepMatrix,
4021
+ sceneInstances,
3594
4022
  sequenceSteps,
3595
4023
  smoothNormals,
3596
4024
  splitModel,
@@ -3599,5 +4027,6 @@ export {
3599
4027
  texmapTriangleUV,
3600
4028
  texmapUV,
3601
4029
  transformTexMap,
4030
+ warmPackGeometry,
3602
4031
  writePack
3603
4032
  };