ldr 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // ../../../../../../../tmp/ldr-build-qIdKSv/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-qIdKSv/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-qIdKSv/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,6 +831,331 @@ 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
  }
834
+
835
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/cull.ts
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;
837
+ var prepCache = new WeakMap;
838
+ function prepPart(H, part) {
839
+ let c = prepCache.get(H);
840
+ if (!c)
841
+ prepCache.set(H, c = new Map);
842
+ let r = c.get(part);
843
+ if (r !== undefined)
844
+ return r;
845
+ const p = H.parts[part];
846
+ if (!p) {
847
+ c.set(part, null);
848
+ return null;
849
+ }
850
+ const n = p.studs.length;
851
+ const studM = new Float64Array(n * 12);
852
+ const kind = [], color = [];
853
+ p.studs.forEach((s, i) => {
854
+ kind.push(s[0]);
855
+ color.push(s[1]);
856
+ for (let k = 0;k < 12; k++)
857
+ studM[i * 12 + k] = s[2 + k];
858
+ });
859
+ let mask = null, nx = 0, nz = 0;
860
+ if (p.mask) {
861
+ nx = p.mask[0];
862
+ nz = p.mask[1];
863
+ const bits = p.mask[2];
864
+ mask = new Uint8Array(bits.length);
865
+ for (let i = 0;i < bits.length; i++)
866
+ mask[i] = bits.charCodeAt(i) === 49 ? 1 : 0;
867
+ }
868
+ c.set(part, r = { nStuds: n, studM, kind, color, mask, nx, nz });
869
+ return r;
870
+ }
871
+ function mul12To(a, b, bo, w, ao = 0) {
872
+ const b0 = b[bo], b1 = b[bo + 1], b2 = b[bo + 2];
873
+ w[0] = a[ao] + a[ao + 3] * b0 + a[ao + 4] * b1 + a[ao + 5] * b2;
874
+ w[1] = a[ao + 1] + a[ao + 6] * b0 + a[ao + 7] * b1 + a[ao + 8] * b2;
875
+ w[2] = a[ao + 2] + a[ao + 9] * b0 + a[ao + 10] * b1 + a[ao + 11] * b2;
876
+ for (let i = 0;i < 3; i++)
877
+ for (let j = 0;j < 3; j++)
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];
879
+ }
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]);
881
+ var BIG = 1073741824;
882
+
883
+ class Int3Table {
884
+ a;
885
+ b;
886
+ c;
887
+ vals;
888
+ used;
889
+ mask;
890
+ size = 0;
891
+ constructor(cap = 1024) {
892
+ let n = 1024;
893
+ while (n < cap * 2)
894
+ n *= 2;
895
+ this.a = new Int32Array(n);
896
+ this.b = new Int32Array(n);
897
+ this.c = new Int32Array(n);
898
+ this.vals = new Int32Array(n);
899
+ this.used = new Uint8Array(n);
900
+ this.mask = n - 1;
901
+ }
902
+ slot(x, y, z) {
903
+ let h = Math.imul(x, 2654435761) ^ Math.imul(y, 2246822507) ^ Math.imul(z, 3266489909);
904
+ h ^= h >>> 15;
905
+ h = Math.imul(h, 739982445);
906
+ h ^= h >>> 12;
907
+ return h & this.mask;
908
+ }
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;
912
+ for (;; ) {
913
+ if (!U[i])
914
+ return -1;
915
+ if (A[i] === x && B[i] === y && C[i] === z)
916
+ return this.vals[i];
917
+ i = i + 1 & this.mask;
918
+ }
919
+ }
920
+ put(x, y, z, v) {
921
+ if ((this.size + 1) * 2 > this.used.length)
922
+ this.grow();
923
+ let i = this.slot(x, y, z);
924
+ const U = this.used, A = this.a, B = this.b, C = this.c;
925
+ for (;; ) {
926
+ if (!U[i]) {
927
+ U[i] = 1;
928
+ A[i] = x;
929
+ B[i] = y;
930
+ C[i] = z;
931
+ this.vals[i] = v;
932
+ this.size++;
933
+ return -1;
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
+ }
940
+ i = i + 1 & this.mask;
941
+ }
942
+ }
943
+ grow() {
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);
949
+ this.vals = new Int32Array(n);
950
+ this.used = new Uint8Array(n);
951
+ this.mask = n - 1;
952
+ this.size = 0;
953
+ for (let i = 0;i < used.length; i++)
954
+ if (used[i])
955
+ this.put(a[i], b[i], c[i], vals[i]);
956
+ }
957
+ }
958
+ var inRange = (x, y, z) => x > -BIG && x < BIG && y > -BIG && y < BIG && z > -BIG && z < BIG;
959
+ var STEP_NEVER = 2147483647;
960
+ function forEachStud(insts, H, fn) {
961
+ const w = new Float64Array(12);
962
+ let j = 0;
963
+ for (let idx = 0;idx < insts.length; idx++) {
964
+ const it = insts[idx];
965
+ const pp = prepPart(H, it.part);
966
+ if (!pp)
967
+ continue;
968
+ for (let s = 0;s < pp.nStuds; s++) {
969
+ mul12To(it.m, pp.studM, s * 12, w);
970
+ const c = pp.color[s];
971
+ fn(j++, idx, w, pp.kind[s], c === "16" ? it.color : c, s);
972
+ }
973
+ }
974
+ }
975
+ function cullCore(insts, H, steps) {
976
+ const CELL = 40;
977
+ const rx0 = [], rx1 = [], rz0 = [], rz1 = [], rInst = [], rPrep = [], rBx = [], rBz = [];
978
+ const cells = new Int3Table(insts.length * 2);
979
+ const nextE = [], rectE = [];
980
+ for (let idx = 0;idx < insts.length; idx++) {
981
+ const it = insts[idx];
982
+ const m = it.m;
983
+ const p = H.parts[it.part];
984
+ if (!p || !p.mask || !upright(m))
985
+ continue;
986
+ const b = p.bbox;
987
+ let x0 = Infinity, x1 = -Infinity, z0 = Infinity, z1 = -Infinity;
988
+ for (let cxi = 0;cxi < 2; cxi++)
989
+ for (let czi = 0;czi < 2; czi++) {
990
+ const x = cxi ? b[3] : b[0], z = czi ? b[5] : b[2];
991
+ const wx = m[0] + m[3] * x + m[5] * z, wz = m[2] + m[9] * x + m[11] * z;
992
+ if (wx < x0)
993
+ x0 = wx;
994
+ if (wx > x1)
995
+ x1 = wx;
996
+ if (wz < z0)
997
+ z0 = wz;
998
+ if (wz > z1)
999
+ z1 = wz;
1000
+ }
1001
+ const ri = rInst.length;
1002
+ rx0.push(x0);
1003
+ rx1.push(x1);
1004
+ rz0.push(z0);
1005
+ rz1.push(z1);
1006
+ rInst.push(idx);
1007
+ rPrep.push(prepPart(H, it.part));
1008
+ rBx.push(b[0]);
1009
+ rBz.push(b[2]);
1010
+ const lv2 = Math.round((m[1] + b[4]) * 2);
1011
+ for (let cx = Math.floor(x0 / CELL);cx <= Math.floor(x1 / CELL); cx++)
1012
+ for (let cz = Math.floor(z0 / CELL);cz <= Math.floor(z1 / CELL); cz++) {
1013
+ if (!inRange(lv2, cx, cz))
1014
+ continue;
1015
+ const e = rectE.length;
1016
+ rectE.push(ri);
1017
+ nextE.push(cells.put(lv2, cx, cz, e));
1018
+ }
1019
+ }
1020
+ const SX = [0, 5, -5, 5, -5], SZ = [0, 5, 5, -5, -5];
1021
+ let kl = NaN, kx = NaN, kz = NaN, ke = -1;
1022
+ const coverStep = (x, y, z, self) => {
1023
+ const l2 = Math.round(y * 2), gx = Math.floor(x / CELL), gz = Math.floor(z / CELL);
1024
+ if (!inRange(l2, gx, gz))
1025
+ return STEP_NEVER;
1026
+ let best = STEP_NEVER;
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]) {
1034
+ const ri = rectE[e];
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))
1036
+ continue;
1037
+ const m = insts[rInst[ri]].m;
1038
+ const pp = rPrep[ri];
1039
+ const bx = rBx[ri], bz = rBz[ri];
1040
+ const dx = x - m[0], dy = y - m[1], dz = z - m[2];
1041
+ const lx = m[3] * dx + m[6] * dy + m[9] * dz, lz = m[5] * dx + m[8] * dy + m[11] * dz;
1042
+ const { nx, nz, mask: bits } = pp;
1043
+ let ok = true;
1044
+ for (let s = 0;s < 5; s++) {
1045
+ const ca = Math.floor((lx + SX[s] - bx) / 20), cb = Math.floor((lz + SZ[s] - bz) / 20);
1046
+ if (ca < 0 || cb < 0 || ca >= nx || cb >= nz || bits[ca * nz + cb] !== 1) {
1047
+ ok = false;
1048
+ break;
1049
+ }
1050
+ }
1051
+ if (ok) {
1052
+ if (!steps)
1053
+ return 0;
1054
+ const st = steps[rInst[ri]];
1055
+ if (st < best)
1056
+ best = st;
1057
+ }
1058
+ }
1059
+ return best;
1060
+ };
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
+ }
801
1159
  var toI8 = (a) => {
802
1160
  const o = new Int8Array(a.length);
803
1161
  for (let i = 0;i < a.length; i++)
@@ -829,37 +1187,37 @@ function flatNormals(pos, idx) {
829
1187
  return n;
830
1188
  }
831
1189
  var geomCache = new WeakMap;
832
- function geom(b, arr, quant = true) {
1190
+ function geom(b, arr) {
833
1191
  if (!b)
834
1192
  return null;
835
1193
  let c = geomCache.get(arr);
836
1194
  if (!c)
837
1195
  geomCache.set(arr, c = new Map);
838
- const ck = quant ? b : b.pos;
839
- let g = c.get(ck);
1196
+ let g = c.get(b);
840
1197
  if (g)
841
1198
  return g;
842
1199
  g = new THREE.BufferGeometry;
843
1200
  g.setAttribute("position", new THREE.BufferAttribute(arr(b.pos), 3));
844
1201
  const nrm = b.nrm ? arr(b.nrm) : flatNormals(arr(b.pos), arr(b.idx));
845
1202
  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));
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));
848
1205
  if (b.idx)
