ldr 0.26.1 → 0.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/cli.js +62 -14
- package/dist/index.d.ts +1 -1
- package/dist/index.js +132 -15
- package/dist/node/build-pack.d.ts +7 -2
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.js +190 -24
- package/dist/scene.d.ts +13 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -144,10 +144,12 @@ MPD-embedded parts, such as Studio/OMR unofficial parts or stickers, become part
|
|
|
144
144
|
| `lodEdgeMinPx` | `0.15` | LOD: draw only edge segments at least this many pixels long on screen. `0` = every segment. |
|
|
145
145
|
| `lodUnder` | `true` | LOD: skip undersides that can't be seen (camera behind every bottom face of a cluster's parts, or the body drawn as its closed bounding box). Lossless in the fidelity checks. |
|
|
146
146
|
|
|
147
|
-
`LdrObject`: `object`, `stats` (`instances`, `drawn`, `missing[]`, `studsHidden/Total`, `undersHidden/Total`, `buildMs`, `condBatches`, `texBatches`, `textures`, `glossmaps`, `clusters`), `stepCount`, `stepViews`, `texturesReady`, `setStep(n | null)`, `setEdges(on)`, `setConditionalLines(on)`, `setCulling(studs, undersides)`, `setSide(side)`, `setLod(on)`, `getBox(target?)`, `dispose()`.
|
|
147
|
+
`LdrObject`: `object`, `stats` (`instances`, `drawn`, `missing[]`, `studsHidden/Total`, `undersHidden/Total`, `buildMs`, `condBatches`, `texBatches`, `textures`, `glossmaps`, `clusters`), `stepCount`, `stepViews`, `texturesReady`, `setStep(n | null)`, `setEdges(on)`, `setConditionalLines(on)`, `setCulling(studs, undersides)`, `setSide(side)`, `setLod(on)`, `setGhost(on, { opacity, color, whiten }?)`, `getBox(target?)`, `dispose()`.
|
|
148
148
|
|
|
149
149
|
`setStep` doesn't rebuild anything: it compacts instance buffers, and culling is step-aware (a stud covered only by a later step's part stays visible). `stats` reflect the shown step.
|
|
150
150
|
|
|
151
|
+
`setGhost(true)` draws the steps still to come as a faint, whitened, depth-written ghost (like the LEGO Builder app). It is built once on first use, without edges, with the steps reversed so `setStep` stays a buffer compaction for it too. It honours the booklet isolate mask, and `getBox` ignores it. Off by default. Cost: about the same as drawing the whole model (Titanic, 9.7k bricks: 1.6 ms off, 2.5 ms on, 2.8 ms full model).
|
|
152
|
+
|
|
151
153
|
**Building instructions.** `parseModel(text, name, { callouts: true })` (or `loadModel(url, { callouts: true })`) sequences a
|
|
152
154
|
submodel placed N times in one step like a booklet: the first copy is built step by step (its instances get `mult = N`, the "xN"),
|
|
153
155
|
the other copies appear finished at the end of that step. `planStepViews(instances, pack.header.parts, stepOf, stepCount)` plans a
|
|
@@ -163,7 +165,7 @@ Everything above, plus:
|
|
|
163
165
|
|
|
164
166
|
| export | description |
|
|
165
167
|
|---|---|
|
|
166
|
-
| `buildPack(options) → { data, parts, studKinds, missing, warnings? }` | Builds a pack. Options: `ldrawRoot`, `models`, `parts`, `allParts`, `studs` (`"low"` \| `"full"`), `primitives` (`"low"` \| `"full"`, default `"low"`), `weld` (`true`), `cond` (`false`), `textures` (`false`), `looseGeometry` (`true`), `colors` (`true`), `lod` (`true`: meshoptimizer-simplified LOD meshes, pack feature `lod`), `reorder` (`false`: vertex-cache order), `onProgress`. |
|
|
168
|
+
| `buildPack(options) → { data, parts, studKinds, missing, warnings? }` | Builds a pack. Options: `ldrawRoot`, `models`, `parts`, `allParts`, `studs` (`"low"` \| `"full"`), `primitives` (`"low"` \| `"full"`, default `"full"`; `"low"` substitutes p/8 primitives and leaves gaps in round parts), `weld` (`true`), `cond` (`false`), `textures` (`false`), `looseGeometry` (`true`), `colors` (`true`), `lod` (`true`: meshoptimizer-simplified LOD meshes, pack feature `lod`), `reorder` (`false`: vertex-cache order), `onProgress`. |
|
|
167
169
|
| `Library(root, unofficialRoot?)` | Filesystem LDraw resolver: `where`, `flatten`, `mesh` (`{ texmap: true }` adds `uv`, per-triangle `texture`, `textures` and, when a map has one, `glossmaps`), `colors`, `texture`, `register`. Handles case-insensitive lookup and `~Moved to` aliases. |
|
|
168
170
|
| `Compiler`, `encodePack`, `writePack`, `loadColors` | Lower-level pack compiler. |
|
|
169
171
|
| `ResolverLibrary`, `splitModel`, `flattenWithLibrary`, `collectDeps` | The resolver that `buildPack` uses. |
|
package/dist/cli.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/cli.ts
|
|
4
4
|
import fs4 from "node:fs";
|
|
5
5
|
import zlib from "node:zlib";
|
|
6
6
|
|
|
7
|
-
// ../../../../../../../tmp/ldr-build-
|
|
7
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/build-pack.ts
|
|
8
8
|
import fs3 from "node:fs";
|
|
9
9
|
import path3 from "node:path";
|
|
10
10
|
|
|
11
|
-
// ../../../../../../../tmp/ldr-build-
|
|
11
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/resolver.ts
|
|
12
12
|
import fs from "node:fs";
|
|
13
13
|
import path from "node:path";
|
|
14
14
|
|
|
15
|
-
// ../../../../../../../tmp/ldr-build-
|
|
15
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/spec.ts
|
|
16
16
|
var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
17
17
|
var COLOUR_ID_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
|
|
18
18
|
var namedCodes = new Map;
|
|
@@ -723,7 +723,7 @@ function fileStepViews(f) {
|
|
|
723
723
|
return out;
|
|
724
724
|
}
|
|
725
725
|
|
|
726
|
-
// ../../../../../../../tmp/ldr-build-
|
|
726
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/model.ts
|
|
727
727
|
var CALLOUT_END = 999999;
|
|
728
728
|
var stepKey = (steps) => steps.map((x) => String(x).padStart(6, "0")).join(".") + "~";
|
|
729
729
|
function flatten(doc, opts = {}) {
|
|
@@ -1106,7 +1106,7 @@ function blendedColourHex(code) {
|
|
|
1106
1106
|
return "#" + [0, 1, 2].map((k) => (a[k] + b[k] >> 1).toString(16).padStart(2, "0")).join("").toUpperCase();
|
|
1107
1107
|
}
|
|
1108
1108
|
|
|
1109
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1109
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/resolver.ts
|
|
1110
1110
|
var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
|
|
1111
1111
|
var UNDER_STUD_RE = /^(stud3|stud3a|stud4.*|stud12|stud16.*|stud18a)\.dat$/i;
|
|
1112
1112
|
var norm2 = (ref) => ref.trim().replace(/\\/g, "/").toLowerCase();
|
|
@@ -1376,11 +1376,11 @@ function collectDeps(lib, refs) {
|
|
|
1376
1376
|
return out;
|
|
1377
1377
|
}
|
|
1378
1378
|
|
|
1379
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1379
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/compile.ts
|
|
1380
1380
|
import fs2 from "node:fs";
|
|
1381
1381
|
import path2 from "node:path";
|
|
1382
1382
|
|
|
1383
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1383
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/lod.ts
|
|
1384
1384
|
import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
|
|
1385
1385
|
await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
|
|
1386
1386
|
function reorderMesh(P, N, C, I) {
|
|
@@ -1572,7 +1572,7 @@ function lodChain(P, C, I) {
|
|
|
1572
1572
|
return out;
|
|
1573
1573
|
}
|
|
1574
1574
|
|
|
1575
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1575
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/compile.ts
|
|
1576
1576
|
function loadColors(root) {
|
|
1577
1577
|
const map = new Map;
|
|
1578
1578
|
for (const l of fs2.readFileSync(path2.join(root, "LDConfig.ldr"), "latin1").split(/\r?\n/)) {
|
|
@@ -1668,6 +1668,7 @@ class Compiler {
|
|
|
1668
1668
|
invertNext = false;
|
|
1669
1669
|
if (isTop && separateStuds) {
|
|
1670
1670
|
out.studs.push({ kind: ck2, color: childColor, m: Mc });
|
|
1671
|
+
fullKind.set(out.studs.length - 1, this.lib.resolve(r.name));
|
|
1671
1672
|
growBox(out.bbox, Mc, this.compile(ck2, false).bbox);
|
|
1672
1673
|
continue;
|
|
1673
1674
|
}
|
|
@@ -1714,7 +1715,9 @@ class Compiler {
|
|
|
1714
1715
|
if (!certified)
|
|
1715
1716
|
out.uncertified = true;
|
|
1716
1717
|
};
|
|
1718
|
+
const fullKind = new Map;
|
|
1717
1719
|
walk(key, IDENT, "16", false, "body", 0);
|
|
1720
|
+
seatStuds(out, fullKind, (k) => this.compile(k, false).bbox);
|
|
1718
1721
|
if (this.opts.tex && this.hasTex(key))
|
|
1719
1722
|
this.texPass(key, out, separateStuds, colorOf);
|
|
1720
1723
|
const [x0, y0, z0, x1, y1, z1] = out.bbox;
|
|
@@ -2005,6 +2008,48 @@ function enclosureMask(c) {
|
|
|
2005
2008
|
}
|
|
2006
2009
|
return { nx, nz, bits };
|
|
2007
2010
|
}
|
|
2011
|
+
function seatStuds(out, fullKind, kindBox) {
|
|
2012
|
+
if (!out.studs.length)
|
|
2013
|
+
return;
|
|
2014
|
+
const tris = [out.body.pos, out.under.pos];
|
|
2015
|
+
const covered = (c, up) => {
|
|
2016
|
+
for (const p of tris)
|
|
2017
|
+
for (let i = 0;i < p.length; i += 9) {
|
|
2018
|
+
const ax = p[i], ay = p[i + 1], az = p[i + 2], ux = p[i + 3] - ax, uy = p[i + 4] - ay, uz = p[i + 5] - az, vx = p[i + 6] - ax, vy = p[i + 7] - ay, vz = p[i + 8] - az;
|
|
2019
|
+
const nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx, nl = Math.hypot(nx, ny, nz);
|
|
2020
|
+
if (nl < 0.000000001)
|
|
2021
|
+
continue;
|
|
2022
|
+
if (!out.uncertified && nx * up[0] + ny * up[1] + nz * up[2] <= 0)
|
|
2023
|
+
continue;
|
|
2024
|
+
const wx = c[0] - ax, wy = c[1] - ay, wz = c[2] - az;
|
|
2025
|
+
if (Math.abs((wx * nx + wy * ny + wz * nz) / nl) > 0.05)
|
|
2026
|
+
continue;
|
|
2027
|
+
const uu = ux * ux + uy * uy + uz * uz, vv = vx * vx + vy * vy + vz * vz, uv = ux * vx + uy * vy + uz * vz, wu = wx * ux + wy * uy + wz * uz, wv = wx * vx + wy * vy + wz * vz;
|
|
2028
|
+
const d = uv * uv - uu * vv, s = (uv * wv - vv * wu) / d, t = (uv * wu - uu * wv) / d, e = 0.0001;
|
|
2029
|
+
if (s >= -e && t >= -e && s + t <= 1 + e)
|
|
2030
|
+
return true;
|
|
2031
|
+
}
|
|
2032
|
+
return false;
|
|
2033
|
+
};
|
|
2034
|
+
out.studs.forEach((s, i) => {
|
|
2035
|
+
const full = fullKind.get(i);
|
|
2036
|
+
if (!full || full === s.kind)
|
|
2037
|
+
return;
|
|
2038
|
+
const b = kindBox(s.kind), r = 0.975 * Math.min(b[3] - b[0], b[5] - b[2]) / 2, cx = (b[0] + b[3]) / 2, cz = (b[2] + b[5]) / 2;
|
|
2039
|
+
const up = [-s.m[4], -s.m[7], -s.m[10]];
|
|
2040
|
+
if (!(r > 0) || !covered(xf(s.m, [cx, 0, cz]), up)) {
|
|
2041
|
+
s.kind = full;
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
for (let k = 0;k < 8; k++) {
|
|
2045
|
+
const a = (k + 0.5) * Math.PI / 4;
|
|
2046
|
+
if (!covered(xf(s.m, [cx + r * Math.cos(a), 0, cz + r * Math.sin(a)]), up)) {
|
|
2047
|
+
s.kind = full;
|
|
2048
|
+
return;
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
});
|
|
2052
|
+
}
|
|
2008
2053
|
function grow(b, p) {
|
|
2009
2054
|
for (let i = 0;i < 3; i++) {
|
|
2010
2055
|
if (p[i] < b[i])
|
|
@@ -2209,7 +2254,10 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
2209
2254
|
return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
|
|
2210
2255
|
}
|
|
2211
2256
|
|
|
2212
|
-
// ../../../../../../../tmp/ldr-build-
|
|
2257
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/build-pack.ts
|
|
2258
|
+
function packCompilerOpts(o) {
|
|
2259
|
+
return { studs: o.studs ?? "low", prims: o.primitives ?? "full", weld: o.weld ?? true, separateStuds: true, cond: !!o.cond, tex: !!o.textures };
|
|
2260
|
+
}
|
|
2213
2261
|
function buildPack(o) {
|
|
2214
2262
|
const lib = new Library(o.ldrawRoot);
|
|
2215
2263
|
const refs = new Map;
|
|
@@ -2243,7 +2291,7 @@ function buildPack(o) {
|
|
|
2243
2291
|
if (lib.isPart(k) && /\.dat$/.test(k))
|
|
2244
2292
|
refs.set(k.slice(6), k);
|
|
2245
2293
|
}
|
|
2246
|
-
const comp = new Compiler(lib,
|
|
2294
|
+
const comp = new Compiler(lib, packCompilerOpts(o));
|
|
2247
2295
|
const parts = new Map, kinds = new Map;
|
|
2248
2296
|
let n = 0;
|
|
2249
2297
|
for (const [ref, key] of refs) {
|
|
@@ -2277,7 +2325,7 @@ function buildPack(o) {
|
|
|
2277
2325
|
return { data: encodePack(parts, kinds, comp.opts.weld, extra, { texture, lod: o.lod !== false, reorder: !!o.reorder }), parts: parts.size, studKinds: kinds.size, missing: [...missing], ...warnings.length ? { warnings } : {} };
|
|
2278
2326
|
}
|
|
2279
2327
|
|
|
2280
|
-
// ../../../../../../../tmp/ldr-build-
|
|
2328
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/cli.ts
|
|
2281
2329
|
var HELP = `ldr pack — build a parts pack for the ldr three.js renderer
|
|
2282
2330
|
|
|
2283
2331
|
Usage:
|
|
@@ -2289,7 +2337,7 @@ Options:
|
|
|
2289
2337
|
--part <ref> Include a part (repeatable), e.g. --part 3001.dat
|
|
2290
2338
|
--all-parts Include every part in the library (large)
|
|
2291
2339
|
--studs low|full Stud detail (default low)
|
|
2292
|
-
--prims low|full Other primitive detail (default low)
|
|
2340
|
+
--prims low|full Other primitive detail (default full; low leaves gaps in round parts)
|
|
2293
2341
|
--no-weld Don't index/weld vertices
|
|
2294
2342
|
--cond Keep conditional (type-5) lines for curved-surface outlines (pack v2, ~+8-14% zstd)
|
|
2295
2343
|
--textures Keep printed/sticker parts' !TEXMAP geometry + UVs and embed their PNGs (pack v2; packs without
|
|
@@ -2311,7 +2359,7 @@ var parts = [];
|
|
|
2311
2359
|
var ldraw = "";
|
|
2312
2360
|
var out = "";
|
|
2313
2361
|
var studs = "low";
|
|
2314
|
-
var prims = "
|
|
2362
|
+
var prims = "full";
|
|
2315
2363
|
var weld = true;
|
|
2316
2364
|
var colors = true;
|
|
2317
2365
|
var all = false;
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { loadPack, decodePack, buildLdrScene, buildLdrSceneAsync, makeMaterial,
|
|
|
8
8
|
export { precomputeCull, sceneInstances } from "./cull.js";
|
|
9
9
|
export type { Pack, LdrParams, Inst, CullResult, BuildLdrSceneAsyncOptions, GlossMap } from "./render.js";
|
|
10
10
|
export { createLdrObject, createLdrObjectAsync } from "./scene.js";
|
|
11
|
-
export type { LdrObject, LdrObjectOptions, LdrStats, ColorSource } from "./scene.js";
|
|
11
|
+
export type { LdrObject, LdrObjectOptions, LdrStats, ColorSource, GhostOptions } from "./scene.js";
|
|
12
12
|
export { decompressPack, decodeModelText, modelFileName } from "./pack-io.js";
|
|
13
13
|
export { loadModel, loadParts, loadPartsIndex, mergePacks, prepareModel, bodyTriangles, estimateBudgetFromIndex, BudgetError, DEFAULT_PARTS_CDN } from "./cdn.js";
|
|
14
14
|
export type { LoadModelOptions, LoadedModel, LoadPartsOptions, PartsCdnIndex, PrepareOptions, PreparedModel } from "./cdn.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/spec.ts
|
|
2
2
|
var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
3
3
|
var COLOUR_ID_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
|
|
4
4
|
var namedCodes = new Map;
|
|
@@ -707,7 +707,7 @@ function fileStepViews(f) {
|
|
|
707
707
|
viewMemo.set(f, out);
|
|
708
708
|
return out;
|
|
709
709
|
}
|
|
710
|
-
// ../../../../../../../tmp/ldr-build-
|
|
710
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/model.ts
|
|
711
711
|
var CALLOUT_END = 999999;
|
|
712
712
|
var stepKey = (steps) => steps.map((x) => String(x).padStart(6, "0")).join(".") + "~";
|
|
713
713
|
function flatten(doc, opts = {}) {
|
|
@@ -1089,7 +1089,7 @@ function blendedColourHex(code) {
|
|
|
1089
1089
|
const a = LDRAW_EXE_16[code - 256 >> 4], b = LDRAW_EXE_16[code - 256 & 15];
|
|
1090
1090
|
return "#" + [0, 1, 2].map((k) => (a[k] + b[k] >> 1).toString(16).padStart(2, "0")).join("").toUpperCase();
|
|
1091
1091
|
}
|
|
1092
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1092
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/instructions.ts
|
|
1093
1093
|
var MIN_VIS = 0.5;
|
|
1094
1094
|
var REORIENT = 0.35;
|
|
1095
1095
|
var deg = Math.PI / 180;
|
|
@@ -1457,10 +1457,10 @@ function planStepViews(insts, parts, stepOf, nSteps, o = {}) {
|
|
|
1457
1457
|
}
|
|
1458
1458
|
};
|
|
1459
1459
|
}
|
|
1460
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1460
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/render.ts
|
|
1461
1461
|
import * as THREE from "three";
|
|
1462
1462
|
|
|
1463
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1463
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/pack-io.ts
|
|
1464
1464
|
import { decompress } from "fzstd";
|
|
1465
1465
|
async function decompressPack(data) {
|
|
1466
1466
|
const u = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
@@ -1483,7 +1483,7 @@ function decodePack(buf) {
|
|
|
1483
1483
|
return { header, arr, bytes: buf.byteLength, buffer: buf };
|
|
1484
1484
|
}
|
|
1485
1485
|
|
|
1486
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1486
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/cull.ts
|
|
1487
1487
|
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;
|
|
1488
1488
|
var prepCache = new WeakMap;
|
|
1489
1489
|
function prepPart(H, part) {
|
|
@@ -1818,7 +1818,7 @@ function precomputeCull(instances, H, useTex = true) {
|
|
|
1818
1818
|
return cullCore(s.all, H, s.nSteps > 1 ? s.stepOf : undefined);
|
|
1819
1819
|
}
|
|
1820
1820
|
|
|
1821
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1821
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/render.ts
|
|
1822
1822
|
async function loadPack(url) {
|
|
1823
1823
|
const res = await fetch(url);
|
|
1824
1824
|
if (!res.ok)
|
|
@@ -3672,8 +3672,27 @@ async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
|
|
|
3672
3672
|
await new Promise((r) => setTimeout(r, 0));
|
|
3673
3673
|
}
|
|
3674
3674
|
}
|
|
3675
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3675
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/scene.ts
|
|
3676
3676
|
import * as THREE2 from "three";
|
|
3677
|
+
function ghostMaterial(side, g) {
|
|
3678
|
+
const m = new THREE2.MeshStandardMaterial({ color: 16777215, roughness: 0.85, metalness: 0, side, transparent: false, depthWrite: true, opacity: g.opacity });
|
|
3679
|
+
m.blending = THREE2.CustomBlending;
|
|
3680
|
+
m.blendSrc = THREE2.SrcAlphaFactor;
|
|
3681
|
+
m.blendDst = THREE2.OneMinusSrcAlphaFactor;
|
|
3682
|
+
m.blendSrcAlpha = THREE2.OneFactor;
|
|
3683
|
+
m.blendDstAlpha = THREE2.OneMinusSrcAlphaFactor;
|
|
3684
|
+
const tint = new THREE2.Color(g.color);
|
|
3685
|
+
const u = { ldrGhostTint: { value: tint }, ldrGhostMix: { value: g.whiten } };
|
|
3686
|
+
m.onBeforeCompile = (sh) => {
|
|
3687
|
+
Object.assign(sh.uniforms, u);
|
|
3688
|
+
sh.fragmentShader = `uniform vec3 ldrGhostTint; uniform float ldrGhostMix;
|
|
3689
|
+
` + sh.fragmentShader.replace("#include <color_fragment>", `#include <color_fragment>
|
|
3690
|
+
diffuseColor.rgb = mix(diffuseColor.rgb, ldrGhostTint, ldrGhostMix);`);
|
|
3691
|
+
};
|
|
3692
|
+
m.customProgramCacheKey = () => "ldrGhost";
|
|
3693
|
+
m.userData.ldrGhost = u;
|
|
3694
|
+
return m;
|
|
3695
|
+
}
|
|
3677
3696
|
function colorFn(src, pack, fallback) {
|
|
3678
3697
|
const table = new Map;
|
|
3679
3698
|
const put = (k, v) => table.set(String(k), new THREE2.Color(typeof v === "string" ? v : v.hex));
|
|
@@ -3787,6 +3806,75 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3787
3806
|
}
|
|
3788
3807
|
cur = null;
|
|
3789
3808
|
};
|
|
3809
|
+
let ghostOn = false, ghost = null, ghostBuild = null, ghostGen = 0;
|
|
3810
|
+
let shownStep = null, shownMask = null;
|
|
3811
|
+
const ghostOpts = { opacity: 0.2, color: 16777215, whiten: 0.75 };
|
|
3812
|
+
const ghostMats = new Map;
|
|
3813
|
+
const syncGhost = () => {
|
|
3814
|
+
if (!ghost)
|
|
3815
|
+
return;
|
|
3816
|
+
const show = ghostOn && shownStep != null && shownStep < uniq.length - 1;
|
|
3817
|
+
ghost.root.visible = show;
|
|
3818
|
+
if (show)
|
|
3819
|
+
ghost.setStep(uniq.length - 2 - shownStep, shownMask);
|
|
3820
|
+
};
|
|
3821
|
+
const disposeGhost = () => {
|
|
3822
|
+
ghostGen++;
|
|
3823
|
+
ghostBuild = null;
|
|
3824
|
+
if (!ghost)
|
|
3825
|
+
return;
|
|
3826
|
+
object.remove(ghost.root);
|
|
3827
|
+
ghost.root.traverse((x) => {
|
|
3828
|
+
if (x.isInstancedMesh)
|
|
3829
|
+
x.dispose();
|
|
3830
|
+
else if (x.isBatchedMesh)
|
|
3831
|
+
x.dispose();
|
|
3832
|
+
});
|
|
3833
|
+
for (const m of ghostMats.values())
|
|
3834
|
+
m.dispose();
|
|
3835
|
+
ghostMats.clear();
|
|
3836
|
+
ghost = null;
|
|
3837
|
+
};
|
|
3838
|
+
const buildGhost = () => ghostBuild ??= (async () => {
|
|
3839
|
+
const my = ghostGen;
|
|
3840
|
+
const n = uniq.length;
|
|
3841
|
+
const rev = new Int32Array(stepOf.length);
|
|
3842
|
+
for (let k = 0;k < rev.length; k++)
|
|
3843
|
+
rev[k] = n - 1 - stepOf[k];
|
|
3844
|
+
const so = { ...sceneOpts(), edges: false, cond: false, tex: false, steps: rev, cull: undefined };
|
|
3845
|
+
so.cull = cullCore(all, pack.header, rev);
|
|
3846
|
+
const g = await buildLdrSceneAsync(all, pack, so, color, () => {}, { postPaintSliceMs: 12 });
|
|
3847
|
+
if (my !== ghostGen) {
|
|
3848
|
+
g.root.traverse((x) => {
|
|
3849
|
+
if (x.isInstancedMesh || x.isBatchedMesh)
|
|
3850
|
+
x.dispose();
|
|
3851
|
+
});
|
|
3852
|
+
return;
|
|
3853
|
+
}
|
|
3854
|
+
const old = new Set;
|
|
3855
|
+
g.root.traverse((x) => {
|
|
3856
|
+
if (!x.isMesh)
|
|
3857
|
+
return;
|
|
3858
|
+
if (x.material)
|
|
3859
|
+
old.add(x.material);
|
|
3860
|
+
let m = ghostMats.get(x.material?.side ?? THREE2.FrontSide);
|
|
3861
|
+
if (!m)
|
|
3862
|
+
ghostMats.set(x.material?.side ?? THREE2.FrontSide, m = ghostMaterial(x.material?.side ?? THREE2.FrontSide, ghostOpts));
|
|
3863
|
+
x.material = m;
|
|
3864
|
+
x.castShadow = x.receiveShadow = false;
|
|
3865
|
+
x.renderOrder = 1;
|
|
3866
|
+
x.userData.ldrGhost = true;
|
|
3867
|
+
});
|
|
3868
|
+
for (const m of old)
|
|
3869
|
+
m.dispose();
|
|
3870
|
+
g.root.name = "ldr-ghost";
|
|
3871
|
+
if (!lodOn)
|
|
3872
|
+
g.setLod(false);
|
|
3873
|
+
g.setCull(cs, cu);
|
|
3874
|
+
ghost = g;
|
|
3875
|
+
object.add(g.root);
|
|
3876
|
+
syncGhost();
|
|
3877
|
+
})();
|
|
3790
3878
|
const multiStep = uniq.length > 1;
|
|
3791
3879
|
const drawnAt = (step, mask) => all.filter((i, k) => (step == null || stepOf[k] <= step) && (!mask || mask[k]) && pack.header.parts[i.part]).length;
|
|
3792
3880
|
const sceneOpts = () => ({ localColours: localColours.size ? localColours : undefined, cullStuds: cs, cullUnder: cu, edges: o.edges, side, cond: o.conditionalLines, 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 });
|
|
@@ -3819,7 +3907,12 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3819
3907
|
if (!multiStep)
|
|
3820
3908
|
return;
|
|
3821
3909
|
const t0 = performance.now();
|
|
3910
|
+
shownStep = step;
|
|
3911
|
+
shownMask = mask;
|
|
3822
3912
|
Object.assign(stats, cur.setStep(step, mask), { drawn: drawnAt(step, mask), buildMs: performance.now() - t0 });
|
|
3913
|
+
if (ghostOn && step != null && !ghost)
|
|
3914
|
+
buildGhost();
|
|
3915
|
+
syncGhost();
|
|
3823
3916
|
};
|
|
3824
3917
|
const api = { texturesReady: Promise.resolve() };
|
|
3825
3918
|
const finish = () => {
|
|
@@ -3848,10 +3941,31 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3848
3941
|
applyBuilt(buildLdrScene(all, pack, sceneOpts(), color, () => {}), t0);
|
|
3849
3942
|
} else
|
|
3850
3943
|
cur.setCull(a, b);
|
|
3944
|
+
ghost?.setCull(a, b);
|
|
3851
3945
|
},
|
|
3852
3946
|
setLod: (v) => {
|
|
3853
3947
|
lodOn = v;
|
|
3854
3948
|
cur.setLod(v);
|
|
3949
|
+
ghost?.setLod(v);
|
|
3950
|
+
},
|
|
3951
|
+
setGhost: (on, go = {}) => {
|
|
3952
|
+
ghostOn = on && multiStep;
|
|
3953
|
+
Object.assign(ghostOpts, Object.fromEntries(Object.entries(go).filter(([, v]) => v !== undefined)));
|
|
3954
|
+
for (const m of ghostMats.values()) {
|
|
3955
|
+
m.opacity = ghostOpts.opacity;
|
|
3956
|
+
const u = m.userData.ldrGhost;
|
|
3957
|
+
u.ldrGhostTint.value.set(ghostOpts.color);
|
|
3958
|
+
u.ldrGhostMix.value = ghostOpts.whiten;
|
|
3959
|
+
}
|
|
3960
|
+
if (!ghostOn) {
|
|
3961
|
+
syncGhost();
|
|
3962
|
+
return ghostBuild ?? Promise.resolve();
|
|
3963
|
+
}
|
|
3964
|
+
if (shownStep == null && !ghost)
|
|
3965
|
+
return Promise.resolve();
|
|
3966
|
+
const b = buildGhost();
|
|
3967
|
+
syncGhost();
|
|
3968
|
+
return b;
|
|
3855
3969
|
},
|
|
3856
3970
|
setSide: (s) => {
|
|
3857
3971
|
side = s;
|
|
@@ -3865,7 +3979,7 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3865
3979
|
object.updateMatrixWorld(true);
|
|
3866
3980
|
target.makeEmpty();
|
|
3867
3981
|
object.traverse((x) => {
|
|
3868
|
-
if (x.isInstancedMesh && x.count && !x.userData.ldrLod) {
|
|
3982
|
+
if (x.isInstancedMesh && x.count && !x.userData.ldrLod && !x.userData.ldrGhost) {
|
|
3869
3983
|
x.computeBoundingBox();
|
|
3870
3984
|
const b = x.boundingBox.clone().applyMatrix4(x.matrixWorld);
|
|
3871
3985
|
target.union(b);
|
|
@@ -3873,7 +3987,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3873
3987
|
});
|
|
3874
3988
|
return target;
|
|
3875
3989
|
},
|
|
3876
|
-
dispose:
|
|
3990
|
+
dispose: () => {
|
|
3991
|
+
disposeGhost();
|
|
3992
|
+
disposeCur();
|
|
3993
|
+
}
|
|
3877
3994
|
});
|
|
3878
3995
|
};
|
|
3879
3996
|
if (!progressive) {
|
|
@@ -3899,10 +4016,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3899
4016
|
return finish();
|
|
3900
4017
|
})();
|
|
3901
4018
|
}
|
|
3902
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4019
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/parts-cdn.ts
|
|
3903
4020
|
import { decompress as decompress2 } from "fzstd";
|
|
3904
4021
|
|
|
3905
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4022
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/embedded.ts
|
|
3906
4023
|
function splitFiles(text, fallback) {
|
|
3907
4024
|
const files = new Map;
|
|
3908
4025
|
let cur = null, saw = false;
|
|
@@ -3974,7 +4091,7 @@ function embeddedKeys(text, names, fallback = "main.ldr") {
|
|
|
3974
4091
|
return out;
|
|
3975
4092
|
}
|
|
3976
4093
|
|
|
3977
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4094
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/parts-cdn.ts
|
|
3978
4095
|
var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
|
|
3979
4096
|
var indexCache = new Map;
|
|
3980
4097
|
var shardCache = new Map;
|
|
@@ -4206,10 +4323,10 @@ async function prepareModel(source, o = {}) {
|
|
|
4206
4323
|
return { insts, pack, missing, requests, bytes, cull, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, ...cull ? { cull: performance.now() - t3 } : {} } };
|
|
4207
4324
|
}
|
|
4208
4325
|
|
|
4209
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4326
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/load-worker.gen.ts
|
|
4210
4327
|
var load_worker_gen_default = 'var vt=ArrayBuffer,Z=Uint8Array,de=Uint16Array,Ct=Int16Array;var be=Int32Array,Le=function(e,t,n){if(Z.prototype.slice)return Z.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 Z(n-t);return r.set(e.subarray(t,n)),r},ce=function(e,t,n,r){if(Z.prototype.fill)return Z.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},Tt=function(e,t,n,r){if(Z.prototype.copyWithin)return Z.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 Lt=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],J=function(e,t,n){var r=Error(t||Lt[e]);if(r.code=e,Error.captureStackTrace)Error.captureStackTrace(r,J);if(!n)throw r;return r},Ke=function(e,t,n){var r=0,s=0;for(;r<n;++r)s|=e[t++]<<(r<<3);return s},Et=function(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0},St=function(e,t){var n=e[0]|e[1]<<8|e[2]<<16;if(n==3126568&&e[3]==253){var r=e[4],s=r>>5&1,o=r>>2&1,i=r&3,a=r>>6;if(r&8)J(0);var u=6-s,c=i==3?4:i,f=Ke(e,u,c);u+=c;var l=a?1<<a:s,p=Ke(e,u,l)+(a==1&&256),d=p;if(!s){var w=1<<10+(e[5]>>3);d=w+(w>>3)*(e[5]&7)}if(d>2145386496)J(1);var y=new Z((t==1?p||d:t?0:d)+12);return y[0]=1,y[4]=4,y[8]=8,{b:u+l,y:0,l:0,d:f,w:t&&t!=1?t:y.subarray(12),e:d,o:new be(y.buffer,0,3),u:p,c:o,m:Math.min(131072,d)}}else if((n>>4|e[3]<<20)==25481893)return Et(e,4)+8;J(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,s=(e[t]&15)+5;if(s>n)J(3);var o=1<<s,i=o,a=-1,u=-1,c=-1,f=o,l=new vt(512+(o<<2)),p=new Ct(l,0,256),d=new de(l,0,256),w=new de(l,512,o),y=512+(o<<1),L=new Z(l,y,o),g=new Z(l,y+o);while(a<255&&i>0){var m=re(i+1),b=r>>3,h=(1<<m+1)-1,P=(e[b]|e[b+1]<<8|e[b+2]<<16)>>(r&7)&h,A=(1<<m)-1,E=h-i-1,T=P&A;if(T<E)r+=m,P=T;else if(r+=m+1,P>A)P-=E;if(p[++a]=--P,P==-1)i+=P,L[--f]=a;else i-=P;if(!P)do{var B=r>>3;u=(e[B]|e[B+1]<<8)>>(r&7)&3,r+=2,a+=u}while(u==3)}if(a>255||i)J(0);var v=0,F=(o>>1)+(o>>3)+3,Y=o-1;for(var _=0;_<=a;++_){var C=p[_];if(C<1){d[_]=-C;continue}for(c=0;c<C;++c){L[v]=_;do v=v+F&Y;while(v>=f)}}if(v)J(0);for(c=0;c<o;++c){var M=d[L[c]]++,k=g[c]=s-re(M);w[c]=(M<<k)-o}return[r+7>>3,{b:s,s:L,n:g,t:w}]},Pt=function(e,t){var n=0,r=-1,s=new Z(292),o=e[t],i=s.subarray(0,256),a=s.subarray(256,268),u=new de(s.buffer,268);if(o<128){var c=ue(e,t+1,6),f=c[0],l=c[1];t+=o;var p=f<<3,d=e[t];if(!d)J(0);var w=0,y=0,L=l.b,g=L,m=(++t<<3)-8+re(d);for(;;){if(m-=L,m<p)break;var b=m>>3;if(w+=(e[b]|e[b+1]<<8)>>(m&7)&(1<<L)-1,i[++r]=l.s[w],m-=g,m<p)break;b=m>>3,y+=(e[b]|e[b+1]<<8)>>(m&7)&(1<<g)-1,i[++r]=l.s[y],L=l.n[w],w=l.t[w],g=l.n[y],y=l.t[y]}if(++r>255)J(0)}else{r=o-127;for(;n<r;n+=2){var h=e[++t];i[n]=h>>4,i[n+1]=h&15}++t}var P=0;for(n=0;n<r;++n){var A=i[n];if(A>11)J(0);P+=A&&1<<A-1}var E=re(P)+1,T=1<<E,B=T-P;if(B&B-1)J(0);i[r++]=re(B)+1;for(n=0;n<r;++n){var A=i[n];++a[i[n]=A&&E+1-A]}var v=new Z(T<<1),F=v.subarray(0,T),Y=v.subarray(T);u[E]=0;for(n=E;n>0;--n){var _=u[n];ce(Y,n,_,u[n-1]=_+a[n]*(1<<E-n))}if(u[0]!=T)J(0);for(n=0;n<r;++n){var C=i[n];if(C){var M=u[C];ce(F,n,M,u[C]=M+(1<<E-C))}}return[t,{n:Y,b:E,s:F}]},kt=ue(new Z([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],It=ue(new Z([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],Bt=ue(new Z([32,132,16,66,102,70,68,68,68,68,36,73,2]),0,5)[1],We=function(e,t){var n=e.length,r=new be(n);for(var s=0;s<n;++s)r[s]=t,t+=1<<e[s];return r},Ee=new Z(new be([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),Ft=We(Ee,0),Se=new Z(new be([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),Rt=We(Se,3),le=function(e,t,n){var r=e.length,s=t.length,o=e[r-1],i=(1<<n.b)-1,a=-n.b;if(!o)J(0);var u=0,c=n.b,f=(r<<3)-8+re(o)-c,l=-1;for(;f>a&&l<s;){var p=f>>3,d=(e[p]|e[p+1]<<8|e[p+2]<<16)>>(f&7);u=(u<<c|d)&i,t[++l]=n.s[u],f-=c=n.n[u]}if(f!=a||l+1!=s)J(0)},Dt=function(e,t,n){var r=6,s=t.length,o=s+3>>2,i=o<<1,a=o+i;le(e.subarray(r,r+=e[0]|e[1]<<8),t.subarray(0,o),n),le(e.subarray(r,r+=e[2]|e[3]<<8),t.subarray(o,i),n),le(e.subarray(r,r+=e[4]|e[5]<<8),t.subarray(i,a),n),le(e.subarray(r),t.subarray(a),n)},Ut=function(e,t,n){var r,s=t.b,o=e[s],i=o>>1&3;t.l=o&1;var a=o>>3|e[s+1]<<5|e[s+2]<<13,u=(s+=3)+a;if(i==1){if(s>=e.length)return;if(t.b=s+1,n)return ce(n,e[s],t.y,t.y+=a),n;return ce(new Z(a),e[s])}if(u>e.length)return;if(i==0){if(t.b=u,n)return n.set(e.subarray(s,u),t.y),t.y+=a,n;return Le(e,s,u)}if(i==2){var c=e[s],f=c&3,l=c>>2&3,p=c>>4,d=0,w=0;if(f<2)if(l&1)p|=e[++s]<<4|(l&2&&e[++s]<<12);else p=c>>3;else if(w=l,l<2)p|=(e[++s]&63)<<4,d=e[s]>>6|e[++s]<<2;else if(l==2)p|=e[++s]<<4|(e[++s]&3)<<12,d=e[s]>>2|e[++s]<<6;else p|=e[++s]<<4|(e[++s]&63)<<12,d=e[s]>>6|e[++s]<<2|e[++s]<<10;++s;var y=n?n.subarray(t.y,t.y+t.m):new Z(t.m),L=y.length-p;if(f==0)y.set(e.subarray(s,s+=p),L);else if(f==1)ce(y,e[s++],L);else{var g=t.h;if(f==2){var m=Pt(e,s);d+=s-(s=m[0]),t.h=g=m[1]}else if(!g)J(0);(w?Dt:le)(e.subarray(s,s+=d),y.subarray(L),g)}var b=e[s++];if(b){if(b==255)b=(e[s++]|e[s++]<<8)+32512;else if(b>127)b=b-128<<8|e[s++];var h=e[s++];if(h&3)J(0);var P=[It,Bt,kt];for(var A=2;A>-1;--A){var E=h>>(A<<1)+2&3;if(E==1){var T=new Z([0,0,e[s++]]);P[A]={s:T.subarray(2,3),n:T.subarray(0,1),t:new de(T.buffer,0,1),b:0}}else if(E==2)r=ue(e,s,9-(A&1)),s=r[0],P[A]=r[1];else if(E==3){if(!t.t)J(0);P[A]=t.t[A]}}var B=t.t=P,v=B[0],F=B[1],Y=B[2],_=e[u-1];if(!_)J(0);var C=(u<<3)-8+re(_)-Y.b,M=C>>3,k=0,G=(e[M]|e[M+1]<<8)>>(C&7)&(1<<Y.b)-1;M=(C-=F.b)>>3;var I=(e[M]|e[M+1]<<8)>>(C&7)&(1<<F.b)-1;M=(C-=v.b)>>3;var N=(e[M]|e[M+1]<<8)>>(C&7)&(1<<v.b)-1;for(++b;--b;){var j=Y.s[G],X=Y.n[G],W=v.s[N],S=v.n[N],x=F.s[I],R=F.n[I];M=(C-=x)>>3;var D=1<<x,U=D+((e[M]|e[M+1]<<8|e[M+2]<<16|e[M+3]<<24)>>>(C&7)&D-1);M=(C-=Se[W])>>3;var H=Rt[W]+((e[M]|e[M+1]<<8|e[M+2]<<16)>>(C&7)&(1<<Se[W])-1);M=(C-=Ee[j])>>3;var z=Ft[j]+((e[M]|e[M+1]<<8|e[M+2]<<16)>>(C&7)&(1<<Ee[j])-1);if(M=(C-=X)>>3,G=Y.t[G]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<X)-1),M=(C-=S)>>3,N=v.t[N]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<S)-1),M=(C-=R)>>3,I=F.t[I]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<R)-1),U>3)t.o[2]=t.o[1],t.o[1]=t.o[0],t.o[0]=U-=3;else{var V=U-(z!=0);if(V){if(U=V==3?t.o[0]-1:t.o[V],V>1)t.o[2]=t.o[1];t.o[1]=t.o[0],t.o[0]=U}else U=t.o[0]}for(var A=0;A<z;++A)y[k+A]=y[L+A];k+=z,L+=z;var O=k-U;if(O<0){var K=-O,q=t.e+O;if(K>H)K=H;for(var A=0;A<K;++A)y[k+A]=t.w[q+A];k+=K,H-=K,O=0}for(var A=0;A<H;++A)y[k+A]=y[O+A];k+=H}if(k!=L)while(L<y.length)y[k++]=y[L++];else k=y.length;if(n)t.y+=k;else y=Le(y,0,k)}else if(n){if(t.y+=p,L)for(var A=0;A<p;++A)y[A]=y[L+A]}else if(L)y=Le(y,L);return t.b=u,y}J(2)},Ot=function(e,t){if(e.length==1)return e[0];var n=new Z(t);for(var r=0,s=0;r<e.length;++r){var o=e[r];n.set(o,s),s+=o.length}return n};function ye(e,t){var n=[],r=+!t,s=0,o=0;for(;e.length;){var i=St(e,r||t);if(typeof i=="object"){if(r){if(t=null,i.w.length==i.u)n.push(t=i.w),o+=i.u}else n.push(t),i.e=0;for(;!i.l;){var a=Ut(e,i,t);if(!a)J(5);if(t)i.e=i.y;else n.push(a),o+=a.length,Tt(i.w,0,a.length),i.w.set(a,i.w.length-a.length)}s=i.b+i.c*4}else s=i;e=e.subarray(s)}return Ot(n,o)}async function Nt(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),n=(r)=>r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);if(t[0]===40&&t[1]===181&&t[2]===47&&t[3]===253)return n(ye(t));if(t[0]===31&&t[1]===139)return new Response(new Blob([t]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();return n(t)}async function Xe(e){return new TextDecoder().decode(await Nt(e))}var Ze=(e)=>decodeURIComponent(e.split(/[?#]/)[0].split("/").pop()||"main.ldr").replace(/\\.(zst|gz)$/i,"")||"main.ldr";function xe(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:(o)=>o&&(o[2]==="f32"?new Float32Array(e,r+o[0],o[1]):o[2]==="u16"?new Uint16Array(e,r+o[0],o[1]):o[2]==="u8"?new Uint8Array(e,r+o[0],o[1]):new Uint32Array(e,r+o[0],o[1])),bytes:e.byteLength,buffer:e}}var Q=(e)=>e.trim().toLowerCase().replace(/\\\\/g,"/").replace(/\\/+/g,"/"),ke=/^[A-Za-z][A-Za-z0-9_]*$/,Pe=new Map;function Ie(e){let t=e.toLowerCase(),n=2166136261;for(let s=0;s<t.length;s++)n^=t.charCodeAt(s),n=Math.imul(n,16777619);let r=-1-(n>>>0&1073741823);if(!Pe.has(r))Pe.set(r,t);return r}function Be(e){let t=e.charCodeAt(0)|32;if(t>=97&&t<=122&&ke.test(e))return Ie(e);if(/^0x/i.test(e))return parseInt(e,16);return+e}var Ye=/^~?\\s*moved\\s+to\\s+(.+)$/i,zt=new Set(["FILE","NOFILE","!DATA","!:","STEP","BFC","ROTSTEP","BUFEXCHG","!TEXMAP"]),st=new Set(["part","subpart","primitive","8_primitive","48_primitive","shortcut","helper"]),$t=new Set(["model","submodel","configuration"]),jt=/^(?:!?LDRAW_ORG|Unofficial|Official\\s+LCAD)\\s+(\\S+)/i;function Je(e){let t=jt.exec(e);if(!t)return;let n=t[1].toLowerCase().replace(/^unofficial_/,"");return st.has(n)||$t.has(n)?n:void 0}function Vt(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 _t(e,t=!1){let n=/^\\s*(\\S+)\\s+(.*)$/.exec(e);if(!n)return null;let r=n[1].toUpperCase(),s=r==="PLANAR"?9:r==="CYLINDRICAL"?10:r==="SPHERICAL"?11:0;if(!s)return null;let o=n[2].trim().split(/\\s+/);if(o.length<s+1)return null;let i=o.slice(0,s).map(Number);if(!i.every(Number.isFinite))return null;let a=n[2].trim();for(let l=0;l<s;l++)a=a.replace(/^\\S+\\s*/,"");let u=Vt(a);if(!u.length)return null;let c={method:r,p1:i.slice(0,3),p2:i.slice(3,6),p3:i.slice(6,9),texture:u[0]};if(s>=10)c.a=i[9];if(s===11)c.b=i[10];let f=u.findIndex((l,p)=>p>0&&l.toUpperCase()==="GLOSSMAP");if(f>0&&u[f+1])c.glossmap=u[f+1];if(t)c.next=!0;return c}var Ht=(e)=>{let t=e.replace(/[^A-Za-z0-9+/]/g,""),n=t+"=".repeat((4-t.length%4)%4),r=atob(n),s=new Uint8Array(r.length);for(let o=0;o<r.length;o++)s[o]=r.charCodeAt(o);return s};function Gt(e){let t=e.length,n=1,r=(c)=>c===32||c===9,s=()=>{while(n<t&&r(e.charCodeAt(n)))n++;let c=n;while(n<t&&!r(e.charCodeAt(n)))n++;return c<n?e.slice(c,n):null},o=s();if(o===null)return null;let i=Array(12);for(let c=0;c<12;c++){let f=s();if(f===null)return null;i[c]=+f}while(n<t&&r(e.charCodeAt(n)))n++;if(n>=t)return null;let a=e.slice(n),u=/[ \\t]{2,}|\\t/.test(a)?a.split(/\\s+/).join(" "):a;return{t:1,color:Be(o),m:i,file:Q(u)}}function qe(e){let t=+e[0];if(!(t>=1&&t<=5)||e.length<2)return null;let n=Be(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 ot(e,t="main.ldr",n={}){let r=!!n.geometryText,s=new Map,o=null,i="",a,u=null,c=[],f=null,l=()=>{if(!u)return;let m=Ht(u.chunks.join("")),b=m[0]===137&&m[1]===80&&m[2]===78&&m[3]===71;(a??=new Map).set(Q(u.name),{name:u.name,bytes:m,...b?{mime:"image/png"}:{}}),u=null},p=!0,d=(m)=>{if(l(),o={name:Q(m),cmds:[]},s.set(o.name,o),!i)i=o.name;c=[],f=null,p=!0},w=!1,y=!1,L=()=>{if(y)return;y=!0,s.clear(),o=null,i=""},g=(m,b)=>{if(f){m.tex=f,f=null;return}let h=c[c.length-1];if(!h)return;if(h.fallback){if(!b)m.fallback=!0}else m.tex=h.map};for(let m of e.split(`\n`)){let b=m.trim();if(!b)continue;if(r&&b.charCodeAt(0)>=50&&b.charCodeAt(0)<=53&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)){if(u||w)continue;if(!o)d(t);let E=b.slice(2).trimStart(),T=E.search(/\\s/),B={t:b.charCodeAt(0)-48,color:Be(T<0?E:E.slice(0,T)),p:[],src:b};g(B,!1),o.cmds.push(B),p=!1;continue}if(b.charCodeAt(0)===48&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)){let E=2;while(b.charCodeAt(E)===32||b.charCodeAt(E)===9)E++;let T=E;while(T<b.length&&b.charCodeAt(T)!==32&&b.charCodeAt(T)!==9)T++;let B=b.slice(E,T);if(!zt.has(B)){if(w||u)continue;if(!o)d(t);let v=b.slice(E),F={t:0,text:v};if(B.charCodeAt(0)===33)F.meta=B;if(f=null,p&&!o.org){let _=Je(v);if(_)o.org=_}let Y=v.match(Ye);if(Y&&!o.movedTo){let _=Y[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(_))_+=".dat";o.movedTo=Q(_)}o.cmds.push(F);continue}}if(b.charCodeAt(0)===49&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)&&!u&&!w){let E=Gt(b);if(E){if(!o)d(t);g(E,!1),o.cmds.push(E),p=!1;continue}}let h=b.split(/\\s+/);if(+h[0]===0){let E=b.slice(1).trim();if(h[1]==="FILE"){L(),w=!1,d(E.slice(5));continue}if(h[1]==="NOFILE"){l(),o=null,w=!0;continue}if(h[1]==="!DATA"){L(),l(),o=null,w=!1,u={name:E.slice(5).trim(),chunks:[]};continue}if(w)continue;if(u){if(h[1]==="!:")u.chunks.push(h.slice(2).join(""));continue}if(!o)d(t);let T={t:0,text:E};if(h[1]==="STEP")T.step=!0,c=[],f=null;else if(h[1]==="BFC")T.bfc=h.slice(2).join(" ");else if(h[1]==="ROTSTEP")if(T.meta="ROTSTEP",T.step=!0,c=[],f=null,(h[2]??"").toUpperCase()==="END")T.rotstep={x:0,y:0,z:0,mode:"END"};else{let v=(h[5]??"REL").toUpperCase();T.rotstep={x:+h[2]||0,y:+h[3]||0,z:+h[4]||0,mode:["REL","ABS","ADD"].includes(v)?v:"REL"}}else if(h[1]==="BUFEXCHG"){T.meta="BUFEXCHG";let v=(h[2]??"").toUpperCase();T.bufexchg={op:v==="RETRIEVE"?"RETRIEVE":"STORE",buf:h[3]??"A"}}else if(h[1]?.startsWith("!"))T.meta=h[1];if(p&&!o.org){let v=Je(E);if(v)o.org=v}if(h[1]==="!TEXMAP"){let v=(h[2]??"").toUpperCase();if(f=null,v==="START"||v==="NEXT"){let F=_t(E.replace(/^!TEXMAP\\s+\\S+/i,""),v==="NEXT");if(T.texmap={op:v,...F?{map:F}:{}},F)if((o.texmaps??=[]).push(F),v==="START")c.push({map:F,fallback:!1});else f=F}else if(v==="FALLBACK"){T.texmap={op:v};let F=c[c.length-1];if(F)F.fallback=!0}else if(v==="END")T.texmap={op:v},c.pop()}else if(h[1]==="!:"){f=null;let v=qe(h.slice(2));if(v)g(v,!0),T.geom=v}else f=null;let B=E.match(Ye);if(B&&!o.movedTo){let v=B[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(v))v+=".dat";o.movedTo=Q(v)}o.cmds.push(T);continue}if(u||w)continue;if(!o)d(t);let A=qe(h);if(!A)continue;g(A,!1),o.cmds.push(A),p=!1}return l(),a?{main:i,files:s,data:a}:{main:i,files:s}}var yn=Math.PI/180;function it(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 at(e,t){let[n,r,s,o,i,a,u,c,f,l,p,d]=e,[w,y,L,g,m,b,h,P,A,E,T,B]=t;return[o*w+i*y+a*L+n,u*w+c*y+f*L+r,l*w+p*y+d*L+s,o*g+i*h+a*E,o*m+i*P+a*T,o*b+i*A+a*B,u*g+c*h+f*E,u*m+c*P+f*T,u*b+c*A+f*B,l*g+p*h+d*E,l*m+p*P+d*T,l*b+p*A+d*B]}var Fe=[0,0,0,1,0,0,0,1,0,0,0,1];var Qe=new WeakMap,Kt=/^(s|8|48)\\//;function Re(e,t){let n=e.files.get(Q(t));if(!n)return"part";let r=Qe.get(n);if(r)return r;if(n.org)r=st.has(n.org)?"part":"model";else if(n.name===e.main)r="model";else r=n.cmds.some((s)=>s.t>=2||s.t===0&&!!s.geom||s.t===1&&Kt.test(s.file))?"part":"model";return Qe.set(n,r),r}var et=new WeakMap;function lt(e){let t=et.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 et.set(e,t),t}var tt=(e)=>e>16777215?"0x"+e.toString(16).toUpperCase():e<0?Pe.get(e)??String(e):String(e),Wt=(e)=>e.t===0?"0 "+e.text:e.t===1?`1 ${tt(e.color)} ${e.m.join(" ")} ${e.file}`:e.src?e.src:`${e.t} ${tt(e.color)} ${e.p.join(" ")}`,De=(e,t)=>`${Q(e)}#${t}`;function Xt(e,t){let n=[],r=0,s=(o)=>!!o&&o.t===0&&o.texmap?.op==="NEXT";for(let o of e.cmds){if(o.t===0){if(o.step){r++;continue}if(o.bfc!==void 0){n.push(o);continue}if(r!==t)continue;if(o.texmap)n.push(o);else if(o.geom){if(o.geom.t>=2)n.push(o);else if(s(n[n.length-1]))n.pop()}continue}if(r!==t)continue;if(o.t===1){if(s(n[n.length-1]))n.pop();continue}n.push(o)}return{name:De(e.name,t),cmds:n}}function ct(e,t){return[`0 ldr: own geometry of ${e.name}, step ${t}`,...Xt(e,t).cmds.map(Wt)].join(`\n`)+`\n`}function Zt(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 ut(e){let[t,n,r,s,o,i,a,u,c,f,l,p]=e,d=u*p-c*l,w=-(a*p-c*f),y=a*l-u*f,L=s*d+o*w+i*y;if(!Number.isFinite(L)||Math.abs(L)<0.000000000001)return null;let g=1/L,m=[d*g,-(o*p-i*l)*g,(o*c-i*u)*g,w*g,(s*p-i*f)*g,-(s*c-i*a)*g,y*g,-(s*l-o*f)*g,(s*u-o*a)*g];return[-(m[0]*t+m[1]*n+m[2]*r),-(m[3]*t+m[4]*n+m[5]*r),-(m[6]*t+m[7]*n+m[8]*r),...m]}var Yt=(e)=>String(+e.toFixed(6)||0),nt=(e)=>\'"\'+e.replace(/\\\\/g,"\\\\\\\\").replace(/"/g,"\\\\\\"")+\'"\';function ft(e,t){let n=[...t.p1,...t.p2,...t.p3,...t.method!=="PLANAR"?[t.a??360]:[],...t.method==="SPHERICAL"?[t.b??180]:[]].map(Yt).join(" "),r=`0 ldr: ${e} with a model-level !TEXMAP\n0 BFC CERTIFY CCW\n0 !TEXMAP START ${t.method} ${n} ${nt(t.texture)}${t.glossmap?" GLOSSMAP "+nt(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-${Zt(r)}`,source:r}}var Jt=(e,t)=>{let n=[,,,,,,,,,];for(let r=0;r<3;r++)for(let s=0;s<3;s++)n[r*3+s]=e[r*3]*t[s]+e[r*3+1]*t[3+s]+e[r*3+2]*t[6+s];return n};function qt(e,t,n){let r=Math.PI/180,s=Math.sin(e*r),o=Math.cos(e*r),i=Math.sin(t*r),a=Math.cos(t*r),u=Math.sin(n*r),c=Math.cos(n*r);return[a*c,-a*u,i,o*u+s*i*c,o*c-s*i*u,-s*a,s*u-o*i*c,s*c+o*i*u,o*a]}var rt=new WeakMap;function pt(e){let t=rt.get(e);if(t)return t;let n=[],r=null;for(let s of e.cmds){if(s.t!==0||!s.step)continue;let o=s.rotstep;if(o)if(o.mode==="END")r=null;else{let i=qt(o.x,o.y,o.z);r=o.mode==="ABS"?{abs:!0,m:i,rotstep:o}:o.mode==="ADD"&&r?{abs:r.abs,m:Jt(r.m,i),rotstep:o}:{abs:!1,m:i,rotstep:o}}n.push(r)}return n.push(r),rt.set(e,n),n}var mt=999999,gt=(e)=>e.map((t)=>String(t).padStart(6,"0")).join(".")+"~";function Qt(e,t={}){let n=[],r=t.maxDepth??64,s=t.looseGeometry!==!1,o=!!t.textures,i=!!t.callouts,a=new Map,u=0,c=(l,p)=>{let d=l.name+"#"+p,w=a.get(d);if(!w){let y;w=Object.assign(()=>y??=ct(l,p),{file:l,step:p}),a.set(d,w)}return w},f=(l,p,d,w,y,L,g,m,b=null,h=[],P=[],A=void 0,E=null)=>{let T=l.files.get(p);if(!T||g>r)return;let B=E,v=0,F=g>0?++u:0,Y=i&&F?[...h,F]:h,_=i&&F?[...P,d]:P,C=i&&!b?new Map:null,M=-1,k=0,G=(S,x,R,D,U,H,z)=>{if(M!==v)M=v,k=0;let V=C?.get(v+"|"+x);if(V)return V.n++,f(S,S===l?x:S.main,R,D,y+"/"+x,[...U,mt],g+1,H,[...U,mt],Y,_,z,B);let O=[...U,k++],K=n.length;f(S,S===l?x:S.main,R,D,y+"/"+x,O,g+1,H,b,Y,_,z,B),C?.set(v+"|"+x,{n:1,from:K,to:n.length})},I=pt(T),N=s?lt(T):[],j=0,X=(S,x,R,D,U,H,z,V)=>{if(b)D=b;let O={part:S,color:x,m:R,step:D[0],steps:D,localStep:U,path:y};if(V)O.colour=V;if(F){if(O.sub=F,i)O.subPath=Y,O.subMats=_}if(H)O.embedded=!0;if(z){let q=ft(S,z);O.texPart=q.name,O.texSource=q.source}let K=I[U];if(K)O.view=K;return n.push(O),O},W=(S)=>{while(j<N.length&&N[j]<=S){let x=N[j++];X(De(T.name,x),w,d,[...L,x],x,!1,null,A).source=c(T,x)}};for(let S of T.cmds){if(S.t===0&&S.step){v++;continue}let x=S;if(x.t>=2||x.t===0&&x.geom&&x.geom.t>=2){W(v);continue}if(x.t===0){if(x.meta==="!COLOUR"){let q=tn(x.text);if(q&&q.code!==16&&q.code!==24)(B=new Map(B??[])).set(q.code,q);continue}if(o&&x.geom?.t===1)x=x.geom;else continue}if(x.t!==1)continue;if(o&&x.fallback)continue;let R=x.color===16?w:x.color,D=x.color===16?A:B?.get(x.color),U=at(d,x.m),H=[...L,v],z=o?x.tex??m:null,V=z?ut(x.m):null,O=z&&V?it(z,V):null;if(l.files.has(x.file)){if(Re(l,x.file)==="model"){G(l,x.file,U,R,H,O,D);continue}X(x.file,R,U,H,v,!0,O,D);continue}let K=t.resolveModel?.(x.file);if(K){G(K,x.file,U,R,H,O,D);continue}X(x.file,R,U,H,v,!1,O,D)}if(W(1/0),C){for(let S of C.values())if(S.n>1)for(let x=S.from;x<S.to;x++)n[x].mult??=S.n}};if(Re(e,e.main)==="part"){if(e.files.get(e.main))n.push({part:e.main,color:16,m:[...Fe],step:0,steps:[0],localStep:0,path:e.main,embedded:!0});return n}return f(e,e.main,Fe,16,e.main,[],0,null),n}function dt(e,t="main.ldr",n){return Qt(ot(e,t,{geometryText:!0}),n)}var en=new Set(["CHROME","PEARLESCENT","RUBBER","MATTE_METALLIC","METAL","MATERIAL"]);function Ue(e){if(!e)return null;if(e.startsWith("#")&&/^#[0-9A-Fa-f]{6}$/.test(e))return e.toUpperCase();if(/^0x[0-9A-Fa-f]{6}$/i.test(e))return("#"+e.slice(2)).toUpperCase();return null}function ht(e,t){let n={value:"#FFFFFF",fraction:0.5};while(t<e.length){let r=e[t].toUpperCase(),s=e[t+1];if(r==="VALUE"){let o=Ue(s);if(o)n.value=o;t+=2}else if(r==="ALPHA")n.alpha=+s,t+=2;else if(r==="LUMINANCE")n.luminance=+s,t+=2;else if(r==="FRACTION")n.fraction=+s,t+=2;else if(r==="VFRACTION")n.vfraction=+s,t+=2;else if(r==="SIZE")n.size=+s,t+=2;else if(r==="MINSIZE")n.minsize=+s,t+=2;else if(r==="MAXSIZE")n.maxsize=+s,t+=2;else break}return{grain:n,next:t}}function tn(e){let t=e.indexOf("!COLOUR");if(t<0)return null;let n=e.slice(t+7).trim().split(/\\s+/).filter(Boolean);if(n.length<2)return null;let r=n[0],s=NaN,o="#FF00FF",i="#333333",a=255,u=0,c={type:"default"},f=1;while(f<n.length){let l=n[f].toUpperCase(),p=n[f+1];if(l==="CODE")s=p!==void 0&&ke.test(p)?Ie(p):p!==void 0&&/^\\d+$/.test(p)?+p:NaN,f+=2;else if(l==="VALUE"){let d=Ue(p);if(d)o=d;f+=2}else if(l==="EDGE")i=Ue(p)??p,f+=2;else if(l==="ALPHA")a=+p,f+=2;else if(l==="LUMINANCE")u=+p,f+=2;else if(l==="CHROME")c={type:"chrome"},f+=1;else if(l==="PEARLESCENT")c={type:"pearlescent"},f+=1;else if(l==="RUBBER")c={type:"rubber"},f+=1;else if(l==="MATTE_METALLIC")c={type:"matte_metallic"},f+=1;else if(l==="METAL")c={type:"metal"},f+=1;else if(l==="MATERIAL"){let d=(n[f+1]||"").toUpperCase();if(d==="GLITTER"){let{grain:w,next:y}=ht(n,f+2);c={type:"glitter",material:w},f=y}else if(d==="SPECKLE"){let{grain:w,next:y}=ht(n,f+2);c={type:"speckle",material:w},f=y}else if(d==="FABRIC"){let w=(n[f+2]||"").toUpperCase(),y=["VELVET","CANVAS","STRING","FUR"].includes(w)?w.toLowerCase():void 0;c={type:"fabric",kind:y},f+=y?3:2}else f=n.length}else if(en.has(l))f+=1;else f+=1}if(Number.isNaN(s)||!o)return null;return{code:s,name:r,hex:o,edge:i,alpha:Number.isFinite(a)?a:255,luminance:Number.isFinite(u)?u:0,finish:c}}function nn(e){let t=Math.max(0,Math.min(1,(e.alpha??255)/255)),n=t<1,r=Math.max(0,Math.min(1,(e.luminance??0)/255)),s={opacity:t,transparent:n,depthWrite:!n,emissive:r,clearcoat:0,clearcoatRoughness:0,sheen:0,sheenRoughness:0};switch(e.finish?.type??"default"){case"chrome":return{...s,metalness:1,roughness:0,finish:"chrome"};case"pearlescent":return{...s,metalness:0.25,roughness:0.3,clearcoat:0.5,clearcoatRoughness:0.25,sheen:0.4,sheenRoughness:0.35,finish:"pearlescent"};case"rubber":return{...s,metalness:0,roughness:0.9,finish:"rubber"};case"matte_metallic":return{...s,metalness:0.4,roughness:0.8,finish:"matte_metallic"};case"metal":return{...s,metalness:0.85,roughness:0.2,finish:"metal"};case"glitter":{let i=e.finish.material,a=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.35,roughness:0.25,clearcoat:1,clearcoatRoughness:0.08,particleHex:i.value,particleFraction:i.fraction,particleSize:a,finish:"glitter"}}case"speckle":{let i=e.finish.material,a=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.2,roughness:0.55,particleHex:i.value,particleFraction:i.fraction,particleSize:a,finish:"speckle"}}case"fabric":return{...s,metalness:0,roughness:0.85,sheen:0.65,sheenRoughness:0.75,finish:"fabric"};default:return{...s,metalness:0,roughness:0.45,finish:"default"}}}function Oe(e){let t=nn(e),n=!t.transparent?"op":t.opacity>=0.75?"a200":t.opacity>=0.4?"a128":`a${Math.round(t.opacity*255)}`,r=t.emissive>0?`L${Math.round(t.emissive*16)}`:"",s=`${t.finish}:${n}${r}`;if(t.particleHex)s+=`:${t.particleHex}:${(t.particleFraction??0).toFixed(2)}`;return s}function rn(e,t){let n=new Map,r=null,s=!1;for(let o of e.split(/\\r?\\n/)){let i=/^\\s*0\\s+FILE\\s+(.+)$/i.exec(o);if(i){if(!s)n.clear();s=!0,r=[],n.set(Q(i[1]),r);continue}if(/^\\s*0\\s+(NOFILE|!DATA)(\\s|$)/i.test(o)){if(!s)n.clear();s=!0,r=null;continue}if(!r){if(s)continue;r=[],n.set(Q(t),r)}let a=o.trim().replace(/\\s+/g," ");if(a)r.push(a)}return n}var sn=(e)=>{if(!e.startsWith("1 "))return null;let t=e.split(" ");return t.length>=15?Q(t.slice(14).join(" ")):null};function on(e){let t=2166136261,n=1523705862;for(let r=0;r<e.length;r++){let s=e.charCodeAt(r);t=Math.imul(t^s,16777619),n=Math.imul(n^s,16777629)^n>>>15}return(t>>>0).toString(16).padStart(8,"0")+(n>>>0).toString(16).padStart(8,"0")}function bt(e,t,n="main.ldr"){let r=rn(e,n),s=new Map;for(let o of t){let i=Q(o);if(!r.has(i)||s.has(i))continue;let a=new Set([i]),u=[i];while(u.length)for(let f of r.get(u.pop())){let l=sn(f);if(l&&r.has(l)&&!a.has(l))a.add(l),u.push(l)}let c=[i,...[...a].filter((f)=>f!==i).sort()].map((f)=>"0 FILE "+(f===i?"":f)+`\n`+r.get(f).join(`\n`)).join(`\n`);s.set(i,`emb/${on(c)}.dat`)}return s}var yt=(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,xt=new WeakMap;function Ne(e,t){let n=xt.get(e);if(!n)xt.set(e,n=new Map);let r=n.get(t);if(r!==void 0)return r;let s=e.parts[t];if(!s)return n.set(t,null),null;let o=s.studs.length,i=new Float64Array(o*12),a=[],u=[];s.studs.forEach((p,d)=>{a.push(p[0]),u.push(p[1]);for(let w=0;w<12;w++)i[d*12+w]=p[2+w]});let c=null,f=0,l=0;if(s.mask){f=s.mask[0],l=s.mask[1];let p=s.mask[2];c=new Uint8Array(p.length);for(let d=0;d<p.length;d++)c[d]=p.charCodeAt(d)===49?1:0}return n.set(t,r={nStuds:o,studM:i,kind:a,color:u,mask:c,nx:f,nz:l}),r}var ie=1073741824;class ze{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),s=this.used,o=this.a,i=this.b,a=this.c;for(;;){if(!s[r])return-1;if(o[r]===e&&i[r]===t&&a[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 s=this.slot(e,t,n),o=this.used,i=this.a,a=this.b,u=this.c;for(;;){if(!o[s])return o[s]=1,i[s]=e,a[s]=t,u[s]=n,this.vals[s]=r,this.size++,-1;if(i[s]===e&&a[s]===t&&u[s]===n){let c=this.vals[s];return this.vals[s]=r,c}s=s+1&this.mask}}grow(){let{a:e,b:t,c:n,vals:r,used:s}=this,o=s.length*2;this.a=new Int32Array(o),this.b=new Int32Array(o),this.c=new Int32Array(o),this.vals=new Int32Array(o),this.used=new Uint8Array(o),this.mask=o-1,this.size=0;for(let i=0;i<s.length;i++)if(s[i])this.put(e[i],t[i],n[i],r[i])}}var we=(e,t,n)=>e>-ie&&e<ie&&t>-ie&&t<ie&&n>-ie&&n<ie,fe=2147483647;function an(e,t,n){let s=[],o=[],i=[],a=[],u=[],c=[],f=[],l=[],p=new ze(e.length*2),d=[],w=[];for(let C=0;C<e.length;C++){let M=e[C],k=M.m,G=t.parts[M.part];if(!G||!G.mask||!yt(k))continue;let I=G.bbox,N=1/0,j=-1/0,X=1/0,W=-1/0;for(let R=0;R<2;R++)for(let D=0;D<2;D++){let U=R?I[3]:I[0],H=D?I[5]:I[2],z=k[0]+k[3]*U+k[5]*H,V=k[2]+k[9]*U+k[11]*H;if(z<N)N=z;if(z>j)j=z;if(V<X)X=V;if(V>W)W=V}let S=u.length;s.push(N),o.push(j),i.push(X),a.push(W),u.push(C),c.push(Ne(t,M.part)),f.push(I[0]),l.push(I[2]);let x=Math.round((k[1]+I[4])*2);for(let R=Math.floor(N/40);R<=Math.floor(j/40);R++)for(let D=Math.floor(X/40);D<=Math.floor(W/40);D++){if(!we(x,R,D))continue;let U=w.length;w.push(S),d.push(p.put(x,R,D,U))}}let y=[0,5,-5,5,-5],L=[0,5,5,-5,-5],g=NaN,m=NaN,b=NaN,h=-1,P=(C,M,k,G)=>{let I=Math.round(M*2),N=Math.floor(C/40),j=Math.floor(k/40);if(!we(I,N,j))return fe;let X=fe;if(I!==g||N!==m||j!==b)g=I,m=N,b=j,h=p.get(I,N,j);for(let W=h;W>=0;W=d[W]){let S=w[W];if(u[S]===G||!(C-6>=s[S]-0.5&&C+6<=o[S]+0.5&&k-6>=i[S]-0.5&&k+6<=a[S]+0.5))continue;let x=e[u[S]].m,R=c[S],D=f[S],U=l[S],H=C-x[0],z=M-x[1],V=k-x[2],O=x[3]*H+x[6]*z+x[9]*V,K=x[5]*H+x[8]*z+x[11]*V,{nx:q,nz:se,mask:ae}=R,oe=!0;for(let ee=0;ee<5;ee++){let te=Math.floor((O+y[ee]-D)/20),ne=Math.floor((K+L[ee]-U)/20);if(te<0||ne<0||te>=q||ne>=se||ae[te*se+ne]!==1){oe=!1;break}}if(oe){if(!n)return 0;let ee=n[u[S]];if(ee<X)X=ee}}return X},A=0;for(let C of e){let M=Ne(t,C.part);if(M)A+=M.nStuds}let E=new Uint8Array(A),T=new Uint8Array(A),B=new ze(A),v=0,F=n?new Int32Array(A).fill(fe):void 0;for(let C=0,M=0;C<e.length;C++){let k=e[C],G=Ne(t,k.part);if(!G)continue;let I=k.m,N=G.studM,j=I[0],X=I[1],W=I[2],S=I[3],x=I[4],R=I[5],D=I[6],U=I[7],H=I[8],z=I[9],V=I[10],O=I[11];for(let K=0;K<G.nStuds;K++,M++){let q=K*12,se=N[q+4],ae=N[q+7],oe=N[q+10];if(!(Math.abs(D*se+U*ae+H*oe-1)<0.001&&Math.abs(S*se+x*ae+R*oe)<0.001&&Math.abs(z*se+V*ae+O*oe)<0.001))continue;T[M]=1;let ee=N[q],te=N[q+1],ne=N[q+2],$e=j+S*ee+x*te+R*ne,je=X+D*ee+U*te+H*ne,Ve=W+z*ee+V*te+O*ne,_e=P($e,je,Ve,C);if(_e!==fe){if(E[M]=1,v++,F)F[M]=_e}let me=Math.round($e),he=Math.round(je),ge=Math.round(Ve);if(!we(me,he,ge))continue;if(!n){B.put(me,he,ge,1);continue}let He=n[C],Ge=B.get(me,he,ge);if(Ge<0||He<Ge)B.put(me,he,ge,He)}}let Y=new Uint8Array(e.length),_=n?new Int32Array(e.length).fill(fe):void 0;for(let C=0;C<e.length;C++){let M=e[C],k=t.parts[M.part];if(!k||!k.under||!yt(M.m))continue;let G=k.bbox,I=Math.round((G[3]-G[0])/20),N=Math.round((G[5]-G[2])/20);if(!I||!N||I*N>4096)continue;let j=M.m,X=!0,W=0;for(let S=0;S<I&&X;S++)for(let x=0;x<N;x++){let R=G[0]+10+20*S,D=G[2]+10+20*x,U=j[0]+j[3]*R+j[5]*D,H=j[2]+j[9]*R+j[11]*D,z=Math.round(U),V=Math.round(j[1]+G[4]),O=Math.round(H),K=we(z,V,O)?B.get(z,V,O):-1;if(K<0){X=!1;break}if(K>W)W=K}if(X){if(Y[C]=1,_)_[C]=W}}return{nStuds:A,studHidden:E,studUp:T,underHidden:Y,studsHidden:v,studHideStep:F,underHideStep:_}}function ln(e,t,n){let r=(l)=>n&&l.texPart&&t.parts[l.texPart]?l.texPart:l.part,s=new Map,o=new Map,i=(l)=>{let p=l.colour;if(!p)return String(l.color);let d=o.get(p);if(d!==void 0)return d;let w=t.colorTable?.[l.color],y=w?.hex??t.colors?.[l.color],L=w?Oe({alpha:w.alpha??255,luminance:w.luminance??0,finish:w.finish??{type:"default"}}):"default:op",g=Oe(p);if(d=y&&y.toUpperCase()===p.hex.toUpperCase()&&L===g?String(l.color):p.hex.toUpperCase()+"/"+g,d!==String(l.color))s.set(d,p);return o.set(p,d),d},a=e.map((l)=>({part:r(l),color:i(l),m:l.m,steps:l.steps})),u=a.map((l)=>gt(l.steps)),c=[...new Set(u)].sort(),f=new Map(c.map((l,p)=>[l,p]));return{all:a,stepOf:u.map((l)=>f.get(l)),nSteps:c.length,localColours:s}}function Ae(e,t,n=!0){let r=ln(e,t,n);return an(r.all,t,r.nSteps>1?r.stepOf:void 0)}var Te="https://ldr-demo.vercel.app/cdn/v1/",ve=new Map,Me=new Map;function At(e=Te,t=fetch){let n=ve.get(e);if(!n)n=t(e+"parts.json").then((r)=>{if(!r.ok)throw Error(`ldr: parts CDN index ${r.status} (${e}parts.json)`);return r.json()}),n.catch(()=>ve.delete(e)),ve.set(e,n);return n}var cn=(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"),Ce=(e,t)=>cn(e)?[e[0]+t,e[1],e[2]]:Array.isArray(e)?e.map((n)=>Ce(n,t)):e&&typeof e==="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,Ce(r,t)])):e;function un(e,t={}){let n=[],r=0,s={},o={};for(let p of e){let d=p.buffer;if(!d)throw Error("ldr: mergePacks needs packs from decodePack/loadPack");let w=new DataView(d).getUint32(0,!0),y=new Uint8Array(d,4+w),L=r;n.push(y),r+=y.byteLength;let g=(4-r%4)%4;if(g)n.push(new Uint8Array(g)),r+=g;for(let[m,b]of Object.entries(p.header.parts??{}))if(!(m in s))s[m]=Ce(b,L);for(let[m,b]of Object.entries(p.header.studKinds??{}))if(!(m in o))o[m]=Ce(b,L)}let i=e[0]?.header??{version:1,weld:!0},a=new TextEncoder().encode(JSON.stringify({...i,parts:s,studKinds:o,...t})),u=(4-(4+a.length)%4)%4,c=4+a.length+u,f=new Uint8Array(c+r);new DataView(f.buffer).setUint32(0,a.length+u,!0),f.set(a,4),f.fill(32,4+a.length,c);let l=c;for(let p of n)f.set(p,l),l+=p.byteLength;return xe(f.buffer)}async function fn(e,t={}){e=[...e];try{return await wt(e,t)}catch(n){let r=t.cdn??Te,s=t.fetch??fetch;ve.delete(r);let o=(i,a)=>s(i,{...a,cache:"reload"});try{return await wt(e,{...t,fetch:o})}catch{throw n}}}async function wt(e,t){let n=t.cdn??Te,r=t.fetch??fetch,s=t.gap??16384,o=await At(n,r),i=[...new Set([...e].map(Q))],a=[],u=[];for(let g of i){if(Me.has(n+g))continue;let m=o.parts[g];if(m)u.push({name:g,off:m[0],len:m[1],file:m[2]??0});else a.push(g)}u.sort((g,m)=>g.file-m.file||g.off-m.off);let c=[];for(let g of u){let m=c[c.length-1];if(m&&m.file===g.file&&g.off-m.end<=s)m.end=Math.max(m.end,g.off+g.len),m.items.push(g);else c.push({file:g.file,start:g.off,end:g.off+g.len,items:[g]})}let f=0,l=0,p=0,d=new Map,w=async()=>{while(p<c.length){let g=c[p++],m=d.get(g.file);if(m)m=m.subarray(g.start,g.end);else{let b=await r(new URL(o.archives[g.file],n).href,{headers:{Range:`bytes=${g.start}-${g.end-1}`,"Accept-Encoding":"identity"}});if(!b.ok)throw Error(`ldr: parts CDN ${b.status}`);if(l++,m=new Uint8Array(await b.arrayBuffer()),f+=m.byteLength,b.status===200)d.set(g.file,m),m=m.subarray(g.start,g.end)}for(let b of g.items){let h=ye(m.subarray(b.off-g.start,b.off-g.start+b.len)),P=h.buffer.slice(h.byteOffset,h.byteOffset+h.byteLength);Me.set(n+b.name,xe(P))}}};await Promise.all(Array.from({length:Math.min(t.concurrency??24,c.length)},w));let y=i.filter((g)=>Me.has(n+g)).map((g)=>Me.get(n+g));return{pack:y.length?un(y,{colors:o.colors}):xe(pn(o.colors)),missing:a,requests:l,bytes:f}}function pn(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}function mn(e,t){let n=t.header.parts;if(!n)return 0;let r=0;for(let s of e){let o=n[s.part]?.body?.tris;if(o)r+=o}return r}function hn(e,t,n){let r=0,s=0,o=!1,i=new Set;for(let a of e){let u=a.embedded?t.get(a.part):Q(a.part),c=u?n.parts[u]:void 0;if(!c)continue;if(c[3]!=null)o=!0,r+=c[3];if(!i.has(u))i.add(u),s+=c[1]}return{bodyTris:r,packBytes:s,known:o}}class pe extends Error{code="ldr-budget";bodyTris;packBytes;maxBodyTris;maxPackBytes;constructor(e){let t=[e.maxBodyTris!=null&&e.bodyTris>e.maxBodyTris?`${e.bodyTris} triangles (limit ${e.maxBodyTris})`:"",e.maxPackBytes!=null&&e.packBytes>e.maxPackBytes?`${(e.packBytes/1e6).toFixed(1)} MB parts pack (limit ${(e.maxPackBytes/1e6).toFixed(0)} MB)`:""].filter(Boolean).join(", ");super(`ldr: model exceeds device budget: ${t}`);this.name="BudgetError",this.bodyTris=e.bodyTris,this.packBytes=e.packBytes,this.maxBodyTris=e.maxBodyTris,this.maxPackBytes=e.maxPackBytes}}async function Mt(e,t={}){let n=performance.now(),r=t.fetch??fetch,s=At(t.cdn??Te,r);s.catch(()=>{});let o=t.text?e:await r(e).then(async(h)=>{if(!h.ok)throw Error(`ldr: ${h.status} fetching ${e}`);return Xe(await h.arrayBuffer())}),i=performance.now(),a=t.name??(t.text?"main.ldr":Ze(e)),u=dt(o,a,{looseGeometry:!1,callouts:t.callouts}),c=performance.now();t.onParsed?.(u),await s;let f=bt(o,new Set(u.filter((h)=>h.embedded).map((h)=>h.part)),a),l=(h,P)=>t.maxBodyTris!=null&&h>t.maxBodyTris||t.maxPackBytes!=null&&P>t.maxPackBytes;if(t.maxBodyTris!=null||t.maxPackBytes!=null){let h=hn(u,f,await s);if(l(h.known?h.bodyTris:0,h.packBytes))throw new pe({bodyTris:h.bodyTris,packBytes:h.packBytes,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let{pack:p,missing:d,requests:w,bytes:y}=await fn([...u.filter((h)=>!h.embedded).map((h)=>h.part),...f.values()],t),L=new Map([...f].map(([h,P])=>[P,h])),g=d.map((h)=>L.get(h)??h);for(let[h,P]of f){let A=p.header.parts[P];if(A)p.header.parts[h]=A}let m=performance.now();if(t.maxBodyTris!=null||t.maxPackBytes!=null){let h=p.buffer?.byteLength??p.bytes??0,P=mn(u,p);if(l(P,h))throw new pe({bodyTris:P,packBytes:h,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let b=t.cull?Ae(u,p.header,t.textures!==!1):void 0;return{insts:u,pack:p,missing:g,requests:w,bytes:y,cull:b,timings:{fetchModel:i-n,parse:c-i,parts:m-c,...b?{cull:performance.now()-m}:{}}}}self.onmessage=async(e)=>{let{id:t,source:n,opts:r}=e.data;try{let s=await Mt(n,{...r,cull:!1,onParsed:(f)=>self.postMessage({id:t,insts:f})}),o=s.pack.buffer;if(self.postMessage({id:t,buffer:o,missing:s.missing,requests:s.requests,bytes:s.bytes,timings:s.timings},[o]),!r.cull)return;let i=performance.now(),a=Ae(s.insts,s.pack.header,r.textures!==!1),u=performance.now()-i,c=[];for(let f of[a.studHidden,a.studUp,a.underHidden,a.studHideStep,a.underHideStep])if(f)c.push(f.buffer);self.postMessage({id:t,cull:a,ms:u},c)}catch(s){if(s instanceof pe||s?.code==="ldr-budget")self.postMessage({id:t,phase:"error",error:String(s?.message??s),budget:{bodyTris:s.bodyTris,packBytes:s.packBytes,maxBodyTris:s.maxBodyTris,maxPackBytes:s.maxPackBytes}});else self.postMessage({id:t,phase:"error",error:String(s?.message??s)})}};\n';
|
|
4211
4328
|
|
|
4212
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4329
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/cdn.ts
|
|
4213
4330
|
var worker;
|
|
4214
4331
|
var seq = 0;
|
|
4215
4332
|
var pending = new Map;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Opts as CompileOpts } from "./compile.js";
|
|
1
2
|
export interface BuildPackOptions {
|
|
2
3
|
/** Root of an LDraw library (folder containing LDConfig.ldr, parts/, p/). Get it from https://library.ldraw.org (complete.zip). */
|
|
3
4
|
ldrawRoot: string;
|
|
@@ -10,9 +11,11 @@ export interface BuildPackOptions {
|
|
|
10
11
|
parts?: string[];
|
|
11
12
|
/** Include every part in parts/ (large: the full library is ~20k parts). */
|
|
12
13
|
allParts?: boolean;
|
|
13
|
-
/** Stud geometry: 'low' uses p/8 low-res
|
|
14
|
+
/** Stud geometry: 'low' uses p/8 low-res studs (default, ~visually lossless at distance) wherever the stud sits on a surface; a stud
|
|
15
|
+
* whose foot is a round part's ring edge keeps its full primitive (an 8-sided stud would leave gaps). 'full' keeps full detail everywhere. */
|
|
14
16
|
studs?: "low" | "full";
|
|
15
|
-
/** Non-stud primitive detail: '
|
|
17
|
+
/** Non-stud primitive detail: 'full' (default) keeps the part's own hi-res / 48 primitives. 'low' substitutes p/8 primitives (~18% fewer
|
|
18
|
+
* body tris) but is lossy: next to geometry that stays 16/48-segment it opens see-through gaps in most round parts (Round 50). */
|
|
16
19
|
primitives?: "low" | "full";
|
|
17
20
|
/** Weld + index vertices (smaller GPU buffers, faster). Default true. */
|
|
18
21
|
weld?: boolean;
|
|
@@ -43,4 +46,6 @@ export interface BuildPackResult {
|
|
|
43
46
|
/** e.g. two models embedding different files under the same name (the first one is used). */
|
|
44
47
|
warnings?: string[];
|
|
45
48
|
}
|
|
49
|
+
/** The part compiler options `buildPack` uses for `o` (its defaults: studs low, primitives full, welded, separated studs). */
|
|
50
|
+
export declare function packCompilerOpts(o: Pick<BuildPackOptions, "studs" | "primitives" | "weld" | "cond" | "textures">): CompileOpts;
|
|
46
51
|
export declare function buildPack(o: BuildPackOptions): BuildPackResult;
|
package/dist/node/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from "../index.js";
|
|
2
2
|
export { Library } from "./library.js";
|
|
3
|
-
export { buildPack } from "./build-pack.js";
|
|
3
|
+
export { buildPack, packCompilerOpts } from "./build-pack.js";
|
|
4
4
|
export type { BuildPackOptions, BuildPackResult } from "./build-pack.js";
|
|
5
5
|
export { Compiler, encodePack, writePack, loadColors } from "./compile.js";
|
|
6
6
|
export type { Compiled, Opts as CompileOptions, Bucket } from "./compile.js";
|
package/dist/node/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/spec.ts
|
|
2
2
|
var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
3
3
|
var COLOUR_ID_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
|
|
4
4
|
var namedCodes = new Map;
|
|
@@ -708,7 +708,7 @@ function fileStepViews(f) {
|
|
|
708
708
|
viewMemo.set(f, out);
|
|
709
709
|
return out;
|
|
710
710
|
}
|
|
711
|
-
// ../../../../../../../tmp/ldr-build-
|
|
711
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/model.ts
|
|
712
712
|
var CALLOUT_END = 999999;
|
|
713
713
|
var stepKey = (steps) => steps.map((x) => String(x).padStart(6, "0")).join(".") + "~";
|
|
714
714
|
function flatten(doc, opts = {}) {
|
|
@@ -1090,7 +1090,7 @@ function blendedColourHex(code) {
|
|
|
1090
1090
|
const a = LDRAW_EXE_16[code - 256 >> 4], b = LDRAW_EXE_16[code - 256 & 15];
|
|
1091
1091
|
return "#" + [0, 1, 2].map((k) => (a[k] + b[k] >> 1).toString(16).padStart(2, "0")).join("").toUpperCase();
|
|
1092
1092
|
}
|
|
1093
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1093
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/instructions.ts
|
|
1094
1094
|
var MIN_VIS = 0.5;
|
|
1095
1095
|
var REORIENT = 0.35;
|
|
1096
1096
|
var deg = Math.PI / 180;
|
|
@@ -1458,10 +1458,10 @@ function planStepViews(insts, parts, stepOf, nSteps, o = {}) {
|
|
|
1458
1458
|
}
|
|
1459
1459
|
};
|
|
1460
1460
|
}
|
|
1461
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1461
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/render.ts
|
|
1462
1462
|
import * as THREE from "three";
|
|
1463
1463
|
|
|
1464
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1464
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/pack-io.ts
|
|
1465
1465
|
import { decompress } from "fzstd";
|
|
1466
1466
|
async function decompressPack(data) {
|
|
1467
1467
|
const u = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
@@ -1484,7 +1484,7 @@ function decodePack(buf) {
|
|
|
1484
1484
|
return { header, arr, bytes: buf.byteLength, buffer: buf };
|
|
1485
1485
|
}
|
|
1486
1486
|
|
|
1487
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1487
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/cull.ts
|
|
1488
1488
|
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;
|
|
1489
1489
|
var prepCache = new WeakMap;
|
|
1490
1490
|
function prepPart(H, part) {
|
|
@@ -1819,7 +1819,7 @@ function precomputeCull(instances, H, useTex = true) {
|
|
|
1819
1819
|
return cullCore(s.all, H, s.nSteps > 1 ? s.stepOf : undefined);
|
|
1820
1820
|
}
|
|
1821
1821
|
|
|
1822
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1822
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/render.ts
|
|
1823
1823
|
async function loadPack(url) {
|
|
1824
1824
|
const res = await fetch(url);
|
|
1825
1825
|
if (!res.ok)
|
|
@@ -3673,8 +3673,27 @@ async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
|
|
|
3673
3673
|
await new Promise((r) => setTimeout(r, 0));
|
|
3674
3674
|
}
|
|
3675
3675
|
}
|
|
3676
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3676
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/scene.ts
|
|
3677
3677
|
import * as THREE2 from "three";
|
|
3678
|
+
function ghostMaterial(side, g) {
|
|
3679
|
+
const m = new THREE2.MeshStandardMaterial({ color: 16777215, roughness: 0.85, metalness: 0, side, transparent: false, depthWrite: true, opacity: g.opacity });
|
|
3680
|
+
m.blending = THREE2.CustomBlending;
|
|
3681
|
+
m.blendSrc = THREE2.SrcAlphaFactor;
|
|
3682
|
+
m.blendDst = THREE2.OneMinusSrcAlphaFactor;
|
|
3683
|
+
m.blendSrcAlpha = THREE2.OneFactor;
|
|
3684
|
+
m.blendDstAlpha = THREE2.OneMinusSrcAlphaFactor;
|
|
3685
|
+
const tint = new THREE2.Color(g.color);
|
|
3686
|
+
const u = { ldrGhostTint: { value: tint }, ldrGhostMix: { value: g.whiten } };
|
|
3687
|
+
m.onBeforeCompile = (sh) => {
|
|
3688
|
+
Object.assign(sh.uniforms, u);
|
|
3689
|
+
sh.fragmentShader = `uniform vec3 ldrGhostTint; uniform float ldrGhostMix;
|
|
3690
|
+
` + sh.fragmentShader.replace("#include <color_fragment>", `#include <color_fragment>
|
|
3691
|
+
diffuseColor.rgb = mix(diffuseColor.rgb, ldrGhostTint, ldrGhostMix);`);
|
|
3692
|
+
};
|
|
3693
|
+
m.customProgramCacheKey = () => "ldrGhost";
|
|
3694
|
+
m.userData.ldrGhost = u;
|
|
3695
|
+
return m;
|
|
3696
|
+
}
|
|
3678
3697
|
function colorFn(src, pack, fallback) {
|
|
3679
3698
|
const table = new Map;
|
|
3680
3699
|
const put = (k, v) => table.set(String(k), new THREE2.Color(typeof v === "string" ? v : v.hex));
|
|
@@ -3788,6 +3807,75 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3788
3807
|
}
|
|
3789
3808
|
cur = null;
|
|
3790
3809
|
};
|
|
3810
|
+
let ghostOn = false, ghost = null, ghostBuild = null, ghostGen = 0;
|
|
3811
|
+
let shownStep = null, shownMask = null;
|
|
3812
|
+
const ghostOpts = { opacity: 0.2, color: 16777215, whiten: 0.75 };
|
|
3813
|
+
const ghostMats = new Map;
|
|
3814
|
+
const syncGhost = () => {
|
|
3815
|
+
if (!ghost)
|
|
3816
|
+
return;
|
|
3817
|
+
const show = ghostOn && shownStep != null && shownStep < uniq.length - 1;
|
|
3818
|
+
ghost.root.visible = show;
|
|
3819
|
+
if (show)
|
|
3820
|
+
ghost.setStep(uniq.length - 2 - shownStep, shownMask);
|
|
3821
|
+
};
|
|
3822
|
+
const disposeGhost = () => {
|
|
3823
|
+
ghostGen++;
|
|
3824
|
+
ghostBuild = null;
|
|
3825
|
+
if (!ghost)
|
|
3826
|
+
return;
|
|
3827
|
+
object.remove(ghost.root);
|
|
3828
|
+
ghost.root.traverse((x) => {
|
|
3829
|
+
if (x.isInstancedMesh)
|
|
3830
|
+
x.dispose();
|
|
3831
|
+
else if (x.isBatchedMesh)
|
|
3832
|
+
x.dispose();
|
|
3833
|
+
});
|
|
3834
|
+
for (const m of ghostMats.values())
|
|
3835
|
+
m.dispose();
|
|
3836
|
+
ghostMats.clear();
|
|
3837
|
+
ghost = null;
|
|
3838
|
+
};
|
|
3839
|
+
const buildGhost = () => ghostBuild ??= (async () => {
|
|
3840
|
+
const my = ghostGen;
|
|
3841
|
+
const n = uniq.length;
|
|
3842
|
+
const rev = new Int32Array(stepOf.length);
|
|
3843
|
+
for (let k = 0;k < rev.length; k++)
|
|
3844
|
+
rev[k] = n - 1 - stepOf[k];
|
|
3845
|
+
const so = { ...sceneOpts(), edges: false, cond: false, tex: false, steps: rev, cull: undefined };
|
|
3846
|
+
so.cull = cullCore(all, pack.header, rev);
|
|
3847
|
+
const g = await buildLdrSceneAsync(all, pack, so, color, () => {}, { postPaintSliceMs: 12 });
|
|
3848
|
+
if (my !== ghostGen) {
|
|
3849
|
+
g.root.traverse((x) => {
|
|
3850
|
+
if (x.isInstancedMesh || x.isBatchedMesh)
|
|
3851
|
+
x.dispose();
|
|
3852
|
+
});
|
|
3853
|
+
return;
|
|
3854
|
+
}
|
|
3855
|
+
const old = new Set;
|
|
3856
|
+
g.root.traverse((x) => {
|
|
3857
|
+
if (!x.isMesh)
|
|
3858
|
+
return;
|
|
3859
|
+
if (x.material)
|
|
3860
|
+
old.add(x.material);
|
|
3861
|
+
let m = ghostMats.get(x.material?.side ?? THREE2.FrontSide);
|
|
3862
|
+
if (!m)
|
|
3863
|
+
ghostMats.set(x.material?.side ?? THREE2.FrontSide, m = ghostMaterial(x.material?.side ?? THREE2.FrontSide, ghostOpts));
|
|
3864
|
+
x.material = m;
|
|
3865
|
+
x.castShadow = x.receiveShadow = false;
|
|
3866
|
+
x.renderOrder = 1;
|
|
3867
|
+
x.userData.ldrGhost = true;
|
|
3868
|
+
});
|
|
3869
|
+
for (const m of old)
|
|
3870
|
+
m.dispose();
|
|
3871
|
+
g.root.name = "ldr-ghost";
|
|
3872
|
+
if (!lodOn)
|
|
3873
|
+
g.setLod(false);
|
|
3874
|
+
g.setCull(cs, cu);
|
|
3875
|
+
ghost = g;
|
|
3876
|
+
object.add(g.root);
|
|
3877
|
+
syncGhost();
|
|
3878
|
+
})();
|
|
3791
3879
|
const multiStep = uniq.length > 1;
|
|
3792
3880
|
const drawnAt = (step, mask) => all.filter((i, k) => (step == null || stepOf[k] <= step) && (!mask || mask[k]) && pack.header.parts[i.part]).length;
|
|
3793
3881
|
const sceneOpts = () => ({ localColours: localColours.size ? localColours : undefined, cullStuds: cs, cullUnder: cu, edges: o.edges, side, cond: o.conditionalLines, 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 });
|
|
@@ -3820,7 +3908,12 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3820
3908
|
if (!multiStep)
|
|
3821
3909
|
return;
|
|
3822
3910
|
const t0 = performance.now();
|
|
3911
|
+
shownStep = step;
|
|
3912
|
+
shownMask = mask;
|
|
3823
3913
|
Object.assign(stats, cur.setStep(step, mask), { drawn: drawnAt(step, mask), buildMs: performance.now() - t0 });
|
|
3914
|
+
if (ghostOn && step != null && !ghost)
|
|
3915
|
+
buildGhost();
|
|
3916
|
+
syncGhost();
|
|
3824
3917
|
};
|
|
3825
3918
|
const api = { texturesReady: Promise.resolve() };
|
|
3826
3919
|
const finish = () => {
|
|
@@ -3849,10 +3942,31 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3849
3942
|
applyBuilt(buildLdrScene(all, pack, sceneOpts(), color, () => {}), t0);
|
|
3850
3943
|
} else
|
|
3851
3944
|
cur.setCull(a, b);
|
|
3945
|
+
ghost?.setCull(a, b);
|
|
3852
3946
|
},
|
|
3853
3947
|
setLod: (v) => {
|
|
3854
3948
|
lodOn = v;
|
|
3855
3949
|
cur.setLod(v);
|
|
3950
|
+
ghost?.setLod(v);
|
|
3951
|
+
},
|
|
3952
|
+
setGhost: (on, go = {}) => {
|
|
3953
|
+
ghostOn = on && multiStep;
|
|
3954
|
+
Object.assign(ghostOpts, Object.fromEntries(Object.entries(go).filter(([, v]) => v !== undefined)));
|
|
3955
|
+
for (const m of ghostMats.values()) {
|
|
3956
|
+
m.opacity = ghostOpts.opacity;
|
|
3957
|
+
const u = m.userData.ldrGhost;
|
|
3958
|
+
u.ldrGhostTint.value.set(ghostOpts.color);
|
|
3959
|
+
u.ldrGhostMix.value = ghostOpts.whiten;
|
|
3960
|
+
}
|
|
3961
|
+
if (!ghostOn) {
|
|
3962
|
+
syncGhost();
|
|
3963
|
+
return ghostBuild ?? Promise.resolve();
|
|
3964
|
+
}
|
|
3965
|
+
if (shownStep == null && !ghost)
|
|
3966
|
+
return Promise.resolve();
|
|
3967
|
+
const b = buildGhost();
|
|
3968
|
+
syncGhost();
|
|
3969
|
+
return b;
|
|
3856
3970
|
},
|
|
3857
3971
|
setSide: (s) => {
|
|
3858
3972
|
side = s;
|
|
@@ -3866,7 +3980,7 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3866
3980
|
object.updateMatrixWorld(true);
|
|
3867
3981
|
target.makeEmpty();
|
|
3868
3982
|
object.traverse((x) => {
|
|
3869
|
-
if (x.isInstancedMesh && x.count && !x.userData.ldrLod) {
|
|
3983
|
+
if (x.isInstancedMesh && x.count && !x.userData.ldrLod && !x.userData.ldrGhost) {
|
|
3870
3984
|
x.computeBoundingBox();
|
|
3871
3985
|
const b = x.boundingBox.clone().applyMatrix4(x.matrixWorld);
|
|
3872
3986
|
target.union(b);
|
|
@@ -3874,7 +3988,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3874
3988
|
});
|
|
3875
3989
|
return target;
|
|
3876
3990
|
},
|
|
3877
|
-
dispose:
|
|
3991
|
+
dispose: () => {
|
|
3992
|
+
disposeGhost();
|
|
3993
|
+
disposeCur();
|
|
3994
|
+
}
|
|
3878
3995
|
});
|
|
3879
3996
|
};
|
|
3880
3997
|
if (!progressive) {
|
|
@@ -3900,10 +4017,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3900
4017
|
return finish();
|
|
3901
4018
|
})();
|
|
3902
4019
|
}
|
|
3903
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4020
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/parts-cdn.ts
|
|
3904
4021
|
import { decompress as decompress2 } from "fzstd";
|
|
3905
4022
|
|
|
3906
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4023
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/embedded.ts
|
|
3907
4024
|
function splitFiles(text, fallback) {
|
|
3908
4025
|
const files = new Map;
|
|
3909
4026
|
let cur = null, saw = false;
|
|
@@ -3975,7 +4092,7 @@ function embeddedKeys(text, names, fallback = "main.ldr") {
|
|
|
3975
4092
|
return out;
|
|
3976
4093
|
}
|
|
3977
4094
|
|
|
3978
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4095
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/parts-cdn.ts
|
|
3979
4096
|
var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
|
|
3980
4097
|
var indexCache = new Map;
|
|
3981
4098
|
var shardCache = new Map;
|
|
@@ -4207,10 +4324,10 @@ async function prepareModel(source, o = {}) {
|
|
|
4207
4324
|
return { insts, pack, missing, requests, bytes, cull, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, ...cull ? { cull: performance.now() - t3 } : {} } };
|
|
4208
4325
|
}
|
|
4209
4326
|
|
|
4210
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4327
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/load-worker.gen.ts
|
|
4211
4328
|
var load_worker_gen_default = 'var vt=ArrayBuffer,Z=Uint8Array,de=Uint16Array,Ct=Int16Array;var be=Int32Array,Le=function(e,t,n){if(Z.prototype.slice)return Z.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 Z(n-t);return r.set(e.subarray(t,n)),r},ce=function(e,t,n,r){if(Z.prototype.fill)return Z.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},Tt=function(e,t,n,r){if(Z.prototype.copyWithin)return Z.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 Lt=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],J=function(e,t,n){var r=Error(t||Lt[e]);if(r.code=e,Error.captureStackTrace)Error.captureStackTrace(r,J);if(!n)throw r;return r},Ke=function(e,t,n){var r=0,s=0;for(;r<n;++r)s|=e[t++]<<(r<<3);return s},Et=function(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0},St=function(e,t){var n=e[0]|e[1]<<8|e[2]<<16;if(n==3126568&&e[3]==253){var r=e[4],s=r>>5&1,o=r>>2&1,i=r&3,a=r>>6;if(r&8)J(0);var u=6-s,c=i==3?4:i,f=Ke(e,u,c);u+=c;var l=a?1<<a:s,p=Ke(e,u,l)+(a==1&&256),d=p;if(!s){var w=1<<10+(e[5]>>3);d=w+(w>>3)*(e[5]&7)}if(d>2145386496)J(1);var y=new Z((t==1?p||d:t?0:d)+12);return y[0]=1,y[4]=4,y[8]=8,{b:u+l,y:0,l:0,d:f,w:t&&t!=1?t:y.subarray(12),e:d,o:new be(y.buffer,0,3),u:p,c:o,m:Math.min(131072,d)}}else if((n>>4|e[3]<<20)==25481893)return Et(e,4)+8;J(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,s=(e[t]&15)+5;if(s>n)J(3);var o=1<<s,i=o,a=-1,u=-1,c=-1,f=o,l=new vt(512+(o<<2)),p=new Ct(l,0,256),d=new de(l,0,256),w=new de(l,512,o),y=512+(o<<1),L=new Z(l,y,o),g=new Z(l,y+o);while(a<255&&i>0){var m=re(i+1),b=r>>3,h=(1<<m+1)-1,P=(e[b]|e[b+1]<<8|e[b+2]<<16)>>(r&7)&h,A=(1<<m)-1,E=h-i-1,T=P&A;if(T<E)r+=m,P=T;else if(r+=m+1,P>A)P-=E;if(p[++a]=--P,P==-1)i+=P,L[--f]=a;else i-=P;if(!P)do{var B=r>>3;u=(e[B]|e[B+1]<<8)>>(r&7)&3,r+=2,a+=u}while(u==3)}if(a>255||i)J(0);var v=0,F=(o>>1)+(o>>3)+3,Y=o-1;for(var _=0;_<=a;++_){var C=p[_];if(C<1){d[_]=-C;continue}for(c=0;c<C;++c){L[v]=_;do v=v+F&Y;while(v>=f)}}if(v)J(0);for(c=0;c<o;++c){var M=d[L[c]]++,k=g[c]=s-re(M);w[c]=(M<<k)-o}return[r+7>>3,{b:s,s:L,n:g,t:w}]},Pt=function(e,t){var n=0,r=-1,s=new Z(292),o=e[t],i=s.subarray(0,256),a=s.subarray(256,268),u=new de(s.buffer,268);if(o<128){var c=ue(e,t+1,6),f=c[0],l=c[1];t+=o;var p=f<<3,d=e[t];if(!d)J(0);var w=0,y=0,L=l.b,g=L,m=(++t<<3)-8+re(d);for(;;){if(m-=L,m<p)break;var b=m>>3;if(w+=(e[b]|e[b+1]<<8)>>(m&7)&(1<<L)-1,i[++r]=l.s[w],m-=g,m<p)break;b=m>>3,y+=(e[b]|e[b+1]<<8)>>(m&7)&(1<<g)-1,i[++r]=l.s[y],L=l.n[w],w=l.t[w],g=l.n[y],y=l.t[y]}if(++r>255)J(0)}else{r=o-127;for(;n<r;n+=2){var h=e[++t];i[n]=h>>4,i[n+1]=h&15}++t}var P=0;for(n=0;n<r;++n){var A=i[n];if(A>11)J(0);P+=A&&1<<A-1}var E=re(P)+1,T=1<<E,B=T-P;if(B&B-1)J(0);i[r++]=re(B)+1;for(n=0;n<r;++n){var A=i[n];++a[i[n]=A&&E+1-A]}var v=new Z(T<<1),F=v.subarray(0,T),Y=v.subarray(T);u[E]=0;for(n=E;n>0;--n){var _=u[n];ce(Y,n,_,u[n-1]=_+a[n]*(1<<E-n))}if(u[0]!=T)J(0);for(n=0;n<r;++n){var C=i[n];if(C){var M=u[C];ce(F,n,M,u[C]=M+(1<<E-C))}}return[t,{n:Y,b:E,s:F}]},kt=ue(new Z([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],It=ue(new Z([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],Bt=ue(new Z([32,132,16,66,102,70,68,68,68,68,36,73,2]),0,5)[1],We=function(e,t){var n=e.length,r=new be(n);for(var s=0;s<n;++s)r[s]=t,t+=1<<e[s];return r},Ee=new Z(new be([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),Ft=We(Ee,0),Se=new Z(new be([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),Rt=We(Se,3),le=function(e,t,n){var r=e.length,s=t.length,o=e[r-1],i=(1<<n.b)-1,a=-n.b;if(!o)J(0);var u=0,c=n.b,f=(r<<3)-8+re(o)-c,l=-1;for(;f>a&&l<s;){var p=f>>3,d=(e[p]|e[p+1]<<8|e[p+2]<<16)>>(f&7);u=(u<<c|d)&i,t[++l]=n.s[u],f-=c=n.n[u]}if(f!=a||l+1!=s)J(0)},Dt=function(e,t,n){var r=6,s=t.length,o=s+3>>2,i=o<<1,a=o+i;le(e.subarray(r,r+=e[0]|e[1]<<8),t.subarray(0,o),n),le(e.subarray(r,r+=e[2]|e[3]<<8),t.subarray(o,i),n),le(e.subarray(r,r+=e[4]|e[5]<<8),t.subarray(i,a),n),le(e.subarray(r),t.subarray(a),n)},Ut=function(e,t,n){var r,s=t.b,o=e[s],i=o>>1&3;t.l=o&1;var a=o>>3|e[s+1]<<5|e[s+2]<<13,u=(s+=3)+a;if(i==1){if(s>=e.length)return;if(t.b=s+1,n)return ce(n,e[s],t.y,t.y+=a),n;return ce(new Z(a),e[s])}if(u>e.length)return;if(i==0){if(t.b=u,n)return n.set(e.subarray(s,u),t.y),t.y+=a,n;return Le(e,s,u)}if(i==2){var c=e[s],f=c&3,l=c>>2&3,p=c>>4,d=0,w=0;if(f<2)if(l&1)p|=e[++s]<<4|(l&2&&e[++s]<<12);else p=c>>3;else if(w=l,l<2)p|=(e[++s]&63)<<4,d=e[s]>>6|e[++s]<<2;else if(l==2)p|=e[++s]<<4|(e[++s]&3)<<12,d=e[s]>>2|e[++s]<<6;else p|=e[++s]<<4|(e[++s]&63)<<12,d=e[s]>>6|e[++s]<<2|e[++s]<<10;++s;var y=n?n.subarray(t.y,t.y+t.m):new Z(t.m),L=y.length-p;if(f==0)y.set(e.subarray(s,s+=p),L);else if(f==1)ce(y,e[s++],L);else{var g=t.h;if(f==2){var m=Pt(e,s);d+=s-(s=m[0]),t.h=g=m[1]}else if(!g)J(0);(w?Dt:le)(e.subarray(s,s+=d),y.subarray(L),g)}var b=e[s++];if(b){if(b==255)b=(e[s++]|e[s++]<<8)+32512;else if(b>127)b=b-128<<8|e[s++];var h=e[s++];if(h&3)J(0);var P=[It,Bt,kt];for(var A=2;A>-1;--A){var E=h>>(A<<1)+2&3;if(E==1){var T=new Z([0,0,e[s++]]);P[A]={s:T.subarray(2,3),n:T.subarray(0,1),t:new de(T.buffer,0,1),b:0}}else if(E==2)r=ue(e,s,9-(A&1)),s=r[0],P[A]=r[1];else if(E==3){if(!t.t)J(0);P[A]=t.t[A]}}var B=t.t=P,v=B[0],F=B[1],Y=B[2],_=e[u-1];if(!_)J(0);var C=(u<<3)-8+re(_)-Y.b,M=C>>3,k=0,G=(e[M]|e[M+1]<<8)>>(C&7)&(1<<Y.b)-1;M=(C-=F.b)>>3;var I=(e[M]|e[M+1]<<8)>>(C&7)&(1<<F.b)-1;M=(C-=v.b)>>3;var N=(e[M]|e[M+1]<<8)>>(C&7)&(1<<v.b)-1;for(++b;--b;){var j=Y.s[G],X=Y.n[G],W=v.s[N],S=v.n[N],x=F.s[I],R=F.n[I];M=(C-=x)>>3;var D=1<<x,U=D+((e[M]|e[M+1]<<8|e[M+2]<<16|e[M+3]<<24)>>>(C&7)&D-1);M=(C-=Se[W])>>3;var H=Rt[W]+((e[M]|e[M+1]<<8|e[M+2]<<16)>>(C&7)&(1<<Se[W])-1);M=(C-=Ee[j])>>3;var z=Ft[j]+((e[M]|e[M+1]<<8|e[M+2]<<16)>>(C&7)&(1<<Ee[j])-1);if(M=(C-=X)>>3,G=Y.t[G]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<X)-1),M=(C-=S)>>3,N=v.t[N]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<S)-1),M=(C-=R)>>3,I=F.t[I]+((e[M]|e[M+1]<<8)>>(C&7)&(1<<R)-1),U>3)t.o[2]=t.o[1],t.o[1]=t.o[0],t.o[0]=U-=3;else{var V=U-(z!=0);if(V){if(U=V==3?t.o[0]-1:t.o[V],V>1)t.o[2]=t.o[1];t.o[1]=t.o[0],t.o[0]=U}else U=t.o[0]}for(var A=0;A<z;++A)y[k+A]=y[L+A];k+=z,L+=z;var O=k-U;if(O<0){var K=-O,q=t.e+O;if(K>H)K=H;for(var A=0;A<K;++A)y[k+A]=t.w[q+A];k+=K,H-=K,O=0}for(var A=0;A<H;++A)y[k+A]=y[O+A];k+=H}if(k!=L)while(L<y.length)y[k++]=y[L++];else k=y.length;if(n)t.y+=k;else y=Le(y,0,k)}else if(n){if(t.y+=p,L)for(var A=0;A<p;++A)y[A]=y[L+A]}else if(L)y=Le(y,L);return t.b=u,y}J(2)},Ot=function(e,t){if(e.length==1)return e[0];var n=new Z(t);for(var r=0,s=0;r<e.length;++r){var o=e[r];n.set(o,s),s+=o.length}return n};function ye(e,t){var n=[],r=+!t,s=0,o=0;for(;e.length;){var i=St(e,r||t);if(typeof i=="object"){if(r){if(t=null,i.w.length==i.u)n.push(t=i.w),o+=i.u}else n.push(t),i.e=0;for(;!i.l;){var a=Ut(e,i,t);if(!a)J(5);if(t)i.e=i.y;else n.push(a),o+=a.length,Tt(i.w,0,a.length),i.w.set(a,i.w.length-a.length)}s=i.b+i.c*4}else s=i;e=e.subarray(s)}return Ot(n,o)}async function Nt(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),n=(r)=>r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);if(t[0]===40&&t[1]===181&&t[2]===47&&t[3]===253)return n(ye(t));if(t[0]===31&&t[1]===139)return new Response(new Blob([t]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();return n(t)}async function Xe(e){return new TextDecoder().decode(await Nt(e))}var Ze=(e)=>decodeURIComponent(e.split(/[?#]/)[0].split("/").pop()||"main.ldr").replace(/\\.(zst|gz)$/i,"")||"main.ldr";function xe(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:(o)=>o&&(o[2]==="f32"?new Float32Array(e,r+o[0],o[1]):o[2]==="u16"?new Uint16Array(e,r+o[0],o[1]):o[2]==="u8"?new Uint8Array(e,r+o[0],o[1]):new Uint32Array(e,r+o[0],o[1])),bytes:e.byteLength,buffer:e}}var Q=(e)=>e.trim().toLowerCase().replace(/\\\\/g,"/").replace(/\\/+/g,"/"),ke=/^[A-Za-z][A-Za-z0-9_]*$/,Pe=new Map;function Ie(e){let t=e.toLowerCase(),n=2166136261;for(let s=0;s<t.length;s++)n^=t.charCodeAt(s),n=Math.imul(n,16777619);let r=-1-(n>>>0&1073741823);if(!Pe.has(r))Pe.set(r,t);return r}function Be(e){let t=e.charCodeAt(0)|32;if(t>=97&&t<=122&&ke.test(e))return Ie(e);if(/^0x/i.test(e))return parseInt(e,16);return+e}var Ye=/^~?\\s*moved\\s+to\\s+(.+)$/i,zt=new Set(["FILE","NOFILE","!DATA","!:","STEP","BFC","ROTSTEP","BUFEXCHG","!TEXMAP"]),st=new Set(["part","subpart","primitive","8_primitive","48_primitive","shortcut","helper"]),$t=new Set(["model","submodel","configuration"]),jt=/^(?:!?LDRAW_ORG|Unofficial|Official\\s+LCAD)\\s+(\\S+)/i;function Je(e){let t=jt.exec(e);if(!t)return;let n=t[1].toLowerCase().replace(/^unofficial_/,"");return st.has(n)||$t.has(n)?n:void 0}function Vt(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 _t(e,t=!1){let n=/^\\s*(\\S+)\\s+(.*)$/.exec(e);if(!n)return null;let r=n[1].toUpperCase(),s=r==="PLANAR"?9:r==="CYLINDRICAL"?10:r==="SPHERICAL"?11:0;if(!s)return null;let o=n[2].trim().split(/\\s+/);if(o.length<s+1)return null;let i=o.slice(0,s).map(Number);if(!i.every(Number.isFinite))return null;let a=n[2].trim();for(let l=0;l<s;l++)a=a.replace(/^\\S+\\s*/,"");let u=Vt(a);if(!u.length)return null;let c={method:r,p1:i.slice(0,3),p2:i.slice(3,6),p3:i.slice(6,9),texture:u[0]};if(s>=10)c.a=i[9];if(s===11)c.b=i[10];let f=u.findIndex((l,p)=>p>0&&l.toUpperCase()==="GLOSSMAP");if(f>0&&u[f+1])c.glossmap=u[f+1];if(t)c.next=!0;return c}var Ht=(e)=>{let t=e.replace(/[^A-Za-z0-9+/]/g,""),n=t+"=".repeat((4-t.length%4)%4),r=atob(n),s=new Uint8Array(r.length);for(let o=0;o<r.length;o++)s[o]=r.charCodeAt(o);return s};function Gt(e){let t=e.length,n=1,r=(c)=>c===32||c===9,s=()=>{while(n<t&&r(e.charCodeAt(n)))n++;let c=n;while(n<t&&!r(e.charCodeAt(n)))n++;return c<n?e.slice(c,n):null},o=s();if(o===null)return null;let i=Array(12);for(let c=0;c<12;c++){let f=s();if(f===null)return null;i[c]=+f}while(n<t&&r(e.charCodeAt(n)))n++;if(n>=t)return null;let a=e.slice(n),u=/[ \\t]{2,}|\\t/.test(a)?a.split(/\\s+/).join(" "):a;return{t:1,color:Be(o),m:i,file:Q(u)}}function qe(e){let t=+e[0];if(!(t>=1&&t<=5)||e.length<2)return null;let n=Be(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 ot(e,t="main.ldr",n={}){let r=!!n.geometryText,s=new Map,o=null,i="",a,u=null,c=[],f=null,l=()=>{if(!u)return;let m=Ht(u.chunks.join("")),b=m[0]===137&&m[1]===80&&m[2]===78&&m[3]===71;(a??=new Map).set(Q(u.name),{name:u.name,bytes:m,...b?{mime:"image/png"}:{}}),u=null},p=!0,d=(m)=>{if(l(),o={name:Q(m),cmds:[]},s.set(o.name,o),!i)i=o.name;c=[],f=null,p=!0},w=!1,y=!1,L=()=>{if(y)return;y=!0,s.clear(),o=null,i=""},g=(m,b)=>{if(f){m.tex=f,f=null;return}let h=c[c.length-1];if(!h)return;if(h.fallback){if(!b)m.fallback=!0}else m.tex=h.map};for(let m of e.split(`\n`)){let b=m.trim();if(!b)continue;if(r&&b.charCodeAt(0)>=50&&b.charCodeAt(0)<=53&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)){if(u||w)continue;if(!o)d(t);let E=b.slice(2).trimStart(),T=E.search(/\\s/),B={t:b.charCodeAt(0)-48,color:Be(T<0?E:E.slice(0,T)),p:[],src:b};g(B,!1),o.cmds.push(B),p=!1;continue}if(b.charCodeAt(0)===48&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)){let E=2;while(b.charCodeAt(E)===32||b.charCodeAt(E)===9)E++;let T=E;while(T<b.length&&b.charCodeAt(T)!==32&&b.charCodeAt(T)!==9)T++;let B=b.slice(E,T);if(!zt.has(B)){if(w||u)continue;if(!o)d(t);let v=b.slice(E),F={t:0,text:v};if(B.charCodeAt(0)===33)F.meta=B;if(f=null,p&&!o.org){let _=Je(v);if(_)o.org=_}let Y=v.match(Ye);if(Y&&!o.movedTo){let _=Y[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(_))_+=".dat";o.movedTo=Q(_)}o.cmds.push(F);continue}}if(b.charCodeAt(0)===49&&(b.charCodeAt(1)===32||b.charCodeAt(1)===9)&&!u&&!w){let E=Gt(b);if(E){if(!o)d(t);g(E,!1),o.cmds.push(E),p=!1;continue}}let h=b.split(/\\s+/);if(+h[0]===0){let E=b.slice(1).trim();if(h[1]==="FILE"){L(),w=!1,d(E.slice(5));continue}if(h[1]==="NOFILE"){l(),o=null,w=!0;continue}if(h[1]==="!DATA"){L(),l(),o=null,w=!1,u={name:E.slice(5).trim(),chunks:[]};continue}if(w)continue;if(u){if(h[1]==="!:")u.chunks.push(h.slice(2).join(""));continue}if(!o)d(t);let T={t:0,text:E};if(h[1]==="STEP")T.step=!0,c=[],f=null;else if(h[1]==="BFC")T.bfc=h.slice(2).join(" ");else if(h[1]==="ROTSTEP")if(T.meta="ROTSTEP",T.step=!0,c=[],f=null,(h[2]??"").toUpperCase()==="END")T.rotstep={x:0,y:0,z:0,mode:"END"};else{let v=(h[5]??"REL").toUpperCase();T.rotstep={x:+h[2]||0,y:+h[3]||0,z:+h[4]||0,mode:["REL","ABS","ADD"].includes(v)?v:"REL"}}else if(h[1]==="BUFEXCHG"){T.meta="BUFEXCHG";let v=(h[2]??"").toUpperCase();T.bufexchg={op:v==="RETRIEVE"?"RETRIEVE":"STORE",buf:h[3]??"A"}}else if(h[1]?.startsWith("!"))T.meta=h[1];if(p&&!o.org){let v=Je(E);if(v)o.org=v}if(h[1]==="!TEXMAP"){let v=(h[2]??"").toUpperCase();if(f=null,v==="START"||v==="NEXT"){let F=_t(E.replace(/^!TEXMAP\\s+\\S+/i,""),v==="NEXT");if(T.texmap={op:v,...F?{map:F}:{}},F)if((o.texmaps??=[]).push(F),v==="START")c.push({map:F,fallback:!1});else f=F}else if(v==="FALLBACK"){T.texmap={op:v};let F=c[c.length-1];if(F)F.fallback=!0}else if(v==="END")T.texmap={op:v},c.pop()}else if(h[1]==="!:"){f=null;let v=qe(h.slice(2));if(v)g(v,!0),T.geom=v}else f=null;let B=E.match(Ye);if(B&&!o.movedTo){let v=B[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(v))v+=".dat";o.movedTo=Q(v)}o.cmds.push(T);continue}if(u||w)continue;if(!o)d(t);let A=qe(h);if(!A)continue;g(A,!1),o.cmds.push(A),p=!1}return l(),a?{main:i,files:s,data:a}:{main:i,files:s}}var yn=Math.PI/180;function it(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 at(e,t){let[n,r,s,o,i,a,u,c,f,l,p,d]=e,[w,y,L,g,m,b,h,P,A,E,T,B]=t;return[o*w+i*y+a*L+n,u*w+c*y+f*L+r,l*w+p*y+d*L+s,o*g+i*h+a*E,o*m+i*P+a*T,o*b+i*A+a*B,u*g+c*h+f*E,u*m+c*P+f*T,u*b+c*A+f*B,l*g+p*h+d*E,l*m+p*P+d*T,l*b+p*A+d*B]}var Fe=[0,0,0,1,0,0,0,1,0,0,0,1];var Qe=new WeakMap,Kt=/^(s|8|48)\\//;function Re(e,t){let n=e.files.get(Q(t));if(!n)return"part";let r=Qe.get(n);if(r)return r;if(n.org)r=st.has(n.org)?"part":"model";else if(n.name===e.main)r="model";else r=n.cmds.some((s)=>s.t>=2||s.t===0&&!!s.geom||s.t===1&&Kt.test(s.file))?"part":"model";return Qe.set(n,r),r}var et=new WeakMap;function lt(e){let t=et.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 et.set(e,t),t}var tt=(e)=>e>16777215?"0x"+e.toString(16).toUpperCase():e<0?Pe.get(e)??String(e):String(e),Wt=(e)=>e.t===0?"0 "+e.text:e.t===1?`1 ${tt(e.color)} ${e.m.join(" ")} ${e.file}`:e.src?e.src:`${e.t} ${tt(e.color)} ${e.p.join(" ")}`,De=(e,t)=>`${Q(e)}#${t}`;function Xt(e,t){let n=[],r=0,s=(o)=>!!o&&o.t===0&&o.texmap?.op==="NEXT";for(let o of e.cmds){if(o.t===0){if(o.step){r++;continue}if(o.bfc!==void 0){n.push(o);continue}if(r!==t)continue;if(o.texmap)n.push(o);else if(o.geom){if(o.geom.t>=2)n.push(o);else if(s(n[n.length-1]))n.pop()}continue}if(r!==t)continue;if(o.t===1){if(s(n[n.length-1]))n.pop();continue}n.push(o)}return{name:De(e.name,t),cmds:n}}function ct(e,t){return[`0 ldr: own geometry of ${e.name}, step ${t}`,...Xt(e,t).cmds.map(Wt)].join(`\n`)+`\n`}function Zt(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 ut(e){let[t,n,r,s,o,i,a,u,c,f,l,p]=e,d=u*p-c*l,w=-(a*p-c*f),y=a*l-u*f,L=s*d+o*w+i*y;if(!Number.isFinite(L)||Math.abs(L)<0.000000000001)return null;let g=1/L,m=[d*g,-(o*p-i*l)*g,(o*c-i*u)*g,w*g,(s*p-i*f)*g,-(s*c-i*a)*g,y*g,-(s*l-o*f)*g,(s*u-o*a)*g];return[-(m[0]*t+m[1]*n+m[2]*r),-(m[3]*t+m[4]*n+m[5]*r),-(m[6]*t+m[7]*n+m[8]*r),...m]}var Yt=(e)=>String(+e.toFixed(6)||0),nt=(e)=>\'"\'+e.replace(/\\\\/g,"\\\\\\\\").replace(/"/g,"\\\\\\"")+\'"\';function ft(e,t){let n=[...t.p1,...t.p2,...t.p3,...t.method!=="PLANAR"?[t.a??360]:[],...t.method==="SPHERICAL"?[t.b??180]:[]].map(Yt).join(" "),r=`0 ldr: ${e} with a model-level !TEXMAP\n0 BFC CERTIFY CCW\n0 !TEXMAP START ${t.method} ${n} ${nt(t.texture)}${t.glossmap?" GLOSSMAP "+nt(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-${Zt(r)}`,source:r}}var Jt=(e,t)=>{let n=[,,,,,,,,,];for(let r=0;r<3;r++)for(let s=0;s<3;s++)n[r*3+s]=e[r*3]*t[s]+e[r*3+1]*t[3+s]+e[r*3+2]*t[6+s];return n};function qt(e,t,n){let r=Math.PI/180,s=Math.sin(e*r),o=Math.cos(e*r),i=Math.sin(t*r),a=Math.cos(t*r),u=Math.sin(n*r),c=Math.cos(n*r);return[a*c,-a*u,i,o*u+s*i*c,o*c-s*i*u,-s*a,s*u-o*i*c,s*c+o*i*u,o*a]}var rt=new WeakMap;function pt(e){let t=rt.get(e);if(t)return t;let n=[],r=null;for(let s of e.cmds){if(s.t!==0||!s.step)continue;let o=s.rotstep;if(o)if(o.mode==="END")r=null;else{let i=qt(o.x,o.y,o.z);r=o.mode==="ABS"?{abs:!0,m:i,rotstep:o}:o.mode==="ADD"&&r?{abs:r.abs,m:Jt(r.m,i),rotstep:o}:{abs:!1,m:i,rotstep:o}}n.push(r)}return n.push(r),rt.set(e,n),n}var mt=999999,gt=(e)=>e.map((t)=>String(t).padStart(6,"0")).join(".")+"~";function Qt(e,t={}){let n=[],r=t.maxDepth??64,s=t.looseGeometry!==!1,o=!!t.textures,i=!!t.callouts,a=new Map,u=0,c=(l,p)=>{let d=l.name+"#"+p,w=a.get(d);if(!w){let y;w=Object.assign(()=>y??=ct(l,p),{file:l,step:p}),a.set(d,w)}return w},f=(l,p,d,w,y,L,g,m,b=null,h=[],P=[],A=void 0,E=null)=>{let T=l.files.get(p);if(!T||g>r)return;let B=E,v=0,F=g>0?++u:0,Y=i&&F?[...h,F]:h,_=i&&F?[...P,d]:P,C=i&&!b?new Map:null,M=-1,k=0,G=(S,x,R,D,U,H,z)=>{if(M!==v)M=v,k=0;let V=C?.get(v+"|"+x);if(V)return V.n++,f(S,S===l?x:S.main,R,D,y+"/"+x,[...U,mt],g+1,H,[...U,mt],Y,_,z,B);let O=[...U,k++],K=n.length;f(S,S===l?x:S.main,R,D,y+"/"+x,O,g+1,H,b,Y,_,z,B),C?.set(v+"|"+x,{n:1,from:K,to:n.length})},I=pt(T),N=s?lt(T):[],j=0,X=(S,x,R,D,U,H,z,V)=>{if(b)D=b;let O={part:S,color:x,m:R,step:D[0],steps:D,localStep:U,path:y};if(V)O.colour=V;if(F){if(O.sub=F,i)O.subPath=Y,O.subMats=_}if(H)O.embedded=!0;if(z){let q=ft(S,z);O.texPart=q.name,O.texSource=q.source}let K=I[U];if(K)O.view=K;return n.push(O),O},W=(S)=>{while(j<N.length&&N[j]<=S){let x=N[j++];X(De(T.name,x),w,d,[...L,x],x,!1,null,A).source=c(T,x)}};for(let S of T.cmds){if(S.t===0&&S.step){v++;continue}let x=S;if(x.t>=2||x.t===0&&x.geom&&x.geom.t>=2){W(v);continue}if(x.t===0){if(x.meta==="!COLOUR"){let q=tn(x.text);if(q&&q.code!==16&&q.code!==24)(B=new Map(B??[])).set(q.code,q);continue}if(o&&x.geom?.t===1)x=x.geom;else continue}if(x.t!==1)continue;if(o&&x.fallback)continue;let R=x.color===16?w:x.color,D=x.color===16?A:B?.get(x.color),U=at(d,x.m),H=[...L,v],z=o?x.tex??m:null,V=z?ut(x.m):null,O=z&&V?it(z,V):null;if(l.files.has(x.file)){if(Re(l,x.file)==="model"){G(l,x.file,U,R,H,O,D);continue}X(x.file,R,U,H,v,!0,O,D);continue}let K=t.resolveModel?.(x.file);if(K){G(K,x.file,U,R,H,O,D);continue}X(x.file,R,U,H,v,!1,O,D)}if(W(1/0),C){for(let S of C.values())if(S.n>1)for(let x=S.from;x<S.to;x++)n[x].mult??=S.n}};if(Re(e,e.main)==="part"){if(e.files.get(e.main))n.push({part:e.main,color:16,m:[...Fe],step:0,steps:[0],localStep:0,path:e.main,embedded:!0});return n}return f(e,e.main,Fe,16,e.main,[],0,null),n}function dt(e,t="main.ldr",n){return Qt(ot(e,t,{geometryText:!0}),n)}var en=new Set(["CHROME","PEARLESCENT","RUBBER","MATTE_METALLIC","METAL","MATERIAL"]);function Ue(e){if(!e)return null;if(e.startsWith("#")&&/^#[0-9A-Fa-f]{6}$/.test(e))return e.toUpperCase();if(/^0x[0-9A-Fa-f]{6}$/i.test(e))return("#"+e.slice(2)).toUpperCase();return null}function ht(e,t){let n={value:"#FFFFFF",fraction:0.5};while(t<e.length){let r=e[t].toUpperCase(),s=e[t+1];if(r==="VALUE"){let o=Ue(s);if(o)n.value=o;t+=2}else if(r==="ALPHA")n.alpha=+s,t+=2;else if(r==="LUMINANCE")n.luminance=+s,t+=2;else if(r==="FRACTION")n.fraction=+s,t+=2;else if(r==="VFRACTION")n.vfraction=+s,t+=2;else if(r==="SIZE")n.size=+s,t+=2;else if(r==="MINSIZE")n.minsize=+s,t+=2;else if(r==="MAXSIZE")n.maxsize=+s,t+=2;else break}return{grain:n,next:t}}function tn(e){let t=e.indexOf("!COLOUR");if(t<0)return null;let n=e.slice(t+7).trim().split(/\\s+/).filter(Boolean);if(n.length<2)return null;let r=n[0],s=NaN,o="#FF00FF",i="#333333",a=255,u=0,c={type:"default"},f=1;while(f<n.length){let l=n[f].toUpperCase(),p=n[f+1];if(l==="CODE")s=p!==void 0&&ke.test(p)?Ie(p):p!==void 0&&/^\\d+$/.test(p)?+p:NaN,f+=2;else if(l==="VALUE"){let d=Ue(p);if(d)o=d;f+=2}else if(l==="EDGE")i=Ue(p)??p,f+=2;else if(l==="ALPHA")a=+p,f+=2;else if(l==="LUMINANCE")u=+p,f+=2;else if(l==="CHROME")c={type:"chrome"},f+=1;else if(l==="PEARLESCENT")c={type:"pearlescent"},f+=1;else if(l==="RUBBER")c={type:"rubber"},f+=1;else if(l==="MATTE_METALLIC")c={type:"matte_metallic"},f+=1;else if(l==="METAL")c={type:"metal"},f+=1;else if(l==="MATERIAL"){let d=(n[f+1]||"").toUpperCase();if(d==="GLITTER"){let{grain:w,next:y}=ht(n,f+2);c={type:"glitter",material:w},f=y}else if(d==="SPECKLE"){let{grain:w,next:y}=ht(n,f+2);c={type:"speckle",material:w},f=y}else if(d==="FABRIC"){let w=(n[f+2]||"").toUpperCase(),y=["VELVET","CANVAS","STRING","FUR"].includes(w)?w.toLowerCase():void 0;c={type:"fabric",kind:y},f+=y?3:2}else f=n.length}else if(en.has(l))f+=1;else f+=1}if(Number.isNaN(s)||!o)return null;return{code:s,name:r,hex:o,edge:i,alpha:Number.isFinite(a)?a:255,luminance:Number.isFinite(u)?u:0,finish:c}}function nn(e){let t=Math.max(0,Math.min(1,(e.alpha??255)/255)),n=t<1,r=Math.max(0,Math.min(1,(e.luminance??0)/255)),s={opacity:t,transparent:n,depthWrite:!n,emissive:r,clearcoat:0,clearcoatRoughness:0,sheen:0,sheenRoughness:0};switch(e.finish?.type??"default"){case"chrome":return{...s,metalness:1,roughness:0,finish:"chrome"};case"pearlescent":return{...s,metalness:0.25,roughness:0.3,clearcoat:0.5,clearcoatRoughness:0.25,sheen:0.4,sheenRoughness:0.35,finish:"pearlescent"};case"rubber":return{...s,metalness:0,roughness:0.9,finish:"rubber"};case"matte_metallic":return{...s,metalness:0.4,roughness:0.8,finish:"matte_metallic"};case"metal":return{...s,metalness:0.85,roughness:0.2,finish:"metal"};case"glitter":{let i=e.finish.material,a=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.35,roughness:0.25,clearcoat:1,clearcoatRoughness:0.08,particleHex:i.value,particleFraction:i.fraction,particleSize:a,finish:"glitter"}}case"speckle":{let i=e.finish.material,a=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.2,roughness:0.55,particleHex:i.value,particleFraction:i.fraction,particleSize:a,finish:"speckle"}}case"fabric":return{...s,metalness:0,roughness:0.85,sheen:0.65,sheenRoughness:0.75,finish:"fabric"};default:return{...s,metalness:0,roughness:0.45,finish:"default"}}}function Oe(e){let t=nn(e),n=!t.transparent?"op":t.opacity>=0.75?"a200":t.opacity>=0.4?"a128":`a${Math.round(t.opacity*255)}`,r=t.emissive>0?`L${Math.round(t.emissive*16)}`:"",s=`${t.finish}:${n}${r}`;if(t.particleHex)s+=`:${t.particleHex}:${(t.particleFraction??0).toFixed(2)}`;return s}function rn(e,t){let n=new Map,r=null,s=!1;for(let o of e.split(/\\r?\\n/)){let i=/^\\s*0\\s+FILE\\s+(.+)$/i.exec(o);if(i){if(!s)n.clear();s=!0,r=[],n.set(Q(i[1]),r);continue}if(/^\\s*0\\s+(NOFILE|!DATA)(\\s|$)/i.test(o)){if(!s)n.clear();s=!0,r=null;continue}if(!r){if(s)continue;r=[],n.set(Q(t),r)}let a=o.trim().replace(/\\s+/g," ");if(a)r.push(a)}return n}var sn=(e)=>{if(!e.startsWith("1 "))return null;let t=e.split(" ");return t.length>=15?Q(t.slice(14).join(" ")):null};function on(e){let t=2166136261,n=1523705862;for(let r=0;r<e.length;r++){let s=e.charCodeAt(r);t=Math.imul(t^s,16777619),n=Math.imul(n^s,16777629)^n>>>15}return(t>>>0).toString(16).padStart(8,"0")+(n>>>0).toString(16).padStart(8,"0")}function bt(e,t,n="main.ldr"){let r=rn(e,n),s=new Map;for(let o of t){let i=Q(o);if(!r.has(i)||s.has(i))continue;let a=new Set([i]),u=[i];while(u.length)for(let f of r.get(u.pop())){let l=sn(f);if(l&&r.has(l)&&!a.has(l))a.add(l),u.push(l)}let c=[i,...[...a].filter((f)=>f!==i).sort()].map((f)=>"0 FILE "+(f===i?"":f)+`\n`+r.get(f).join(`\n`)).join(`\n`);s.set(i,`emb/${on(c)}.dat`)}return s}var yt=(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,xt=new WeakMap;function Ne(e,t){let n=xt.get(e);if(!n)xt.set(e,n=new Map);let r=n.get(t);if(r!==void 0)return r;let s=e.parts[t];if(!s)return n.set(t,null),null;let o=s.studs.length,i=new Float64Array(o*12),a=[],u=[];s.studs.forEach((p,d)=>{a.push(p[0]),u.push(p[1]);for(let w=0;w<12;w++)i[d*12+w]=p[2+w]});let c=null,f=0,l=0;if(s.mask){f=s.mask[0],l=s.mask[1];let p=s.mask[2];c=new Uint8Array(p.length);for(let d=0;d<p.length;d++)c[d]=p.charCodeAt(d)===49?1:0}return n.set(t,r={nStuds:o,studM:i,kind:a,color:u,mask:c,nx:f,nz:l}),r}var ie=1073741824;class ze{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),s=this.used,o=this.a,i=this.b,a=this.c;for(;;){if(!s[r])return-1;if(o[r]===e&&i[r]===t&&a[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 s=this.slot(e,t,n),o=this.used,i=this.a,a=this.b,u=this.c;for(;;){if(!o[s])return o[s]=1,i[s]=e,a[s]=t,u[s]=n,this.vals[s]=r,this.size++,-1;if(i[s]===e&&a[s]===t&&u[s]===n){let c=this.vals[s];return this.vals[s]=r,c}s=s+1&this.mask}}grow(){let{a:e,b:t,c:n,vals:r,used:s}=this,o=s.length*2;this.a=new Int32Array(o),this.b=new Int32Array(o),this.c=new Int32Array(o),this.vals=new Int32Array(o),this.used=new Uint8Array(o),this.mask=o-1,this.size=0;for(let i=0;i<s.length;i++)if(s[i])this.put(e[i],t[i],n[i],r[i])}}var we=(e,t,n)=>e>-ie&&e<ie&&t>-ie&&t<ie&&n>-ie&&n<ie,fe=2147483647;function an(e,t,n){let s=[],o=[],i=[],a=[],u=[],c=[],f=[],l=[],p=new ze(e.length*2),d=[],w=[];for(let C=0;C<e.length;C++){let M=e[C],k=M.m,G=t.parts[M.part];if(!G||!G.mask||!yt(k))continue;let I=G.bbox,N=1/0,j=-1/0,X=1/0,W=-1/0;for(let R=0;R<2;R++)for(let D=0;D<2;D++){let U=R?I[3]:I[0],H=D?I[5]:I[2],z=k[0]+k[3]*U+k[5]*H,V=k[2]+k[9]*U+k[11]*H;if(z<N)N=z;if(z>j)j=z;if(V<X)X=V;if(V>W)W=V}let S=u.length;s.push(N),o.push(j),i.push(X),a.push(W),u.push(C),c.push(Ne(t,M.part)),f.push(I[0]),l.push(I[2]);let x=Math.round((k[1]+I[4])*2);for(let R=Math.floor(N/40);R<=Math.floor(j/40);R++)for(let D=Math.floor(X/40);D<=Math.floor(W/40);D++){if(!we(x,R,D))continue;let U=w.length;w.push(S),d.push(p.put(x,R,D,U))}}let y=[0,5,-5,5,-5],L=[0,5,5,-5,-5],g=NaN,m=NaN,b=NaN,h=-1,P=(C,M,k,G)=>{let I=Math.round(M*2),N=Math.floor(C/40),j=Math.floor(k/40);if(!we(I,N,j))return fe;let X=fe;if(I!==g||N!==m||j!==b)g=I,m=N,b=j,h=p.get(I,N,j);for(let W=h;W>=0;W=d[W]){let S=w[W];if(u[S]===G||!(C-6>=s[S]-0.5&&C+6<=o[S]+0.5&&k-6>=i[S]-0.5&&k+6<=a[S]+0.5))continue;let x=e[u[S]].m,R=c[S],D=f[S],U=l[S],H=C-x[0],z=M-x[1],V=k-x[2],O=x[3]*H+x[6]*z+x[9]*V,K=x[5]*H+x[8]*z+x[11]*V,{nx:q,nz:se,mask:ae}=R,oe=!0;for(let ee=0;ee<5;ee++){let te=Math.floor((O+y[ee]-D)/20),ne=Math.floor((K+L[ee]-U)/20);if(te<0||ne<0||te>=q||ne>=se||ae[te*se+ne]!==1){oe=!1;break}}if(oe){if(!n)return 0;let ee=n[u[S]];if(ee<X)X=ee}}return X},A=0;for(let C of e){let M=Ne(t,C.part);if(M)A+=M.nStuds}let E=new Uint8Array(A),T=new Uint8Array(A),B=new ze(A),v=0,F=n?new Int32Array(A).fill(fe):void 0;for(let C=0,M=0;C<e.length;C++){let k=e[C],G=Ne(t,k.part);if(!G)continue;let I=k.m,N=G.studM,j=I[0],X=I[1],W=I[2],S=I[3],x=I[4],R=I[5],D=I[6],U=I[7],H=I[8],z=I[9],V=I[10],O=I[11];for(let K=0;K<G.nStuds;K++,M++){let q=K*12,se=N[q+4],ae=N[q+7],oe=N[q+10];if(!(Math.abs(D*se+U*ae+H*oe-1)<0.001&&Math.abs(S*se+x*ae+R*oe)<0.001&&Math.abs(z*se+V*ae+O*oe)<0.001))continue;T[M]=1;let ee=N[q],te=N[q+1],ne=N[q+2],$e=j+S*ee+x*te+R*ne,je=X+D*ee+U*te+H*ne,Ve=W+z*ee+V*te+O*ne,_e=P($e,je,Ve,C);if(_e!==fe){if(E[M]=1,v++,F)F[M]=_e}let me=Math.round($e),he=Math.round(je),ge=Math.round(Ve);if(!we(me,he,ge))continue;if(!n){B.put(me,he,ge,1);continue}let He=n[C],Ge=B.get(me,he,ge);if(Ge<0||He<Ge)B.put(me,he,ge,He)}}let Y=new Uint8Array(e.length),_=n?new Int32Array(e.length).fill(fe):void 0;for(let C=0;C<e.length;C++){let M=e[C],k=t.parts[M.part];if(!k||!k.under||!yt(M.m))continue;let G=k.bbox,I=Math.round((G[3]-G[0])/20),N=Math.round((G[5]-G[2])/20);if(!I||!N||I*N>4096)continue;let j=M.m,X=!0,W=0;for(let S=0;S<I&&X;S++)for(let x=0;x<N;x++){let R=G[0]+10+20*S,D=G[2]+10+20*x,U=j[0]+j[3]*R+j[5]*D,H=j[2]+j[9]*R+j[11]*D,z=Math.round(U),V=Math.round(j[1]+G[4]),O=Math.round(H),K=we(z,V,O)?B.get(z,V,O):-1;if(K<0){X=!1;break}if(K>W)W=K}if(X){if(Y[C]=1,_)_[C]=W}}return{nStuds:A,studHidden:E,studUp:T,underHidden:Y,studsHidden:v,studHideStep:F,underHideStep:_}}function ln(e,t,n){let r=(l)=>n&&l.texPart&&t.parts[l.texPart]?l.texPart:l.part,s=new Map,o=new Map,i=(l)=>{let p=l.colour;if(!p)return String(l.color);let d=o.get(p);if(d!==void 0)return d;let w=t.colorTable?.[l.color],y=w?.hex??t.colors?.[l.color],L=w?Oe({alpha:w.alpha??255,luminance:w.luminance??0,finish:w.finish??{type:"default"}}):"default:op",g=Oe(p);if(d=y&&y.toUpperCase()===p.hex.toUpperCase()&&L===g?String(l.color):p.hex.toUpperCase()+"/"+g,d!==String(l.color))s.set(d,p);return o.set(p,d),d},a=e.map((l)=>({part:r(l),color:i(l),m:l.m,steps:l.steps})),u=a.map((l)=>gt(l.steps)),c=[...new Set(u)].sort(),f=new Map(c.map((l,p)=>[l,p]));return{all:a,stepOf:u.map((l)=>f.get(l)),nSteps:c.length,localColours:s}}function Ae(e,t,n=!0){let r=ln(e,t,n);return an(r.all,t,r.nSteps>1?r.stepOf:void 0)}var Te="https://ldr-demo.vercel.app/cdn/v1/",ve=new Map,Me=new Map;function At(e=Te,t=fetch){let n=ve.get(e);if(!n)n=t(e+"parts.json").then((r)=>{if(!r.ok)throw Error(`ldr: parts CDN index ${r.status} (${e}parts.json)`);return r.json()}),n.catch(()=>ve.delete(e)),ve.set(e,n);return n}var cn=(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"),Ce=(e,t)=>cn(e)?[e[0]+t,e[1],e[2]]:Array.isArray(e)?e.map((n)=>Ce(n,t)):e&&typeof e==="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,Ce(r,t)])):e;function un(e,t={}){let n=[],r=0,s={},o={};for(let p of e){let d=p.buffer;if(!d)throw Error("ldr: mergePacks needs packs from decodePack/loadPack");let w=new DataView(d).getUint32(0,!0),y=new Uint8Array(d,4+w),L=r;n.push(y),r+=y.byteLength;let g=(4-r%4)%4;if(g)n.push(new Uint8Array(g)),r+=g;for(let[m,b]of Object.entries(p.header.parts??{}))if(!(m in s))s[m]=Ce(b,L);for(let[m,b]of Object.entries(p.header.studKinds??{}))if(!(m in o))o[m]=Ce(b,L)}let i=e[0]?.header??{version:1,weld:!0},a=new TextEncoder().encode(JSON.stringify({...i,parts:s,studKinds:o,...t})),u=(4-(4+a.length)%4)%4,c=4+a.length+u,f=new Uint8Array(c+r);new DataView(f.buffer).setUint32(0,a.length+u,!0),f.set(a,4),f.fill(32,4+a.length,c);let l=c;for(let p of n)f.set(p,l),l+=p.byteLength;return xe(f.buffer)}async function fn(e,t={}){e=[...e];try{return await wt(e,t)}catch(n){let r=t.cdn??Te,s=t.fetch??fetch;ve.delete(r);let o=(i,a)=>s(i,{...a,cache:"reload"});try{return await wt(e,{...t,fetch:o})}catch{throw n}}}async function wt(e,t){let n=t.cdn??Te,r=t.fetch??fetch,s=t.gap??16384,o=await At(n,r),i=[...new Set([...e].map(Q))],a=[],u=[];for(let g of i){if(Me.has(n+g))continue;let m=o.parts[g];if(m)u.push({name:g,off:m[0],len:m[1],file:m[2]??0});else a.push(g)}u.sort((g,m)=>g.file-m.file||g.off-m.off);let c=[];for(let g of u){let m=c[c.length-1];if(m&&m.file===g.file&&g.off-m.end<=s)m.end=Math.max(m.end,g.off+g.len),m.items.push(g);else c.push({file:g.file,start:g.off,end:g.off+g.len,items:[g]})}let f=0,l=0,p=0,d=new Map,w=async()=>{while(p<c.length){let g=c[p++],m=d.get(g.file);if(m)m=m.subarray(g.start,g.end);else{let b=await r(new URL(o.archives[g.file],n).href,{headers:{Range:`bytes=${g.start}-${g.end-1}`,"Accept-Encoding":"identity"}});if(!b.ok)throw Error(`ldr: parts CDN ${b.status}`);if(l++,m=new Uint8Array(await b.arrayBuffer()),f+=m.byteLength,b.status===200)d.set(g.file,m),m=m.subarray(g.start,g.end)}for(let b of g.items){let h=ye(m.subarray(b.off-g.start,b.off-g.start+b.len)),P=h.buffer.slice(h.byteOffset,h.byteOffset+h.byteLength);Me.set(n+b.name,xe(P))}}};await Promise.all(Array.from({length:Math.min(t.concurrency??24,c.length)},w));let y=i.filter((g)=>Me.has(n+g)).map((g)=>Me.get(n+g));return{pack:y.length?un(y,{colors:o.colors}):xe(pn(o.colors)),missing:a,requests:l,bytes:f}}function pn(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}function mn(e,t){let n=t.header.parts;if(!n)return 0;let r=0;for(let s of e){let o=n[s.part]?.body?.tris;if(o)r+=o}return r}function hn(e,t,n){let r=0,s=0,o=!1,i=new Set;for(let a of e){let u=a.embedded?t.get(a.part):Q(a.part),c=u?n.parts[u]:void 0;if(!c)continue;if(c[3]!=null)o=!0,r+=c[3];if(!i.has(u))i.add(u),s+=c[1]}return{bodyTris:r,packBytes:s,known:o}}class pe extends Error{code="ldr-budget";bodyTris;packBytes;maxBodyTris;maxPackBytes;constructor(e){let t=[e.maxBodyTris!=null&&e.bodyTris>e.maxBodyTris?`${e.bodyTris} triangles (limit ${e.maxBodyTris})`:"",e.maxPackBytes!=null&&e.packBytes>e.maxPackBytes?`${(e.packBytes/1e6).toFixed(1)} MB parts pack (limit ${(e.maxPackBytes/1e6).toFixed(0)} MB)`:""].filter(Boolean).join(", ");super(`ldr: model exceeds device budget: ${t}`);this.name="BudgetError",this.bodyTris=e.bodyTris,this.packBytes=e.packBytes,this.maxBodyTris=e.maxBodyTris,this.maxPackBytes=e.maxPackBytes}}async function Mt(e,t={}){let n=performance.now(),r=t.fetch??fetch,s=At(t.cdn??Te,r);s.catch(()=>{});let o=t.text?e:await r(e).then(async(h)=>{if(!h.ok)throw Error(`ldr: ${h.status} fetching ${e}`);return Xe(await h.arrayBuffer())}),i=performance.now(),a=t.name??(t.text?"main.ldr":Ze(e)),u=dt(o,a,{looseGeometry:!1,callouts:t.callouts}),c=performance.now();t.onParsed?.(u),await s;let f=bt(o,new Set(u.filter((h)=>h.embedded).map((h)=>h.part)),a),l=(h,P)=>t.maxBodyTris!=null&&h>t.maxBodyTris||t.maxPackBytes!=null&&P>t.maxPackBytes;if(t.maxBodyTris!=null||t.maxPackBytes!=null){let h=hn(u,f,await s);if(l(h.known?h.bodyTris:0,h.packBytes))throw new pe({bodyTris:h.bodyTris,packBytes:h.packBytes,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let{pack:p,missing:d,requests:w,bytes:y}=await fn([...u.filter((h)=>!h.embedded).map((h)=>h.part),...f.values()],t),L=new Map([...f].map(([h,P])=>[P,h])),g=d.map((h)=>L.get(h)??h);for(let[h,P]of f){let A=p.header.parts[P];if(A)p.header.parts[h]=A}let m=performance.now();if(t.maxBodyTris!=null||t.maxPackBytes!=null){let h=p.buffer?.byteLength??p.bytes??0,P=mn(u,p);if(l(P,h))throw new pe({bodyTris:P,packBytes:h,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let b=t.cull?Ae(u,p.header,t.textures!==!1):void 0;return{insts:u,pack:p,missing:g,requests:w,bytes:y,cull:b,timings:{fetchModel:i-n,parse:c-i,parts:m-c,...b?{cull:performance.now()-m}:{}}}}self.onmessage=async(e)=>{let{id:t,source:n,opts:r}=e.data;try{let s=await Mt(n,{...r,cull:!1,onParsed:(f)=>self.postMessage({id:t,insts:f})}),o=s.pack.buffer;if(self.postMessage({id:t,buffer:o,missing:s.missing,requests:s.requests,bytes:s.bytes,timings:s.timings},[o]),!r.cull)return;let i=performance.now(),a=Ae(s.insts,s.pack.header,r.textures!==!1),u=performance.now()-i,c=[];for(let f of[a.studHidden,a.studUp,a.underHidden,a.studHideStep,a.underHideStep])if(f)c.push(f.buffer);self.postMessage({id:t,cull:a,ms:u},c)}catch(s){if(s instanceof pe||s?.code==="ldr-budget")self.postMessage({id:t,phase:"error",error:String(s?.message??s),budget:{bodyTris:s.bodyTris,packBytes:s.packBytes,maxBodyTris:s.maxBodyTris,maxPackBytes:s.maxPackBytes}});else self.postMessage({id:t,phase:"error",error:String(s?.message??s)})}};\n';
|
|
4212
4329
|
|
|
4213
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4330
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/cdn.ts
|
|
4214
4331
|
var worker;
|
|
4215
4332
|
var seq = 0;
|
|
4216
4333
|
var pending = new Map;
|
|
@@ -4323,7 +4440,7 @@ async function loadModel(source, o = {}) {
|
|
|
4323
4440
|
timings: { ...prep.timings, parts: t3 - t0 - prep.timings.fetchModel - prep.timings.parse, build: t4 - t3, total: t4 - t0 }
|
|
4324
4441
|
});
|
|
4325
4442
|
}
|
|
4326
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4443
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/library.ts
|
|
4327
4444
|
import { existsSync, readFileSync } from "fs";
|
|
4328
4445
|
import { join } from "path";
|
|
4329
4446
|
var xf = (m, x, y, z) => [m[3] * x + m[4] * y + m[5] * z + m[0], m[6] * x + m[7] * y + m[8] * z + m[1], m[9] * x + m[10] * y + m[11] * z + m[2]];
|
|
@@ -4577,11 +4694,11 @@ class Library {
|
|
|
4577
4694
|
return insts;
|
|
4578
4695
|
}
|
|
4579
4696
|
}
|
|
4580
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4697
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/build-pack.ts
|
|
4581
4698
|
import fs3 from "node:fs";
|
|
4582
4699
|
import path3 from "node:path";
|
|
4583
4700
|
|
|
4584
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4701
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/resolver.ts
|
|
4585
4702
|
import fs from "node:fs";
|
|
4586
4703
|
import path from "node:path";
|
|
4587
4704
|
var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
|
|
@@ -4853,11 +4970,11 @@ function collectDeps(lib, refs) {
|
|
|
4853
4970
|
return out;
|
|
4854
4971
|
}
|
|
4855
4972
|
|
|
4856
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4973
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/compile.ts
|
|
4857
4974
|
import fs2 from "node:fs";
|
|
4858
4975
|
import path2 from "node:path";
|
|
4859
4976
|
|
|
4860
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4977
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/lod.ts
|
|
4861
4978
|
import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
|
|
4862
4979
|
await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
|
|
4863
4980
|
function reorderMesh(P, N, C, I) {
|
|
@@ -5049,7 +5166,7 @@ function lodChain(P, C, I) {
|
|
|
5049
5166
|
return out;
|
|
5050
5167
|
}
|
|
5051
5168
|
|
|
5052
|
-
// ../../../../../../../tmp/ldr-build-
|
|
5169
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/compile.ts
|
|
5053
5170
|
function loadColors(root) {
|
|
5054
5171
|
const map = new Map;
|
|
5055
5172
|
for (const l of fs2.readFileSync(path2.join(root, "LDConfig.ldr"), "latin1").split(/\r?\n/)) {
|
|
@@ -5145,6 +5262,7 @@ class Compiler {
|
|
|
5145
5262
|
invertNext = false;
|
|
5146
5263
|
if (isTop && separateStuds) {
|
|
5147
5264
|
out.studs.push({ kind: ck2, color: childColor, m: Mc });
|
|
5265
|
+
fullKind.set(out.studs.length - 1, this.lib.resolve(r.name));
|
|
5148
5266
|
growBox(out.bbox, Mc, this.compile(ck2, false).bbox);
|
|
5149
5267
|
continue;
|
|
5150
5268
|
}
|
|
@@ -5191,7 +5309,9 @@ class Compiler {
|
|
|
5191
5309
|
if (!certified)
|
|
5192
5310
|
out.uncertified = true;
|
|
5193
5311
|
};
|
|
5312
|
+
const fullKind = new Map;
|
|
5194
5313
|
walk(key, IDENT, "16", false, "body", 0);
|
|
5314
|
+
seatStuds(out, fullKind, (k) => this.compile(k, false).bbox);
|
|
5195
5315
|
if (this.opts.tex && this.hasTex(key))
|
|
5196
5316
|
this.texPass(key, out, separateStuds, colorOf);
|
|
5197
5317
|
const [x0, y0, z0, x1, y1, z1] = out.bbox;
|
|
@@ -5482,6 +5602,48 @@ function enclosureMask(c) {
|
|
|
5482
5602
|
}
|
|
5483
5603
|
return { nx, nz, bits };
|
|
5484
5604
|
}
|
|
5605
|
+
function seatStuds(out, fullKind, kindBox) {
|
|
5606
|
+
if (!out.studs.length)
|
|
5607
|
+
return;
|
|
5608
|
+
const tris = [out.body.pos, out.under.pos];
|
|
5609
|
+
const covered = (c, up) => {
|
|
5610
|
+
for (const p of tris)
|
|
5611
|
+
for (let i = 0;i < p.length; i += 9) {
|
|
5612
|
+
const ax = p[i], ay = p[i + 1], az = p[i + 2], ux = p[i + 3] - ax, uy = p[i + 4] - ay, uz = p[i + 5] - az, vx = p[i + 6] - ax, vy = p[i + 7] - ay, vz = p[i + 8] - az;
|
|
5613
|
+
const nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx, nl = Math.hypot(nx, ny, nz);
|
|
5614
|
+
if (nl < 0.000000001)
|
|
5615
|
+
continue;
|
|
5616
|
+
if (!out.uncertified && nx * up[0] + ny * up[1] + nz * up[2] <= 0)
|
|
5617
|
+
continue;
|
|
5618
|
+
const wx = c[0] - ax, wy = c[1] - ay, wz = c[2] - az;
|
|
5619
|
+
if (Math.abs((wx * nx + wy * ny + wz * nz) / nl) > 0.05)
|
|
5620
|
+
continue;
|
|
5621
|
+
const uu = ux * ux + uy * uy + uz * uz, vv = vx * vx + vy * vy + vz * vz, uv = ux * vx + uy * vy + uz * vz, wu = wx * ux + wy * uy + wz * uz, wv = wx * vx + wy * vy + wz * vz;
|
|
5622
|
+
const d = uv * uv - uu * vv, s = (uv * wv - vv * wu) / d, t = (uv * wu - uu * wv) / d, e = 0.0001;
|
|
5623
|
+
if (s >= -e && t >= -e && s + t <= 1 + e)
|
|
5624
|
+
return true;
|
|
5625
|
+
}
|
|
5626
|
+
return false;
|
|
5627
|
+
};
|
|
5628
|
+
out.studs.forEach((s, i) => {
|
|
5629
|
+
const full = fullKind.get(i);
|
|
5630
|
+
if (!full || full === s.kind)
|
|
5631
|
+
return;
|
|
5632
|
+
const b = kindBox(s.kind), r = 0.975 * Math.min(b[3] - b[0], b[5] - b[2]) / 2, cx = (b[0] + b[3]) / 2, cz = (b[2] + b[5]) / 2;
|
|
5633
|
+
const up = [-s.m[4], -s.m[7], -s.m[10]];
|
|
5634
|
+
if (!(r > 0) || !covered(xf2(s.m, [cx, 0, cz]), up)) {
|
|
5635
|
+
s.kind = full;
|
|
5636
|
+
return;
|
|
5637
|
+
}
|
|
5638
|
+
for (let k = 0;k < 8; k++) {
|
|
5639
|
+
const a = (k + 0.5) * Math.PI / 4;
|
|
5640
|
+
if (!covered(xf2(s.m, [cx + r * Math.cos(a), 0, cz + r * Math.sin(a)]), up)) {
|
|
5641
|
+
s.kind = full;
|
|
5642
|
+
return;
|
|
5643
|
+
}
|
|
5644
|
+
}
|
|
5645
|
+
});
|
|
5646
|
+
}
|
|
5485
5647
|
function grow(b, p) {
|
|
5486
5648
|
for (let i = 0;i < 3; i++) {
|
|
5487
5649
|
if (p[i] < b[i])
|
|
@@ -5686,7 +5848,10 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
5686
5848
|
return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
|
|
5687
5849
|
}
|
|
5688
5850
|
|
|
5689
|
-
// ../../../../../../../tmp/ldr-build-
|
|
5851
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/build-pack.ts
|
|
5852
|
+
function packCompilerOpts(o) {
|
|
5853
|
+
return { studs: o.studs ?? "low", prims: o.primitives ?? "full", weld: o.weld ?? true, separateStuds: true, cond: !!o.cond, tex: !!o.textures };
|
|
5854
|
+
}
|
|
5690
5855
|
function buildPack(o) {
|
|
5691
5856
|
const lib = new Library2(o.ldrawRoot);
|
|
5692
5857
|
const refs = new Map;
|
|
@@ -5720,7 +5885,7 @@ function buildPack(o) {
|
|
|
5720
5885
|
if (lib.isPart(k) && /\.dat$/.test(k))
|
|
5721
5886
|
refs.set(k.slice(6), k);
|
|
5722
5887
|
}
|
|
5723
|
-
const comp = new Compiler(lib,
|
|
5888
|
+
const comp = new Compiler(lib, packCompilerOpts(o));
|
|
5724
5889
|
const parts = new Map, kinds = new Map;
|
|
5725
5890
|
let n = 0;
|
|
5726
5891
|
for (const [ref, key] of refs) {
|
|
@@ -5753,7 +5918,7 @@ function buildPack(o) {
|
|
|
5753
5918
|
const warnings = [...lib.conflicts].map((n) => `${n}: defined differently by two models; the first definition is used`);
|
|
5754
5919
|
return { data: encodePack(parts, kinds, comp.opts.weld, extra, { texture, lod: o.lod !== false, reorder: !!o.reorder }), parts: parts.size, studKinds: kinds.size, missing: [...missing], ...warnings.length ? { warnings } : {} };
|
|
5755
5920
|
}
|
|
5756
|
-
// ../../../../../../../tmp/ldr-build-
|
|
5921
|
+
// ../../../../../../../tmp/ldr-build-3WYmlh/src/node/promote.ts
|
|
5757
5922
|
var GEOM = /^\s*[2-5]\s/;
|
|
5758
5923
|
var REF = /^\s*1\s/;
|
|
5759
5924
|
var FILE = /^\s*0\s+FILE\s+(.+?)\s*$/i;
|
|
@@ -6055,6 +6220,7 @@ export {
|
|
|
6055
6220
|
mul,
|
|
6056
6221
|
namedColorCode,
|
|
6057
6222
|
norm,
|
|
6223
|
+
packCompilerOpts,
|
|
6058
6224
|
packTexture,
|
|
6059
6225
|
parse,
|
|
6060
6226
|
parseColor,
|
package/dist/scene.d.ts
CHANGED
|
@@ -108,10 +108,23 @@ export interface LdrObject {
|
|
|
108
108
|
setSide(side: "front" | "double"): void;
|
|
109
109
|
/** Turn distance LOD on/off (off = full detail and edges everywhere). Only has an effect if the object was built with `lod` (default). */
|
|
110
110
|
setLod(on: boolean): void;
|
|
111
|
+
/** Ghost overlay of the upcoming steps (like the LEGO Builder app): while a step is shown with `setStep`, the parts of later steps
|
|
112
|
+
* are drawn as a faint, whitish, depth-tested ghost of the finished model; built parts draw as usual. Built lazily (a second,
|
|
113
|
+
* edge-free copy of the scene with the steps reversed, so its step-aware culling matches the ghosted set) the first time it is
|
|
114
|
+
* needed, with yields like the progressive build; resolves when it is ready. No effect on single-step models. */
|
|
115
|
+
setGhost(on: boolean, options?: GhostOptions): Promise<void>;
|
|
111
116
|
/** Bounding box in the object's parent space. */
|
|
112
117
|
getBox(target?: THREE.Box3): THREE.Box3;
|
|
113
118
|
dispose(): void;
|
|
114
119
|
}
|
|
120
|
+
export interface GhostOptions {
|
|
121
|
+
/** Ghost opacity, 0-1. Default 0.2. */
|
|
122
|
+
opacity?: number;
|
|
123
|
+
/** Ghost tint (mixed with each part's own colour by `whiten`). Default white. */
|
|
124
|
+
color?: THREE.ColorRepresentation;
|
|
125
|
+
/** How far each part's colour is pushed towards `color`, 0-1. Default 0.75. */
|
|
126
|
+
whiten?: number;
|
|
127
|
+
}
|
|
115
128
|
/**
|
|
116
129
|
* Build a three.js object for a flattened model using a parts pack.
|
|
117
130
|
* Instances whose part is not in the pack are skipped and listed in `stats.missing`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ldr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.1",
|
|
4
4
|
"description": "High-performance LEGO (LDraw) rendering for three.js: instanced parts packs, hidden stud/tube culling, low-detail studs, indexed edges, build steps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Evan Bacon",
|