ldr 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/cli.js +64 -17
- package/dist/index.d.ts +2 -2
- package/dist/index.js +78 -26
- package/dist/node/compile.d.ts +4 -2
- package/dist/node/index.js +144 -42
- package/dist/node/library.d.ts +2 -1
- package/dist/render.d.ts +14 -4
- package/dist/scene.d.ts +3 -1
- package/dist/spec.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,7 +117,7 @@ MPD-embedded parts, such as Studio/OMR unofficial parts or stickers, become part
|
|
|
117
117
|
| `createLdrObject(instances, pack, options?) → LdrObject` | High-level three.js object (see below). |
|
|
118
118
|
| `createInstancedEdges(pos, instancedMesh, material?)` | Welded, indexed edge lines that share an `InstancedMesh`'s instance matrices. |
|
|
119
119
|
| `conditionalLines(pack, entry, which?)` / `createInstancedConditionalEdges(cond, instancedMesh, material?)` / `conditionalLineVisible` | Type-5 conditional lines from a `cond` pack. A vertex shader keeps a segment only where both control points project to the same side of the line. |
|
|
120
|
-
| `makeTexturedMaterial(side, texture, wrapU?)` / `packTexture(pack, i)` | Printed and sticker parts from a `textures` pack: a UV material and the decoded embedded PNG. |
|
|
120
|
+
| `makeTexturedMaterial(side, texture, wrapU?, base?, gloss?)` / `packTexture(pack, i, data?)` / `pngHasAlpha(bytes)` | Printed and sticker parts from a `textures` pack: a UV material and the decoded embedded PNG. `gloss` (`{ map, alpha }`, a `GLOSSMAP` PNG decoded with `data = true`) adds specularity where its alpha is set (its grey value if the PNG has no alpha channel). |
|
|
121
121
|
| `buildLdrScene`, `computeCulling`, `cullCore`, `makeMaterial` | Low-level renderer used by the benchmarks. `cullCore(instances, header, steps?)` is the typed-array culling core (with `steps`, also the step at which each stud and underside becomes hidden). |
|
|
122
122
|
|
|
123
123
|
`LdrObjectOptions`:
|
|
@@ -131,7 +131,7 @@ MPD-embedded parts, such as Studio/OMR unofficial parts or stickers, become part
|
|
|
131
131
|
| `material` | `"plastic"` | `"plastic"` is `MeshPhysicalMaterial` with clearcoat; `"standard"` is `MeshStandardMaterial`, the cheapest option. |
|
|
132
132
|
| `conditionalLines` | `true` | Conditional (silhouette) lines. Only takes effect with `cond` packs, and follows `edges`. |
|
|
133
133
|
| `conditionalStudLines` | `true` | Conditional lines on studs. `false` roughly halves the conditional-line cost on large scenes. |
|
|
134
|
-
| `textures` | `true` | Renders `!TEXMAP` images from `textures` packs; `false` draws the FALLBACK geometry. `object.texturesReady` resolves once the images are decoded. |
|
|
134
|
+
| `textures` | `true` | Renders `!TEXMAP` images from `textures` packs, with `GLOSSMAP` images as extra gloss (lower roughness, more specular) on the printed area; `false` draws the FALLBACK geometry. `object.texturesReady` resolves once the images are decoded. |
|
|
135
135
|
| `colors` | pack table | Colour override: a `Map`, a record, or `(code) => color`. |
|
|
136
136
|
| `fallbackColor` | `#A0A5A9` | Colour used for unknown codes. |
|
|
137
137
|
| `ldrawSpace` | `false` | `true` keeps native LDraw space (-Y up). |
|
|
@@ -143,7 +143,7 @@ MPD-embedded parts, such as Studio/OMR unofficial parts or stickers, become part
|
|
|
143
143
|
| `lodEdgeMinPx` | `0.15` | LOD: draw only edge segments at least this many pixels long on screen. `0` = every segment. |
|
|
144
144
|
| `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. |
|
|
145
145
|
|
|
146
|
-
`LdrObject`: `object`, `stats` (`instances`, `drawn`, `missing[]`, `studsHidden/Total`, `undersHidden/Total`, `buildMs`, `condBatches`, `texBatches`, `textures`, `clusters`), `stepCount`, `stepViews`, `texturesReady`, `setStep(n | null)`, `setEdges(on)`, `setConditionalLines(on)`, `setCulling(studs, undersides)`, `setSide(side)`, `setLod(on)`, `getBox(target?)`, `dispose()`.
|
|
146
|
+
`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
147
|
|
|
148
148
|
`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.
|
|
149
149
|
|
|
@@ -163,7 +163,7 @@ Everything above, plus:
|
|
|
163
163
|
| export | description |
|
|
164
164
|
|---|---|
|
|
165
165
|
| `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`. |
|
|
166
|
-
| `Library(root, unofficialRoot?)` | Filesystem LDraw resolver: `where`, `flatten`, `mesh`, `colors`, `texture`, `register`. Handles case-insensitive lookup and `~Moved to` aliases. |
|
|
166
|
+
| `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. |
|
|
167
167
|
| `Compiler`, `encodePack`, `writePack`, `loadColors` | Lower-level pack compiler. |
|
|
168
168
|
| `ResolverLibrary`, `splitModel`, `flattenWithLibrary`, `collectDeps` | The resolver that `buildPack` uses. |
|
|
169
169
|
|
|
@@ -207,7 +207,7 @@ Reproduce: `cd bench && bun run setup && bun run perf` (regression gate) or `bun
|
|
|
207
207
|
- MPD: `0 FILE` / `0 NOFILE`, and `0 !DATA` (base64 PNGs). An MPD file is a part or a model by its `!LDRAW_ORG` type, otherwise by whether it has its own geometry. Embedded parts override library parts.
|
|
208
208
|
- Geometry drawn directly in model files (type 2–5 lines outside parts), on by default.
|
|
209
209
|
- `0 STEP`, nested submodel step sequencing, `0 ROTSTEP` (`REL`/`ADD`/`ABS`/`END`), and `0 BUFEXCHG`.
|
|
210
|
-
- `!TEXMAP` `START`/`NEXT`/`FALLBACK`/`END`, with `PLANAR`, `CYLINDRICAL` and `SPHERICAL` projections (orientation matches LDView), and model-level `!TEXMAP` around part references.
|
|
210
|
+
- `!TEXMAP` `START`/`NEXT`/`FALLBACK`/`END`, with `PLANAR`, `CYLINDRICAL` and `SPHERICAL` projections (orientation matches LDView), `GLOSSMAP` (alpha = gloss amount, same UVs), and model-level `!TEXMAP` around part references.
|
|
211
211
|
- Colours: LDConfig `!COLOUR`, edge colours, main/edge colour inheritance (16/24), and direct colours (`0x2RRGGBB`).
|
|
212
212
|
- Case-insensitive, backslash-normalized file lookup; `~Moved to` alias parts.
|
|
213
213
|
|
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-Q8idpr/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-Q8idpr/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-Q8idpr/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-Q8idpr/src/spec.ts
|
|
16
16
|
var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
17
17
|
function parseColor(tok) {
|
|
18
18
|
if (/^0x/i.test(tok))
|
|
@@ -705,7 +705,7 @@ function fileStepViews(f) {
|
|
|
705
705
|
return out;
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
-
// ../../../../../../../tmp/ldr-build-
|
|
708
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/model.ts
|
|
709
709
|
var CALLOUT_END = 999999;
|
|
710
710
|
var stepKey = (steps) => steps.map((x) => String(x).padStart(6, "0")).join(".") + "~";
|
|
711
711
|
function flatten(doc, opts = {}) {
|
|
@@ -1055,7 +1055,7 @@ function parseLDConfig(text) {
|
|
|
1055
1055
|
return out;
|
|
1056
1056
|
}
|
|
1057
1057
|
|
|
1058
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1058
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/resolver.ts
|
|
1059
1059
|
var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
|
|
1060
1060
|
var UNDER_STUD_RE = /^(stud3|stud3a|stud4.*|stud12|stud16.*|stud18a)\.dat$/i;
|
|
1061
1061
|
var norm2 = (ref) => ref.trim().replace(/\\/g, "/").toLowerCase();
|
|
@@ -1325,11 +1325,11 @@ function collectDeps(lib, refs) {
|
|
|
1325
1325
|
return out;
|
|
1326
1326
|
}
|
|
1327
1327
|
|
|
1328
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1328
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/compile.ts
|
|
1329
1329
|
import fs2 from "node:fs";
|
|
1330
1330
|
import path2 from "node:path";
|
|
1331
1331
|
|
|
1332
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1332
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/lod.ts
|
|
1333
1333
|
import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
|
|
1334
1334
|
await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
|
|
1335
1335
|
function reorderMesh(P, N, C, I) {
|
|
@@ -1521,7 +1521,7 @@ function lodChain(P, C, I) {
|
|
|
1521
1521
|
return out;
|
|
1522
1522
|
}
|
|
1523
1523
|
|
|
1524
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1524
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/compile.ts
|
|
1525
1525
|
function loadColors(root) {
|
|
1526
1526
|
const map = new Map;
|
|
1527
1527
|
for (const l of fs2.readFileSync(path2.join(root, "LDConfig.ldr"), "latin1").split(/\r?\n/)) {
|
|
@@ -1670,6 +1670,21 @@ class Compiler {
|
|
|
1670
1670
|
az1 = Math.max(az1, b.pos[i + 2]);
|
|
1671
1671
|
}
|
|
1672
1672
|
out.fullBottom = isFinite(x0) && ax0 <= x0 + 0.5 && ax1 >= x1 - 0.5 && az0 <= z0 + 0.5 && az1 >= z1 - 0.5;
|
|
1673
|
+
if (out.under.pos.length && !underEnclosed(out)) {
|
|
1674
|
+
const add = (d, s) => {
|
|
1675
|
+
for (const v of s)
|
|
1676
|
+
d.push(v);
|
|
1677
|
+
};
|
|
1678
|
+
for (const b of out.tbody ? [out.body, out.tbody] : [out.body]) {
|
|
1679
|
+
add(b.pos, out.under.pos);
|
|
1680
|
+
add(b.col, out.under.col);
|
|
1681
|
+
}
|
|
1682
|
+
if (out.cond && out.condUnder) {
|
|
1683
|
+
add(out.cond, out.condUnder);
|
|
1684
|
+
out.condUnder.length = 0;
|
|
1685
|
+
}
|
|
1686
|
+
out.under = { pos: [], col: [] };
|
|
1687
|
+
}
|
|
1673
1688
|
if (separateStuds && isFinite(x0))
|
|
1674
1689
|
out.bottomMask = enclosureMask(out);
|
|
1675
1690
|
this.cache.set(ck, out);
|
|
@@ -1811,9 +1826,10 @@ class Compiler {
|
|
|
1811
1826
|
order = n === 3 ? [0, 2, 1] : [0, 2, 1, 0, 3, 2];
|
|
1812
1827
|
const rgba = colorOf(code);
|
|
1813
1828
|
if (tex) {
|
|
1814
|
-
|
|
1829
|
+
const tk = tex.glossmap ? tex.texture + "\x00" + tex.glossmap : tex.texture;
|
|
1830
|
+
let b = texb.get(tk);
|
|
1815
1831
|
if (!b)
|
|
1816
|
-
texb.set(
|
|
1832
|
+
texb.set(tk, b = { pos: [], col: [], uv: [], texture: tex.texture, ...tex.glossmap ? { glossmap: tex.glossmap } : {} });
|
|
1817
1833
|
if (Math.abs(tex.a ?? 0) >= 360)
|
|
1818
1834
|
b.wrapU = true;
|
|
1819
1835
|
for (let k = 0;k < order.length; k += 3) {
|
|
@@ -1839,6 +1855,33 @@ class Compiler {
|
|
|
1839
1855
|
}
|
|
1840
1856
|
}
|
|
1841
1857
|
}
|
|
1858
|
+
function underEnclosed(c) {
|
|
1859
|
+
const u = c.under.pos;
|
|
1860
|
+
let uy0 = Infinity, uy1 = -Infinity, ux0 = Infinity, ux1 = -Infinity, uz0 = Infinity, uz1 = -Infinity;
|
|
1861
|
+
for (let i = 0;i < u.length; i += 3) {
|
|
1862
|
+
ux0 = Math.min(ux0, u[i]);
|
|
1863
|
+
ux1 = Math.max(ux1, u[i]);
|
|
1864
|
+
uy0 = Math.min(uy0, u[i + 1]);
|
|
1865
|
+
uy1 = Math.max(uy1, u[i + 1]);
|
|
1866
|
+
uz0 = Math.min(uz0, u[i + 2]);
|
|
1867
|
+
uz1 = Math.max(uz1, u[i + 2]);
|
|
1868
|
+
}
|
|
1869
|
+
const lo = uy0 + Math.min(0.5, (uy1 - uy0) / 4), hi = uy1 - Math.min(0.5, (uy1 - uy0) / 4);
|
|
1870
|
+
const p = c.body.pos;
|
|
1871
|
+
let bx0 = Infinity, bx1 = -Infinity, bz0 = Infinity, bz1 = -Infinity;
|
|
1872
|
+
for (let i = 0;i < p.length; i += 9) {
|
|
1873
|
+
const y0 = Math.min(p[i + 1], p[i + 4], p[i + 7]), y1 = Math.max(p[i + 1], p[i + 4], p[i + 7]);
|
|
1874
|
+
if (y1 <= lo || y0 >= hi)
|
|
1875
|
+
continue;
|
|
1876
|
+
for (let k = i;k < i + 9; k += 3) {
|
|
1877
|
+
bx0 = Math.min(bx0, p[k]);
|
|
1878
|
+
bx1 = Math.max(bx1, p[k]);
|
|
1879
|
+
bz0 = Math.min(bz0, p[k + 2]);
|
|
1880
|
+
bz1 = Math.max(bz1, p[k + 2]);
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
return bx0 < ux0 + 0.01 && bx1 > ux1 - 0.01 && bz0 < uz0 + 0.01 && bz1 > uz1 - 0.01;
|
|
1884
|
+
}
|
|
1842
1885
|
function enclosureMask(c) {
|
|
1843
1886
|
const [x0, , z0, x1, y1, z1] = c.bbox;
|
|
1844
1887
|
const nx = Math.round((x1 - x0) / 20), nz = Math.round((z1 - z0) / 20);
|
|
@@ -2074,11 +2117,15 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
2074
2117
|
const encTex = (c) => {
|
|
2075
2118
|
if (!c.texb)
|
|
2076
2119
|
return {};
|
|
2120
|
+
const idx = (name) => {
|
|
2121
|
+
let i = texNames.indexOf(name);
|
|
2122
|
+
if (i < 0)
|
|
2123
|
+
i = texNames.push(name) - 1;
|
|
2124
|
+
return i;
|
|
2125
|
+
};
|
|
2077
2126
|
const tex = [...c.texb].map(([name, b]) => {
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
t = texNames.push(name) - 1;
|
|
2081
|
-
return { t, ...b.wrapU ? { wrapU: true } : {}, ...texBucket(b) };
|
|
2127
|
+
const t = idx(b.texture ?? name);
|
|
2128
|
+
return { t, ...b.glossmap ? { g: idx(b.glossmap) } : {}, ...b.wrapU ? { wrapU: true } : {}, ...texBucket(b) };
|
|
2082
2129
|
});
|
|
2083
2130
|
return { tbody: bucket(c.tbody), tex };
|
|
2084
2131
|
};
|
|
@@ -2104,7 +2151,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
2104
2151
|
return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
|
|
2105
2152
|
}
|
|
2106
2153
|
|
|
2107
|
-
// ../../../../../../../tmp/ldr-build-
|
|
2154
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/build-pack.ts
|
|
2108
2155
|
function buildPack(o) {
|
|
2109
2156
|
const lib = new Library(o.ldrawRoot);
|
|
2110
2157
|
const refs = new Map;
|
|
@@ -2172,7 +2219,7 @@ function buildPack(o) {
|
|
|
2172
2219
|
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 } : {} };
|
|
2173
2220
|
}
|
|
2174
2221
|
|
|
2175
|
-
// ../../../../../../../tmp/ldr-build-
|
|
2222
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/cli.ts
|
|
2176
2223
|
var HELP = `ldr pack — build a parts pack for the ldr three.js renderer
|
|
2177
2224
|
|
|
2178
2225
|
Usage:
|
package/dist/index.d.ts
CHANGED
|
@@ -4,9 +4,9 @@ export { flatten, parseModel, sequenceSteps, stepKey, parseLDConfig, parseColour
|
|
|
4
4
|
export { planStepViews, isolateMask, viewDir, instanceBoxes, MIN_VIS, REORIENT } from "./instructions.js";
|
|
5
5
|
export type { StepCameraView, StepCameraOptions, Vec3 } from "./instructions.js";
|
|
6
6
|
export type { PartInstance, FlattenOptions, LDrawColor, LDrawFinish, LDrawFinishType, LDrawMaterialGrain, ColourSurface } from "./model.js";
|
|
7
|
-
export { loadPack, decodePack, buildLdrScene, buildLdrSceneAsync, makeMaterial, makeFinishMaterial, createInstancedEdges, computeCulling, cullCore, forEachStud, conditionalLines, createInstancedConditionalEdges, conditionalLineVisible, warmPackGeometry } from "./render.js";
|
|
7
|
+
export { loadPack, decodePack, buildLdrScene, buildLdrSceneAsync, makeMaterial, makeFinishMaterial, createInstancedEdges, computeCulling, cullCore, forEachStud, conditionalLines, createInstancedConditionalEdges, conditionalLineVisible, warmPackGeometry, makeTexturedMaterial, packTexture, pngHasAlpha } from "./render.js";
|
|
8
8
|
export { precomputeCull, sceneInstances } from "./cull.js";
|
|
9
|
-
export type { Pack, LdrParams, Inst, CullResult, BuildLdrSceneAsyncOptions } from "./render.js";
|
|
9
|
+
export type { Pack, LdrParams, Inst, CullResult, BuildLdrSceneAsyncOptions, GlossMap } from "./render.js";
|
|
10
10
|
export { createLdrObject, createLdrObjectAsync } from "./scene.js";
|
|
11
11
|
export type { LdrObject, LdrObjectOptions, LdrStats, ColorSource } from "./scene.js";
|
|
12
12
|
export { decompressPack, decodeModelText, modelFileName } from "./pack-io.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/spec.ts
|
|
2
2
|
var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
3
3
|
function parseColor(tok) {
|
|
4
4
|
if (/^0x/i.test(tok))
|
|
@@ -689,7 +689,7 @@ function fileStepViews(f) {
|
|
|
689
689
|
viewMemo.set(f, out);
|
|
690
690
|
return out;
|
|
691
691
|
}
|
|
692
|
-
// ../../../../../../../tmp/ldr-build-
|
|
692
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/model.ts
|
|
693
693
|
var CALLOUT_END = 999999;
|
|
694
694
|
var stepKey = (steps) => steps.map((x) => String(x).padStart(6, "0")).join(".") + "~";
|
|
695
695
|
function flatten(doc, opts = {}) {
|
|
@@ -1038,7 +1038,7 @@ function parseLDConfig(text) {
|
|
|
1038
1038
|
}
|
|
1039
1039
|
return out;
|
|
1040
1040
|
}
|
|
1041
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1041
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/instructions.ts
|
|
1042
1042
|
var MIN_VIS = 0.5;
|
|
1043
1043
|
var REORIENT = 0.35;
|
|
1044
1044
|
var deg = Math.PI / 180;
|
|
@@ -1406,10 +1406,10 @@ function planStepViews(insts, parts, stepOf, nSteps, o = {}) {
|
|
|
1406
1406
|
}
|
|
1407
1407
|
};
|
|
1408
1408
|
}
|
|
1409
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1409
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/render.ts
|
|
1410
1410
|
import * as THREE from "three";
|
|
1411
1411
|
|
|
1412
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1412
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/pack-io.ts
|
|
1413
1413
|
import { decompress } from "fzstd";
|
|
1414
1414
|
async function decompressPack(data) {
|
|
1415
1415
|
const u = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
@@ -1432,7 +1432,7 @@ function decodePack(buf) {
|
|
|
1432
1432
|
return { header, arr, bytes: buf.byteLength, buffer: buf };
|
|
1433
1433
|
}
|
|
1434
1434
|
|
|
1435
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1435
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/cull.ts
|
|
1436
1436
|
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;
|
|
1437
1437
|
var prepCache = new WeakMap;
|
|
1438
1438
|
function prepPart(H, part) {
|
|
@@ -1749,7 +1749,7 @@ function precomputeCull(instances, H, useTex = true) {
|
|
|
1749
1749
|
return cullCore(s.all, H, s.nSteps > 1 ? s.stepOf : undefined);
|
|
1750
1750
|
}
|
|
1751
1751
|
|
|
1752
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1752
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/render.ts
|
|
1753
1753
|
async function loadPack(url) {
|
|
1754
1754
|
const res = await fetch(url);
|
|
1755
1755
|
if (!res.ok)
|
|
@@ -1900,7 +1900,7 @@ function makeFinishMaterial(side, surface) {
|
|
|
1900
1900
|
m.userData.ldrSurface = surface;
|
|
1901
1901
|
return m;
|
|
1902
1902
|
}
|
|
1903
|
-
function makeTexturedMaterial(side, map, wrapU = false, baseMat) {
|
|
1903
|
+
function makeTexturedMaterial(side, map, wrapU = false, baseMat, gloss) {
|
|
1904
1904
|
const surface = baseMat?.userData?.ldrSurface ?? colourSurface({ alpha: 255, luminance: 0, finish: { type: "default" } });
|
|
1905
1905
|
const m = makeFinishMaterial(side, surface);
|
|
1906
1906
|
const prev = m.onBeforeCompile;
|
|
@@ -1912,20 +1912,48 @@ function makeTexturedMaterial(side, map, wrapU = false, baseMat) {
|
|
|
1912
1912
|
sh.vertexShader = `attribute vec2 ldrUV; varying vec2 vLdrUV;
|
|
1913
1913
|
` + sh.vertexShader.replace("#include <uv_vertex>", `#include <uv_vertex>
|
|
1914
1914
|
vLdrUV = ldrUV;`);
|
|
1915
|
-
|
|
1915
|
+
let fs = `uniform sampler2D ldrMap; uniform int ldrWrapU; varying vec2 vLdrUV;
|
|
1916
1916
|
` + sh.fragmentShader.replace("#include <color_fragment>", `#include <color_fragment>
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1917
|
+
vec2 ldrUv = vec2(ldrWrapU == 1 ? fract(vLdrUV.x) : vLdrUV.x, vLdrUV.y);
|
|
1918
|
+
float ldrInside = step(0.0, ldrUv.x) * step(ldrUv.x, 1.0) * step(0.0, ldrUv.y) * step(ldrUv.y, 1.0);
|
|
1919
|
+
{ vec4 t = texture2D(ldrMap, ldrUv); diffuseColor.rgb = mix(diffuseColor.rgb, t.rgb, t.a * ldrInside); }`);
|
|
1920
|
+
if (gloss) {
|
|
1921
|
+
sh.uniforms.ldrGlossMap = { value: gloss.map };
|
|
1922
|
+
sh.uniforms.ldrGlossA = { value: gloss.alpha ? 1 : 0 };
|
|
1923
|
+
fs = `uniform sampler2D ldrGlossMap; uniform float ldrGlossA;
|
|
1924
|
+
` + fs.replace("#include <roughnessmap_fragment>", `#include <roughnessmap_fragment>
|
|
1925
|
+
vec4 ldrG = texture2D(ldrGlossMap, ldrUv); float ldrGloss = mix(ldrG.r, ldrG.a, ldrGlossA) * ldrInside;
|
|
1926
|
+
roughnessFactor = mix(roughnessFactor, 0.08, ldrGloss);`).replace("#include <lights_fragment_end>", `#include <lights_fragment_end>
|
|
1927
|
+
reflectedLight.directSpecular *= 1.0 + 0.5 * ldrGloss; reflectedLight.indirectSpecular *= 1.0 + 0.5 * ldrGloss;`);
|
|
1928
|
+
}
|
|
1929
|
+
sh.fragmentShader = fs;
|
|
1920
1930
|
};
|
|
1921
|
-
m.customProgramCacheKey = () => "ldrColorTex|" + baseKey;
|
|
1931
|
+
m.customProgramCacheKey = () => "ldrColorTex|" + baseKey + (gloss ? "|g" : "");
|
|
1922
1932
|
m.userData.ldrMap = map;
|
|
1933
|
+
if (gloss)
|
|
1934
|
+
m.userData.ldrGloss = gloss;
|
|
1923
1935
|
return m;
|
|
1924
1936
|
}
|
|
1925
|
-
function
|
|
1937
|
+
function pngHasAlpha(b) {
|
|
1938
|
+
if (b.length < 33 || b[0] !== 137 || b[1] !== 80 || b[2] !== 78 || b[3] !== 71)
|
|
1939
|
+
return false;
|
|
1940
|
+
const type = b[25];
|
|
1941
|
+
if (type === 4 || type === 6)
|
|
1942
|
+
return true;
|
|
1943
|
+
for (let o = 8;o + 8 <= b.length; ) {
|
|
1944
|
+
const len = (b[o] << 24 | b[o + 1] << 16 | b[o + 2] << 8 | b[o + 3]) >>> 0, t = String.fromCharCode(b[o + 4], b[o + 5], b[o + 6], b[o + 7]);
|
|
1945
|
+
if (t === "tRNS")
|
|
1946
|
+
return true;
|
|
1947
|
+
if (t === "IDAT" || t === "IEND")
|
|
1948
|
+
return false;
|
|
1949
|
+
o += 12 + len;
|
|
1950
|
+
}
|
|
1951
|
+
return false;
|
|
1952
|
+
}
|
|
1953
|
+
function packTexture(pack, i, data = false) {
|
|
1926
1954
|
const t = new THREE.Texture;
|
|
1927
1955
|
t.flipY = false;
|
|
1928
|
-
t.colorSpace = THREE.SRGBColorSpace;
|
|
1956
|
+
t.colorSpace = data ? THREE.NoColorSpace : THREE.SRGBColorSpace;
|
|
1929
1957
|
t.wrapS = t.wrapT = THREE.ClampToEdgeWrapping;
|
|
1930
1958
|
const e = pack.header.textures?.[i];
|
|
1931
1959
|
const bytes = e?.data ? pack.arr(e.data) : null;
|
|
@@ -2713,10 +2741,29 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
|
|
|
2713
2741
|
const texCache = new Map;
|
|
2714
2742
|
const texMats = new Map;
|
|
2715
2743
|
const pending = [];
|
|
2716
|
-
const
|
|
2744
|
+
const glossCache = new Map;
|
|
2745
|
+
const glossOf = (g) => {
|
|
2746
|
+
if (g === undefined)
|
|
2747
|
+
return;
|
|
2748
|
+
let gm = glossCache.get(g);
|
|
2749
|
+
if (gm === undefined) {
|
|
2750
|
+
const e = H.textures?.[g];
|
|
2751
|
+
const bytes = e?.data ? pack.arr(e.data) : null;
|
|
2752
|
+
if (bytes) {
|
|
2753
|
+
const r = packTexture(pack, g, true);
|
|
2754
|
+
pending.push(r.ready);
|
|
2755
|
+
gm = { map: r.texture, alpha: pngHasAlpha(bytes) };
|
|
2756
|
+
} else
|
|
2757
|
+
gm = null;
|
|
2758
|
+
glossCache.set(g, gm);
|
|
2759
|
+
}
|
|
2760
|
+
return gm ?? undefined;
|
|
2761
|
+
};
|
|
2762
|
+
const texMat = (t, base, wrapU, g) => {
|
|
2717
2763
|
const role = base.userData?.ldrSideRole ?? (base.side === THREE.BackSide ? "B" : base.side === THREE.DoubleSide ? "D" : "F");
|
|
2718
2764
|
const fin = base.userData?.ldrFinish ?? "default";
|
|
2719
|
-
const
|
|
2765
|
+
const gloss = glossOf(g);
|
|
2766
|
+
const k = t + ":" + role + ":" + fin + ":" + (wrapU ? 1 : 0) + (gloss ? ":g" + g : "");
|
|
2720
2767
|
let m = texMats.get(k);
|
|
2721
2768
|
if (!m) {
|
|
2722
2769
|
let tx = texCache.get(t);
|
|
@@ -2726,7 +2773,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
|
|
|
2726
2773
|
pending.push(r.ready);
|
|
2727
2774
|
texCache.set(t, tx);
|
|
2728
2775
|
}
|
|
2729
|
-
texMats.set(k, m = makeTexturedMaterial(base.side, tx, wrapU, base));
|
|
2776
|
+
texMats.set(k, m = makeTexturedMaterial(base.side, tx, wrapU, base, gloss));
|
|
2730
2777
|
}
|
|
2731
2778
|
return m;
|
|
2732
2779
|
};
|
|
@@ -2795,7 +2842,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
|
|
|
2795
2842
|
if (textured)
|
|
2796
2843
|
for (const tb of p.tex) {
|
|
2797
2844
|
const gg = geom(tb, arr);
|
|
2798
|
-
const im = newIM(gg, texMat(tb.t, mat, !!tb.wrapU), ids.length);
|
|
2845
|
+
const im = newIM(gg, texMat(tb.t, mat, !!tb.wrapU, tb.g), ids.length);
|
|
2799
2846
|
texBatches++;
|
|
2800
2847
|
lv0.push(im);
|
|
2801
2848
|
if (bodyIm) {
|
|
@@ -3209,6 +3256,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
|
|
|
3209
3256
|
stats.condBatches = condObjs.length;
|
|
3210
3257
|
stats.texBatches = texBatches;
|
|
3211
3258
|
stats.textures = texCache.size;
|
|
3259
|
+
stats.glossmaps = [...glossCache.values()].filter(Boolean).length;
|
|
3212
3260
|
stats.clusters = root.clusters.length;
|
|
3213
3261
|
const texturesReady = Promise.all(pending).then(() => {});
|
|
3214
3262
|
let stepS = STEP_NEVER - 1, cullS = !!P.cullStuds, cullU = !!P.cullUnder;
|
|
@@ -3415,7 +3463,7 @@ async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
|
|
|
3415
3463
|
await new Promise((r) => setTimeout(r, 0));
|
|
3416
3464
|
}
|
|
3417
3465
|
}
|
|
3418
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3466
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/scene.ts
|
|
3419
3467
|
import * as THREE2 from "three";
|
|
3420
3468
|
function colorFn(src, pack, fallback) {
|
|
3421
3469
|
const table = new Map;
|
|
@@ -3516,6 +3564,7 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3516
3564
|
});
|
|
3517
3565
|
for (const m of [...mats, ...pairs.values()]) {
|
|
3518
3566
|
m.userData.ldrMap?.dispose();
|
|
3567
|
+
m.userData.ldrGloss?.map.dispose();
|
|
3519
3568
|
m.dispose();
|
|
3520
3569
|
}
|
|
3521
3570
|
cur = null;
|
|
@@ -3545,7 +3594,7 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3545
3594
|
cur.setLod(false);
|
|
3546
3595
|
if (cur.root.parent !== object)
|
|
3547
3596
|
object.add(cur.root);
|
|
3548
|
-
Object.assign(stats, { drawn: drawnAt(null), studsTotal: cur.stats.studsTotal, studsHidden: cur.stats.studsHidden, undersTotal: cur.stats.undersTotal, undersHidden: cur.stats.undersHidden, condBatches: cur.stats.condBatches ?? 0, texBatches: cur.stats.texBatches ?? 0, textures: cur.stats.textures ?? 0, clusters: cur.stats.clusters ?? 0, longestSliceMs: cur.stats.longestSliceMs, buildYields: cur.stats.buildYields, buildMs: performance.now() - t0 });
|
|
3597
|
+
Object.assign(stats, { drawn: drawnAt(null), studsTotal: cur.stats.studsTotal, studsHidden: cur.stats.studsHidden, undersTotal: cur.stats.undersTotal, undersHidden: cur.stats.undersHidden, condBatches: cur.stats.condBatches ?? 0, texBatches: cur.stats.texBatches ?? 0, textures: cur.stats.textures ?? 0, glossmaps: cur.stats.glossmaps ?? 0, clusters: cur.stats.clusters ?? 0, longestSliceMs: cur.stats.longestSliceMs, buildYields: cur.stats.buildYields, buildMs: performance.now() - t0 });
|
|
3549
3598
|
api.texturesReady = cur.texturesReady;
|
|
3550
3599
|
};
|
|
3551
3600
|
const setStep = (step, mask = null) => {
|
|
@@ -3632,10 +3681,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3632
3681
|
return finish();
|
|
3633
3682
|
})();
|
|
3634
3683
|
}
|
|
3635
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3684
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/parts-cdn.ts
|
|
3636
3685
|
import { decompress as decompress2 } from "fzstd";
|
|
3637
3686
|
|
|
3638
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3687
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/embedded.ts
|
|
3639
3688
|
function splitFiles(text, fallback) {
|
|
3640
3689
|
const files = new Map;
|
|
3641
3690
|
let cur = null, saw = false;
|
|
@@ -3707,7 +3756,7 @@ function embeddedKeys(text, names, fallback = "main.ldr") {
|
|
|
3707
3756
|
return out;
|
|
3708
3757
|
}
|
|
3709
3758
|
|
|
3710
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3759
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/parts-cdn.ts
|
|
3711
3760
|
var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
|
|
3712
3761
|
var indexCache = new Map;
|
|
3713
3762
|
var shardCache = new Map;
|
|
@@ -3939,10 +3988,10 @@ async function prepareModel(source, o = {}) {
|
|
|
3939
3988
|
return { insts, pack, missing, requests, bytes, cull, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, ...cull ? { cull: performance.now() - t3 } : {} } };
|
|
3940
3989
|
}
|
|
3941
3990
|
|
|
3942
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3991
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/load-worker.gen.ts
|
|
3943
3992
|
var load_worker_gen_default = 'var bt=ArrayBuffer,W=Uint8Array,de=Uint16Array,yt=Int16Array;var be=Int32Array,Ee=function(e,t,n){if(W.prototype.slice)return W.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 W(n-t);return r.set(e.subarray(t,n)),r},ce=function(e,t,n,r){if(W.prototype.fill)return W.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},xt=function(e,t,n,r){if(W.prototype.copyWithin)return W.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 wt=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],K=function(e,t,n){var r=Error(t||wt[e]);if(r.code=e,Error.captureStackTrace)Error.captureStackTrace(r,K);if(!n)throw r;return r},je=function(e,t,n){var r=0,s=0;for(;r<n;++r)s|=e[t++]<<(r<<3);return s},At=function(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0},Mt=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,l=r>>6;if(r&8)K(0);var a=6-s,c=i==3?4:i,f=je(e,a,c);a+=c;var m=l?1<<l:s,g=je(e,a,m)+(l==1&&256),y=g;if(!s){var v=1<<10+(e[5]>>3);y=v+(v>>3)*(e[5]&7)}if(y>2145386496)K(1);var x=new W((t==1?g||y:t?0:y)+12);return x[0]=1,x[4]=4,x[8]=8,{b:a+m,y:0,l:0,d:f,w:t&&t!=1?t:x.subarray(12),e:y,o:new be(x.buffer,0,3),u:g,c:o,m:Math.min(131072,y)}}else if((n>>4|e[3]<<20)==25481893)return At(e,4)+8;K(0)},re=function(e){var t=0;for(;1<<t<=e;++t);return t-1},ue=function(e,t,n){var r=(t<<3)+4,s=(e[t]&15)+5;if(s>n)K(3);var o=1<<s,i=o,l=-1,a=-1,c=-1,f=o,m=new bt(512+(o<<2)),g=new yt(m,0,256),y=new de(m,0,256),v=new de(m,512,o),x=512+(o<<1),S=new W(m,x,o),h=new W(m,x+o);while(l<255&&i>0){var u=re(i+1),d=r>>3,p=(1<<u+1)-1,L=(e[d]|e[d+1]<<8|e[d+2]<<16)>>(r&7)&p,b=(1<<u)-1,T=p-i-1,E=L&b;if(E<T)r+=u,L=E;else if(r+=u+1,L>b)L-=T;if(g[++l]=--L,L==-1)i+=L,S[--f]=l;else i-=L;if(!L)do{var D=r>>3;a=(e[D]|e[D+1]<<8)>>(r&7)&3,r+=2,l+=a}while(a==3)}if(l>255||i)K(0);var C=0,U=(o>>1)+(o>>3)+3,X=o-1;for(var H=0;H<=l;++H){var M=g[H];if(M<1){y[H]=-M;continue}for(c=0;c<M;++c){S[C]=H;do C=C+U&X;while(C>=f)}}if(C)K(0);for(c=0;c<o;++c){var A=y[S[c]]++,k=h[c]=s-re(A);v[c]=(A<<k)-o}return[r+7>>3,{b:s,s:S,n:h,t:v}]},vt=function(e,t){var n=0,r=-1,s=new W(292),o=e[t],i=s.subarray(0,256),l=s.subarray(256,268),a=new de(s.buffer,268);if(o<128){var c=ue(e,t+1,6),f=c[0],m=c[1];t+=o;var g=f<<3,y=e[t];if(!y)K(0);var v=0,x=0,S=m.b,h=S,u=(++t<<3)-8+re(y);for(;;){if(u-=S,u<g)break;var d=u>>3;if(v+=(e[d]|e[d+1]<<8)>>(u&7)&(1<<S)-1,i[++r]=m.s[v],u-=h,u<g)break;d=u>>3,x+=(e[d]|e[d+1]<<8)>>(u&7)&(1<<h)-1,i[++r]=m.s[x],S=m.n[v],v=m.t[v],h=m.n[x],x=m.t[x]}if(++r>255)K(0)}else{r=o-127;for(;n<r;n+=2){var p=e[++t];i[n]=p>>4,i[n+1]=p&15}++t}var L=0;for(n=0;n<r;++n){var b=i[n];if(b>11)K(0);L+=b&&1<<b-1}var T=re(L)+1,E=1<<T,D=E-L;if(D&D-1)K(0);i[r++]=re(D)+1;for(n=0;n<r;++n){var b=i[n];++l[i[n]=b&&T+1-b]}var C=new W(E<<1),U=C.subarray(0,E),X=C.subarray(E);a[T]=0;for(n=T;n>0;--n){var H=a[n];ce(X,n,H,a[n-1]=H+l[n]*(1<<T-n))}if(a[0]!=E)K(0);for(n=0;n<r;++n){var M=i[n];if(M){var A=a[M];ce(U,n,A,a[M]=A+(1<<T-M))}}return[t,{n:X,b:T,s:U}]},Tt=ue(new W([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],Ct=ue(new W([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],Et=ue(new W([32,132,16,66,102,70,68,68,68,68,36,73,2]),0,5)[1],Ve=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},Se=new W(new be([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),St=Ve(Se,0),Pe=new W(new be([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),Pt=Ve(Pe,3),le=function(e,t,n){var r=e.length,s=t.length,o=e[r-1],i=(1<<n.b)-1,l=-n.b;if(!o)K(0);var a=0,c=n.b,f=(r<<3)-8+re(o)-c,m=-1;for(;f>l&&m<s;){var g=f>>3,y=(e[g]|e[g+1]<<8|e[g+2]<<16)>>(f&7);a=(a<<c|y)&i,t[++m]=n.s[a],f-=c=n.n[a]}if(f!=l||m+1!=s)K(0)},Lt=function(e,t,n){var r=6,s=t.length,o=s+3>>2,i=o<<1,l=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,l),n),le(e.subarray(r),t.subarray(l),n)},kt=function(e,t,n){var r,s=t.b,o=e[s],i=o>>1&3;t.l=o&1;var l=o>>3|e[s+1]<<5|e[s+2]<<13,a=(s+=3)+l;if(i==1){if(s>=e.length)return;if(t.b=s+1,n)return ce(n,e[s],t.y,t.y+=l),n;return ce(new W(l),e[s])}if(a>e.length)return;if(i==0){if(t.b=a,n)return n.set(e.subarray(s,a),t.y),t.y+=l,n;return Ee(e,s,a)}if(i==2){var c=e[s],f=c&3,m=c>>2&3,g=c>>4,y=0,v=0;if(f<2)if(m&1)g|=e[++s]<<4|(m&2&&e[++s]<<12);else g=c>>3;else if(v=m,m<2)g|=(e[++s]&63)<<4,y=e[s]>>6|e[++s]<<2;else if(m==2)g|=e[++s]<<4|(e[++s]&3)<<12,y=e[s]>>2|e[++s]<<6;else g|=e[++s]<<4|(e[++s]&63)<<12,y=e[s]>>6|e[++s]<<2|e[++s]<<10;++s;var x=n?n.subarray(t.y,t.y+t.m):new W(t.m),S=x.length-g;if(f==0)x.set(e.subarray(s,s+=g),S);else if(f==1)ce(x,e[s++],S);else{var h=t.h;if(f==2){var u=vt(e,s);y+=s-(s=u[0]),t.h=h=u[1]}else if(!h)K(0);(v?Lt:le)(e.subarray(s,s+=y),x.subarray(S),h)}var d=e[s++];if(d){if(d==255)d=(e[s++]|e[s++]<<8)+32512;else if(d>127)d=d-128<<8|e[s++];var p=e[s++];if(p&3)K(0);var L=[Ct,Et,Tt];for(var b=2;b>-1;--b){var T=p>>(b<<1)+2&3;if(T==1){var E=new W([0,0,e[s++]]);L[b]={s:E.subarray(2,3),n:E.subarray(0,1),t:new de(E.buffer,0,1),b:0}}else if(T==2)r=ue(e,s,9-(b&1)),s=r[0],L[b]=r[1];else if(T==3){if(!t.t)K(0);L[b]=t.t[b]}}var D=t.t=L,C=D[0],U=D[1],X=D[2],H=e[a-1];if(!H)K(0);var M=(a<<3)-8+re(H)-X.b,A=M>>3,k=0,V=(e[A]|e[A+1]<<8)>>(M&7)&(1<<X.b)-1;A=(M-=U.b)>>3;var B=(e[A]|e[A+1]<<8)>>(M&7)&(1<<U.b)-1;A=(M-=C.b)>>3;var N=(e[A]|e[A+1]<<8)>>(M&7)&(1<<C.b)-1;for(++d;--d;){var P=X.s[V],w=X.n[V],O=C.s[N],F=C.n[N],R=U.s[B],z=U.n[B];A=(M-=R)>>3;var j=1<<R,I=j+((e[A]|e[A+1]<<8|e[A+2]<<16|e[A+3]<<24)>>>(M&7)&j-1);A=(M-=Pe[O])>>3;var G=Pt[O]+((e[A]|e[A+1]<<8|e[A+2]<<16)>>(M&7)&(1<<Pe[O])-1);A=(M-=Se[P])>>3;var _=St[P]+((e[A]|e[A+1]<<8|e[A+2]<<16)>>(M&7)&(1<<Se[P])-1);if(A=(M-=w)>>3,V=X.t[V]+((e[A]|e[A+1]<<8)>>(M&7)&(1<<w)-1),A=(M-=F)>>3,N=C.t[N]+((e[A]|e[A+1]<<8)>>(M&7)&(1<<F)-1),A=(M-=z)>>3,B=U.t[B]+((e[A]|e[A+1]<<8)>>(M&7)&(1<<z)-1),I>3)t.o[2]=t.o[1],t.o[1]=t.o[0],t.o[0]=I-=3;else{var Y=I-(_!=0);if(Y){if(I=Y==3?t.o[0]-1:t.o[Y],Y>1)t.o[2]=t.o[1];t.o[1]=t.o[0],t.o[0]=I}else I=t.o[0]}for(var b=0;b<_;++b)x[k+b]=x[S+b];k+=_,S+=_;var q=k-I;if(q<0){var J=-q,ee=t.e+q;if(J>G)J=G;for(var b=0;b<J;++b)x[k+b]=t.w[ee+b];k+=J,G-=J,q=0}for(var b=0;b<G;++b)x[k+b]=x[q+b];k+=G}if(k!=S)while(S<x.length)x[k++]=x[S++];else k=x.length;if(n)t.y+=k;else x=Ee(x,0,k)}else if(n){if(t.y+=g,S)for(var b=0;b<g;++b)x[b]=x[S+b]}else if(S)x=Ee(x,S);return t.b=a,x}K(2)},Bt=function(e,t){if(e.length==1)return e[0];var n=new W(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=Mt(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 l=kt(e,i,t);if(!l)K(5);if(t)i.e=i.y;else n.push(l),o+=l.length,xt(i.w,0,l.length),i.w.set(l,i.w.length-l.length)}s=i.b+i.c*4}else s=i;e=e.subarray(s)}return Bt(n,o)}async function It(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 He(e){return new TextDecoder().decode(await It(e))}var Ge=(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 Z=(e)=>e.trim().toLowerCase().replace(/\\\\/g,"/").replace(/\\/+/g,"/");function Le(e){if(/^0x/i.test(e))return parseInt(e,16);return+e}var _e=/^~?\\s*moved\\s+to\\s+(.+)$/i,Ft=new Set(["FILE","NOFILE","!DATA","!:","STEP","BFC","ROTSTEP","BUFEXCHG","!TEXMAP"]),Qe=new Set(["part","subpart","primitive","8_primitive","48_primitive","shortcut","helper"]),Rt=new Set(["model","submodel","configuration"]),Dt=/^(?:!?LDRAW_ORG|Unofficial|Official\\s+LCAD)\\s+(\\S+)/i;function We(e){let t=Dt.exec(e);if(!t)return;let n=t[1].toLowerCase().replace(/^unofficial_/,"");return Qe.has(n)||Rt.has(n)?n:void 0}function Ut(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 zt(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 l=n[2].trim();for(let m=0;m<s;m++)l=l.replace(/^\\S+\\s*/,"");let a=Ut(l);if(!a.length)return null;let c={method:r,p1:i.slice(0,3),p2:i.slice(3,6),p3:i.slice(6,9),texture:a[0]};if(s>=10)c.a=i[9];if(s===11)c.b=i[10];let f=a.findIndex((m,g)=>g>0&&m.toUpperCase()==="GLOSSMAP");if(f>0&&a[f+1])c.glossmap=a[f+1];if(t)c.next=!0;return c}var Ot=(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 Nt(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 l=e.slice(n),a=/[ \\t]{2,}|\\t/.test(l)?l.split(/\\s+/).join(" "):l;return{t:1,color:Le(o),m:i,file:Z(a)}}function Ke(e){let t=+e[0];if(!(t>=1&&t<=5)||e.length<2)return null;let n=Le(e[1]),r=e.slice(2).map(Number);if(t===1)return{t:1,color:n,m:r.slice(0,12),file:Z(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 et(e,t="main.ldr",n={}){let r=!!n.geometryText,s=new Map,o=null,i="",l,a=null,c=[],f=null,m=()=>{if(!a)return;let u=Ot(a.chunks.join("")),d=u[0]===137&&u[1]===80&&u[2]===78&&u[3]===71;(l??=new Map).set(Z(a.name),{name:a.name,bytes:u,...d?{mime:"image/png"}:{}}),a=null},g=!0,y=(u)=>{if(m(),o={name:Z(u),cmds:[]},s.set(o.name,o),!i)i=o.name;c=[],f=null,g=!0},v=!1,x=!1,S=()=>{if(x)return;x=!0,s.clear(),o=null,i=""},h=(u,d)=>{if(f){u.tex=f,f=null;return}let p=c[c.length-1];if(!p)return;if(p.fallback){if(!d)u.fallback=!0}else u.tex=p.map};for(let u of e.split(`\n`)){let d=u.trim();if(!d)continue;if(r&&d.charCodeAt(0)>=50&&d.charCodeAt(0)<=53&&(d.charCodeAt(1)===32||d.charCodeAt(1)===9)){if(a||v)continue;if(!o)y(t);let T=d.slice(2).trimStart(),E=T.search(/\\s/),D={t:d.charCodeAt(0)-48,color:Le(E<0?T:T.slice(0,E)),p:[],src:d};h(D,!1),o.cmds.push(D),g=!1;continue}if(d.charCodeAt(0)===48&&(d.charCodeAt(1)===32||d.charCodeAt(1)===9)){let T=2;while(d.charCodeAt(T)===32||d.charCodeAt(T)===9)T++;let E=T;while(E<d.length&&d.charCodeAt(E)!==32&&d.charCodeAt(E)!==9)E++;let D=d.slice(T,E);if(!Ft.has(D)){if(v||a)continue;if(!o)y(t);let C=d.slice(T),U={t:0,text:C};if(D.charCodeAt(0)===33)U.meta=D;if(f=null,g&&!o.org){let H=We(C);if(H)o.org=H}let X=C.match(_e);if(X&&!o.movedTo){let H=X[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(H))H+=".dat";o.movedTo=Z(H)}o.cmds.push(U);continue}}if(d.charCodeAt(0)===49&&(d.charCodeAt(1)===32||d.charCodeAt(1)===9)&&!a&&!v){let T=Nt(d);if(T){if(!o)y(t);h(T,!1),o.cmds.push(T),g=!1;continue}}let p=d.split(/\\s+/);if(+p[0]===0){let T=d.slice(1).trim();if(p[1]==="FILE"){S(),v=!1,y(T.slice(5));continue}if(p[1]==="NOFILE"){m(),o=null,v=!0;continue}if(p[1]==="!DATA"){S(),m(),o=null,v=!1,a={name:T.slice(5).trim(),chunks:[]};continue}if(v)continue;if(a){if(p[1]==="!:")a.chunks.push(p.slice(2).join(""));continue}if(!o)y(t);let E={t:0,text:T};if(p[1]==="STEP")E.step=!0,c=[],f=null;else if(p[1]==="BFC")E.bfc=p.slice(2).join(" ");else if(p[1]==="ROTSTEP")if(E.meta="ROTSTEP",E.step=!0,c=[],f=null,(p[2]??"").toUpperCase()==="END")E.rotstep={x:0,y:0,z:0,mode:"END"};else{let C=(p[5]??"REL").toUpperCase();E.rotstep={x:+p[2]||0,y:+p[3]||0,z:+p[4]||0,mode:["REL","ABS","ADD"].includes(C)?C:"REL"}}else if(p[1]==="BUFEXCHG"){E.meta="BUFEXCHG";let C=(p[2]??"").toUpperCase();E.bufexchg={op:C==="RETRIEVE"?"RETRIEVE":"STORE",buf:p[3]??"A"}}else if(p[1]?.startsWith("!"))E.meta=p[1];if(g&&!o.org){let C=We(T);if(C)o.org=C}if(p[1]==="!TEXMAP"){let C=(p[2]??"").toUpperCase();if(f=null,C==="START"||C==="NEXT"){let U=zt(T.replace(/^!TEXMAP\\s+\\S+/i,""),C==="NEXT");if(E.texmap={op:C,...U?{map:U}:{}},U)if((o.texmaps??=[]).push(U),C==="START")c.push({map:U,fallback:!1});else f=U}else if(C==="FALLBACK"){E.texmap={op:C};let U=c[c.length-1];if(U)U.fallback=!0}else if(C==="END")E.texmap={op:C},c.pop()}else if(p[1]==="!:"){f=null;let C=Ke(p.slice(2));if(C)h(C,!0),E.geom=C}else f=null;let D=T.match(_e);if(D&&!o.movedTo){let C=D[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(C))C+=".dat";o.movedTo=Z(C)}o.cmds.push(E);continue}if(a||v)continue;if(!o)y(t);let b=Ke(p);if(!b)continue;h(b,!1),o.cmds.push(b),g=!1}return m(),l?{main:i,files:s,data:l}:{main:i,files:s}}var cn=Math.PI/180;function tt(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 nt(e,t){let[n,r,s,o,i,l,a,c,f,m,g,y]=e,[v,x,S,h,u,d,p,L,b,T,E,D]=t;return[o*v+i*x+l*S+n,a*v+c*x+f*S+r,m*v+g*x+y*S+s,o*h+i*p+l*T,o*u+i*L+l*E,o*d+i*b+l*D,a*h+c*p+f*T,a*u+c*L+f*E,a*d+c*b+f*D,m*h+g*p+y*T,m*u+g*L+y*E,m*d+g*b+y*D]}var ke=[0,0,0,1,0,0,0,1,0,0,0,1];var Xe=new WeakMap,$t=/^(s|8|48)\\//;function Be(e,t){let n=e.files.get(Z(t));if(!n)return"part";let r=Xe.get(n);if(r)return r;if(n.org)r=Qe.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&&$t.test(s.file))?"part":"model";return Xe.set(n,r),r}var Ze=new WeakMap;function rt(e){let t=Ze.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 Ze.set(e,t),t}var Ye=(e)=>e>16777215?"0x"+e.toString(16).toUpperCase():String(e),jt=(e)=>e.t===0?"0 "+e.text:e.t===1?`1 ${Ye(e.color)} ${e.m.join(" ")} ${e.file}`:e.src?e.src:`${e.t} ${Ye(e.color)} ${e.p.join(" ")}`,Ie=(e,t)=>`${Z(e)}#${t}`;function Vt(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:Ie(e.name,t),cmds:n}}function st(e,t){return[`0 ldr: own geometry of ${e.name}, step ${t}`,...Vt(e,t).cmds.map(jt)].join(`\n`)+`\n`}function Ht(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 ot(e){let[t,n,r,s,o,i,l,a,c,f,m,g]=e,y=a*g-c*m,v=-(l*g-c*f),x=l*m-a*f,S=s*y+o*v+i*x;if(!Number.isFinite(S)||Math.abs(S)<0.000000000001)return null;let h=1/S,u=[y*h,-(o*g-i*m)*h,(o*c-i*a)*h,v*h,(s*g-i*f)*h,-(s*c-i*l)*h,x*h,-(s*m-o*f)*h,(s*a-o*l)*h];return[-(u[0]*t+u[1]*n+u[2]*r),-(u[3]*t+u[4]*n+u[5]*r),-(u[6]*t+u[7]*n+u[8]*r),...u]}var Gt=(e)=>String(+e.toFixed(6)||0),Je=(e)=>\'"\'+e.replace(/\\\\/g,"\\\\\\\\").replace(/"/g,"\\\\\\"")+\'"\';function it(e,t){let n=[...t.p1,...t.p2,...t.p3,...t.method!=="PLANAR"?[t.a??360]:[],...t.method==="SPHERICAL"?[t.b??180]:[]].map(Gt).join(" "),r=`0 ldr: ${e} with a model-level !TEXMAP\n0 BFC CERTIFY CCW\n0 !TEXMAP START ${t.method} ${n} ${Je(t.texture)}${t.glossmap?" GLOSSMAP "+Je(t.glossmap):""}\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 ${Z(e)}\n0 !TEXMAP END\n`;return{name:`${Z(e)}#tex-${Ht(r)}`,source:r}}var _t=(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 Wt(e,t,n){let r=Math.PI/180,s=Math.sin(e*r),o=Math.cos(e*r),i=Math.sin(t*r),l=Math.cos(t*r),a=Math.sin(n*r),c=Math.cos(n*r);return[l*c,-l*a,i,o*a+s*i*c,o*c-s*i*a,-s*l,s*a-o*i*c,s*c+o*i*a,o*l]}var qe=new WeakMap;function at(e){let t=qe.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=Wt(o.x,o.y,o.z);r=o.mode==="ABS"?{abs:!0,m:i,rotstep:o}:o.mode==="ADD"&&r?{abs:r.abs,m:_t(r.m,i),rotstep:o}:{abs:!1,m:i,rotstep:o}}n.push(r)}return n.push(r),qe.set(e,n),n}var lt=999999,ct=(e)=>e.map((t)=>String(t).padStart(6,"0")).join(".")+"~";function Kt(e,t={}){let n=[],r=t.maxDepth??64,s=t.looseGeometry!==!1,o=!!t.textures,i=!!t.callouts,l=new Map,a=0,c=(m,g)=>{let y=m.name+"#"+g,v=l.get(y);if(!v){let x;v=Object.assign(()=>x??=st(m,g),{file:m,step:g}),l.set(y,v)}return v},f=(m,g,y,v,x,S,h,u,d=null,p=[],L=[])=>{let b=m.files.get(g);if(!b||h>r)return;let T=0,E=h>0?++a:0,D=i&&E?[...p,E]:p,C=i&&E?[...L,y]:L,U=i&&!d?new Map:null,X=-1,H=0,M=(P,w,O,F,R,z)=>{if(X!==T)X=T,H=0;let j=U?.get(T+"|"+w);if(j)return j.n++,f(P,P===m?w:P.main,O,F,x+"/"+w,[...R,lt],h+1,z,[...R,lt],D,C);let I=[...R,H++],G=n.length;f(P,P===m?w:P.main,O,F,x+"/"+w,I,h+1,z,d,D,C),U?.set(T+"|"+w,{n:1,from:G,to:n.length})},A=at(b),k=s?rt(b):[],V=0,B=(P,w,O,F,R,z,j)=>{if(d)F=d;let I={part:P,color:w,m:O,step:F[0],steps:F,localStep:R,path:x};if(E){if(I.sub=E,i)I.subPath=D,I.subMats=C}if(z)I.embedded=!0;if(j){let _=it(P,j);I.texPart=_.name,I.texSource=_.source}let G=A[R];if(G)I.view=G;return n.push(I),I},N=(P)=>{while(V<k.length&&k[V]<=P){let w=k[V++];B(Ie(b.name,w),v,y,[...S,w],w,!1,null).source=c(b,w)}};for(let P of b.cmds){if(P.t===0&&P.step){T++;continue}let w=P;if(w.t>=2||w.t===0&&w.geom&&w.geom.t>=2){N(T);continue}if(w.t===0)if(o&&w.geom?.t===1)w=w.geom;else continue;if(w.t!==1)continue;if(o&&w.fallback)continue;let O=w.color===16?v:w.color,F=nt(y,w.m),R=[...S,T],z=o?w.tex??u:null,j=z?ot(w.m):null,I=z&&j?tt(z,j):null;if(m.files.has(w.file)){if(Be(m,w.file)==="model"){M(m,w.file,F,O,R,I);continue}B(w.file,O,F,R,T,!0,I);continue}let G=t.resolveModel?.(w.file);if(G){M(G,w.file,F,O,R,I);continue}B(w.file,O,F,R,T,!1,I)}if(N(1/0),U){for(let P of U.values())if(P.n>1)for(let w=P.from;w<P.to;w++)n[w].mult??=P.n}};if(Be(e,e.main)==="part"){if(e.files.get(e.main))n.push({part:e.main,color:16,m:[...ke],step:0,steps:[0],localStep:0,path:e.main,embedded:!0});return n}return f(e,e.main,ke,16,e.main,[],0,null),n}function ut(e,t="main.ldr",n){return Kt(et(e,t,{geometryText:!0}),n)}function Xt(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(Z(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(Z(t),r)}let l=o.trim().replace(/\\s+/g," ");if(l)r.push(l)}return n}var Zt=(e)=>{if(!e.startsWith("1 "))return null;let t=e.split(" ");return t.length>=15?Z(t.slice(14).join(" ")):null};function Yt(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 ft(e,t,n="main.ldr"){let r=Xt(e,n),s=new Map;for(let o of t){let i=Z(o);if(!r.has(i)||s.has(i))continue;let l=new Set([i]),a=[i];while(a.length)for(let f of r.get(a.pop())){let m=Zt(f);if(m&&r.has(m)&&!l.has(m))l.add(m),a.push(m)}let c=[i,...[...l].filter((f)=>f!==i).sort()].map((f)=>"0 FILE "+(f===i?"":f)+`\n`+r.get(f).join(`\n`)).join(`\n`);s.set(i,`emb/${Yt(c)}.dat`)}return s}var pt=(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,mt=new WeakMap;function Fe(e,t){let n=mt.get(e);if(!n)mt.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),l=[],a=[];s.studs.forEach((g,y)=>{l.push(g[0]),a.push(g[1]);for(let v=0;v<12;v++)i[y*12+v]=g[2+v]});let c=null,f=0,m=0;if(s.mask){f=s.mask[0],m=s.mask[1];let g=s.mask[2];c=new Uint8Array(g.length);for(let y=0;y<g.length;y++)c[y]=g.charCodeAt(y)===49?1:0}return n.set(t,r={nStuds:o,studM:i,kind:l,color:a,mask:c,nx:f,nz:m}),r}var ie=1073741824;class Re{a;b;c;vals;used;mask;size=0;constructor(e=1024){let t=1024;while(t<e*2)t*=2;this.a=new Int32Array(t),this.b=new Int32Array(t),this.c=new Int32Array(t),this.vals=new Int32Array(t),this.used=new Uint8Array(t),this.mask=t-1}slot(e,t,n){let r=Math.imul(e,2654435761)^Math.imul(t,2246822507)^Math.imul(n,3266489909);return r^=r>>>15,r=Math.imul(r,739982445),r^=r>>>12,r&this.mask}get(e,t,n){let r=this.slot(e,t,n),s=this.used,o=this.a,i=this.b,l=this.c;for(;;){if(!s[r])return-1;if(o[r]===e&&i[r]===t&&l[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,l=this.b,a=this.c;for(;;){if(!o[s])return o[s]=1,i[s]=e,l[s]=t,a[s]=n,this.vals[s]=r,this.size++,-1;if(i[s]===e&&l[s]===t&&a[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 Jt(e,t,n){let s=[],o=[],i=[],l=[],a=[],c=[],f=[],m=[],g=new Re(e.length*2),y=[],v=[];for(let M=0;M<e.length;M++){let A=e[M],k=A.m,V=t.parts[A.part];if(!V||!V.mask||!pt(k))continue;let B=V.bbox,N=1/0,P=-1/0,w=1/0,O=-1/0;for(let z=0;z<2;z++)for(let j=0;j<2;j++){let I=z?B[3]:B[0],G=j?B[5]:B[2],_=k[0]+k[3]*I+k[5]*G,Y=k[2]+k[9]*I+k[11]*G;if(_<N)N=_;if(_>P)P=_;if(Y<w)w=Y;if(Y>O)O=Y}let F=a.length;s.push(N),o.push(P),i.push(w),l.push(O),a.push(M),c.push(Fe(t,A.part)),f.push(B[0]),m.push(B[2]);let R=Math.round((k[1]+B[4])*2);for(let z=Math.floor(N/40);z<=Math.floor(P/40);z++)for(let j=Math.floor(w/40);j<=Math.floor(O/40);j++){if(!we(R,z,j))continue;let I=v.length;v.push(F),y.push(g.put(R,z,j,I))}}let x=[0,5,-5,5,-5],S=[0,5,5,-5,-5],h=NaN,u=NaN,d=NaN,p=-1,L=(M,A,k,V)=>{let B=Math.round(A*2),N=Math.floor(M/40),P=Math.floor(k/40);if(!we(B,N,P))return fe;let w=fe;if(B!==h||N!==u||P!==d)h=B,u=N,d=P,p=g.get(B,N,P);for(let O=p;O>=0;O=y[O]){let F=v[O];if(a[F]===V||!(M-6>=s[F]-0.5&&M+6<=o[F]+0.5&&k-6>=i[F]-0.5&&k+6<=l[F]+0.5))continue;let R=e[a[F]].m,z=c[F],j=f[F],I=m[F],G=M-R[0],_=A-R[1],Y=k-R[2],q=R[3]*G+R[6]*_+R[9]*Y,J=R[5]*G+R[8]*_+R[11]*Y,{nx:ee,nz:se,mask:ae}=z,oe=!0;for(let Q=0;Q<5;Q++){let te=Math.floor((q+x[Q]-j)/20),ne=Math.floor((J+S[Q]-I)/20);if(te<0||ne<0||te>=ee||ne>=se||ae[te*se+ne]!==1){oe=!1;break}}if(oe){if(!n)return 0;let Q=n[a[F]];if(Q<w)w=Q}}return w},b=0;for(let M of e){let A=Fe(t,M.part);if(A)b+=A.nStuds}let T=new Uint8Array(b),E=new Uint8Array(b),D=new Re(b),C=0,U=n?new Int32Array(b).fill(fe):void 0;for(let M=0,A=0;M<e.length;M++){let k=e[M],V=Fe(t,k.part);if(!V)continue;let B=k.m,N=V.studM,P=B[0],w=B[1],O=B[2],F=B[3],R=B[4],z=B[5],j=B[6],I=B[7],G=B[8],_=B[9],Y=B[10],q=B[11];for(let J=0;J<V.nStuds;J++,A++){let ee=J*12,se=N[ee+4],ae=N[ee+7],oe=N[ee+10];if(!(Math.abs(j*se+I*ae+G*oe-1)<0.001&&Math.abs(F*se+R*ae+z*oe)<0.001&&Math.abs(_*se+Y*ae+q*oe)<0.001))continue;E[A]=1;let Q=N[ee],te=N[ee+1],ne=N[ee+2],De=P+F*Q+R*te+z*ne,Ue=w+j*Q+I*te+G*ne,ze=O+_*Q+Y*te+q*ne,Oe=L(De,Ue,ze,M);if(Oe!==fe){if(T[A]=1,C++,U)U[A]=Oe}let me=Math.round(De),he=Math.round(Ue),ge=Math.round(ze);if(!we(me,he,ge))continue;if(!n){D.put(me,he,ge,1);continue}let Ne=n[M],$e=D.get(me,he,ge);if($e<0||Ne<$e)D.put(me,he,ge,Ne)}}let X=new Uint8Array(e.length),H=n?new Int32Array(e.length).fill(fe):void 0;for(let M=0;M<e.length;M++){let A=e[M],k=t.parts[A.part];if(!k||!k.under||!pt(A.m))continue;let V=k.bbox,B=Math.round((V[3]-V[0])/20),N=Math.round((V[5]-V[2])/20);if(!B||!N||B*N>4096)continue;let P=A.m,w=!0,O=0;for(let F=0;F<B&&w;F++)for(let R=0;R<N;R++){let z=V[0]+10+20*F,j=V[2]+10+20*R,I=P[0]+P[3]*z+P[5]*j,G=P[2]+P[9]*z+P[11]*j,_=Math.round(I),Y=Math.round(P[1]+V[4]),q=Math.round(G),J=we(_,Y,q)?D.get(_,Y,q):-1;if(J<0){w=!1;break}if(J>O)O=J}if(w){if(X[M]=1,H)H[M]=O}}return{nStuds:b,studHidden:T,studUp:E,underHidden:X,studsHidden:C,studHideStep:U,underHideStep:H}}function qt(e,t,n){let r=(a)=>n&&a.texPart&&t.parts[a.texPart]?a.texPart:a.part,s=e.map((a)=>({part:r(a),color:String(a.color),m:a.m,steps:a.steps})),o=s.map((a)=>ct(a.steps)),i=[...new Set(o)].sort(),l=new Map(i.map((a,c)=>[a,c]));return{all:s,stepOf:o.map((a)=>l.get(a)),nSteps:i.length}}function Ae(e,t,n=!0){let r=qt(e,t,n);return Jt(r.all,t,r.nSteps>1?r.stepOf:void 0)}var Ce="https://ldr-demo.vercel.app/cdn/v1/",ve=new Map,Me=new Map;function gt(e=Ce,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 Qt=(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"),Te=(e,t)=>Qt(e)?[e[0]+t,e[1],e[2]]:Array.isArray(e)?e.map((n)=>Te(n,t)):e&&typeof e==="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,Te(r,t)])):e;function en(e,t={}){let n=[],r=0,s={},o={};for(let g of e){let y=g.buffer;if(!y)throw Error("ldr: mergePacks needs packs from decodePack/loadPack");let v=new DataView(y).getUint32(0,!0),x=new Uint8Array(y,4+v),S=r;n.push(x),r+=x.byteLength;let h=(4-r%4)%4;if(h)n.push(new Uint8Array(h)),r+=h;for(let[u,d]of Object.entries(g.header.parts??{}))if(!(u in s))s[u]=Te(d,S);for(let[u,d]of Object.entries(g.header.studKinds??{}))if(!(u in o))o[u]=Te(d,S)}let i=e[0]?.header??{version:1,weld:!0},l=new TextEncoder().encode(JSON.stringify({...i,parts:s,studKinds:o,...t})),a=(4-(4+l.length)%4)%4,c=4+l.length+a,f=new Uint8Array(c+r);new DataView(f.buffer).setUint32(0,l.length+a,!0),f.set(l,4),f.fill(32,4+l.length,c);let m=c;for(let g of n)f.set(g,m),m+=g.byteLength;return xe(f.buffer)}async function tn(e,t={}){e=[...e];try{return await ht(e,t)}catch(n){let r=t.cdn??Ce,s=t.fetch??fetch;ve.delete(r);let o=(i,l)=>s(i,{...l,cache:"reload"});try{return await ht(e,{...t,fetch:o})}catch{throw n}}}async function ht(e,t){let n=t.cdn??Ce,r=t.fetch??fetch,s=t.gap??16384,o=await gt(n,r),i=[...new Set([...e].map(Z))],l=[],a=[];for(let h of i){if(Me.has(n+h))continue;let u=o.parts[h];if(u)a.push({name:h,off:u[0],len:u[1],file:u[2]??0});else l.push(h)}a.sort((h,u)=>h.file-u.file||h.off-u.off);let c=[];for(let h of a){let u=c[c.length-1];if(u&&u.file===h.file&&h.off-u.end<=s)u.end=Math.max(u.end,h.off+h.len),u.items.push(h);else c.push({file:h.file,start:h.off,end:h.off+h.len,items:[h]})}let f=0,m=0,g=0,y=new Map,v=async()=>{while(g<c.length){let h=c[g++],u=y.get(h.file);if(u)u=u.subarray(h.start,h.end);else{let d=await r(new URL(o.archives[h.file],n).href,{headers:{Range:`bytes=${h.start}-${h.end-1}`,"Accept-Encoding":"identity"}});if(!d.ok)throw Error(`ldr: parts CDN ${d.status}`);if(m++,u=new Uint8Array(await d.arrayBuffer()),f+=u.byteLength,d.status===200)y.set(h.file,u),u=u.subarray(h.start,h.end)}for(let d of h.items){let p=ye(u.subarray(d.off-h.start,d.off-h.start+d.len)),L=p.buffer.slice(p.byteOffset,p.byteOffset+p.byteLength);Me.set(n+d.name,xe(L))}}};await Promise.all(Array.from({length:Math.min(t.concurrency??24,c.length)},v));let x=i.filter((h)=>Me.has(n+h)).map((h)=>Me.get(n+h));return{pack:x.length?en(x,{colors:o.colors}):xe(nn(o.colors)),missing:l,requests:m,bytes:f}}function nn(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 rn(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 sn(e,t,n){let r=0,s=0,o=!1,i=new Set;for(let l of e){let a=l.embedded?t.get(l.part):Z(l.part),c=a?n.parts[a]:void 0;if(!c)continue;if(c[3]!=null)o=!0,r+=c[3];if(!i.has(a))i.add(a),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 dt(e,t={}){let n=performance.now(),r=t.fetch??fetch,s=gt(t.cdn??Ce,r);s.catch(()=>{});let o=t.text?e:await r(e).then(async(p)=>{if(!p.ok)throw Error(`ldr: ${p.status} fetching ${e}`);return He(await p.arrayBuffer())}),i=performance.now(),l=t.name??(t.text?"main.ldr":Ge(e)),a=ut(o,l,{looseGeometry:!1,callouts:t.callouts}),c=performance.now();t.onParsed?.(a),await s;let f=ft(o,new Set(a.filter((p)=>p.embedded).map((p)=>p.part)),l),m=(p,L)=>t.maxBodyTris!=null&&p>t.maxBodyTris||t.maxPackBytes!=null&&L>t.maxPackBytes;if(t.maxBodyTris!=null||t.maxPackBytes!=null){let p=sn(a,f,await s);if(m(p.known?p.bodyTris:0,p.packBytes))throw new pe({bodyTris:p.bodyTris,packBytes:p.packBytes,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let{pack:g,missing:y,requests:v,bytes:x}=await tn([...a.filter((p)=>!p.embedded).map((p)=>p.part),...f.values()],t),S=new Map([...f].map(([p,L])=>[L,p])),h=y.map((p)=>S.get(p)??p);for(let[p,L]of f){let b=g.header.parts[L];if(b)g.header.parts[p]=b}let u=performance.now();if(t.maxBodyTris!=null||t.maxPackBytes!=null){let p=g.buffer?.byteLength??g.bytes??0,L=rn(a,g);if(m(L,p))throw new pe({bodyTris:L,packBytes:p,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let d=t.cull?Ae(a,g.header,t.textures!==!1):void 0;return{insts:a,pack:g,missing:h,requests:v,bytes:x,cull:d,timings:{fetchModel:i-n,parse:c-i,parts:u-c,...d?{cull:performance.now()-u}:{}}}}self.onmessage=async(e)=>{let{id:t,source:n,opts:r}=e.data;try{let s=await dt(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(),l=Ae(s.insts,s.pack.header,r.textures!==!1),a=performance.now()-i,c=[];for(let f of[l.studHidden,l.studUp,l.underHidden,l.studHideStep,l.underHideStep])if(f)c.push(f.buffer);self.postMessage({id:t,cull:l,ms:a},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';
|
|
3944
3993
|
|
|
3945
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3994
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/cdn.ts
|
|
3946
3995
|
var worker;
|
|
3947
3996
|
var seq = 0;
|
|
3948
3997
|
var pending = new Map;
|
|
@@ -4100,10 +4149,12 @@ export {
|
|
|
4100
4149
|
looseSteps,
|
|
4101
4150
|
makeFinishMaterial,
|
|
4102
4151
|
makeMaterial,
|
|
4152
|
+
makeTexturedMaterial,
|
|
4103
4153
|
mergePacks,
|
|
4104
4154
|
modelFileName,
|
|
4105
4155
|
mul,
|
|
4106
4156
|
norm,
|
|
4157
|
+
packTexture,
|
|
4107
4158
|
parse,
|
|
4108
4159
|
parseColor,
|
|
4109
4160
|
parseColourLine,
|
|
@@ -4111,6 +4162,7 @@ export {
|
|
|
4111
4162
|
parseModel,
|
|
4112
4163
|
parseTexMap,
|
|
4113
4164
|
planStepViews,
|
|
4165
|
+
pngHasAlpha,
|
|
4114
4166
|
precomputeCull,
|
|
4115
4167
|
prepareModel,
|
|
4116
4168
|
resolveTexture,
|
package/dist/node/compile.d.ts
CHANGED
|
@@ -13,10 +13,12 @@ export type Bucket = {
|
|
|
13
13
|
pos: number[];
|
|
14
14
|
col: number[];
|
|
15
15
|
};
|
|
16
|
-
/** Textured triangles for one PNG: `uv` = 2 floats per vertex (LDraw !TEXMAP projection, v = 0 at the image's top row). */
|
|
16
|
+
/** Textured triangles for one PNG (+ optional GLOSSMAP PNG): `uv` = 2 floats per vertex (LDraw !TEXMAP projection, v = 0 at the image's top row). */
|
|
17
17
|
export type TexBucket = Bucket & {
|
|
18
18
|
uv: number[];
|
|
19
19
|
wrapU?: boolean;
|
|
20
|
+
texture?: string;
|
|
21
|
+
glossmap?: string;
|
|
20
22
|
};
|
|
21
23
|
export type Compiled = {
|
|
22
24
|
body: Bucket;
|
|
@@ -41,7 +43,7 @@ export type Compiled = {
|
|
|
41
43
|
bits: number[];
|
|
42
44
|
};
|
|
43
45
|
/** Only with `opts.tex`, for parts whose tree uses !TEXMAP: the untextured body a TEXMAP-aware renderer draws instead of
|
|
44
|
-
* `body` (FALLBACK geometry dropped, `0 !:` geometry kept), plus textured triangles per texture name. Under/studs/edges are shared. */
|
|
46
|
+
* `body` (FALLBACK geometry dropped, `0 !:` geometry kept), plus textured triangles per texture (keyed by texture name, plus `\0<glossmap>` when the map has a GLOSSMAP). Under/studs/edges are shared. */
|
|
45
47
|
tbody?: Bucket;
|
|
46
48
|
texb?: Map<string, TexBucket>;
|
|
47
49
|
};
|
package/dist/node/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/spec.ts
|
|
2
2
|
var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
3
3
|
function parseColor(tok) {
|
|
4
4
|
if (/^0x/i.test(tok))
|
|
@@ -690,7 +690,7 @@ function fileStepViews(f) {
|
|
|
690
690
|
viewMemo.set(f, out);
|
|
691
691
|
return out;
|
|
692
692
|
}
|
|
693
|
-
// ../../../../../../../tmp/ldr-build-
|
|
693
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/model.ts
|
|
694
694
|
var CALLOUT_END = 999999;
|
|
695
695
|
var stepKey = (steps) => steps.map((x) => String(x).padStart(6, "0")).join(".") + "~";
|
|
696
696
|
function flatten(doc, opts = {}) {
|
|
@@ -1039,7 +1039,7 @@ function parseLDConfig(text) {
|
|
|
1039
1039
|
}
|
|
1040
1040
|
return out;
|
|
1041
1041
|
}
|
|
1042
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1042
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/instructions.ts
|
|
1043
1043
|
var MIN_VIS = 0.5;
|
|
1044
1044
|
var REORIENT = 0.35;
|
|
1045
1045
|
var deg = Math.PI / 180;
|
|
@@ -1407,10 +1407,10 @@ function planStepViews(insts, parts, stepOf, nSteps, o = {}) {
|
|
|
1407
1407
|
}
|
|
1408
1408
|
};
|
|
1409
1409
|
}
|
|
1410
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1410
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/render.ts
|
|
1411
1411
|
import * as THREE from "three";
|
|
1412
1412
|
|
|
1413
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1413
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/pack-io.ts
|
|
1414
1414
|
import { decompress } from "fzstd";
|
|
1415
1415
|
async function decompressPack(data) {
|
|
1416
1416
|
const u = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
@@ -1433,7 +1433,7 @@ function decodePack(buf) {
|
|
|
1433
1433
|
return { header, arr, bytes: buf.byteLength, buffer: buf };
|
|
1434
1434
|
}
|
|
1435
1435
|
|
|
1436
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1436
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/cull.ts
|
|
1437
1437
|
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;
|
|
1438
1438
|
var prepCache = new WeakMap;
|
|
1439
1439
|
function prepPart(H, part) {
|
|
@@ -1750,7 +1750,7 @@ function precomputeCull(instances, H, useTex = true) {
|
|
|
1750
1750
|
return cullCore(s.all, H, s.nSteps > 1 ? s.stepOf : undefined);
|
|
1751
1751
|
}
|
|
1752
1752
|
|
|
1753
|
-
// ../../../../../../../tmp/ldr-build-
|
|
1753
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/render.ts
|
|
1754
1754
|
async function loadPack(url) {
|
|
1755
1755
|
const res = await fetch(url);
|
|
1756
1756
|
if (!res.ok)
|
|
@@ -1901,7 +1901,7 @@ function makeFinishMaterial(side, surface) {
|
|
|
1901
1901
|
m.userData.ldrSurface = surface;
|
|
1902
1902
|
return m;
|
|
1903
1903
|
}
|
|
1904
|
-
function makeTexturedMaterial(side, map, wrapU = false, baseMat) {
|
|
1904
|
+
function makeTexturedMaterial(side, map, wrapU = false, baseMat, gloss) {
|
|
1905
1905
|
const surface = baseMat?.userData?.ldrSurface ?? colourSurface({ alpha: 255, luminance: 0, finish: { type: "default" } });
|
|
1906
1906
|
const m = makeFinishMaterial(side, surface);
|
|
1907
1907
|
const prev = m.onBeforeCompile;
|
|
@@ -1913,20 +1913,48 @@ function makeTexturedMaterial(side, map, wrapU = false, baseMat) {
|
|
|
1913
1913
|
sh.vertexShader = `attribute vec2 ldrUV; varying vec2 vLdrUV;
|
|
1914
1914
|
` + sh.vertexShader.replace("#include <uv_vertex>", `#include <uv_vertex>
|
|
1915
1915
|
vLdrUV = ldrUV;`);
|
|
1916
|
-
|
|
1916
|
+
let fs = `uniform sampler2D ldrMap; uniform int ldrWrapU; varying vec2 vLdrUV;
|
|
1917
1917
|
` + sh.fragmentShader.replace("#include <color_fragment>", `#include <color_fragment>
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1918
|
+
vec2 ldrUv = vec2(ldrWrapU == 1 ? fract(vLdrUV.x) : vLdrUV.x, vLdrUV.y);
|
|
1919
|
+
float ldrInside = step(0.0, ldrUv.x) * step(ldrUv.x, 1.0) * step(0.0, ldrUv.y) * step(ldrUv.y, 1.0);
|
|
1920
|
+
{ vec4 t = texture2D(ldrMap, ldrUv); diffuseColor.rgb = mix(diffuseColor.rgb, t.rgb, t.a * ldrInside); }`);
|
|
1921
|
+
if (gloss) {
|
|
1922
|
+
sh.uniforms.ldrGlossMap = { value: gloss.map };
|
|
1923
|
+
sh.uniforms.ldrGlossA = { value: gloss.alpha ? 1 : 0 };
|
|
1924
|
+
fs = `uniform sampler2D ldrGlossMap; uniform float ldrGlossA;
|
|
1925
|
+
` + fs.replace("#include <roughnessmap_fragment>", `#include <roughnessmap_fragment>
|
|
1926
|
+
vec4 ldrG = texture2D(ldrGlossMap, ldrUv); float ldrGloss = mix(ldrG.r, ldrG.a, ldrGlossA) * ldrInside;
|
|
1927
|
+
roughnessFactor = mix(roughnessFactor, 0.08, ldrGloss);`).replace("#include <lights_fragment_end>", `#include <lights_fragment_end>
|
|
1928
|
+
reflectedLight.directSpecular *= 1.0 + 0.5 * ldrGloss; reflectedLight.indirectSpecular *= 1.0 + 0.5 * ldrGloss;`);
|
|
1929
|
+
}
|
|
1930
|
+
sh.fragmentShader = fs;
|
|
1921
1931
|
};
|
|
1922
|
-
m.customProgramCacheKey = () => "ldrColorTex|" + baseKey;
|
|
1932
|
+
m.customProgramCacheKey = () => "ldrColorTex|" + baseKey + (gloss ? "|g" : "");
|
|
1923
1933
|
m.userData.ldrMap = map;
|
|
1934
|
+
if (gloss)
|
|
1935
|
+
m.userData.ldrGloss = gloss;
|
|
1924
1936
|
return m;
|
|
1925
1937
|
}
|
|
1926
|
-
function
|
|
1938
|
+
function pngHasAlpha(b) {
|
|
1939
|
+
if (b.length < 33 || b[0] !== 137 || b[1] !== 80 || b[2] !== 78 || b[3] !== 71)
|
|
1940
|
+
return false;
|
|
1941
|
+
const type = b[25];
|
|
1942
|
+
if (type === 4 || type === 6)
|
|
1943
|
+
return true;
|
|
1944
|
+
for (let o = 8;o + 8 <= b.length; ) {
|
|
1945
|
+
const len = (b[o] << 24 | b[o + 1] << 16 | b[o + 2] << 8 | b[o + 3]) >>> 0, t = String.fromCharCode(b[o + 4], b[o + 5], b[o + 6], b[o + 7]);
|
|
1946
|
+
if (t === "tRNS")
|
|
1947
|
+
return true;
|
|
1948
|
+
if (t === "IDAT" || t === "IEND")
|
|
1949
|
+
return false;
|
|
1950
|
+
o += 12 + len;
|
|
1951
|
+
}
|
|
1952
|
+
return false;
|
|
1953
|
+
}
|
|
1954
|
+
function packTexture(pack, i, data = false) {
|
|
1927
1955
|
const t = new THREE.Texture;
|
|
1928
1956
|
t.flipY = false;
|
|
1929
|
-
t.colorSpace = THREE.SRGBColorSpace;
|
|
1957
|
+
t.colorSpace = data ? THREE.NoColorSpace : THREE.SRGBColorSpace;
|
|
1930
1958
|
t.wrapS = t.wrapT = THREE.ClampToEdgeWrapping;
|
|
1931
1959
|
const e = pack.header.textures?.[i];
|
|
1932
1960
|
const bytes = e?.data ? pack.arr(e.data) : null;
|
|
@@ -2714,10 +2742,29 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
|
|
|
2714
2742
|
const texCache = new Map;
|
|
2715
2743
|
const texMats = new Map;
|
|
2716
2744
|
const pending = [];
|
|
2717
|
-
const
|
|
2745
|
+
const glossCache = new Map;
|
|
2746
|
+
const glossOf = (g) => {
|
|
2747
|
+
if (g === undefined)
|
|
2748
|
+
return;
|
|
2749
|
+
let gm = glossCache.get(g);
|
|
2750
|
+
if (gm === undefined) {
|
|
2751
|
+
const e = H.textures?.[g];
|
|
2752
|
+
const bytes = e?.data ? pack.arr(e.data) : null;
|
|
2753
|
+
if (bytes) {
|
|
2754
|
+
const r = packTexture(pack, g, true);
|
|
2755
|
+
pending.push(r.ready);
|
|
2756
|
+
gm = { map: r.texture, alpha: pngHasAlpha(bytes) };
|
|
2757
|
+
} else
|
|
2758
|
+
gm = null;
|
|
2759
|
+
glossCache.set(g, gm);
|
|
2760
|
+
}
|
|
2761
|
+
return gm ?? undefined;
|
|
2762
|
+
};
|
|
2763
|
+
const texMat = (t, base, wrapU, g) => {
|
|
2718
2764
|
const role = base.userData?.ldrSideRole ?? (base.side === THREE.BackSide ? "B" : base.side === THREE.DoubleSide ? "D" : "F");
|
|
2719
2765
|
const fin = base.userData?.ldrFinish ?? "default";
|
|
2720
|
-
const
|
|
2766
|
+
const gloss = glossOf(g);
|
|
2767
|
+
const k = t + ":" + role + ":" + fin + ":" + (wrapU ? 1 : 0) + (gloss ? ":g" + g : "");
|
|
2721
2768
|
let m = texMats.get(k);
|
|
2722
2769
|
if (!m) {
|
|
2723
2770
|
let tx = texCache.get(t);
|
|
@@ -2727,7 +2774,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
|
|
|
2727
2774
|
pending.push(r.ready);
|
|
2728
2775
|
texCache.set(t, tx);
|
|
2729
2776
|
}
|
|
2730
|
-
texMats.set(k, m = makeTexturedMaterial(base.side, tx, wrapU, base));
|
|
2777
|
+
texMats.set(k, m = makeTexturedMaterial(base.side, tx, wrapU, base, gloss));
|
|
2731
2778
|
}
|
|
2732
2779
|
return m;
|
|
2733
2780
|
};
|
|
@@ -2796,7 +2843,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
|
|
|
2796
2843
|
if (textured)
|
|
2797
2844
|
for (const tb of p.tex) {
|
|
2798
2845
|
const gg = geom(tb, arr);
|
|
2799
|
-
const im = newIM(gg, texMat(tb.t, mat, !!tb.wrapU), ids.length);
|
|
2846
|
+
const im = newIM(gg, texMat(tb.t, mat, !!tb.wrapU, tb.g), ids.length);
|
|
2800
2847
|
texBatches++;
|
|
2801
2848
|
lv0.push(im);
|
|
2802
2849
|
if (bodyIm) {
|
|
@@ -3210,6 +3257,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
|
|
|
3210
3257
|
stats.condBatches = condObjs.length;
|
|
3211
3258
|
stats.texBatches = texBatches;
|
|
3212
3259
|
stats.textures = texCache.size;
|
|
3260
|
+
stats.glossmaps = [...glossCache.values()].filter(Boolean).length;
|
|
3213
3261
|
stats.clusters = root.clusters.length;
|
|
3214
3262
|
const texturesReady = Promise.all(pending).then(() => {});
|
|
3215
3263
|
let stepS = STEP_NEVER - 1, cullS = !!P.cullStuds, cullU = !!P.cullUnder;
|
|
@@ -3416,7 +3464,7 @@ async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
|
|
|
3416
3464
|
await new Promise((r) => setTimeout(r, 0));
|
|
3417
3465
|
}
|
|
3418
3466
|
}
|
|
3419
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3467
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/scene.ts
|
|
3420
3468
|
import * as THREE2 from "three";
|
|
3421
3469
|
function colorFn(src, pack, fallback) {
|
|
3422
3470
|
const table = new Map;
|
|
@@ -3517,6 +3565,7 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3517
3565
|
});
|
|
3518
3566
|
for (const m of [...mats, ...pairs.values()]) {
|
|
3519
3567
|
m.userData.ldrMap?.dispose();
|
|
3568
|
+
m.userData.ldrGloss?.map.dispose();
|
|
3520
3569
|
m.dispose();
|
|
3521
3570
|
}
|
|
3522
3571
|
cur = null;
|
|
@@ -3546,7 +3595,7 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3546
3595
|
cur.setLod(false);
|
|
3547
3596
|
if (cur.root.parent !== object)
|
|
3548
3597
|
object.add(cur.root);
|
|
3549
|
-
Object.assign(stats, { drawn: drawnAt(null), studsTotal: cur.stats.studsTotal, studsHidden: cur.stats.studsHidden, undersTotal: cur.stats.undersTotal, undersHidden: cur.stats.undersHidden, condBatches: cur.stats.condBatches ?? 0, texBatches: cur.stats.texBatches ?? 0, textures: cur.stats.textures ?? 0, clusters: cur.stats.clusters ?? 0, longestSliceMs: cur.stats.longestSliceMs, buildYields: cur.stats.buildYields, buildMs: performance.now() - t0 });
|
|
3598
|
+
Object.assign(stats, { drawn: drawnAt(null), studsTotal: cur.stats.studsTotal, studsHidden: cur.stats.studsHidden, undersTotal: cur.stats.undersTotal, undersHidden: cur.stats.undersHidden, condBatches: cur.stats.condBatches ?? 0, texBatches: cur.stats.texBatches ?? 0, textures: cur.stats.textures ?? 0, glossmaps: cur.stats.glossmaps ?? 0, clusters: cur.stats.clusters ?? 0, longestSliceMs: cur.stats.longestSliceMs, buildYields: cur.stats.buildYields, buildMs: performance.now() - t0 });
|
|
3550
3599
|
api.texturesReady = cur.texturesReady;
|
|
3551
3600
|
};
|
|
3552
3601
|
const setStep = (step, mask = null) => {
|
|
@@ -3633,10 +3682,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
|
|
|
3633
3682
|
return finish();
|
|
3634
3683
|
})();
|
|
3635
3684
|
}
|
|
3636
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3685
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/parts-cdn.ts
|
|
3637
3686
|
import { decompress as decompress2 } from "fzstd";
|
|
3638
3687
|
|
|
3639
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3688
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/embedded.ts
|
|
3640
3689
|
function splitFiles(text, fallback) {
|
|
3641
3690
|
const files = new Map;
|
|
3642
3691
|
let cur = null, saw = false;
|
|
@@ -3708,7 +3757,7 @@ function embeddedKeys(text, names, fallback = "main.ldr") {
|
|
|
3708
3757
|
return out;
|
|
3709
3758
|
}
|
|
3710
3759
|
|
|
3711
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3760
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/parts-cdn.ts
|
|
3712
3761
|
var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
|
|
3713
3762
|
var indexCache = new Map;
|
|
3714
3763
|
var shardCache = new Map;
|
|
@@ -3940,10 +3989,10 @@ async function prepareModel(source, o = {}) {
|
|
|
3940
3989
|
return { insts, pack, missing, requests, bytes, cull, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, ...cull ? { cull: performance.now() - t3 } : {} } };
|
|
3941
3990
|
}
|
|
3942
3991
|
|
|
3943
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3992
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/load-worker.gen.ts
|
|
3944
3993
|
var load_worker_gen_default = 'var bt=ArrayBuffer,W=Uint8Array,de=Uint16Array,yt=Int16Array;var be=Int32Array,Ee=function(e,t,n){if(W.prototype.slice)return W.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 W(n-t);return r.set(e.subarray(t,n)),r},ce=function(e,t,n,r){if(W.prototype.fill)return W.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},xt=function(e,t,n,r){if(W.prototype.copyWithin)return W.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 wt=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],K=function(e,t,n){var r=Error(t||wt[e]);if(r.code=e,Error.captureStackTrace)Error.captureStackTrace(r,K);if(!n)throw r;return r},je=function(e,t,n){var r=0,s=0;for(;r<n;++r)s|=e[t++]<<(r<<3);return s},At=function(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0},Mt=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,l=r>>6;if(r&8)K(0);var a=6-s,c=i==3?4:i,f=je(e,a,c);a+=c;var m=l?1<<l:s,g=je(e,a,m)+(l==1&&256),y=g;if(!s){var v=1<<10+(e[5]>>3);y=v+(v>>3)*(e[5]&7)}if(y>2145386496)K(1);var x=new W((t==1?g||y:t?0:y)+12);return x[0]=1,x[4]=4,x[8]=8,{b:a+m,y:0,l:0,d:f,w:t&&t!=1?t:x.subarray(12),e:y,o:new be(x.buffer,0,3),u:g,c:o,m:Math.min(131072,y)}}else if((n>>4|e[3]<<20)==25481893)return At(e,4)+8;K(0)},re=function(e){var t=0;for(;1<<t<=e;++t);return t-1},ue=function(e,t,n){var r=(t<<3)+4,s=(e[t]&15)+5;if(s>n)K(3);var o=1<<s,i=o,l=-1,a=-1,c=-1,f=o,m=new bt(512+(o<<2)),g=new yt(m,0,256),y=new de(m,0,256),v=new de(m,512,o),x=512+(o<<1),S=new W(m,x,o),h=new W(m,x+o);while(l<255&&i>0){var u=re(i+1),d=r>>3,p=(1<<u+1)-1,L=(e[d]|e[d+1]<<8|e[d+2]<<16)>>(r&7)&p,b=(1<<u)-1,T=p-i-1,E=L&b;if(E<T)r+=u,L=E;else if(r+=u+1,L>b)L-=T;if(g[++l]=--L,L==-1)i+=L,S[--f]=l;else i-=L;if(!L)do{var D=r>>3;a=(e[D]|e[D+1]<<8)>>(r&7)&3,r+=2,l+=a}while(a==3)}if(l>255||i)K(0);var C=0,U=(o>>1)+(o>>3)+3,X=o-1;for(var H=0;H<=l;++H){var M=g[H];if(M<1){y[H]=-M;continue}for(c=0;c<M;++c){S[C]=H;do C=C+U&X;while(C>=f)}}if(C)K(0);for(c=0;c<o;++c){var A=y[S[c]]++,k=h[c]=s-re(A);v[c]=(A<<k)-o}return[r+7>>3,{b:s,s:S,n:h,t:v}]},vt=function(e,t){var n=0,r=-1,s=new W(292),o=e[t],i=s.subarray(0,256),l=s.subarray(256,268),a=new de(s.buffer,268);if(o<128){var c=ue(e,t+1,6),f=c[0],m=c[1];t+=o;var g=f<<3,y=e[t];if(!y)K(0);var v=0,x=0,S=m.b,h=S,u=(++t<<3)-8+re(y);for(;;){if(u-=S,u<g)break;var d=u>>3;if(v+=(e[d]|e[d+1]<<8)>>(u&7)&(1<<S)-1,i[++r]=m.s[v],u-=h,u<g)break;d=u>>3,x+=(e[d]|e[d+1]<<8)>>(u&7)&(1<<h)-1,i[++r]=m.s[x],S=m.n[v],v=m.t[v],h=m.n[x],x=m.t[x]}if(++r>255)K(0)}else{r=o-127;for(;n<r;n+=2){var p=e[++t];i[n]=p>>4,i[n+1]=p&15}++t}var L=0;for(n=0;n<r;++n){var b=i[n];if(b>11)K(0);L+=b&&1<<b-1}var T=re(L)+1,E=1<<T,D=E-L;if(D&D-1)K(0);i[r++]=re(D)+1;for(n=0;n<r;++n){var b=i[n];++l[i[n]=b&&T+1-b]}var C=new W(E<<1),U=C.subarray(0,E),X=C.subarray(E);a[T]=0;for(n=T;n>0;--n){var H=a[n];ce(X,n,H,a[n-1]=H+l[n]*(1<<T-n))}if(a[0]!=E)K(0);for(n=0;n<r;++n){var M=i[n];if(M){var A=a[M];ce(U,n,A,a[M]=A+(1<<T-M))}}return[t,{n:X,b:T,s:U}]},Tt=ue(new W([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],Ct=ue(new W([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],Et=ue(new W([32,132,16,66,102,70,68,68,68,68,36,73,2]),0,5)[1],Ve=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},Se=new W(new be([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),St=Ve(Se,0),Pe=new W(new be([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),Pt=Ve(Pe,3),le=function(e,t,n){var r=e.length,s=t.length,o=e[r-1],i=(1<<n.b)-1,l=-n.b;if(!o)K(0);var a=0,c=n.b,f=(r<<3)-8+re(o)-c,m=-1;for(;f>l&&m<s;){var g=f>>3,y=(e[g]|e[g+1]<<8|e[g+2]<<16)>>(f&7);a=(a<<c|y)&i,t[++m]=n.s[a],f-=c=n.n[a]}if(f!=l||m+1!=s)K(0)},Lt=function(e,t,n){var r=6,s=t.length,o=s+3>>2,i=o<<1,l=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,l),n),le(e.subarray(r),t.subarray(l),n)},kt=function(e,t,n){var r,s=t.b,o=e[s],i=o>>1&3;t.l=o&1;var l=o>>3|e[s+1]<<5|e[s+2]<<13,a=(s+=3)+l;if(i==1){if(s>=e.length)return;if(t.b=s+1,n)return ce(n,e[s],t.y,t.y+=l),n;return ce(new W(l),e[s])}if(a>e.length)return;if(i==0){if(t.b=a,n)return n.set(e.subarray(s,a),t.y),t.y+=l,n;return Ee(e,s,a)}if(i==2){var c=e[s],f=c&3,m=c>>2&3,g=c>>4,y=0,v=0;if(f<2)if(m&1)g|=e[++s]<<4|(m&2&&e[++s]<<12);else g=c>>3;else if(v=m,m<2)g|=(e[++s]&63)<<4,y=e[s]>>6|e[++s]<<2;else if(m==2)g|=e[++s]<<4|(e[++s]&3)<<12,y=e[s]>>2|e[++s]<<6;else g|=e[++s]<<4|(e[++s]&63)<<12,y=e[s]>>6|e[++s]<<2|e[++s]<<10;++s;var x=n?n.subarray(t.y,t.y+t.m):new W(t.m),S=x.length-g;if(f==0)x.set(e.subarray(s,s+=g),S);else if(f==1)ce(x,e[s++],S);else{var h=t.h;if(f==2){var u=vt(e,s);y+=s-(s=u[0]),t.h=h=u[1]}else if(!h)K(0);(v?Lt:le)(e.subarray(s,s+=y),x.subarray(S),h)}var d=e[s++];if(d){if(d==255)d=(e[s++]|e[s++]<<8)+32512;else if(d>127)d=d-128<<8|e[s++];var p=e[s++];if(p&3)K(0);var L=[Ct,Et,Tt];for(var b=2;b>-1;--b){var T=p>>(b<<1)+2&3;if(T==1){var E=new W([0,0,e[s++]]);L[b]={s:E.subarray(2,3),n:E.subarray(0,1),t:new de(E.buffer,0,1),b:0}}else if(T==2)r=ue(e,s,9-(b&1)),s=r[0],L[b]=r[1];else if(T==3){if(!t.t)K(0);L[b]=t.t[b]}}var D=t.t=L,C=D[0],U=D[1],X=D[2],H=e[a-1];if(!H)K(0);var M=(a<<3)-8+re(H)-X.b,A=M>>3,k=0,V=(e[A]|e[A+1]<<8)>>(M&7)&(1<<X.b)-1;A=(M-=U.b)>>3;var B=(e[A]|e[A+1]<<8)>>(M&7)&(1<<U.b)-1;A=(M-=C.b)>>3;var N=(e[A]|e[A+1]<<8)>>(M&7)&(1<<C.b)-1;for(++d;--d;){var P=X.s[V],w=X.n[V],O=C.s[N],F=C.n[N],R=U.s[B],z=U.n[B];A=(M-=R)>>3;var j=1<<R,I=j+((e[A]|e[A+1]<<8|e[A+2]<<16|e[A+3]<<24)>>>(M&7)&j-1);A=(M-=Pe[O])>>3;var G=Pt[O]+((e[A]|e[A+1]<<8|e[A+2]<<16)>>(M&7)&(1<<Pe[O])-1);A=(M-=Se[P])>>3;var _=St[P]+((e[A]|e[A+1]<<8|e[A+2]<<16)>>(M&7)&(1<<Se[P])-1);if(A=(M-=w)>>3,V=X.t[V]+((e[A]|e[A+1]<<8)>>(M&7)&(1<<w)-1),A=(M-=F)>>3,N=C.t[N]+((e[A]|e[A+1]<<8)>>(M&7)&(1<<F)-1),A=(M-=z)>>3,B=U.t[B]+((e[A]|e[A+1]<<8)>>(M&7)&(1<<z)-1),I>3)t.o[2]=t.o[1],t.o[1]=t.o[0],t.o[0]=I-=3;else{var Y=I-(_!=0);if(Y){if(I=Y==3?t.o[0]-1:t.o[Y],Y>1)t.o[2]=t.o[1];t.o[1]=t.o[0],t.o[0]=I}else I=t.o[0]}for(var b=0;b<_;++b)x[k+b]=x[S+b];k+=_,S+=_;var q=k-I;if(q<0){var J=-q,ee=t.e+q;if(J>G)J=G;for(var b=0;b<J;++b)x[k+b]=t.w[ee+b];k+=J,G-=J,q=0}for(var b=0;b<G;++b)x[k+b]=x[q+b];k+=G}if(k!=S)while(S<x.length)x[k++]=x[S++];else k=x.length;if(n)t.y+=k;else x=Ee(x,0,k)}else if(n){if(t.y+=g,S)for(var b=0;b<g;++b)x[b]=x[S+b]}else if(S)x=Ee(x,S);return t.b=a,x}K(2)},Bt=function(e,t){if(e.length==1)return e[0];var n=new W(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=Mt(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 l=kt(e,i,t);if(!l)K(5);if(t)i.e=i.y;else n.push(l),o+=l.length,xt(i.w,0,l.length),i.w.set(l,i.w.length-l.length)}s=i.b+i.c*4}else s=i;e=e.subarray(s)}return Bt(n,o)}async function It(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 He(e){return new TextDecoder().decode(await It(e))}var Ge=(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 Z=(e)=>e.trim().toLowerCase().replace(/\\\\/g,"/").replace(/\\/+/g,"/");function Le(e){if(/^0x/i.test(e))return parseInt(e,16);return+e}var _e=/^~?\\s*moved\\s+to\\s+(.+)$/i,Ft=new Set(["FILE","NOFILE","!DATA","!:","STEP","BFC","ROTSTEP","BUFEXCHG","!TEXMAP"]),Qe=new Set(["part","subpart","primitive","8_primitive","48_primitive","shortcut","helper"]),Rt=new Set(["model","submodel","configuration"]),Dt=/^(?:!?LDRAW_ORG|Unofficial|Official\\s+LCAD)\\s+(\\S+)/i;function We(e){let t=Dt.exec(e);if(!t)return;let n=t[1].toLowerCase().replace(/^unofficial_/,"");return Qe.has(n)||Rt.has(n)?n:void 0}function Ut(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 zt(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 l=n[2].trim();for(let m=0;m<s;m++)l=l.replace(/^\\S+\\s*/,"");let a=Ut(l);if(!a.length)return null;let c={method:r,p1:i.slice(0,3),p2:i.slice(3,6),p3:i.slice(6,9),texture:a[0]};if(s>=10)c.a=i[9];if(s===11)c.b=i[10];let f=a.findIndex((m,g)=>g>0&&m.toUpperCase()==="GLOSSMAP");if(f>0&&a[f+1])c.glossmap=a[f+1];if(t)c.next=!0;return c}var Ot=(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 Nt(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 l=e.slice(n),a=/[ \\t]{2,}|\\t/.test(l)?l.split(/\\s+/).join(" "):l;return{t:1,color:Le(o),m:i,file:Z(a)}}function Ke(e){let t=+e[0];if(!(t>=1&&t<=5)||e.length<2)return null;let n=Le(e[1]),r=e.slice(2).map(Number);if(t===1)return{t:1,color:n,m:r.slice(0,12),file:Z(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 et(e,t="main.ldr",n={}){let r=!!n.geometryText,s=new Map,o=null,i="",l,a=null,c=[],f=null,m=()=>{if(!a)return;let u=Ot(a.chunks.join("")),d=u[0]===137&&u[1]===80&&u[2]===78&&u[3]===71;(l??=new Map).set(Z(a.name),{name:a.name,bytes:u,...d?{mime:"image/png"}:{}}),a=null},g=!0,y=(u)=>{if(m(),o={name:Z(u),cmds:[]},s.set(o.name,o),!i)i=o.name;c=[],f=null,g=!0},v=!1,x=!1,S=()=>{if(x)return;x=!0,s.clear(),o=null,i=""},h=(u,d)=>{if(f){u.tex=f,f=null;return}let p=c[c.length-1];if(!p)return;if(p.fallback){if(!d)u.fallback=!0}else u.tex=p.map};for(let u of e.split(`\n`)){let d=u.trim();if(!d)continue;if(r&&d.charCodeAt(0)>=50&&d.charCodeAt(0)<=53&&(d.charCodeAt(1)===32||d.charCodeAt(1)===9)){if(a||v)continue;if(!o)y(t);let T=d.slice(2).trimStart(),E=T.search(/\\s/),D={t:d.charCodeAt(0)-48,color:Le(E<0?T:T.slice(0,E)),p:[],src:d};h(D,!1),o.cmds.push(D),g=!1;continue}if(d.charCodeAt(0)===48&&(d.charCodeAt(1)===32||d.charCodeAt(1)===9)){let T=2;while(d.charCodeAt(T)===32||d.charCodeAt(T)===9)T++;let E=T;while(E<d.length&&d.charCodeAt(E)!==32&&d.charCodeAt(E)!==9)E++;let D=d.slice(T,E);if(!Ft.has(D)){if(v||a)continue;if(!o)y(t);let C=d.slice(T),U={t:0,text:C};if(D.charCodeAt(0)===33)U.meta=D;if(f=null,g&&!o.org){let H=We(C);if(H)o.org=H}let X=C.match(_e);if(X&&!o.movedTo){let H=X[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(H))H+=".dat";o.movedTo=Z(H)}o.cmds.push(U);continue}}if(d.charCodeAt(0)===49&&(d.charCodeAt(1)===32||d.charCodeAt(1)===9)&&!a&&!v){let T=Nt(d);if(T){if(!o)y(t);h(T,!1),o.cmds.push(T),g=!1;continue}}let p=d.split(/\\s+/);if(+p[0]===0){let T=d.slice(1).trim();if(p[1]==="FILE"){S(),v=!1,y(T.slice(5));continue}if(p[1]==="NOFILE"){m(),o=null,v=!0;continue}if(p[1]==="!DATA"){S(),m(),o=null,v=!1,a={name:T.slice(5).trim(),chunks:[]};continue}if(v)continue;if(a){if(p[1]==="!:")a.chunks.push(p.slice(2).join(""));continue}if(!o)y(t);let E={t:0,text:T};if(p[1]==="STEP")E.step=!0,c=[],f=null;else if(p[1]==="BFC")E.bfc=p.slice(2).join(" ");else if(p[1]==="ROTSTEP")if(E.meta="ROTSTEP",E.step=!0,c=[],f=null,(p[2]??"").toUpperCase()==="END")E.rotstep={x:0,y:0,z:0,mode:"END"};else{let C=(p[5]??"REL").toUpperCase();E.rotstep={x:+p[2]||0,y:+p[3]||0,z:+p[4]||0,mode:["REL","ABS","ADD"].includes(C)?C:"REL"}}else if(p[1]==="BUFEXCHG"){E.meta="BUFEXCHG";let C=(p[2]??"").toUpperCase();E.bufexchg={op:C==="RETRIEVE"?"RETRIEVE":"STORE",buf:p[3]??"A"}}else if(p[1]?.startsWith("!"))E.meta=p[1];if(g&&!o.org){let C=We(T);if(C)o.org=C}if(p[1]==="!TEXMAP"){let C=(p[2]??"").toUpperCase();if(f=null,C==="START"||C==="NEXT"){let U=zt(T.replace(/^!TEXMAP\\s+\\S+/i,""),C==="NEXT");if(E.texmap={op:C,...U?{map:U}:{}},U)if((o.texmaps??=[]).push(U),C==="START")c.push({map:U,fallback:!1});else f=U}else if(C==="FALLBACK"){E.texmap={op:C};let U=c[c.length-1];if(U)U.fallback=!0}else if(C==="END")E.texmap={op:C},c.pop()}else if(p[1]==="!:"){f=null;let C=Ke(p.slice(2));if(C)h(C,!0),E.geom=C}else f=null;let D=T.match(_e);if(D&&!o.movedTo){let C=D[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(C))C+=".dat";o.movedTo=Z(C)}o.cmds.push(E);continue}if(a||v)continue;if(!o)y(t);let b=Ke(p);if(!b)continue;h(b,!1),o.cmds.push(b),g=!1}return m(),l?{main:i,files:s,data:l}:{main:i,files:s}}var cn=Math.PI/180;function tt(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 nt(e,t){let[n,r,s,o,i,l,a,c,f,m,g,y]=e,[v,x,S,h,u,d,p,L,b,T,E,D]=t;return[o*v+i*x+l*S+n,a*v+c*x+f*S+r,m*v+g*x+y*S+s,o*h+i*p+l*T,o*u+i*L+l*E,o*d+i*b+l*D,a*h+c*p+f*T,a*u+c*L+f*E,a*d+c*b+f*D,m*h+g*p+y*T,m*u+g*L+y*E,m*d+g*b+y*D]}var ke=[0,0,0,1,0,0,0,1,0,0,0,1];var Xe=new WeakMap,$t=/^(s|8|48)\\//;function Be(e,t){let n=e.files.get(Z(t));if(!n)return"part";let r=Xe.get(n);if(r)return r;if(n.org)r=Qe.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&&$t.test(s.file))?"part":"model";return Xe.set(n,r),r}var Ze=new WeakMap;function rt(e){let t=Ze.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 Ze.set(e,t),t}var Ye=(e)=>e>16777215?"0x"+e.toString(16).toUpperCase():String(e),jt=(e)=>e.t===0?"0 "+e.text:e.t===1?`1 ${Ye(e.color)} ${e.m.join(" ")} ${e.file}`:e.src?e.src:`${e.t} ${Ye(e.color)} ${e.p.join(" ")}`,Ie=(e,t)=>`${Z(e)}#${t}`;function Vt(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:Ie(e.name,t),cmds:n}}function st(e,t){return[`0 ldr: own geometry of ${e.name}, step ${t}`,...Vt(e,t).cmds.map(jt)].join(`\n`)+`\n`}function Ht(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 ot(e){let[t,n,r,s,o,i,l,a,c,f,m,g]=e,y=a*g-c*m,v=-(l*g-c*f),x=l*m-a*f,S=s*y+o*v+i*x;if(!Number.isFinite(S)||Math.abs(S)<0.000000000001)return null;let h=1/S,u=[y*h,-(o*g-i*m)*h,(o*c-i*a)*h,v*h,(s*g-i*f)*h,-(s*c-i*l)*h,x*h,-(s*m-o*f)*h,(s*a-o*l)*h];return[-(u[0]*t+u[1]*n+u[2]*r),-(u[3]*t+u[4]*n+u[5]*r),-(u[6]*t+u[7]*n+u[8]*r),...u]}var Gt=(e)=>String(+e.toFixed(6)||0),Je=(e)=>\'"\'+e.replace(/\\\\/g,"\\\\\\\\").replace(/"/g,"\\\\\\"")+\'"\';function it(e,t){let n=[...t.p1,...t.p2,...t.p3,...t.method!=="PLANAR"?[t.a??360]:[],...t.method==="SPHERICAL"?[t.b??180]:[]].map(Gt).join(" "),r=`0 ldr: ${e} with a model-level !TEXMAP\n0 BFC CERTIFY CCW\n0 !TEXMAP START ${t.method} ${n} ${Je(t.texture)}${t.glossmap?" GLOSSMAP "+Je(t.glossmap):""}\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 ${Z(e)}\n0 !TEXMAP END\n`;return{name:`${Z(e)}#tex-${Ht(r)}`,source:r}}var _t=(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 Wt(e,t,n){let r=Math.PI/180,s=Math.sin(e*r),o=Math.cos(e*r),i=Math.sin(t*r),l=Math.cos(t*r),a=Math.sin(n*r),c=Math.cos(n*r);return[l*c,-l*a,i,o*a+s*i*c,o*c-s*i*a,-s*l,s*a-o*i*c,s*c+o*i*a,o*l]}var qe=new WeakMap;function at(e){let t=qe.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=Wt(o.x,o.y,o.z);r=o.mode==="ABS"?{abs:!0,m:i,rotstep:o}:o.mode==="ADD"&&r?{abs:r.abs,m:_t(r.m,i),rotstep:o}:{abs:!1,m:i,rotstep:o}}n.push(r)}return n.push(r),qe.set(e,n),n}var lt=999999,ct=(e)=>e.map((t)=>String(t).padStart(6,"0")).join(".")+"~";function Kt(e,t={}){let n=[],r=t.maxDepth??64,s=t.looseGeometry!==!1,o=!!t.textures,i=!!t.callouts,l=new Map,a=0,c=(m,g)=>{let y=m.name+"#"+g,v=l.get(y);if(!v){let x;v=Object.assign(()=>x??=st(m,g),{file:m,step:g}),l.set(y,v)}return v},f=(m,g,y,v,x,S,h,u,d=null,p=[],L=[])=>{let b=m.files.get(g);if(!b||h>r)return;let T=0,E=h>0?++a:0,D=i&&E?[...p,E]:p,C=i&&E?[...L,y]:L,U=i&&!d?new Map:null,X=-1,H=0,M=(P,w,O,F,R,z)=>{if(X!==T)X=T,H=0;let j=U?.get(T+"|"+w);if(j)return j.n++,f(P,P===m?w:P.main,O,F,x+"/"+w,[...R,lt],h+1,z,[...R,lt],D,C);let I=[...R,H++],G=n.length;f(P,P===m?w:P.main,O,F,x+"/"+w,I,h+1,z,d,D,C),U?.set(T+"|"+w,{n:1,from:G,to:n.length})},A=at(b),k=s?rt(b):[],V=0,B=(P,w,O,F,R,z,j)=>{if(d)F=d;let I={part:P,color:w,m:O,step:F[0],steps:F,localStep:R,path:x};if(E){if(I.sub=E,i)I.subPath=D,I.subMats=C}if(z)I.embedded=!0;if(j){let _=it(P,j);I.texPart=_.name,I.texSource=_.source}let G=A[R];if(G)I.view=G;return n.push(I),I},N=(P)=>{while(V<k.length&&k[V]<=P){let w=k[V++];B(Ie(b.name,w),v,y,[...S,w],w,!1,null).source=c(b,w)}};for(let P of b.cmds){if(P.t===0&&P.step){T++;continue}let w=P;if(w.t>=2||w.t===0&&w.geom&&w.geom.t>=2){N(T);continue}if(w.t===0)if(o&&w.geom?.t===1)w=w.geom;else continue;if(w.t!==1)continue;if(o&&w.fallback)continue;let O=w.color===16?v:w.color,F=nt(y,w.m),R=[...S,T],z=o?w.tex??u:null,j=z?ot(w.m):null,I=z&&j?tt(z,j):null;if(m.files.has(w.file)){if(Be(m,w.file)==="model"){M(m,w.file,F,O,R,I);continue}B(w.file,O,F,R,T,!0,I);continue}let G=t.resolveModel?.(w.file);if(G){M(G,w.file,F,O,R,I);continue}B(w.file,O,F,R,T,!1,I)}if(N(1/0),U){for(let P of U.values())if(P.n>1)for(let w=P.from;w<P.to;w++)n[w].mult??=P.n}};if(Be(e,e.main)==="part"){if(e.files.get(e.main))n.push({part:e.main,color:16,m:[...ke],step:0,steps:[0],localStep:0,path:e.main,embedded:!0});return n}return f(e,e.main,ke,16,e.main,[],0,null),n}function ut(e,t="main.ldr",n){return Kt(et(e,t,{geometryText:!0}),n)}function Xt(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(Z(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(Z(t),r)}let l=o.trim().replace(/\\s+/g," ");if(l)r.push(l)}return n}var Zt=(e)=>{if(!e.startsWith("1 "))return null;let t=e.split(" ");return t.length>=15?Z(t.slice(14).join(" ")):null};function Yt(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 ft(e,t,n="main.ldr"){let r=Xt(e,n),s=new Map;for(let o of t){let i=Z(o);if(!r.has(i)||s.has(i))continue;let l=new Set([i]),a=[i];while(a.length)for(let f of r.get(a.pop())){let m=Zt(f);if(m&&r.has(m)&&!l.has(m))l.add(m),a.push(m)}let c=[i,...[...l].filter((f)=>f!==i).sort()].map((f)=>"0 FILE "+(f===i?"":f)+`\n`+r.get(f).join(`\n`)).join(`\n`);s.set(i,`emb/${Yt(c)}.dat`)}return s}var pt=(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,mt=new WeakMap;function Fe(e,t){let n=mt.get(e);if(!n)mt.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),l=[],a=[];s.studs.forEach((g,y)=>{l.push(g[0]),a.push(g[1]);for(let v=0;v<12;v++)i[y*12+v]=g[2+v]});let c=null,f=0,m=0;if(s.mask){f=s.mask[0],m=s.mask[1];let g=s.mask[2];c=new Uint8Array(g.length);for(let y=0;y<g.length;y++)c[y]=g.charCodeAt(y)===49?1:0}return n.set(t,r={nStuds:o,studM:i,kind:l,color:a,mask:c,nx:f,nz:m}),r}var ie=1073741824;class Re{a;b;c;vals;used;mask;size=0;constructor(e=1024){let t=1024;while(t<e*2)t*=2;this.a=new Int32Array(t),this.b=new Int32Array(t),this.c=new Int32Array(t),this.vals=new Int32Array(t),this.used=new Uint8Array(t),this.mask=t-1}slot(e,t,n){let r=Math.imul(e,2654435761)^Math.imul(t,2246822507)^Math.imul(n,3266489909);return r^=r>>>15,r=Math.imul(r,739982445),r^=r>>>12,r&this.mask}get(e,t,n){let r=this.slot(e,t,n),s=this.used,o=this.a,i=this.b,l=this.c;for(;;){if(!s[r])return-1;if(o[r]===e&&i[r]===t&&l[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,l=this.b,a=this.c;for(;;){if(!o[s])return o[s]=1,i[s]=e,l[s]=t,a[s]=n,this.vals[s]=r,this.size++,-1;if(i[s]===e&&l[s]===t&&a[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 Jt(e,t,n){let s=[],o=[],i=[],l=[],a=[],c=[],f=[],m=[],g=new Re(e.length*2),y=[],v=[];for(let M=0;M<e.length;M++){let A=e[M],k=A.m,V=t.parts[A.part];if(!V||!V.mask||!pt(k))continue;let B=V.bbox,N=1/0,P=-1/0,w=1/0,O=-1/0;for(let z=0;z<2;z++)for(let j=0;j<2;j++){let I=z?B[3]:B[0],G=j?B[5]:B[2],_=k[0]+k[3]*I+k[5]*G,Y=k[2]+k[9]*I+k[11]*G;if(_<N)N=_;if(_>P)P=_;if(Y<w)w=Y;if(Y>O)O=Y}let F=a.length;s.push(N),o.push(P),i.push(w),l.push(O),a.push(M),c.push(Fe(t,A.part)),f.push(B[0]),m.push(B[2]);let R=Math.round((k[1]+B[4])*2);for(let z=Math.floor(N/40);z<=Math.floor(P/40);z++)for(let j=Math.floor(w/40);j<=Math.floor(O/40);j++){if(!we(R,z,j))continue;let I=v.length;v.push(F),y.push(g.put(R,z,j,I))}}let x=[0,5,-5,5,-5],S=[0,5,5,-5,-5],h=NaN,u=NaN,d=NaN,p=-1,L=(M,A,k,V)=>{let B=Math.round(A*2),N=Math.floor(M/40),P=Math.floor(k/40);if(!we(B,N,P))return fe;let w=fe;if(B!==h||N!==u||P!==d)h=B,u=N,d=P,p=g.get(B,N,P);for(let O=p;O>=0;O=y[O]){let F=v[O];if(a[F]===V||!(M-6>=s[F]-0.5&&M+6<=o[F]+0.5&&k-6>=i[F]-0.5&&k+6<=l[F]+0.5))continue;let R=e[a[F]].m,z=c[F],j=f[F],I=m[F],G=M-R[0],_=A-R[1],Y=k-R[2],q=R[3]*G+R[6]*_+R[9]*Y,J=R[5]*G+R[8]*_+R[11]*Y,{nx:ee,nz:se,mask:ae}=z,oe=!0;for(let Q=0;Q<5;Q++){let te=Math.floor((q+x[Q]-j)/20),ne=Math.floor((J+S[Q]-I)/20);if(te<0||ne<0||te>=ee||ne>=se||ae[te*se+ne]!==1){oe=!1;break}}if(oe){if(!n)return 0;let Q=n[a[F]];if(Q<w)w=Q}}return w},b=0;for(let M of e){let A=Fe(t,M.part);if(A)b+=A.nStuds}let T=new Uint8Array(b),E=new Uint8Array(b),D=new Re(b),C=0,U=n?new Int32Array(b).fill(fe):void 0;for(let M=0,A=0;M<e.length;M++){let k=e[M],V=Fe(t,k.part);if(!V)continue;let B=k.m,N=V.studM,P=B[0],w=B[1],O=B[2],F=B[3],R=B[4],z=B[5],j=B[6],I=B[7],G=B[8],_=B[9],Y=B[10],q=B[11];for(let J=0;J<V.nStuds;J++,A++){let ee=J*12,se=N[ee+4],ae=N[ee+7],oe=N[ee+10];if(!(Math.abs(j*se+I*ae+G*oe-1)<0.001&&Math.abs(F*se+R*ae+z*oe)<0.001&&Math.abs(_*se+Y*ae+q*oe)<0.001))continue;E[A]=1;let Q=N[ee],te=N[ee+1],ne=N[ee+2],De=P+F*Q+R*te+z*ne,Ue=w+j*Q+I*te+G*ne,ze=O+_*Q+Y*te+q*ne,Oe=L(De,Ue,ze,M);if(Oe!==fe){if(T[A]=1,C++,U)U[A]=Oe}let me=Math.round(De),he=Math.round(Ue),ge=Math.round(ze);if(!we(me,he,ge))continue;if(!n){D.put(me,he,ge,1);continue}let Ne=n[M],$e=D.get(me,he,ge);if($e<0||Ne<$e)D.put(me,he,ge,Ne)}}let X=new Uint8Array(e.length),H=n?new Int32Array(e.length).fill(fe):void 0;for(let M=0;M<e.length;M++){let A=e[M],k=t.parts[A.part];if(!k||!k.under||!pt(A.m))continue;let V=k.bbox,B=Math.round((V[3]-V[0])/20),N=Math.round((V[5]-V[2])/20);if(!B||!N||B*N>4096)continue;let P=A.m,w=!0,O=0;for(let F=0;F<B&&w;F++)for(let R=0;R<N;R++){let z=V[0]+10+20*F,j=V[2]+10+20*R,I=P[0]+P[3]*z+P[5]*j,G=P[2]+P[9]*z+P[11]*j,_=Math.round(I),Y=Math.round(P[1]+V[4]),q=Math.round(G),J=we(_,Y,q)?D.get(_,Y,q):-1;if(J<0){w=!1;break}if(J>O)O=J}if(w){if(X[M]=1,H)H[M]=O}}return{nStuds:b,studHidden:T,studUp:E,underHidden:X,studsHidden:C,studHideStep:U,underHideStep:H}}function qt(e,t,n){let r=(a)=>n&&a.texPart&&t.parts[a.texPart]?a.texPart:a.part,s=e.map((a)=>({part:r(a),color:String(a.color),m:a.m,steps:a.steps})),o=s.map((a)=>ct(a.steps)),i=[...new Set(o)].sort(),l=new Map(i.map((a,c)=>[a,c]));return{all:s,stepOf:o.map((a)=>l.get(a)),nSteps:i.length}}function Ae(e,t,n=!0){let r=qt(e,t,n);return Jt(r.all,t,r.nSteps>1?r.stepOf:void 0)}var Ce="https://ldr-demo.vercel.app/cdn/v1/",ve=new Map,Me=new Map;function gt(e=Ce,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 Qt=(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"),Te=(e,t)=>Qt(e)?[e[0]+t,e[1],e[2]]:Array.isArray(e)?e.map((n)=>Te(n,t)):e&&typeof e==="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,Te(r,t)])):e;function en(e,t={}){let n=[],r=0,s={},o={};for(let g of e){let y=g.buffer;if(!y)throw Error("ldr: mergePacks needs packs from decodePack/loadPack");let v=new DataView(y).getUint32(0,!0),x=new Uint8Array(y,4+v),S=r;n.push(x),r+=x.byteLength;let h=(4-r%4)%4;if(h)n.push(new Uint8Array(h)),r+=h;for(let[u,d]of Object.entries(g.header.parts??{}))if(!(u in s))s[u]=Te(d,S);for(let[u,d]of Object.entries(g.header.studKinds??{}))if(!(u in o))o[u]=Te(d,S)}let i=e[0]?.header??{version:1,weld:!0},l=new TextEncoder().encode(JSON.stringify({...i,parts:s,studKinds:o,...t})),a=(4-(4+l.length)%4)%4,c=4+l.length+a,f=new Uint8Array(c+r);new DataView(f.buffer).setUint32(0,l.length+a,!0),f.set(l,4),f.fill(32,4+l.length,c);let m=c;for(let g of n)f.set(g,m),m+=g.byteLength;return xe(f.buffer)}async function tn(e,t={}){e=[...e];try{return await ht(e,t)}catch(n){let r=t.cdn??Ce,s=t.fetch??fetch;ve.delete(r);let o=(i,l)=>s(i,{...l,cache:"reload"});try{return await ht(e,{...t,fetch:o})}catch{throw n}}}async function ht(e,t){let n=t.cdn??Ce,r=t.fetch??fetch,s=t.gap??16384,o=await gt(n,r),i=[...new Set([...e].map(Z))],l=[],a=[];for(let h of i){if(Me.has(n+h))continue;let u=o.parts[h];if(u)a.push({name:h,off:u[0],len:u[1],file:u[2]??0});else l.push(h)}a.sort((h,u)=>h.file-u.file||h.off-u.off);let c=[];for(let h of a){let u=c[c.length-1];if(u&&u.file===h.file&&h.off-u.end<=s)u.end=Math.max(u.end,h.off+h.len),u.items.push(h);else c.push({file:h.file,start:h.off,end:h.off+h.len,items:[h]})}let f=0,m=0,g=0,y=new Map,v=async()=>{while(g<c.length){let h=c[g++],u=y.get(h.file);if(u)u=u.subarray(h.start,h.end);else{let d=await r(new URL(o.archives[h.file],n).href,{headers:{Range:`bytes=${h.start}-${h.end-1}`,"Accept-Encoding":"identity"}});if(!d.ok)throw Error(`ldr: parts CDN ${d.status}`);if(m++,u=new Uint8Array(await d.arrayBuffer()),f+=u.byteLength,d.status===200)y.set(h.file,u),u=u.subarray(h.start,h.end)}for(let d of h.items){let p=ye(u.subarray(d.off-h.start,d.off-h.start+d.len)),L=p.buffer.slice(p.byteOffset,p.byteOffset+p.byteLength);Me.set(n+d.name,xe(L))}}};await Promise.all(Array.from({length:Math.min(t.concurrency??24,c.length)},v));let x=i.filter((h)=>Me.has(n+h)).map((h)=>Me.get(n+h));return{pack:x.length?en(x,{colors:o.colors}):xe(nn(o.colors)),missing:l,requests:m,bytes:f}}function nn(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 rn(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 sn(e,t,n){let r=0,s=0,o=!1,i=new Set;for(let l of e){let a=l.embedded?t.get(l.part):Z(l.part),c=a?n.parts[a]:void 0;if(!c)continue;if(c[3]!=null)o=!0,r+=c[3];if(!i.has(a))i.add(a),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 dt(e,t={}){let n=performance.now(),r=t.fetch??fetch,s=gt(t.cdn??Ce,r);s.catch(()=>{});let o=t.text?e:await r(e).then(async(p)=>{if(!p.ok)throw Error(`ldr: ${p.status} fetching ${e}`);return He(await p.arrayBuffer())}),i=performance.now(),l=t.name??(t.text?"main.ldr":Ge(e)),a=ut(o,l,{looseGeometry:!1,callouts:t.callouts}),c=performance.now();t.onParsed?.(a),await s;let f=ft(o,new Set(a.filter((p)=>p.embedded).map((p)=>p.part)),l),m=(p,L)=>t.maxBodyTris!=null&&p>t.maxBodyTris||t.maxPackBytes!=null&&L>t.maxPackBytes;if(t.maxBodyTris!=null||t.maxPackBytes!=null){let p=sn(a,f,await s);if(m(p.known?p.bodyTris:0,p.packBytes))throw new pe({bodyTris:p.bodyTris,packBytes:p.packBytes,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let{pack:g,missing:y,requests:v,bytes:x}=await tn([...a.filter((p)=>!p.embedded).map((p)=>p.part),...f.values()],t),S=new Map([...f].map(([p,L])=>[L,p])),h=y.map((p)=>S.get(p)??p);for(let[p,L]of f){let b=g.header.parts[L];if(b)g.header.parts[p]=b}let u=performance.now();if(t.maxBodyTris!=null||t.maxPackBytes!=null){let p=g.buffer?.byteLength??g.bytes??0,L=rn(a,g);if(m(L,p))throw new pe({bodyTris:L,packBytes:p,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes})}let d=t.cull?Ae(a,g.header,t.textures!==!1):void 0;return{insts:a,pack:g,missing:h,requests:v,bytes:x,cull:d,timings:{fetchModel:i-n,parse:c-i,parts:u-c,...d?{cull:performance.now()-u}:{}}}}self.onmessage=async(e)=>{let{id:t,source:n,opts:r}=e.data;try{let s=await dt(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(),l=Ae(s.insts,s.pack.header,r.textures!==!1),a=performance.now()-i,c=[];for(let f of[l.studHidden,l.studUp,l.underHidden,l.studHideStep,l.underHideStep])if(f)c.push(f.buffer);self.postMessage({id:t,cull:l,ms:a},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';
|
|
3945
3994
|
|
|
3946
|
-
// ../../../../../../../tmp/ldr-build-
|
|
3995
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/cdn.ts
|
|
3947
3996
|
var worker;
|
|
3948
3997
|
var seq = 0;
|
|
3949
3998
|
var pending = new Map;
|
|
@@ -4056,7 +4105,7 @@ async function loadModel(source, o = {}) {
|
|
|
4056
4105
|
timings: { ...prep.timings, parts: t3 - t0 - prep.timings.fetchModel - prep.timings.parse, build: t4 - t3, total: t4 - t0 }
|
|
4057
4106
|
});
|
|
4058
4107
|
}
|
|
4059
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4108
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/library.ts
|
|
4060
4109
|
import { existsSync, readFileSync } from "fs";
|
|
4061
4110
|
import { join } from "path";
|
|
4062
4111
|
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]];
|
|
@@ -4147,7 +4196,7 @@ class Library {
|
|
|
4147
4196
|
if (hit)
|
|
4148
4197
|
return hit;
|
|
4149
4198
|
const pos = [], col = [], edges = [], cond = [];
|
|
4150
|
-
const tx = opts.texmap ? { uv: [], tri: [], names: [] } : undefined;
|
|
4199
|
+
const tx = opts.texmap ? { uv: [], tri: [], names: [], gloss: [] } : undefined;
|
|
4151
4200
|
const r = this.where(name);
|
|
4152
4201
|
if (r)
|
|
4153
4202
|
this.emit(r.doc, r.doc.main, I, 16, false, true, pos, col, edges, cond, tx, null);
|
|
@@ -4156,6 +4205,8 @@ class Library {
|
|
|
4156
4205
|
m.uv = new Float32Array(tx.uv);
|
|
4157
4206
|
m.texture = new Int32Array(tx.tri);
|
|
4158
4207
|
m.textures = tx.names;
|
|
4208
|
+
if (tx.gloss.some((g) => g))
|
|
4209
|
+
m.glossmaps = tx.gloss;
|
|
4159
4210
|
}
|
|
4160
4211
|
this.meshCache.set(ck, m);
|
|
4161
4212
|
return m;
|
|
@@ -4188,10 +4239,11 @@ class Library {
|
|
|
4188
4239
|
const flip = inv !== det(m) < 0;
|
|
4189
4240
|
const cc = (c) => c === 16 ? color : c;
|
|
4190
4241
|
const texIdx = (t) => {
|
|
4191
|
-
let i = tx.names.
|
|
4242
|
+
let i = tx.names.findIndex((n, k) => n === t.texture && tx.gloss[k] === t.glossmap);
|
|
4192
4243
|
if (i < 0) {
|
|
4193
4244
|
i = tx.names.length;
|
|
4194
4245
|
tx.names.push(t.texture);
|
|
4246
|
+
tx.gloss.push(t.glossmap);
|
|
4195
4247
|
}
|
|
4196
4248
|
return i;
|
|
4197
4249
|
};
|
|
@@ -4307,11 +4359,11 @@ class Library {
|
|
|
4307
4359
|
return insts;
|
|
4308
4360
|
}
|
|
4309
4361
|
}
|
|
4310
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4362
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/build-pack.ts
|
|
4311
4363
|
import fs3 from "node:fs";
|
|
4312
4364
|
import path3 from "node:path";
|
|
4313
4365
|
|
|
4314
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4366
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/resolver.ts
|
|
4315
4367
|
import fs from "node:fs";
|
|
4316
4368
|
import path from "node:path";
|
|
4317
4369
|
var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
|
|
@@ -4583,11 +4635,11 @@ function collectDeps(lib, refs) {
|
|
|
4583
4635
|
return out;
|
|
4584
4636
|
}
|
|
4585
4637
|
|
|
4586
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4638
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/compile.ts
|
|
4587
4639
|
import fs2 from "node:fs";
|
|
4588
4640
|
import path2 from "node:path";
|
|
4589
4641
|
|
|
4590
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4642
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/lod.ts
|
|
4591
4643
|
import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
|
|
4592
4644
|
await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
|
|
4593
4645
|
function reorderMesh(P, N, C, I) {
|
|
@@ -4779,7 +4831,7 @@ function lodChain(P, C, I) {
|
|
|
4779
4831
|
return out;
|
|
4780
4832
|
}
|
|
4781
4833
|
|
|
4782
|
-
// ../../../../../../../tmp/ldr-build-
|
|
4834
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/compile.ts
|
|
4783
4835
|
function loadColors(root) {
|
|
4784
4836
|
const map = new Map;
|
|
4785
4837
|
for (const l of fs2.readFileSync(path2.join(root, "LDConfig.ldr"), "latin1").split(/\r?\n/)) {
|
|
@@ -4928,6 +4980,21 @@ class Compiler {
|
|
|
4928
4980
|
az1 = Math.max(az1, b.pos[i + 2]);
|
|
4929
4981
|
}
|
|
4930
4982
|
out.fullBottom = isFinite(x0) && ax0 <= x0 + 0.5 && ax1 >= x1 - 0.5 && az0 <= z0 + 0.5 && az1 >= z1 - 0.5;
|
|
4983
|
+
if (out.under.pos.length && !underEnclosed(out)) {
|
|
4984
|
+
const add = (d, s) => {
|
|
4985
|
+
for (const v of s)
|
|
4986
|
+
d.push(v);
|
|
4987
|
+
};
|
|
4988
|
+
for (const b of out.tbody ? [out.body, out.tbody] : [out.body]) {
|
|
4989
|
+
add(b.pos, out.under.pos);
|
|
4990
|
+
add(b.col, out.under.col);
|
|
4991
|
+
}
|
|
4992
|
+
if (out.cond && out.condUnder) {
|
|
4993
|
+
add(out.cond, out.condUnder);
|
|
4994
|
+
out.condUnder.length = 0;
|
|
4995
|
+
}
|
|
4996
|
+
out.under = { pos: [], col: [] };
|
|
4997
|
+
}
|
|
4931
4998
|
if (separateStuds && isFinite(x0))
|
|
4932
4999
|
out.bottomMask = enclosureMask(out);
|
|
4933
5000
|
this.cache.set(ck, out);
|
|
@@ -5069,9 +5136,10 @@ class Compiler {
|
|
|
5069
5136
|
order = n === 3 ? [0, 2, 1] : [0, 2, 1, 0, 3, 2];
|
|
5070
5137
|
const rgba = colorOf(code);
|
|
5071
5138
|
if (tex) {
|
|
5072
|
-
|
|
5139
|
+
const tk = tex.glossmap ? tex.texture + "\x00" + tex.glossmap : tex.texture;
|
|
5140
|
+
let b = texb.get(tk);
|
|
5073
5141
|
if (!b)
|
|
5074
|
-
texb.set(
|
|
5142
|
+
texb.set(tk, b = { pos: [], col: [], uv: [], texture: tex.texture, ...tex.glossmap ? { glossmap: tex.glossmap } : {} });
|
|
5075
5143
|
if (Math.abs(tex.a ?? 0) >= 360)
|
|
5076
5144
|
b.wrapU = true;
|
|
5077
5145
|
for (let k = 0;k < order.length; k += 3) {
|
|
@@ -5097,6 +5165,33 @@ class Compiler {
|
|
|
5097
5165
|
}
|
|
5098
5166
|
}
|
|
5099
5167
|
}
|
|
5168
|
+
function underEnclosed(c) {
|
|
5169
|
+
const u = c.under.pos;
|
|
5170
|
+
let uy0 = Infinity, uy1 = -Infinity, ux0 = Infinity, ux1 = -Infinity, uz0 = Infinity, uz1 = -Infinity;
|
|
5171
|
+
for (let i = 0;i < u.length; i += 3) {
|
|
5172
|
+
ux0 = Math.min(ux0, u[i]);
|
|
5173
|
+
ux1 = Math.max(ux1, u[i]);
|
|
5174
|
+
uy0 = Math.min(uy0, u[i + 1]);
|
|
5175
|
+
uy1 = Math.max(uy1, u[i + 1]);
|
|
5176
|
+
uz0 = Math.min(uz0, u[i + 2]);
|
|
5177
|
+
uz1 = Math.max(uz1, u[i + 2]);
|
|
5178
|
+
}
|
|
5179
|
+
const lo = uy0 + Math.min(0.5, (uy1 - uy0) / 4), hi = uy1 - Math.min(0.5, (uy1 - uy0) / 4);
|
|
5180
|
+
const p = c.body.pos;
|
|
5181
|
+
let bx0 = Infinity, bx1 = -Infinity, bz0 = Infinity, bz1 = -Infinity;
|
|
5182
|
+
for (let i = 0;i < p.length; i += 9) {
|
|
5183
|
+
const y0 = Math.min(p[i + 1], p[i + 4], p[i + 7]), y1 = Math.max(p[i + 1], p[i + 4], p[i + 7]);
|
|
5184
|
+
if (y1 <= lo || y0 >= hi)
|
|
5185
|
+
continue;
|
|
5186
|
+
for (let k = i;k < i + 9; k += 3) {
|
|
5187
|
+
bx0 = Math.min(bx0, p[k]);
|
|
5188
|
+
bx1 = Math.max(bx1, p[k]);
|
|
5189
|
+
bz0 = Math.min(bz0, p[k + 2]);
|
|
5190
|
+
bz1 = Math.max(bz1, p[k + 2]);
|
|
5191
|
+
}
|
|
5192
|
+
}
|
|
5193
|
+
return bx0 < ux0 + 0.01 && bx1 > ux1 - 0.01 && bz0 < uz0 + 0.01 && bz1 > uz1 - 0.01;
|
|
5194
|
+
}
|
|
5100
5195
|
function enclosureMask(c) {
|
|
5101
5196
|
const [x0, , z0, x1, y1, z1] = c.bbox;
|
|
5102
5197
|
const nx = Math.round((x1 - x0) / 20), nz = Math.round((z1 - z0) / 20);
|
|
@@ -5332,11 +5427,15 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
5332
5427
|
const encTex = (c) => {
|
|
5333
5428
|
if (!c.texb)
|
|
5334
5429
|
return {};
|
|
5430
|
+
const idx = (name) => {
|
|
5431
|
+
let i = texNames.indexOf(name);
|
|
5432
|
+
if (i < 0)
|
|
5433
|
+
i = texNames.push(name) - 1;
|
|
5434
|
+
return i;
|
|
5435
|
+
};
|
|
5335
5436
|
const tex = [...c.texb].map(([name, b]) => {
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
t = texNames.push(name) - 1;
|
|
5339
|
-
return { t, ...b.wrapU ? { wrapU: true } : {}, ...texBucket(b) };
|
|
5437
|
+
const t = idx(b.texture ?? name);
|
|
5438
|
+
return { t, ...b.glossmap ? { g: idx(b.glossmap) } : {}, ...b.wrapU ? { wrapU: true } : {}, ...texBucket(b) };
|
|
5340
5439
|
});
|
|
5341
5440
|
return { tbody: bucket(c.tbody), tex };
|
|
5342
5441
|
};
|
|
@@ -5362,7 +5461,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
|
|
|
5362
5461
|
return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
|
|
5363
5462
|
}
|
|
5364
5463
|
|
|
5365
|
-
// ../../../../../../../tmp/ldr-build-
|
|
5464
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/build-pack.ts
|
|
5366
5465
|
function buildPack(o) {
|
|
5367
5466
|
const lib = new Library2(o.ldrawRoot);
|
|
5368
5467
|
const refs = new Map;
|
|
@@ -5429,7 +5528,7 @@ function buildPack(o) {
|
|
|
5429
5528
|
const warnings = [...lib.conflicts].map((n) => `${n}: defined differently by two models; the first definition is used`);
|
|
5430
5529
|
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 } : {} };
|
|
5431
5530
|
}
|
|
5432
|
-
// ../../../../../../../tmp/ldr-build-
|
|
5531
|
+
// ../../../../../../../tmp/ldr-build-Q8idpr/src/node/promote.ts
|
|
5433
5532
|
var GEOM = /^\s*[2-5]\s/;
|
|
5434
5533
|
var REF = /^\s*1\s/;
|
|
5435
5534
|
var FILE = /^\s*0\s+FILE\s+(.+?)\s*$/i;
|
|
@@ -5723,10 +5822,12 @@ export {
|
|
|
5723
5822
|
looseSteps,
|
|
5724
5823
|
makeFinishMaterial,
|
|
5725
5824
|
makeMaterial,
|
|
5825
|
+
makeTexturedMaterial,
|
|
5726
5826
|
mergePacks,
|
|
5727
5827
|
modelFileName,
|
|
5728
5828
|
mul,
|
|
5729
5829
|
norm,
|
|
5830
|
+
packTexture,
|
|
5730
5831
|
parse,
|
|
5731
5832
|
parseColor,
|
|
5732
5833
|
parseColourLine,
|
|
@@ -5734,6 +5835,7 @@ export {
|
|
|
5734
5835
|
parseModel,
|
|
5735
5836
|
parseTexMap,
|
|
5736
5837
|
planStepViews,
|
|
5838
|
+
pngHasAlpha,
|
|
5737
5839
|
precomputeCull,
|
|
5738
5840
|
prepareFlexParts,
|
|
5739
5841
|
prepareModel,
|
package/dist/node/library.d.ts
CHANGED
|
@@ -30,7 +30,8 @@ export declare class Library {
|
|
|
30
30
|
/** Flattened triangle mesh: positions + color code per tri (16 = inherit); edges as line segments.
|
|
31
31
|
* `cond` stores type-5 lines as 12 floats each: endpoint0, endpoint1, control0, control1.
|
|
32
32
|
* Default = what a renderer without !TEXMAP support draws (`0 !:` geometry skipped, FALLBACK geometry drawn).
|
|
33
|
-
* `{ texmap: true }` = TEXMAP-aware geometry (START..FALLBACK incl. `0 !:` lines, FALLBACK..END skipped) plus `uv` / `texture`.
|
|
33
|
+
* `{ texmap: true }` = TEXMAP-aware geometry (START..FALLBACK incl. `0 !:` lines, FALLBACK..END skipped) plus `uv` / `texture`.
|
|
34
|
+
* Texture slots are keyed by (texture, GLOSSMAP): `textures[i]` is the PNG, `glossmaps[i]` its glossmap (only set when some map has one). */
|
|
34
35
|
mesh(name: string, opts?: {
|
|
35
36
|
texmap?: boolean;
|
|
36
37
|
}): PartMesh;
|
package/dist/render.d.ts
CHANGED
|
@@ -35,11 +35,21 @@ export declare function loadPack(url: string): Promise<Pack>;
|
|
|
35
35
|
export declare function makeMaterial(side: THREE.Side): THREE.MeshStandardMaterial;
|
|
36
36
|
/** Build a MeshStandard/Physical material for one LDraw finish bucket (vertex colours supply the RGB). */
|
|
37
37
|
export declare function makeFinishMaterial(side: THREE.Side, surface: ColourSurface): THREE.MeshStandardMaterial;
|
|
38
|
+
/** A !TEXMAP GLOSSMAP texture: `alpha` = the PNG has an alpha channel (gloss = A, per the LDraw spec); false = single-channel /
|
|
39
|
+
* RGB without alpha, where the grey (red) value is the gloss amount. */
|
|
40
|
+
export type GlossMap = {
|
|
41
|
+
map: THREE.Texture;
|
|
42
|
+
alpha: boolean;
|
|
43
|
+
};
|
|
38
44
|
/** Material for textured (!TEXMAP) triangles: the LDraw colour as base, the PNG blended over it by its alpha (LDraw spec),
|
|
39
|
-
* and no texture outside the projection's [0,1] range. `map` should have flipY = false (v = 0 is the image's top row).
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
* and no texture outside the projection's [0,1] range. `map` should have flipY = false (v = 0 is the image's top row).
|
|
46
|
+
* `gloss` (GLOSSMAP): sampled with the same UVs and inside mask; its amount adds specularity on top of the base finish. */
|
|
47
|
+
export declare function makeTexturedMaterial(side: THREE.Side, map: THREE.Texture, wrapU?: boolean, baseMat?: THREE.MeshStandardMaterial, gloss?: GlossMap): THREE.MeshStandardMaterial;
|
|
48
|
+
/** True if the PNG has an alpha channel: colour type 4 / 6 (grey / RGB + alpha), or 0 / 2 / 3 with a tRNS chunk. False for non-PNG bytes. */
|
|
49
|
+
export declare function pngHasAlpha(b: Uint8Array): boolean;
|
|
50
|
+
/** Decode a pack's embedded PNG into a texture (async; the texture fills in when decoded). Needs `createImageBitmap` (browsers, workers).
|
|
51
|
+
* `data`: a non-colour map (GLOSSMAP), sampled linearly instead of as sRGB. */
|
|
52
|
+
export declare function packTexture(pack: Pack, i: number, data?: boolean): {
|
|
43
53
|
texture: THREE.Texture;
|
|
44
54
|
ready: Promise<void>;
|
|
45
55
|
};
|
package/dist/scene.d.ts
CHANGED
|
@@ -76,9 +76,11 @@ export interface LdrStats {
|
|
|
76
76
|
buildYields?: number;
|
|
77
77
|
/** Conditional-line batches (draw calls) created; 0 for packs without conditional lines. */
|
|
78
78
|
condBatches?: number;
|
|
79
|
-
/** Textured batches (one per part x texture) and distinct textures; 0 for packs without textures.
|
|
79
|
+
/** Textured batches (one per part x texture) and distinct textures; 0 for packs without textures.
|
|
80
|
+
* `glossmaps`: distinct !TEXMAP GLOSSMAP textures in use (Round 44); 0 when no map has one. */
|
|
80
81
|
texBatches?: number;
|
|
81
82
|
textures?: number;
|
|
83
|
+
glossmaps?: number;
|
|
82
84
|
/** Drawable clusters (LOD / frustum-culling units). */
|
|
83
85
|
clusters?: number;
|
|
84
86
|
}
|
package/dist/spec.d.ts
CHANGED
|
@@ -149,6 +149,8 @@ export interface PartMesh {
|
|
|
149
149
|
/** Only with texmap: per-triangle index into `textures` (-1 = untextured). */
|
|
150
150
|
texture?: Int32Array;
|
|
151
151
|
textures?: string[];
|
|
152
|
+
/** Only with texmap, when some map has a GLOSSMAP: the glossmap PNG name per `textures` slot (undefined = none). */
|
|
153
|
+
glossmaps?: (string | undefined)[];
|
|
152
154
|
}
|
|
153
155
|
/** A placed part from `Library.flatten` (same fields as `PartInstance`, plus library resolution). */
|
|
154
156
|
export interface Instance {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ldr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
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",
|