849
1206
  g.setIndex(new THREE.BufferAttribute(arr(b.idx), 1));
850
1207
  if (b.uv)
851
1208
  g.setAttribute("ldrUV", new THREE.BufferAttribute(arr(b.uv), 2));
852
- c.set(ck, g);
1209
+ c.set(b, g);
853
1210
  return g;
854
1211
  }
855
1212
  function makeMaterial(side) {
856
1213
  const m = new THREE.MeshStandardMaterial({ vertexColors: true, roughness: 0.45, side });
857
1214
  m.onBeforeCompile = (s) => {
858
1215
  s.vertexShader = `attribute vec4 ldrColor;
859
- ` + s.vertexShader.replace("#include <color_vertex>", `#ifdef USE_INSTANCING_COLOR
860
- vColor = vec4(ldrColor.a > 0.5 ? pow(ldrColor.rgb, vec3(2.2)) : instanceColor.rgb, 1.0); // baked LDConfig colours are sRGB
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
861
1219
  #else
862
- vColor = vec4(pow(ldrColor.rgb, vec3(2.2)), 1.0);
1220
+ vColor.rgb = pow(ldrColor.rgb, vec3(2.2));
863
1221
  #endif`);
864
1222
  };
865
1223
  m.customProgramCacheKey = () => "ldrColor";
@@ -900,30 +1258,36 @@ function packTexture(pack, i) {
900
1258
  }).catch(() => {});
901
1259
  return { texture: t, ready };
902
1260
  }
903
- var lineMat = () => new THREE.ShaderMaterial({
904
- vertexShader: `attribute vec4 im0; attribute vec4 im1; attribute vec4 im2; attribute vec4 im3;
905
- void main(){ gl_Position = projectionMatrix * modelViewMatrix * mat4(im0,im1,im2,im3) * vec4(position,1.0); }`,
906
- fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
907
- });
908
1261
  var sharedLineMat = () => new THREE.ShaderMaterial({
909
1262
  vertexShader: `attribute mat4 instanceMatrix; void main(){ gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position,1.0); }`,
910
1263
  fragmentShader: `void main(){ gl_FragColor = vec4(0.13,0.13,0.13,1.0); }`
911
1264
  });
912
- var weldLines = (pos) => {
1265
+ var weldLines = (pos, byLength = false) => {
913
1266
  const map = new Map;
914
1267
  const P = [];
915
1268
  const I = [];
916
- for (let i = 0;i < pos.length; i += 3) {
917
- const k = pos[i].toFixed(2) + "," + pos[i + 1].toFixed(2) + "," + pos[i + 2].toFixed(2);
918
- let j = map.get(k);
919
- if (j === undefined) {
920
- j = P.length / 3;
921
- map.set(k, j);
922
- P.push(pos[i], pos[i + 1], pos[i + 2]);
923
- }
924
- I.push(j);
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]);
925
1274
  }
926
- return { P: new Float32Array(P), I: P.length / 3 < 65536 ? new Uint16Array(I) : new Uint32Array(I) };
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]) };
927
1291
  };
