ldr 0.2.0 → 0.3.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 -3
- package/dist/cli.js +784 -188
- package/dist/index.d.ts +3 -3
- package/dist/index.js +554 -32
- package/dist/node/build-pack.d.ts +6 -0
- package/dist/node/compile.d.ts +29 -2
- package/dist/node/index.js +969 -71
- package/dist/node/library.d.ts +9 -2
- package/dist/node/resolver.d.ts +1 -0
- package/dist/render.d.ts +26 -0
- package/dist/scene.d.ts +18 -0
- package/dist/spec.d.ts +83 -7
- package/package.json +1 -1
package/dist/node/library.d.ts
CHANGED
|
@@ -27,8 +27,15 @@ export declare class Library {
|
|
|
27
27
|
alpha: number;
|
|
28
28
|
}>;
|
|
29
29
|
/** Flattened triangle mesh: positions + color code per tri (16 = inherit); edges as line segments.
|
|
30
|
-
* `cond` stores type-5 lines as 12 floats each: endpoint0, endpoint1, control0, control1
|
|
31
|
-
|
|
30
|
+
* `cond` stores type-5 lines as 12 floats each: endpoint0, endpoint1, control0, control1.
|
|
31
|
+
* Default = what a renderer without !TEXMAP support draws (`0 !:` geometry skipped, FALLBACK geometry drawn).
|
|
32
|
+
* `{ texmap: true }` = TEXMAP-aware geometry (START..FALLBACK incl. `0 !:` lines, FALLBACK..END skipped) plus `uv` / `texture`. */
|
|
33
|
+
mesh(name: string, opts?: {
|
|
34
|
+
texmap?: boolean;
|
|
35
|
+
}): PartMesh;
|
|
36
|
+
/** Texture PNG bytes for a !TEXMAP name: an MPD `!DATA` block in `doc` first, then the LDraw search path with a
|
|
37
|
+
* `textures/` prefix (parts/, p/, models/, official then unofficial), then without it. Case-insensitive. */
|
|
38
|
+
texture(name: string, doc?: Doc): Uint8Array | null;
|
|
32
39
|
private emit;
|
|
33
40
|
/** Flatten a model into part instances. 24 handled at render (edge color). Alias parts resolve to canonical names. */
|
|
34
41
|
flatten(doc: Doc): Instance[];
|
package/dist/node/resolver.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export declare class Library {
|
|
|
25
25
|
export declare function splitModel(text: any, fallbackName?: string): {
|
|
26
26
|
files: Map<string, string>;
|
|
27
27
|
main: string | null;
|
|
28
|
+
data: Map<string, string>;
|
|
28
29
|
};
|
|
29
30
|
export declare function flatten(model: any, lib: any, onInstance: any): {
|
|
30
31
|
missing: Map<any, any>;
|
package/dist/render.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
+
/** `cond`: draw type-5 conditional lines when the pack carries them (pack v2, built with `cond: true`); 'idx' edges only. Default true.
|
|
3
|
+
* `condStuds`: also draw them on stud batches (stud silhouettes). Default true. */
|
|
2
4
|
export type LdrParams = {
|
|
3
5
|
pack: string;
|
|
4
6
|
cullStuds: boolean;
|
|
@@ -6,6 +8,10 @@ export type LdrParams = {
|
|
|
6
8
|
edges: boolean | 'idx' | 'ss';
|
|
7
9
|
side: 'double' | 'front';
|
|
8
10
|
uncertDouble?: boolean;
|
|
11
|
+
cond?: boolean;
|
|
12
|
+
condStuds?: boolean;
|
|
13
|
+
/** Draw textured (!TEXMAP) parts with their PNGs when the pack carries them (pack v2 "tex", `ldr pack --textures`). Default true. */
|
|
14
|
+
tex?: boolean;
|
|
9
15
|
};
|
|
10
16
|
export type Inst = {
|
|
11
17
|
part: string;
|
|
@@ -21,8 +27,26 @@ export declare function loadPack(url: string): Promise<Pack>;
|
|
|
21
27
|
/** Decode an uncompressed parts pack (4-byte LE header length, JSON header, then aligned typed-array payload). */
|
|
22
28
|
export declare function decodePack(buf: ArrayBuffer): Pack;
|
|
23
29
|
export declare function makeMaterial(side: THREE.Side): THREE.MeshStandardMaterial;
|
|
30
|
+
/** Material for textured (!TEXMAP) triangles: the LDraw colour as base, the PNG blended over it by its alpha (LDraw spec),
|
|
31
|
+
* and no texture outside the projection's [0,1] range. `map` should have flipY = false (v = 0 is the image's top row). */
|
|
32
|
+
export declare function makeTexturedMaterial(side: THREE.Side, map: THREE.Texture, wrapU?: boolean): THREE.MeshStandardMaterial;
|
|
33
|
+
/** Decode a pack's embedded PNG into a texture (async; the texture fills in when decoded). Needs `createImageBitmap` (browsers, workers). */
|
|
34
|
+
export declare function packTexture(pack: Pack, i: number): {
|
|
35
|
+
texture: THREE.Texture;
|
|
36
|
+
ready: Promise<void>;
|
|
37
|
+
};
|
|
24
38
|
/** Edge lines for an InstancedMesh: welds + indexes `pos` (line-segment endpoints, part space) and shares the mesh's instanceMatrix buffer, so edges cost one extra draw and no extra per-instance memory. Keep `geometry.instanceCount` in sync with `im.count`. */
|
|
25
39
|
export declare function createInstancedEdges(pos: ArrayLike<number>, im: THREE.InstancedMesh, material?: THREE.Material): THREE.LineSegments;
|
|
40
|
+
/** Expand a pack entry's conditional lines (pack v2 `condl` body / `condlu` underside) to part-space floats, stride 12:
|
|
41
|
+
* p0, p1, control0, control1. `which` = 'all' (default; body then underside), 'body' or 'under'.
|
|
42
|
+
* Returns null for v1 packs / parts without conditional lines. */
|
|
43
|
+
export declare function conditionalLines(pack: Pack, entry: any, which?: 'all' | 'body' | 'under'): Float32Array | null;
|
|
44
|
+
/** CPU mirror of the conditional-line vertex shader: true if the line p0-p1 is drawn for this model-view-projection matrix. */
|
|
45
|
+
export declare function conditionalLineVisible(cond: ArrayLike<number>, i: number, mvp: THREE.Matrix4): boolean;
|
|
46
|
+
/** Conditional (type-5) lines for an InstancedMesh, sharing its instanceMatrix buffer (one extra draw, no per-instance memory).
|
|
47
|
+
* `cond` is part-space stride 12 (p0, p1, c0, c1), e.g. from `conditionalLines(pack, pack.header.parts[name])`.
|
|
48
|
+
* GPU cost: 2 vertices x 13 floats per line (104 B/line), per part, not per instance. Keep `geometry.instanceCount` in sync with `im.count`. */
|
|
49
|
+
export declare function createInstancedConditionalEdges(cond: ArrayLike<number>, im: THREE.InstancedMesh, material?: THREE.Material): THREE.LineSegments;
|
|
26
50
|
export declare function computeCulling(insts: Inst[], H: any): {
|
|
27
51
|
studs: {
|
|
28
52
|
kind: string;
|
|
@@ -38,6 +62,8 @@ export declare function buildLdrScene(insts: Inst[], pack: Pack, P: LdrParams, c
|
|
|
38
62
|
setCull: (studs: boolean, under: boolean) => void;
|
|
39
63
|
setSide: (front: boolean) => void;
|
|
40
64
|
setEdges: (v: boolean) => void;
|
|
65
|
+
setCond: (v: boolean) => void;
|
|
41
66
|
swapStuds: (alt: any) => () => void;
|
|
42
67
|
box: THREE.Box3;
|
|
68
|
+
texturesReady: Promise<void>;
|
|
43
69
|
};
|
package/dist/scene.d.ts
CHANGED
|
@@ -5,6 +5,15 @@ export type ColorSource = Map<number, string | LDrawColor> | Record<number | str
|
|
|
5
5
|
export interface LdrObjectOptions {
|
|
6
6
|
/** Draw LDraw type-2 edge lines (indexed, sharing each part's instance matrices). Default true. */
|
|
7
7
|
edges?: boolean;
|
|
8
|
+
/** Draw type-5 conditional lines (silhouettes of curved surfaces) when the pack carries them (`ldr pack --cond`, pack v2).
|
|
9
|
+
* Shares each part's instance matrices; follows `edges` on/off. Default true (no effect on packs without them). */
|
|
10
|
+
conditionalLines?: boolean;
|
|
11
|
+
/** Also draw conditional lines on studs (stud silhouettes). Default true. Round 17 (M4 Pro, Datsville 100k): stud lines are
|
|
12
|
+
* ~37% of conditional-line vertex work; turning them off saves ~3.7 ms/frame. Only read when the object is built. */
|
|
13
|
+
conditionalStudLines?: boolean;
|
|
14
|
+
/** Draw textured parts (printed / sticker parts using !TEXMAP) with their images when the pack carries them (`ldr pack --textures`).
|
|
15
|
+
* Default true; false draws the parts' FALLBACK geometry like a pack without textures. Only read when the object is built. */
|
|
16
|
+
textures?: boolean;
|
|
8
17
|
/** Hide studs fully covered by a part above. Default true. */
|
|
9
18
|
cullStuds?: boolean;
|
|
10
19
|
/** Hide undersides (tubes) sitting fully on studs below. Default true. */
|
|
@@ -33,6 +42,11 @@ export interface LdrStats {
|
|
|
33
42
|
undersTotal: number;
|
|
34
43
|
undersHidden: number;
|
|
35
44
|
buildMs: number;
|
|
45
|
+
/** Conditional-line batches (draw calls) created; 0 for packs without conditional lines. */
|
|
46
|
+
condBatches?: number;
|
|
47
|
+
/** Textured batches (one per part x texture) and distinct textures; 0 for packs without textures. */
|
|
48
|
+
texBatches?: number;
|
|
49
|
+
textures?: number;
|
|
36
50
|
}
|
|
37
51
|
export interface LdrObject {
|
|
38
52
|
/** Add this to your scene. */
|
|
@@ -43,6 +57,10 @@ export interface LdrObject {
|
|
|
43
57
|
/** Show instances up to and including `step` (null = all). Rebuilds batches; culling is recomputed for the partial model. */
|
|
44
58
|
setStep(step: number | null): void;
|
|
45
59
|
setEdges(on: boolean): void;
|
|
60
|
+
/** Resolves when the pack's textures (if any) are decoded and ready to render. Replaced by a new promise after `setStep`. */
|
|
61
|
+
texturesReady: Promise<void>;
|
|
62
|
+
/** Toggle conditional lines (only visible while edges are on). */
|
|
63
|
+
setConditionalLines(on: boolean): void;
|
|
46
64
|
setCulling(studs: boolean, undersides: boolean): void;
|
|
47
65
|
setSide(side: "front" | "double"): void;
|
|
48
66
|
/** Bounding box in the object's parent space. */
|
package/dist/spec.d.ts
CHANGED
|
@@ -9,7 +9,35 @@ export type BufExchg = {
|
|
|
9
9
|
op: "STORE" | "RETRIEVE";
|
|
10
10
|
buf: string;
|
|
11
11
|
};
|
|
12
|
-
|
|
12
|
+
/** TEXMAP projection (LDraw !TEXMAP extension). Points are in the coordinates of the file containing the START/NEXT. */
|
|
13
|
+
export type TexMapMethod = "PLANAR" | "CYLINDRICAL" | "SPHERICAL";
|
|
14
|
+
export interface TexMap {
|
|
15
|
+
method: TexMapMethod;
|
|
16
|
+
p1: number[];
|
|
17
|
+
p2: number[];
|
|
18
|
+
p3: number[];
|
|
19
|
+
/** CYLINDRICAL: angular extent (degrees); SPHERICAL: horizontal extent (degrees). */
|
|
20
|
+
a?: number;
|
|
21
|
+
/** SPHERICAL: vertical extent (degrees). */
|
|
22
|
+
b?: number;
|
|
23
|
+
/** PNG name as written (resolve via `textures/<name>` then `<name>`, or an MPD `!DATA` block). */
|
|
24
|
+
texture: string;
|
|
25
|
+
glossmap?: string;
|
|
26
|
+
/** true for `!TEXMAP NEXT` (applies to the next type 1-5 line only). */
|
|
27
|
+
next?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export type TexMapCmd = {
|
|
30
|
+
op: "START" | "NEXT" | "FALLBACK" | "END";
|
|
31
|
+
map?: TexMap;
|
|
32
|
+
};
|
|
33
|
+
/** Texture-mapping annotations on geometry (type 1-5) commands:
|
|
34
|
+
* `tex` = texture in effect for TEXMAP-aware renderers (START..FALLBACK or NEXT); `fallback` = line sits between
|
|
35
|
+
* FALLBACK and END, so TEXMAP-aware renderers skip it and everyone else draws it. */
|
|
36
|
+
export interface TexAnno {
|
|
37
|
+
tex?: TexMap;
|
|
38
|
+
fallback?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export type Cmd = ({
|
|
13
41
|
t: 0;
|
|
14
42
|
text: string;
|
|
15
43
|
meta?: string;
|
|
@@ -17,33 +45,76 @@ export type Cmd = {
|
|
|
17
45
|
step?: boolean;
|
|
18
46
|
rotstep?: RotStep;
|
|
19
47
|
bufexchg?: BufExchg;
|
|
20
|
-
|
|
48
|
+
/** `0 !TEXMAP ...` */
|
|
49
|
+
texmap?: TexMapCmd;
|
|
50
|
+
/** `0 !: <line>`: textured-only geometry, ignored by renderers without TEXMAP support (parsed here for those that have it). */
|
|
51
|
+
geom?: Cmd;
|
|
52
|
+
} & TexAnno) | ({
|
|
21
53
|
t: 1;
|
|
22
54
|
color: number;
|
|
23
55
|
m: M;
|
|
24
56
|
file: string;
|
|
25
|
-
} | {
|
|
57
|
+
} & TexAnno) | ({
|
|
26
58
|
t: 2 | 5;
|
|
27
59
|
color: number;
|
|
28
60
|
p: number[];
|
|
29
|
-
} | {
|
|
61
|
+
} & TexAnno) | ({
|
|
30
62
|
t: 3 | 4;
|
|
31
63
|
color: number;
|
|
32
64
|
p: number[];
|
|
33
|
-
};
|
|
65
|
+
} & TexAnno);
|
|
34
66
|
export interface LFile {
|
|
35
67
|
name: string;
|
|
36
68
|
cmds: Cmd[];
|
|
37
|
-
movedTo?: string;
|
|
69
|
+
movedTo?: string; /** Every TEXMAP START/NEXT in this file, in order. */
|
|
70
|
+
texmaps?: TexMap[];
|
|
71
|
+
}
|
|
72
|
+
/** An MPD `0 !DATA` block (base64-decoded), e.g. an embedded PNG texture. */
|
|
73
|
+
export interface DataBlock {
|
|
74
|
+
name: string;
|
|
75
|
+
bytes: Uint8Array; /** "image/png" when the bytes carry the PNG signature. */
|
|
76
|
+
mime?: string;
|
|
38
77
|
}
|
|
39
78
|
export interface Doc {
|
|
40
79
|
main: string;
|
|
41
|
-
files: Map<string, LFile>;
|
|
80
|
+
files: Map<string, LFile>; /** MPD `!DATA` blocks keyed by normalized name. */
|
|
81
|
+
data?: Map<string, DataBlock>;
|
|
42
82
|
}
|
|
43
83
|
export declare const norm: (s: string) => string;
|
|
44
84
|
/** Parse LDraw color token: decimal code, or direct color 0x2RRGGBB (and related 0xN…… forms). */
|
|
45
85
|
export declare function parseColor(tok: string): number;
|
|
86
|
+
/** Parse the tail of `0 !TEXMAP START|NEXT <method> <params> <png> [GLOSSMAP <png>]`. Returns null when malformed. */
|
|
87
|
+
export declare function parseTexMap(tail: string, next?: boolean): TexMap | null;
|
|
46
88
|
export declare function parse(src: string, name?: string): Doc;
|
|
89
|
+
/** Find an embedded texture in a parsed MPD: tries `name`, then without / with a `textures/` prefix (case-insensitive). */
|
|
90
|
+
export declare function resolveTexture(doc: Doc, name: string): DataBlock | null;
|
|
91
|
+
/**
|
|
92
|
+
* Texture coordinates of point `p` (same space as the map's points) per the LDraw !TEXMAP spec, with the sign and orientation
|
|
93
|
+
* conventions of LDView (the reference renderer the library's textured parts are checked against; the spec leaves them open).
|
|
94
|
+
* v = 0 is the image's top row for all three methods.
|
|
95
|
+
* PLANAR: u = distance from plane P1 (through p1, normal p1->p2) / |p2 - p1|, v likewise along p1->p3 (p1 = top-left corner).
|
|
96
|
+
* CYLINDRICAL: p1 bottom centre, p2 top centre, p3 on the bottom rim under the texture's centre. u = 0.5 + angle / a, the angle
|
|
97
|
+
* from p3's radial direction, right-handed about p1->p2; v = distance below the top plane / |p2 - p1| (0 at the top, 1 at the bottom;
|
|
98
|
+
* LDView 4.6 "cylindrical TEXMAP right side up").
|
|
99
|
+
* SPHERICAL: p1 centre, p2 = texture centre on the sphere, p3 fixes plane P1 (the texture's horizontal bisector). Its normal
|
|
100
|
+
* n = -((p1 - p2) x (p3 - p2)) is "north". u = 0.5 + longitude / a (angle within P1 from p1->p2, right-handed about n);
|
|
101
|
+
* v = 0.5 + latitude / b with latitude negative toward n, so north maps to the image's top. (LDView measures latitude after
|
|
102
|
+
* rotating the point to longitude 0, i.e. equirectangular, rather than the literal "projected to plane P2"; the official
|
|
103
|
+
* globe textures 61287p01..p04 are drawn for that.)
|
|
104
|
+
* `inside` is false when (u, v) falls outside [0, 1] (the spec leaves those points untextured: base colour shows).
|
|
105
|
+
* Use `texmapTriangleUV` for triangles: it unwraps angles across the seam and handles points on the axis / poles like LDView.
|
|
106
|
+
*/
|
|
107
|
+
export declare function texmapUV(map: TexMap, p: number[]): {
|
|
108
|
+
u: number;
|
|
109
|
+
v: number;
|
|
110
|
+
inside: boolean;
|
|
111
|
+
};
|
|
112
|
+
/** (u, v) for the 3 corners of a triangle, flat [u0, v0, u1, v1, u2, v2]. Angular u is unwrapped relative to the first corner
|
|
113
|
+
* (so a triangle across the seam of a 360-degree map stays continuous); corners on the axis (cylindrical) or at a pole
|
|
114
|
+
* (spherical) take the average u of the other corners. */
|
|
115
|
+
export declare function texmapTriangleUV(map: TexMap, pts: number[][]): number[];
|
|
116
|
+
/** Transform a TexMap's points by an LDraw matrix (e.g. into part space when the START lives in a subfile). */
|
|
117
|
+
export declare function transformTexMap(map: TexMap, m: M): TexMap;
|
|
47
118
|
export declare function mul(a: M, b: M): M;
|
|
48
119
|
export declare const I: M;
|
|
49
120
|
/** True if color is an LDraw direct color (0x2RRGGBB etc.), not a palette CODE. */
|
|
@@ -55,6 +126,11 @@ export interface PartMesh {
|
|
|
55
126
|
edges: Float32Array;
|
|
56
127
|
cond: Float32Array;
|
|
57
128
|
nrm: Float32Array;
|
|
129
|
+
/** Only with `mesh(name, { texmap: true })`: per-vertex (u, v) from the active !TEXMAP (NaN where untextured). */
|
|
130
|
+
uv?: Float32Array;
|
|
131
|
+
/** Only with texmap: per-triangle index into `textures` (-1 = untextured). */
|
|
132
|
+
texture?: Int32Array;
|
|
133
|
+
textures?: string[];
|
|
58
134
|
}
|
|
59
135
|
export interface Instance {
|
|
60
136
|
part: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ldr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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",
|