ldr 0.0.0-alpha.1 → 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/LICENSE +21 -0
- package/README.md +121 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1472 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +1239 -0
- package/dist/model.d.ts +44 -0
- package/dist/node/build-pack.d.ts +35 -0
- package/dist/node/compile.d.ts +70 -0
- package/dist/node/index.d.ts +7 -0
- package/dist/node/index.js +2354 -0
- package/dist/node/library.d.ts +42 -0
- package/dist/node/resolver.d.ts +33 -0
- package/dist/pack-io.d.ts +2 -0
- package/dist/render.d.ts +69 -0
- package/dist/scene.d.ts +74 -0
- package/dist/spec.d.ts +149 -0
- package/package.json +56 -36
- package/lib/.DS_Store +0 -0
- package/lib/index.js +0 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type Doc, type PartMesh, type Instance } from "../spec.js";
|
|
2
|
+
export declare class Library {
|
|
3
|
+
root: string;
|
|
4
|
+
unofficialRoot?: string | undefined;
|
|
5
|
+
cache: Map<string, Doc | null>;
|
|
6
|
+
meshCache: Map<string, PartMesh>;
|
|
7
|
+
/** Optional second root for unofficial parts (e.g. Unofficial/ next to the official tree). */
|
|
8
|
+
constructor(root: string, unofficialRoot?: string | undefined);
|
|
9
|
+
/**
|
|
10
|
+
* Resolve a part/prim/model by LDraw search order (case-insensitive):
|
|
11
|
+
* parts/, p/, models/, then parts/s (subparts). If `unofficial/` exists under root
|
|
12
|
+
* (or `unofficialRoot` is set), those trees are tried after the official ones.
|
|
13
|
+
* Follows `~Moved to` aliases to the canonical file.
|
|
14
|
+
*/
|
|
15
|
+
where(name: string, _seen?: Set<string>): {
|
|
16
|
+
kind: "part" | "prim" | "model";
|
|
17
|
+
doc: Doc;
|
|
18
|
+
aliasOf?: string;
|
|
19
|
+
} | null;
|
|
20
|
+
private lookup;
|
|
21
|
+
/** Case-insensitive path resolve (library files are lowercase; callers may pass any case). */
|
|
22
|
+
private resolveFile;
|
|
23
|
+
colors(): Map<number, {
|
|
24
|
+
name: string;
|
|
25
|
+
hex: string;
|
|
26
|
+
edge: string;
|
|
27
|
+
alpha: number;
|
|
28
|
+
}>;
|
|
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
|
+
* 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;
|
|
39
|
+
private emit;
|
|
40
|
+
/** Flatten a model into part instances. 24 handled at render (edge color). Alias parts resolve to canonical names. */
|
|
41
|
+
flatten(doc: Doc): Instance[];
|
|
42
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare const TOP_STUD_RE: RegExp;
|
|
2
|
+
export declare const UNDER_STUD_RE: RegExp;
|
|
3
|
+
export declare const norm: (ref: any) => any;
|
|
4
|
+
export declare const threeName: (ref: any) => any;
|
|
5
|
+
export declare function parseType1(line: any): {
|
|
6
|
+
color: any;
|
|
7
|
+
m: any;
|
|
8
|
+
name: any;
|
|
9
|
+
} | null;
|
|
10
|
+
export declare function xf(m: any, p: any): any[];
|
|
11
|
+
export declare function compose(a: any, b: any): any[];
|
|
12
|
+
export declare const IDENT: number[];
|
|
13
|
+
export declare class Library {
|
|
14
|
+
#private;
|
|
15
|
+
root: string;
|
|
16
|
+
index: Map<string, string>;
|
|
17
|
+
text: Map<string, string>;
|
|
18
|
+
stats: Map<string, any>;
|
|
19
|
+
constructor(root: string);
|
|
20
|
+
resolve(ref: any): string | null;
|
|
21
|
+
read(key: string): string;
|
|
22
|
+
isPart(key: any): any;
|
|
23
|
+
fileStats(key: any): any;
|
|
24
|
+
}
|
|
25
|
+
export declare function splitModel(text: any, fallbackName?: string): {
|
|
26
|
+
files: Map<string, string>;
|
|
27
|
+
main: string | null;
|
|
28
|
+
data: Map<string, string>;
|
|
29
|
+
};
|
|
30
|
+
export declare function flatten(model: any, lib: any, onInstance: any): {
|
|
31
|
+
missing: Map<any, any>;
|
|
32
|
+
};
|
|
33
|
+
export declare function collectDeps(lib: any, refs: any): Map<any, any>;
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
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. */
|
|
4
|
+
export type LdrParams = {
|
|
5
|
+
pack: string;
|
|
6
|
+
cullStuds: boolean;
|
|
7
|
+
cullUnder: boolean;
|
|
8
|
+
edges: boolean | 'idx' | 'ss';
|
|
9
|
+
side: 'double' | 'front';
|
|
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;
|
|
15
|
+
};
|
|
16
|
+
export type Inst = {
|
|
17
|
+
part: string;
|
|
18
|
+
color: string;
|
|
19
|
+
m: number[];
|
|
20
|
+
};
|
|
21
|
+
export type Pack = {
|
|
22
|
+
header: any;
|
|
23
|
+
arr: (r: any) => any;
|
|
24
|
+
bytes: number;
|
|
25
|
+
};
|
|
26
|
+
export declare function loadPack(url: string): Promise<Pack>;
|
|
27
|
+
/** Decode an uncompressed parts pack (4-byte LE header length, JSON header, then aligned typed-array payload). */
|
|
28
|
+
export declare function decodePack(buf: ArrayBuffer): Pack;
|
|
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
|
+
};
|
|
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`. */
|
|
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;
|
|
50
|
+
export declare function computeCulling(insts: Inst[], H: any): {
|
|
51
|
+
studs: {
|
|
52
|
+
kind: string;
|
|
53
|
+
color: string;
|
|
54
|
+
w: number[];
|
|
55
|
+
hidden: boolean;
|
|
56
|
+
}[];
|
|
57
|
+
underHidden: boolean[];
|
|
58
|
+
};
|
|
59
|
+
export declare function buildLdrScene(insts: Inst[], pack: Pack, P: LdrParams, color: (c: string) => THREE.Color, mark: (k: string) => void): {
|
|
60
|
+
root: THREE.Group<THREE.Object3DEventMap>;
|
|
61
|
+
stats: any;
|
|
62
|
+
setCull: (studs: boolean, under: boolean) => void;
|
|
63
|
+
setSide: (front: boolean) => void;
|
|
64
|
+
setEdges: (v: boolean) => void;
|
|
65
|
+
setCond: (v: boolean) => void;
|
|
66
|
+
swapStuds: (alt: any) => () => void;
|
|
67
|
+
box: THREE.Box3;
|
|
68
|
+
texturesReady: Promise<void>;
|
|
69
|
+
};
|
package/dist/scene.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { type Pack } from "./render.js";
|
|
3
|
+
import type { PartInstance, LDrawColor } from "./model.js";
|
|
4
|
+
export type ColorSource = Map<number, string | LDrawColor> | Record<number | string, string | LDrawColor> | ((code: number) => THREE.ColorRepresentation | undefined);
|
|
5
|
+
export interface LdrObjectOptions {
|
|
6
|
+
/** Draw LDraw type-2 edge lines (indexed, sharing each part's instance matrices). Default true. */
|
|
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;
|
|
17
|
+
/** Hide studs fully covered by a part above. Default true. */
|
|
18
|
+
cullStuds?: boolean;
|
|
19
|
+
/** Hide undersides (tubes) sitting fully on studs below. Default true. */
|
|
20
|
+
cullUndersides?: boolean;
|
|
21
|
+
/** 'front' = single-sided BFC faces (fast); 'double' = render both sides. Uncertified parts are always double-sided. Default 'front'. */
|
|
22
|
+
side?: "front" | "double";
|
|
23
|
+
/** 'plastic' = MeshPhysicalMaterial with clearcoat; 'standard' = MeshStandardMaterial (cheapest, used by the benchmarks). Default 'plastic'. */
|
|
24
|
+
material?: "plastic" | "standard";
|
|
25
|
+
/** Colour table override. Defaults to the `colors` table embedded in the pack by `ldr pack`. */
|
|
26
|
+
colors?: ColorSource;
|
|
27
|
+
/** Colour for unknown codes. Default #A0A5A9. */
|
|
28
|
+
fallbackColor?: THREE.ColorRepresentation;
|
|
29
|
+
/** Keep native LDraw space (-Y up, 1 unit = 1 LDU). Default false: the object is rotated to +Y up. */
|
|
30
|
+
ldrawSpace?: boolean;
|
|
31
|
+
/** Uniform scale applied to the object (e.g. 0.4 for millimetres, 0.01 for ~metres-ish). Default 1 (LDU). */
|
|
32
|
+
scale?: number;
|
|
33
|
+
/** Initial step (inclusive, 0-based global sequence from `sequenceSteps`). Default: show all. */
|
|
34
|
+
step?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface LdrStats {
|
|
37
|
+
instances: number;
|
|
38
|
+
drawn: number;
|
|
39
|
+
missing: string[];
|
|
40
|
+
studsTotal: number;
|
|
41
|
+
studsHidden: number;
|
|
42
|
+
undersTotal: number;
|
|
43
|
+
undersHidden: number;
|
|
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;
|
|
50
|
+
}
|
|
51
|
+
export interface LdrObject {
|
|
52
|
+
/** Add this to your scene. */
|
|
53
|
+
object: THREE.Group;
|
|
54
|
+
stats: LdrStats;
|
|
55
|
+
/** Number of build steps (nested submodel steps are sequenced). */
|
|
56
|
+
stepCount: number;
|
|
57
|
+
/** Show instances up to and including `step` (null = all). Rebuilds batches; culling is recomputed for the partial model. */
|
|
58
|
+
setStep(step: number | null): void;
|
|
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;
|
|
64
|
+
setCulling(studs: boolean, undersides: boolean): void;
|
|
65
|
+
setSide(side: "front" | "double"): void;
|
|
66
|
+
/** Bounding box in the object's parent space. */
|
|
67
|
+
getBox(target?: THREE.Box3): THREE.Box3;
|
|
68
|
+
dispose(): void;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Build a three.js object for a flattened model using a parts pack.
|
|
72
|
+
* Instances whose part is not in the pack are skipped and listed in `stats.missing`.
|
|
73
|
+
*/
|
|
74
|
+
export declare function createLdrObject(instances: PartInstance[], pack: Pack, options?: LdrObjectOptions): LdrObject;
|
package/dist/spec.d.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
export type M = number[];
|
|
2
|
+
export type RotStep = {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
z: number;
|
|
6
|
+
mode: "REL" | "ABS" | "ADD" | "END";
|
|
7
|
+
};
|
|
8
|
+
export type BufExchg = {
|
|
9
|
+
op: "STORE" | "RETRIEVE";
|
|
10
|
+
buf: string;
|
|
11
|
+
};
|
|
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 = ({
|
|
41
|
+
t: 0;
|
|
42
|
+
text: string;
|
|
43
|
+
meta?: string;
|
|
44
|
+
bfc?: string;
|
|
45
|
+
step?: boolean;
|
|
46
|
+
rotstep?: RotStep;
|
|
47
|
+
bufexchg?: BufExchg;
|
|
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) | ({
|
|
53
|
+
t: 1;
|
|
54
|
+
color: number;
|
|
55
|
+
m: M;
|
|
56
|
+
file: string;
|
|
57
|
+
} & TexAnno) | ({
|
|
58
|
+
t: 2 | 5;
|
|
59
|
+
color: number;
|
|
60
|
+
p: number[];
|
|
61
|
+
} & TexAnno) | ({
|
|
62
|
+
t: 3 | 4;
|
|
63
|
+
color: number;
|
|
64
|
+
p: number[];
|
|
65
|
+
} & TexAnno);
|
|
66
|
+
export interface LFile {
|
|
67
|
+
name: string;
|
|
68
|
+
cmds: Cmd[];
|
|
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;
|
|
77
|
+
}
|
|
78
|
+
export interface Doc {
|
|
79
|
+
main: string;
|
|
80
|
+
files: Map<string, LFile>; /** MPD `!DATA` blocks keyed by normalized name. */
|
|
81
|
+
data?: Map<string, DataBlock>;
|
|
82
|
+
}
|
|
83
|
+
export declare const norm: (s: string) => string;
|
|
84
|
+
/** Parse LDraw color token: decimal code, or direct color 0x2RRGGBB (and related 0xN…… forms). */
|
|
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;
|
|
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;
|
|
118
|
+
export declare function mul(a: M, b: M): M;
|
|
119
|
+
export declare const I: M;
|
|
120
|
+
/** True if color is an LDraw direct color (0x2RRGGBB etc.), not a palette CODE. */
|
|
121
|
+
export declare const isDirectColor: (c: number) => boolean;
|
|
122
|
+
export interface PartMesh {
|
|
123
|
+
name: string;
|
|
124
|
+
pos: Float32Array;
|
|
125
|
+
col: Uint32Array;
|
|
126
|
+
edges: Float32Array;
|
|
127
|
+
cond: Float32Array;
|
|
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[];
|
|
134
|
+
}
|
|
135
|
+
export interface Instance {
|
|
136
|
+
part: string;
|
|
137
|
+
color: number;
|
|
138
|
+
m: M;
|
|
139
|
+
step: number;
|
|
140
|
+
localStep: number;
|
|
141
|
+
steps: number[];
|
|
142
|
+
path: string;
|
|
143
|
+
missing: boolean;
|
|
144
|
+
aliasOf?: string;
|
|
145
|
+
}
|
|
146
|
+
/** Smooth normals that respect LDraw semantics: faces sharing an edge are smoothed together unless the
|
|
147
|
+
* edge is a type-2 line (hard). Conditional (type-5) lines force smooth; unmarked edges smooth only below creaseDeg.
|
|
148
|
+
* `cond` may be stride-6 (legacy endpoints only) or stride-12 (endpoints + 2 control points). */
|
|
149
|
+
export declare function smoothNormals(pos: number[], edges: number[], cond: number[], creaseDeg?: number): Float32Array;
|
package/package.json
CHANGED
|
@@ -1,52 +1,72 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ldr",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "LDraw",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
3
|
+
"version": "0.3.0",
|
|
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
|
+
"license": "MIT",
|
|
6
|
+
"author": "Evan Bacon",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"sideEffects": false,
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/
|
|
12
|
-
|
|
13
|
-
"bugs": {
|
|
14
|
-
"url": "https://github.com/evanbacon/ldr/issues"
|
|
15
|
-
},
|
|
16
|
-
"main": "lib/index.js",
|
|
17
|
-
"scripts": {
|
|
18
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
19
|
-
"lint": "eslint .",
|
|
20
|
-
"prettier": "eslint . --fix"
|
|
21
|
-
},
|
|
22
|
-
"directories": {
|
|
23
|
-
"example": "examples",
|
|
24
|
-
"lib": "lib"
|
|
11
|
+
"url": "git+https://github.com/EvanBacon/ldr.git",
|
|
12
|
+
"directory": "packages/ldr"
|
|
25
13
|
},
|
|
14
|
+
"homepage": "https://github.com/EvanBacon/ldr#readme",
|
|
15
|
+
"bugs": "https://github.com/EvanBacon/ldr/issues",
|
|
26
16
|
"keywords": [
|
|
27
17
|
"lego",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
18
|
+
"ldraw",
|
|
19
|
+
"three",
|
|
20
|
+
"threejs",
|
|
21
|
+
"webgl",
|
|
22
|
+
"instancing",
|
|
23
|
+
"renderer",
|
|
24
|
+
"mpd",
|
|
25
|
+
"ldr",
|
|
26
|
+
"bricks",
|
|
27
|
+
"3d"
|
|
34
28
|
],
|
|
35
|
-
"
|
|
36
|
-
"
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"module": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./node": {
|
|
38
|
+
"types": "./dist/node/index.d.ts",
|
|
39
|
+
"import": "./dist/node/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./package.json": "./package.json"
|
|
42
|
+
},
|
|
43
|
+
"bin": {
|
|
44
|
+
"ldr": "./dist/cli.js"
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"dist",
|
|
48
|
+
"README.md",
|
|
49
|
+
"LICENSE"
|
|
50
|
+
],
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "rm -rf dist && bun build src/index.ts --outdir dist --target browser --format esm --external three --external fzstd && bun build src/node/index.ts src/cli.ts --outdir dist --root src --target node --format esm --external three --external fzstd && tsc -p tsconfig.build.json && bun scripts/postbuild.ts",
|
|
53
|
+
"test": "bun test",
|
|
54
|
+
"prepublishOnly": "bun run build && bun test"
|
|
55
|
+
},
|
|
37
56
|
"dependencies": {
|
|
38
|
-
"
|
|
57
|
+
"fzstd": "^0.1.1"
|
|
39
58
|
},
|
|
40
59
|
"peerDependencies": {
|
|
41
|
-
"three": "0.
|
|
60
|
+
"three": ">=0.160.0"
|
|
42
61
|
},
|
|
43
62
|
"devDependencies": {
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
63
|
+
"@types/bun": "latest",
|
|
64
|
+
"@types/node": "^26.6.5",
|
|
65
|
+
"@types/three": "^0.180.0",
|
|
66
|
+
"three": "^0.186.1",
|
|
67
|
+
"typescript": "^5.9.0"
|
|
49
68
|
},
|
|
50
|
-
"
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=18"
|
|
51
71
|
}
|
|
52
72
|
}
|
package/lib/.DS_Store
DELETED
|
Binary file
|
package/lib/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default {};
|