928
1292
  function createInstancedEdges(pos, im, material = sharedLineMat()) {
929
1293
  return sharedLines(pos, im, material);
@@ -1000,369 +1364,142 @@ function condBuffers(cond) {
1000
1364
  const n = Math.floor(cond.length / 12);
1001
1365
  const buf = new Float32Array(n * 24), side = new Float32Array(n * 2);
1002
1366
  for (let l = 0;l < n; l++) {
1003
- for (let k = 0;k < 12; k++) {
1004
- const v = cond[l * 12 + k];
1005
- buf[l * 24 + k] = v;
1006
- buf[l * 24 + 12 + k] = v;
1007
- }
1008
- side[l * 2 + 1] = 1;
1009
- }
1010
- return { ib: new THREE.InterleavedBuffer(buf, 12), side: new THREE.BufferAttribute(side, 1) };
1011
- }
1012
- function condEdges({ ib, side }, im, material) {
1013
- const g = new THREE.InstancedBufferGeometry;
1014
- g.setAttribute("position", new THREE.InterleavedBufferAttribute(ib, 3, 0));
1015
- g.setAttribute("ldrP1", new THREE.InterleavedBufferAttribute(ib, 3, 3));
1016
- g.setAttribute("ldrC0", new THREE.InterleavedBufferAttribute(ib, 3, 6));
1017
- g.setAttribute("ldrC1", new THREE.InterleavedBufferAttribute(ib, 3, 9));
1018
- g.setAttribute("ldrSide", side);
1019
- g.setAttribute("instanceMatrix", im.instanceMatrix);
1020
- g.instanceCount = im.count;
1021
- const l = new THREE.LineSegments(g, material);
1022
- l.frustumCulled = false;
1023
- l.name = "ldrCondLines";
1024
- l.onBeforeRender = (_r, _s, cam, _g, mat) => {
1025
- const u = mat.uniforms?.ldrViewProj;
1026
- if (!u)
1027
- return;
1028
- l.modelViewMatrix.multiplyMatrices(cam.matrixWorldInverse, l.matrixWorld);
1029
- u.value.multiplyMatrices(cam.projectionMatrix, l.modelViewMatrix);
1030
- mat.uniformsNeedUpdate = true;
1031
- };
1032
- return l;
1033
- }
1034
- function sharedLines(pos, im, material = sharedLineMat()) {
1035
- const { P, I } = weldLines(pos);
1036
- const g = new THREE.InstancedBufferGeometry;
1037
- g.setAttribute("position", new THREE.BufferAttribute(P, 3));
1038
- g.setIndex(new THREE.BufferAttribute(I, 1));
1039
- g.setAttribute("instanceMatrix", im.instanceMatrix);
1040
- g.instanceCount = im.count;
1041
- const l = new THREE.LineSegments(g, material);
1042
- l.frustumCulled = false;
1043
- return l;
1044
- }
1045
- function instancedLines(pos, mats, count) {
1046
- const g = new THREE.InstancedBufferGeometry;
1047
- g.setAttribute("position", new THREE.BufferAttribute(pos, 3));
1048
- const ib = new THREE.InstancedInterleavedBuffer(mats, 16);
1049
- for (let i = 0;i < 4; i++)
1050
- g.setAttribute("im" + i, new THREE.InterleavedBufferAttribute(ib, 4, i * 4));
1051
- g.instanceCount = count;
1052
- const l = new THREE.LineSegments(g, lineMat());
1053
- l.frustumCulled = false;
1054
- return l;
1055
- }
1056
- function writeM4(t, o, m, mo = 0) {
1057
- t[o] = m[mo + 3];
1058
- t[o + 1] = m[mo + 6];
1059
- t[o + 2] = m[mo + 9];
1060
- t[o + 3] = 0;
1061
- t[o + 4] = m[mo + 4];
1062
- t[o + 5] = m[mo + 7];
1063
- t[o + 6] = m[mo + 10];
1064
- t[o + 7] = 0;
1065
- t[o + 8] = m[mo + 5];
1066
- t[o + 9] = m[mo + 8];
1067
- t[o + 10] = m[mo + 11];
1068
- t[o + 11] = 0;
1069
- t[o + 12] = m[mo];
1070
- t[o + 13] = m[mo + 1];
1071
- t[o + 14] = m[mo + 2];
1072
- t[o + 15] = 1;
1073
- }
1074
- function newIM(g, mat, n) {
1075
- const im = new THREE.InstancedMesh(g, mat, 0);
1076
- im.instanceMatrix = new THREE.InstancedBufferAttribute(new Float32Array(n * 16), 16);
1077
- im.count = n;
1078
- return im;
1079
- }
1080
- function fillInstances(im, ids, insts, color) {
1081
- const M = im.instanceMatrix.array;
1082
- const C = new Float32Array(ids.length * 3);
1083
- for (let k = 0;k < ids.length; k++) {
1084
- const it = insts[ids[k]];
1085
- writeM4(M, k * 16, it.m);
1086
- color(it.color).toArray(C, k * 3);
1087
- }
1088
- im.instanceColor = new THREE.InstancedBufferAttribute(C, 3);
1089
- }
1090
- var upright = (m, o = 0) => Math.abs(m[o + 7] - 1) < 0.001 && Math.abs(m[o + 4]) < 0.001 && Math.abs(m[o + 10]) < 0.001;
1091
- var prepCache = new WeakMap;
1092
- function prepPart(H, part) {
1093
- let c = prepCache.get(H);
1094
- if (!c)
1095
- prepCache.set(H, c = new Map);
1096
- let r = c.get(part);
1097
- if (r !== undefined)
1098
- return r;
1099
- const p = H.parts[part];
1100
- if (!p) {
1101
- c.set(part, null);
1102
- return null;
1103
- }
1104
- const n = p.studs.length;
1105
- const studM = new Float64Array(n * 12);
1106
- const kind = [], color = [];
1107
- p.studs.forEach((s, i) => {
1108
- kind.push(s[0]);
1109
- color.push(s[1]);
1110
- for (let k = 0;k < 12; k++)
1111
- studM[i * 12 + k] = s[2 + k];
1112
- });
1113
- let mask = null, nx = 0, nz = 0;
1114
- if (p.mask) {
1115
- nx = p.mask[0];
1116
- nz = p.mask[1];
1117
- const bits = p.mask[2];
1118
- mask = new Uint8Array(bits.length);
1119
- for (let i = 0;i < bits.length; i++)
1120
- mask[i] = bits.charCodeAt(i) === 49 ? 1 : 0;
1121
- }
1122
- c.set(part, r = { nStuds: n, studM, kind, color, mask, nx, nz });
1123
- return r;
1124
- }
1125
- function mul12To(a, b, bo, w, ao = 0) {
1126
- const b0 = b[bo], b1 = b[bo + 1], b2 = b[bo + 2];
1127
- w[0] = a[ao] + a[ao + 3] * b0 + a[ao + 4] * b1 + a[ao + 5] * b2;
1128
- w[1] = a[ao + 1] + a[ao + 6] * b0 + a[ao + 7] * b1 + a[ao + 8] * b2;
1129
- w[2] = a[ao + 2] + a[ao + 9] * b0 + a[ao + 10] * b1 + a[ao + 11] * b2;
1130
- for (let i = 0;i < 3; i++)
1131
- for (let j = 0;j < 3; j++)
1132
- w[3 + i * 3 + j] = a[ao + 3 + i * 3] * b[bo + 3 + j] + a[ao + 4 + i * 3] * b[bo + 6 + j] + a[ao + 5 + i * 3] * b[bo + 9 + j];
1133
- }
1134
- var det12 = (m) => m[3] * (m[7] * m[11] - m[8] * m[10]) - m[4] * (m[6] * m[11] - m[8] * m[9]) + m[5] * (m[6] * m[10] - m[7] * m[9]);
1135
- var 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);
1136
- var topKey = (x, y, z) => {
1137
- const rx = Math.round(x), ry = Math.round(y), rz = Math.round(z);
1138
- return rx < -131072 || rx >= 131072 || ry < -65536 || ry >= 65536 || rz < -131072 || rz >= 131072 ? -1 : (rx + 131072) * 34359738368 + (ry + 65536) * 262144 + (rz + 131072);
1139
- };
1140
-
1141
- class NumTable {
1142
- keys;
1143
- vals;
1144
- mask;
1145
- size = 0;
1146
- constructor(cap = 1024) {
1147
- let n = 1024;
1148
- while (n < cap * 2)
1149
- n *= 2;
1150
- this.keys = new Float64Array(n).fill(-1);
1151
- this.vals = new Int32Array(n);
1152
- this.mask = n - 1;
1153
- }
1154
- slot(k) {
1155
- const lo = k >>> 0, hi = k / 4294967296 >>> 0;
1156
- let h = Math.imul(lo ^ Math.imul(hi, 2654435761), 2246822507);
1157
- h ^= h >>> 15;
1158
- return h & this.mask;
1159
- }
1160
- get(k) {
1161
- const K = this.keys;
1162
- let i = this.slot(k);
1163
- for (;; ) {
1164
- const x = K[i];
1165
- if (x === k)
1166
- return this.vals[i];
1167
- if (x === -1)
1168
- return -1;
1169
- i = i + 1 & this.mask;
1170
- }
1171
- }
1172
- put(k, v) {
1173
- if ((this.size + 1) * 2 > this.keys.length)
1174
- this.grow();
1175
- const K = this.keys;
1176
- let i = this.slot(k);
1177
- for (;; ) {
1178
- const x = K[i];
1179
- if (x === k) {
1180
- const o = this.vals[i];
1181
- this.vals[i] = v;
1182
- return o;
1183
- }
1184
- if (x === -1) {
1185
- K[i] = k;
1186
- this.vals[i] = v;
1187
- this.size++;
1188
- return -1;
1189
- }
1190
- i = i + 1 & this.mask;
1191
- }
1192
- }
1193
- grow() {
1194
- const ok = this.keys, ov = this.vals;
1195
- const n = ok.length * 2;
1196
- this.keys = new Float64Array(n).fill(-1);
1197
- this.vals = new Int32Array(n);
1198
- this.mask = n - 1;
1199
- this.size = 0;
1200
- for (let i = 0;i < ok.length; i++)
1201
- if (ok[i] !== -1)
1202
- this.put(ok[i], ov[i]);
1203
- }
1204
- }
1205
- var STEP_NEVER = 2147483647;
1206
- function forEachStud(insts, H, fn) {
1207
- const w = new Float64Array(12);
1208
- let j = 0;
1209
- for (let idx = 0;idx < insts.length; idx++) {
1210
- const it = insts[idx];
1211
- const pp = prepPart(H, it.part);
1212
- if (!pp)
1213
- continue;
1214
- for (let s = 0;s < pp.nStuds; s++) {
1215
- mul12To(it.m, pp.studM, s * 12, w);
1216
- const c = pp.color[s];
1217
- fn(j++, idx, w, pp.kind[s], c === "16" ? it.color : c, s);
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;
1218
1371
  }
1372
+ side[l * 2 + 1] = 1;
1219
1373
  }
1374
+ return { ib: new THREE.InterleavedBuffer(buf, 12), side: new THREE.BufferAttribute(side, 1) };
1220
1375
  }
1221
- function cullCore(insts, H, steps) {
1222
- const CELL = 40;
1223
- const rx0 = [], rx1 = [], rz0 = [], rz1 = [], rInst = [], rPrep = [], rBx = [], rBz = [];
1224
- const cells = new NumTable(insts.length * 2);
1225
- const nextE = [], rectE = [];
1226
- for (let idx = 0;idx < insts.length; idx++) {
1227
- const it = insts[idx];
1228
- const m = it.m;
1229
- const p = H.parts[it.part];
1230
- if (!p || !p.mask || !upright(m))
1231
- continue;
1232
- const b = p.bbox;
1233
- let x0 = Infinity, x1 = -Infinity, z0 = Infinity, z1 = -Infinity;
1234
- for (let cxi = 0;cxi < 2; cxi++)
1235
- for (let czi = 0;czi < 2; czi++) {
1236
- const x = cxi ? b[3] : b[0], z = czi ? b[5] : b[2];
1237
- const wx = m[0] + m[3] * x + m[5] * z, wz = m[2] + m[9] * x + m[11] * z;
1238
- if (wx < x0)
1239
- x0 = wx;
1240
- if (wx > x1)
1241
- x1 = wx;
1242
- if (wz < z0)
1243
- z0 = wz;
1244
- if (wz > z1)
1245
- z1 = wz;
1246
- }
1247
- const ri = rInst.length;
1248
- rx0.push(x0);
1249
- rx1.push(x1);
1250
- rz0.push(z0);
1251
- rz1.push(z1);
1252
- rInst.push(idx);
1253
- rPrep.push(prepPart(H, it.part));
1254
- rBx.push(b[0]);
1255
- rBz.push(b[2]);
1256
- const lv2 = Math.round((m[1] + b[4]) * 2);
1257
- for (let cx = Math.floor(x0 / CELL);cx <= Math.floor(x1 / CELL); cx++)
1258
- for (let cz = Math.floor(z0 / CELL);cz <= Math.floor(z1 / CELL); cz++) {
1259
- const k = cellKey(lv2, cx, cz);
1260
- if (k < 0)
1261
- continue;
1262
- const e = rectE.length;
1263
- rectE.push(ri);
1264
- nextE.push(cells.put(k, e));
1265
- }
1266
- }
1267
- const SX = [0, 5, -5, 5, -5], SZ = [0, 5, 5, -5, -5];
1268
- const coverStep = (x, y, z, self) => {
1269
- const k = cellKey(Math.round(y * 2), Math.floor(x / CELL), Math.floor(z / CELL));
1270
- if (k < 0)
1271
- return STEP_NEVER;
1272
- let best = STEP_NEVER;
1273
- for (let e = cells.get(k);e >= 0; e = nextE[e]) {
1274
- const ri = rectE[e];
1275
- if (rInst[ri] === self || !(x - 6 >= rx0[ri] - 0.5 && x + 6 <= rx1[ri] + 0.5 && z - 6 >= rz0[ri] - 0.5 && z + 6 <= rz1[ri] + 0.5))
1276
- continue;
1277
- const m = insts[rInst[ri]].m;
1278
- const pp = rPrep[ri];
1279
- const bx = rBx[ri], bz = rBz[ri];
1280
- const dx = x - m[0], dy = y - m[1], dz = z - m[2];
1281
- const lx = m[3] * dx + m[6] * dy + m[9] * dz, lz = m[5] * dx + m[8] * dy + m[11] * dz;
1282
- const { nx, nz, mask: bits } = pp;
1283
- let ok = true;
1284
- for (let s = 0;s < 5; s++) {
1285
- const ca = Math.floor((lx + SX[s] - bx) / 20), cb = Math.floor((lz + SZ[s] - bz) / 20);
1286
- if (ca < 0 || cb < 0 || ca >= nx || cb >= nz || bits[ca * nz + cb] !== 1) {
1287
- ok = false;
1288
- break;
1289
- }
1290
- }
1291
- if (ok) {
1292
- if (!steps)
1293
- return 0;
1294
- const st = steps[rInst[ri]];
1295
- if (st < best)
1296
- best = st;
1297
- }
1298
- }
1299
- return best;
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)
1391
+ return;
1392
+ l.modelViewMatrix.multiplyMatrices(cam.matrixWorldInverse, l.matrixWorld);
1393
+ u.value.multiplyMatrices(cam.projectionMatrix, l.modelViewMatrix);
1394
+ mat.uniformsNeedUpdate = true;
1300
1395
  };
1301
- let nStuds = 0;
1302
- for (const it of insts) {
1303
- const pp = prepPart(H, it.part);
1304
- if (pp)
1305
- nStuds += pp.nStuds;
1306
- }
1307
- const studHidden = new Uint8Array(nStuds), studUp = new Uint8Array(nStuds);
1308
- const tops = new NumTable(nStuds);
1309
- let studsHidden = 0;
1310
- const studHideStep = steps ? new Int32Array(nStuds).fill(STEP_NEVER) : undefined;
1311
- forEachStud(insts, H, (j, idx, w) => {
1312
- if (!upright(w))
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;
1313
1447
  return;
1314
- studUp[j] = 1;
1315
- const cs = coverStep(w[0], w[1], w[2], idx);
1316
- if (cs !== STEP_NEVER) {
1317
- studHidden[j] = 1;
1318
- studsHidden++;
1319
- if (studHideStep)
1320
- studHideStep[j] = cs;
1321
1448
  }
1322
- const k = topKey(w[0], w[1], w[2]);
1323
- if (k < 0)
1324
- return;
1325
- if (!steps) {
1326
- tops.put(k, 1);
1327
- return;
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;
1328
1459
  }
1329
- const st = steps[idx], o = tops.get(k);
1330
- if (o < 0 || st < o)
1331
- tops.put(k, st);
1332
- });
1333
- const underHidden = new Uint8Array(insts.length);
1334
- const underHideStep = steps ? new Int32Array(insts.length).fill(STEP_NEVER) : undefined;
1335
- for (let idx = 0;idx < insts.length; idx++) {
1336
- const it = insts[idx];
1337
- const p = H.parts[it.part];
1338
- if (!p || !p.under || !upright(it.m))
1460
+ };
1461
+ for (let i = 0, n = im.count;i < n; i++) {
1462
+ const o = i * 16;
1463
+ const e0 = A[o], e1 = A[o + 1], e2 = A[o + 2], e3 = A[o + 3], e4 = A[o + 4], e5 = A[o + 5], e6 = A[o + 6], e7 = A[o + 7], e8 = A[o + 8], e9 = A[o + 9], e10 = A[o + 10], e11 = A[o + 11];
1464
+ const w = 1 / (e3 * gx + e7 * gy + e11 * gz + A[o + 15]);
1465
+ const x = (e0 * gx + e4 * gy + e8 * gz + A[o + 12]) * w, y = (e1 * gx + e5 * gy + e9 * gz + A[o + 13]) * w, z = (e2 * gx + e6 * gy + e10 * gz + A[o + 14]) * w;
1466
+ const sr = gr * Math.sqrt(Math.max(e0 * e0 + e1 * e1 + e2 * e2, e4 * e4 + e5 * e5 + e6 * e6, e8 * e8 + e9 * e9 + e10 * e10));
1467
+ if (r < 0) {
1468
+ cx = x;
1469
+ cy = y;
1470
+ cz = z;
1471
+ r = sr;
1339
1472
  continue;
1340
- const b = p.bbox;
1341
- const nx = Math.round((b[3] - b[0]) / 20), nz = Math.round((b[5] - b[2]) / 20);
1342
- if (!nx || !nz || nx * nz > 4096)
1473
+ }
1474
+ if (x === cx && y === cy && z === cz) {
1475
+ r = Math.max(r, sr);
1343
1476
  continue;
1344
- const m = it.m;
1345
- let all = true, at = 0;
1346
- for (let a = 0;a < nx && all; a++)
1347
- for (let c = 0;c < nz; c++) {
1348
- const lx = b[0] + 10 + 20 * a, lz = b[2] + 10 + 20 * c;
1349
- const x = m[0] + m[3] * lx + m[5] * lz, z = m[2] + m[9] * lx + m[11] * lz;
1350
- const k = topKey(x, m[1] + b[4], z);
1351
- const t = k < 0 ? -1 : tops.get(k);
1352
- if (t < 0) {
1353
- all = false;
1354
- break;
1355
- }
1356
- if (t > at)
1357
- at = t;
1358
- }
1359
- if (all) {
1360
- underHidden[idx] = 1;
1361
- if (underHideStep)
1362
- underHideStep[idx] = at;
1363
1477
  }
1478
+ let dx = x - cx, dy = y - cy, dz = z - cz;
1479
+ const inv = 1 / (Math.sqrt(dx * dx + dy * dy + dz * dz) || 1);
1480
+ dx = dx * inv * sr;
1481
+ dy = dy * inv * sr;
1482
+ dz = dz * inv * sr;
1483
+ expand(x + dx, y + dy, z + dz);
1484
+ expand(x - dx, y - dy, z - dz);
1364
1485
  }
1365
- return { nStuds, studHidden, studUp, underHidden, studsHidden, studHideStep, underHideStep };
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);
1501
+ }
1502
+ im.instanceColor = new THREE.InstancedBufferAttribute(C, 3);
1366
1503
  }
1367
1504
  function computeCulling(insts, H) {
1368
1505
  const c = cullCore(insts, H);
@@ -1418,7 +1555,8 @@ class LdrLodRoot extends THREE.LOD {
1418
1555
  clusters = [];
1419
1556
  vpH = 1080;
1420
1557
  px = 0.5;
1421
- edgePpl = 0.025;
1558
+ edgePpl = 0.5 / 20;
1559
+ edgeMinPx = 0.15;
1422
1560
  enabled = true;
1423
1561
  apply = () => {};
1424
1562
  inv = new THREE.Matrix4;
@@ -1448,37 +1586,90 @@ class LdrLodRoot extends THREE.LOD {
1448
1586
  L = i;
1449
1587
  break;
1450
1588
  }
1589
+ if (c.below !== undefined && x * c.ax[0] + y * c.ax[1] + z * c.ax[2] < c.below - 1 && ppl * 20 < 4)
1590
+ L = -1;
1591
+ if (c.boxErr !== undefined && c.boxErr * ppl <= tau)
1592
+ L = -1;
1451
1593
  const e = ppl >= eppl;
1452
1594
  if (L !== c.cur || e !== c.edgeOk) {
1453
1595
  c.cur = L;
1454
1596
  c.edgeOk = e;
1455
1597
  this.apply(c);
1456
1598
  }
1599
+ if (e && c.lines.length) {
1600
+ const minLen = this.edgeMinPx / ppl;
1601
+ for (const l of c.lines) {
1602
+ const lens = l.userData.ldrLens;
1603
+ if (!lens)
1604
+ continue;
1605
+ let lo = 0, hi = lens.length;
1606
+ while (lo < hi) {
1607
+ const mid = lo + hi >> 1;
1608
+ if (lens[mid] >= minLen)
1609
+ lo = mid + 1;
1610
+ else
1611
+ hi = mid;
1612
+ }
1613
+ l.geometry.drawRange.count = lo * 2;
1614
+ }
1615
+ }
1457
1616
  }
1458
1617
  }
1459
1618
  }
1460
- function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps, colorIndex) {
1619
+ function buildStudMeshes(insts, H, cull, arr, LOD, color, matF, matB, steps, colorIndex) {
1461
1620
  const bucketOf = new Map;
1462
1621
  const bKind = [], bMirror = [];
1463
1622
  const bAll = [];
1464
1623
  const studBucket = new Uint16Array(cull.nStuds);
1465
1624
  const sx = new Float32Array(cull.nStuds), sz = new Float32Array(cull.nStuds);
1466
- forEachStud(insts, H, (j, _i, w, kind) => {
1467
- const neg = det12(w) < 0;
1468
- const k = neg ? kind + "#m" : kind;
1469
- let b = bucketOf.get(k);
1470
- if (b === undefined) {
1471
- b = bKind.length;
1472
- bucketOf.set(k, b);
1473
- bKind.push(kind);
1474
- bMirror.push(neg);
1475
- bAll.push(0);
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 });
1476
1650
  }
1477
- studBucket[j] = b;
1478
- bAll[b]++;
1479
- sx[j] = w[0];
1480
- sz[j] = w[2];
1481
- });
1651
+ const instNeg = det12(a) < 0 ? 1 : 0;
1652
+ const B = pp.studM;
1653
+ for (let si = 0;si < pp.nStuds; si++, j++) {
1654
+ const o = si * 12, b0 = B[o], b1 = B[o + 1], b2 = B[o + 2];
1655
+ const neg = (instNeg ^ ps.neg[si]) === 1;
1656
+ const km = ps.kid[si] * 2 + (neg ? 1 : 0);
1657
+ let b = bucketOfKM[km];
1658
+ if (b === undefined) {
1659
+ const kn = kindNames[ps.kid[si]];
1660
+ b = bKind.length;
1661
+ bucketOfKM[km] = b;
1662
+ bucketOf.set(neg ? kn + "#m" : kn, b);
1663
+ bKind.push(kn);
1664
+ bMirror.push(neg);
1665
+ bAll.push(0);
1666
+ }
1667
+ studBucket[j] = b;
1668
+ bAll[b]++;
1669
+ sx[j] = a[0] + a[3] * b0 + a[4] * b1 + a[5] * b2;
1670
+ sz[j] = a[2] + a[9] * b0 + a[10] * b1 + a[11] * b2;
1671
+ }
1672
+ }
1482
1673
  const bIds = bAll.map((n) => new Int32Array(n));
1483
1674
  {
1484
1675
  const f = bAll.map(() => 0);
@@ -1490,7 +1681,7 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
1490
1681
  const studCl = new Int32Array(cull.nStuds), studSlot = new Int32Array(cull.nStuds);
1491
1682
  const sMesh = [];
1492
1683
  bKind.forEach((kind, b) => {
1493
- const g = geom(H.studKinds[kind].body, arr, Q);
1684
+ const g = geom(H.studKinds[kind].body, arr);
1494
1685
  const ids = bIds[b];
1495
1686
  for (const c of gridClusters(ids.length, (i) => sx[ids[i]], (i) => sz[ids[i]], LOD ? 16384 : Infinity)) {
1496
1687
  const ci = sMesh.length;
@@ -1514,6 +1705,13 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
1514
1705
  sMesh.push({ im, kind, vis: v, ...steps ? { slots: { own: new Int32Array(n), hide: new Int32Array(n), inst: new Int32Array(n), stud: new Int16Array(n), col: new Uint16Array(n) } } : {} });
1515
1706
  }
1516
1707
  });
1708
+ const colCache = new Map;
1709
+ const colorOf = (c) => {
1710
+ let x = colCache.get(c);
1711
+ if (!x)
1712
+ colCache.set(c, x = color(c));
1713
+ return x;
1714
+ };
1517
1715
  forEachStud(insts, H, (j, owner, w, _kind, col, si) => {
1518
1716
  const sm = sMesh[studCl[j]];
1519
1717
  if (!sm)
@@ -1529,18 +1727,46 @@ function buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps,
1529
1727
  t.col[slot] = colorIndex(col);
1530
1728
  }
1531
1729
  writeM4(im.instanceMatrix.array, slot * 16, w);
1532
- color(col).toArray(im.instanceColor.array, slot * 3);
1730
+ colorOf(col).toArray(im.instanceColor.array, slot * 3);
1533
1731
  });
1534
1732
  return sMesh;
1535
1733
  }
1734
+ function undersideGroups(ids, insts) {
1735
+ const by = new Map;
1736
+ const rest = [];
1737
+ for (const id of ids) {
1738
+ const m = insts[id].m;
1739
+ const l = Math.hypot(m[4], m[7], m[10]);
1740
+ if (!(l > 0.000001)) {
1741
+ rest.push(id);
1742
+ continue;
1743
+ }
1744
+ const ax = [m[4] / l, m[7] / l, m[10] / l, l];
1745
+ const k = ax.map((v) => Math.round(v * 1000)).join();
1746
+ let g = by.get(k);
1747
+ if (!g) {
1748
+ if (by.size >= 12) {
1749
+ rest.push(id);
1750
+ continue;
1751
+ }
1752
+ by.set(k, g = { ids: [], ax });
1753
+ }
1754
+ g.ids.push(id);
1755
+ }
1756
+ const out = [...by.values()];
1757
+ if (rest.length)
1758
+ out.push({ ids: rest, ax: null });
1759
+ return out;
1760
+ }
1536
1761
  function buildLdrScene(insts, pack, P, color, mark) {
1537
1762
  const { header: H, arr } = pack;
1538
- const Q = P.quant !== false;
1539
1763
  const LOD = P.lod !== false;
1764
+ const EDGES = !!P.edges;
1540
1765
  const root = new LdrLodRoot;
1541
1766
  root.enabled = LOD;
1542
1767
  root.px = P.lodPx ?? 0.5;
1543
1768
  root.edgePpl = (P.lodEdgePx ?? 0.5) / 20;
1769
+ root.edgeMinPx = P.lodEdgeMinPx ?? 0.15;
1544
1770
  const trackVp = (r) => {
1545
1771
  const rt = r.getRenderTarget();
1546
1772
  const h = rt ? rt.height : r.getContext().drawingBufferHeight;
@@ -1558,7 +1784,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
1558
1784
  }
1559
1785
  });
1560
1786
  const steps = P.steps;
1561
- let cull = cullCore(insts, H, steps);
1787
+ let cull = P.cull ?? cullCore(insts, H, steps);
1562
1788
  mark("culling");
1563
1789
  const stepBatches = [];
1564
1790
  const instM = steps ? new Float64Array(insts.length * 12) : null;
@@ -1584,7 +1810,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
1584
1810
  });
1585
1811
  const edgeObjs = [];
1586
1812
  const condObjs = [];
1587
- const wantCond = P.cond !== false && (P.edges === "idx" || P.edges === true);
1813
+ const wantCond = P.cond !== false && EDGES;
1588
1814
  let condMat = null;
1589
1815
  const cmat = () => condMat ??= condLineMat();
1590
1816
  let lineMatShared = null;
@@ -1615,8 +1841,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
1615
1841
  const addLines = (ref, im, cl) => {
1616
1842
  let w = lineCache.get(ref);
1617
1843
  if (!w) {
1618
- const r = weldLines(arr(ref));
1619
- lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1) });
1844
+ const r = weldLines(arr(ref), LOD);
1845
+ lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1), lens: r.lens });
1620
1846
  }
1621
1847
  const g = new THREE.InstancedBufferGeometry;
1622
1848
  g.setAttribute("position", w.P);
@@ -1625,6 +1851,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
1625
1851
  g.instanceCount = im.count;
1626
1852
  const l = new THREE.LineSegments(g, lmat());
1627
1853
  l.frustumCulled = false;
1854
+ if (LOD)
1855
+ l.userData.ldrLens = w.lens;
1628
1856
  edgeObjs.push(l);
1629
1857
  cl.lines.push(l);
1630
1858
  root.add(l);
@@ -1632,7 +1860,6 @@ function buildLdrScene(insts, pack, P, color, mark) {
1632
1860
  };
1633
1861
  const stats = { studsTotal: cull.nStuds, studsHidden: cull.studsHidden, undersTotal: 0, undersHidden: 0 };
1634
1862
  const toggles = [];
1635
- const studMeshes = [];
1636
1863
  const countTo = (objs) => ({ set count(n) {
1637
1864
  for (const o of objs()) {
1638
1865
  if (o.isInstancedMesh)
@@ -1667,8 +1894,9 @@ function buildLdrScene(insts, pack, P, color, mark) {
1667
1894
  root.clusters.push(c);
1668
1895
  return c;
1669
1896
  };
1670
- const lodLevels = (b, base, mat) => !LOD || P.lodMesh === false || !b?.lod ? [] : b.lod.map((l) => {
1671
- 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 };
1672
1900
  im.instanceMatrix = base.instanceMatrix;
1673
1901
  im.count = base.count;
1674
1902
  im.instanceColor = base.instanceColor;
@@ -1684,10 +1912,10 @@ function buildLdrScene(insts, pack, P, color, mark) {
1684
1912
  for (const [pk, idsAll] of byPart) {
1685
1913
  const part = pk.replace(/#m$/, "");
1686
1914
  const p = H.parts[part];
1687
- const mat = P.uncertDouble !== false && p.uncert ? (nUncert++, matD) : pk.endsWith("#m") ? matB : matF;
1915
+ const mat = p.uncert ? (nUncert++, matD) : pk.endsWith("#m") ? matB : matF;
1688
1916
  const textured = wantTex && !!p.tex;
1689
1917
  const bodyB = textured ? p.tbody : p.body;
1690
- const body = geom(bodyB, arr, Q);
1918
+ const body = geom(bodyB, arr);
1691
1919
  const groups = gridClusters(idsAll.length, (i) => insts[idsAll[i]].m[0], (i) => insts[idsAll[i]].m[2], textured ? Infinity : kFor(tris(p.body) + tris(p.under)));
1692
1920
  for (const g of groups) {
1693
1921
  const ids = Array.from(g, (i) => idsAll[i]);
@@ -1695,7 +1923,8 @@ function buildLdrScene(insts, pack, P, color, mark) {
1695
1923
  const lv0 = [];
1696
1924
  const place = (im) => {
1697
1925
  fillInstances(im, ids, insts, color);
1698
- im.computeBoundingSphere();
1926
+ instancedBoundingSphere(im);
1927
+ im.userData.ldrPart = part;
1699
1928
  root.add(im);
1700
1929
  };
1701
1930
  if (body) {
@@ -1705,7 +1934,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
1705
1934
  }
1706
1935
  if (textured)
1707
1936
  for (const tb of p.tex) {
1708
- const gg = geom(tb, arr, Q);
1937
+ const gg = geom(tb, arr);
1709
1938
  const im = newIM(gg, texMat(tb.t, mat, !!tb.wrapU), ids.length);
1710
1939
  texBatches++;
1711
1940
  lv0.push(im);
@@ -1723,49 +1952,57 @@ function buildLdrScene(insts, pack, P, color, mark) {
1723
1952
  const cl = newCluster(bodyIm.boundingSphere);
1724
1953
  lv0.forEach((o) => o.onBeforeRender = trackVp);
1725
1954
  cl.lv.push({ objs: lv0, err: 0 }, ...textured ? [] : lodLevels(p.body, bodyIm, mat));
1726
- if (P.edges === "idx" && p.edges)
1955
+ if (EDGES && p.edges)
1727
1956
  addLines(p.edges, bodyIm, cl);
1728
1957
  addCond(p, bodyIm, cl);
1729
1958
  if (steps)
1730
1959
  stepBatches.push({ im: bodyIm, objs: [...cl.lv.flatMap((l) => l.objs), ...cl.lines, ...cl.cond], own: Int32Array.from(ids, (id) => steps[id]), hide: null, flag: "body", inst: Int32Array.from(ids), stud: null, col: Uint16Array.from(ids, (id) => instCol[id]) });
1731
- if (P.edges === true && p.edges) {
1732
- const mats = new Float32Array(ids.length * 16);
1733
- ids.forEach((id, k) => writeM4(mats, k * 16, insts[id].m));
1734
- {
1735
- const l = instancedLines(arr(p.edges), mats, ids.length);
1736
- edgeObjs.push(l);
1737
- cl.lines.push(l);
1738
- root.add(l);
1739
- }
1740
- }
1741
1960
  }
1742
- const under = geom(p.under, arr, Q);
1743
- if (under) {
1744
- const ord = [...ids.filter((i) => !cull.underHidden[i]), ...ids.filter((i) => cull.underHidden[i])];
1745
- const vis = ids.length - ids.reduce((a, i) => a + cull.underHidden[i], 0);
1746
- stats.undersTotal += ids.length;
1747
- stats.undersHidden += ids.length - vis;
1748
- 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);
1749
1969
  fillInstances(im, ord, insts, color);
1750
1970
  im.onBeforeRender = trackVp;
1751
- im.computeBoundingSphere();
1752
- 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;
1753
1975
  root.add(im);
1754
1976
  const cl = newCluster(im.boundingSphere);
1755
1977
  cl.lv.push({ objs: [im], err: 0 }, ...lodLevels(p.under, im, mat));
1978
+ {
1979
+ const bl = p.body?.lod;
1980
+ const last = bl?.[bl.length - 1];
1981
+ if (LOD && P.lodUnder !== false && last && last.tris === 12)
1982
+ cl.boxErr = last.err;
1983
+ }
1984
+ if (ax) {
1985
+ let below = Infinity;
1986
+ for (const id of uids) {
1987
+ const m = insts[id].m;
1988
+ below = Math.min(below, m[0] * ax[0] + m[1] * ax[1] + m[2] * ax[2] + p.bbox[4] * ax[3]);
1989
+ }
1990
+ cl.below = below;
1991
+ cl.ax = ax.slice(0, 3);
1992
+ }
1756
1993
  addCond(p, im, cl, "under");
1757
1994
  const objs = [...cl.lv.flatMap((l) => l.objs), ...cl.cond];
1758
1995
  objs.forEach((o) => {
1759
1996
  if (!o.isInstancedMesh)
1760
1997
  o.geometry.instanceCount = im.count;
1761
1998
  });
1762
- toggles.push({ mesh: countTo(() => objs), all: ids.length, visible: vis, flag: "under" });
1999
+ toggles.push({ mesh: countTo(() => objs), all: uids.length, visible: vis, flag: "under" });
1763
2000
  if (steps)
1764
2001
  stepBatches.push({ im, objs, own: Int32Array.from(ord, (id) => steps[id]), hide: Int32Array.from(ord, (id) => cull.underHideStep[id]), flag: "under", inst: Int32Array.from(ord), stud: null, col: Uint16Array.from(ord, (id) => instCol[id]) });
1765
2002
  }
1766
2003
  }
1767
2004
  }
1768
- const sMesh = buildStudMeshes(insts, H, cull, arr, Q, LOD, color, matF, matB, steps, steps && colorIndex);
2005
+ const sMesh = buildStudMeshes(insts, H, cull, arr, LOD, color, matF, matB, steps, steps && colorIndex);
1769
2006
  const sKind = sMesh.map((x) => x?.kind ?? "");
1770
2007
  const sVis = sMesh.map((x) => x?.vis ?? 0);
1771
2008
  const STUD_ERR = 12;
@@ -1776,26 +2013,19 @@ function buildLdrScene(insts, pack, P, color, mark) {
1776
2013
  const kind = sKind[ci];
1777
2014
  const k = H.studKinds[kind];
1778
2015
  const vis = sVis[ci], all = im.instanceMatrix.count;
1779
- im.computeBoundingSphere();
2016
+ instancedBoundingSphere(im);
1780
2017
  im.count = P.cullStuds ? vis : all;
1781
2018
  im.onBeforeRender = trackVp;
1782
2019
  im.userData.ldrStud = true;
1783
2020
  root.add(im);
1784
- studMeshes.push({ im, kind });
1785
2021
  const cl = newCluster(im.boundingSphere);
1786
2022
  cl.lv.push({ objs: [im], err: 0 });
1787
- if (LOD && P.lodStuds !== false)
2023
+ if (LOD)
1788
2024
  cl.lv.push({ objs: [], err: STUD_ERR });
1789
- if (P.edges === "idx" && k.edges)
2025
+ if (EDGES && k.edges)
1790
2026
  addLines(k.edges, im, cl);
1791
2027
  if (P.condStuds !== false)
1792
2028
  addCond(k, im, cl);
1793
- if (P.edges === true && k.edges) {
1794
- const l = instancedLines(arr(k.edges), im.instanceMatrix.array.slice(), im.count);
1795
- edgeObjs.push(l);
1796
- cl.lines.push(l);
1797
- root.add(l);
1798
- }
1799
2029
  const objs = [im, ...cl.lines, ...cl.cond];
1800
2030
  objs.forEach((o) => {
1801
2031
  if (!o.isInstancedMesh)
@@ -1813,7 +2043,7 @@ function buildLdrScene(insts, pack, P, color, mark) {
1813
2043
  for (const o of l.objs)
1814
2044
  o.visible = i === c.cur;
1815
2045
  });
1816
- const lineVis = edgesOn && c.edgeOk && (c.cur === 0 || !LOD || c.lv[c.cur].objs.length > 0);
2046
+ const lineVis = edgesOn && c.edgeOk && c.cur >= 0 && (c.cur === 0 || !LOD || c.lv[c.cur].objs.length > 0);
1817
2047
  for (const o of c.lines)
1818
2048
  o.visible = lineVis;
1819
2049
  for (const o of c.cond)
@@ -1923,21 +2153,14 @@ function buildLdrScene(insts, pack, P, color, mark) {
1923
2153
  m.needsUpdate = true;
1924
2154
  }
1925
2155
  };
1926
- const swapStuds = (alt) => {
1927
- const saved = studMeshes.map((s) => s.im.geometry);
1928
- for (const s of studMeshes) {
1929
- const k2 = alt.header.studKinds[s.kind] ? s.kind : Object.keys(alt.header.studKinds).find((k) => k.replace("p/8/", "p/") === s.kind.replace("p/8/", "p/"));
1930
- if (k2)
1931
- s.im.geometry = geom(alt.header.studKinds[k2].body, alt.arr, Q);
1932
- }
1933
- return () => studMeshes.forEach((s, i) => s.im.geometry = saved[i]);
1934
- };
1935
2156
  const setLod = (on) => {
1936
2157
  root.enabled = on && LOD;
1937
2158
  if (!root.enabled) {
1938
2159
  for (const c of root.clusters) {
1939
2160
  c.cur = 0;
1940
2161
  c.edgeOk = true;
2162
+ for (const l of c.lines)
2163
+ l.geometry.drawRange.count = Infinity;
1941
2164
  }
1942
2165
  refresh();
1943
2166
  }
@@ -1945,9 +2168,31 @@ function buildLdrScene(insts, pack, P, color, mark) {
1945
2168
  insts = null;
1946
2169
  cull = null;
1947
2170
  byPart.clear();
1948
- return { root, stats, setCull, setSide, setEdges, setCond, 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
+ }
1949
2194
  }
1950
- // ../../../../../../../tmp/ldr-build-qIdKSv/src/scene.ts
2195
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/scene.ts
1951
2196
  import * as THREE2 from "three";
1952
2197
  function colorFn(src, pack, fallback) {
1953
2198
  const table = new Map;
@@ -1992,12 +2237,8 @@ function createLdrObject(instances, pack, options = {}) {
1992
2237
  const o = { edges: true, conditionalLines: true, cullStuds: true, cullUndersides: true, side: "front", material: "plastic", ...options };
1993
2238
  const color = colorFn(o.colors, pack, new THREE2.Color(o.fallbackColor ?? 10528169));
1994
2239
  const useTex = o.textures !== false;
1995
- const pick = (i) => useTex && i.texPart && pack.header.parts[i.texPart] ? i.texPart : i.part;
1996
- const all = instances.map((i) => ({ part: pick(i), color: String(i.color), m: i.m, steps: i.steps }));
1997
- const key = (i) => i.steps.map((x) => String(x).padStart(6, "0")).join(".");
1998
- const uniq = [...new Set(all.map(key))].sort();
1999
- const rank = new Map(uniq.map((k, j) => [k, j]));
2000
- const stepOf = all.map((i) => rank.get(key(i)));
2240
+ const { all, stepOf, nSteps } = sceneInstances(instances, pack.header, useTex);
2241
+ const uniq = { length: nSteps };
2001
2242
  const stepViews = new Array(uniq.length).fill(null);
2002
2243
  instances.forEach((i, k) => {
2003
2244
  if (i.view)
@@ -2036,7 +2277,7 @@ function createLdrObject(instances, pack, options = {}) {
2036
2277
  const drawnAt = (step) => all.filter((i, k) => (step == null || stepOf[k] <= step) && pack.header.parts[i.part]).length;
2037
2278
  const build = () => {
2038
2279
  const t0 = performance.now();
2039
- cur = buildLdrScene(all, pack, { 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, () => {});
2040
2281
  pairs.clear();
2041
2282
  if (o.material === "plastic")
2042
2283
  cur.root.traverse((x) => {
@@ -2107,18 +2348,7 @@ function createLdrObject(instances, pack, options = {}) {
2107
2348
  dispose: disposeCur
2108
2349
  });
2109
2350
  }
2110
- // ../../../../../../../tmp/ldr-build-qIdKSv/src/pack-io.ts
2111
- import { decompress } from "fzstd";
2112
- async function decompressPack(data) {
2113
- const u = data instanceof Uint8Array ? data : new Uint8Array(data);
2114
- const own = (o) => o.buffer.slice(o.byteOffset, o.byteOffset + o.byteLength);
2115
- if (u[0] === 40 && u[1] === 181 && u[2] === 47 && u[3] === 253)
2116
- return own(decompress(u));
2117
- if (u[0] === 31 && u[1] === 139)
2118
- return new Response(new Blob([u]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();
2119
- return own(u);
2120
- }
2121
- // ../../../../../../../tmp/ldr-build-qIdKSv/src/cdn.ts
2351
+ // ../../../../../../../tmp/ldr-build-NB5kkP/src/parts-cdn.ts
2122
2352
  import { decompress as decompress2 } from "fzstd";
2123
2353
  var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
2124
2354
  var indexCache = new Map;
@@ -2179,7 +2409,7 @@ function mergePacks(packs, extra = {}) {
2179
2409
  return decodePack(out.buffer);
2180
2410
  }
2181
2411
  async function loadParts(names, o = {}) {
2182
- const cdn = o.cdn ?? DEFAULT_PARTS_CDN, f = o.fetch ?? fetch, gap = o.gap ?? 65536;
2412
+ const cdn = o.cdn ?? DEFAULT_PARTS_CDN, f = o.fetch ?? fetch, gap = o.gap ?? 16384;
2183
2413
  const idx = await loadPartsIndex(cdn, f);
2184
2414
  const want = [...new Set([...names].map(norm))];
2185
2415
  const missing = [];
@@ -2222,7 +2452,7 @@ async function loadParts(names, o = {}) {
2222
2452
  }
2223
2453
  }
2224
2454
  };
2225
- await Promise.all(Array.from({ length: Math.min(o.concurrency ?? 6, groups.length) }, worker));
2455
+ await Promise.all(Array.from({ length: Math.min(o.concurrency ?? 24, groups.length) }, worker));
2226
2456
  const shards = want.filter((n) => shardCache.has(cdn + n)).map((n) => shardCache.get(cdn + n));
2227
2457
  const pack = shards.length ? mergePacks(shards, { colors: idx.colors }) : decodePack(emptyPack(idx.colors));
2228
2458
  return { pack, missing, requests: groups.length, bytes };
@@ -2235,10 +2465,11 @@ function emptyPack(colors) {
2235
2465
  b.set(h, 4);
2236
2466
  return b.buffer;
2237
2467
  }
2238
- async function loadModel(source, o = {}) {
2468
+ async function prepareModel(source, o = {}) {
2239
2469
  const t0 = performance.now();
2240
2470
  const f = o.fetch ?? fetch;
2241
2471
  const idxP = loadPartsIndex(o.cdn ?? DEFAULT_PARTS_CDN, f);
2472
+ idxP.catch(() => {});
2242
2473
  const text = o.text ? source : await f(source).then((r) => {
2243
2474
  if (!r.ok)
2244
2475
  throw new Error(`ldr: ${r.status} fetching ${source}`);
@@ -2248,15 +2479,125 @@ async function loadModel(source, o = {}) {
2248
2479
  const name = o.name ?? (o.text ? "main.ldr" : decodeURIComponent(source.split(/[?#]/)[0].split("/").pop() || "main.ldr"));
2249
2480
  const insts = parseModel(text, name, { looseGeometry: false });
2250
2481
  const t2 = performance.now();
2482
+ o.onParsed?.(insts);
2251
2483
  await idxP;
2252
2484
  const { pack, missing, requests, bytes } = await loadParts(insts.filter((i) => !i.embedded).map((i) => i.part), o);
2253
2485
  const t3 = performance.now();
2254
- const obj = createLdrObject(insts, pack, o);
2255
- 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)
2256
2590
  if (!obj.stats.missing.includes(m))
2257
2591
  obj.stats.missing.push(m);
2258
2592
  const t4 = performance.now();
2259
- return Object.assign(obj, { 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
+ });
2260
2601
  }
2261
2602
  export {
2262
2603
  DEFAULT_PARTS_CDN,
@@ -2296,13 +2637,17 @@ export {
2296
2637
  parseLDConfig,
2297
2638
  parseModel,
2298
2639
  parseTexMap,
2640
+ precomputeCull,
2641
+ prepareModel,
2299
2642
  resolveTexture,
2300
2643
  rotStepMatrix,
2644
+ sceneInstances,
2301
2645
  sequenceSteps,
2302
2646
  smoothNormals,
2303
2647
  stepViewMatrix,
2304
2648
  texWrapper,
2305
2649
  texmapTriangleUV,
2306
2650
  texmapUV,
2307
- transformTexMap
2651
+ transformTexMap,
2652
+ warmPackGeometry
2308
2653
  };