poppygl 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +127 -0
- package/dist/index.js +18 -13
- package/package.json +3 -2
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { mat4 } from 'gl-matrix';
|
|
2
|
+
|
|
3
|
+
type RGBA = readonly [number, number, number, number];
|
|
4
|
+
type MutableRGBA = [number, number, number, number];
|
|
5
|
+
interface BitmapLike {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
data: Uint8Array | Uint8ClampedArray;
|
|
9
|
+
}
|
|
10
|
+
type ImageFactory = (width: number, height: number) => BitmapLike;
|
|
11
|
+
declare const createUint8Bitmap: ImageFactory;
|
|
12
|
+
|
|
13
|
+
declare const DEFAULT_LIGHT_DIR: readonly [-0.4, -0.9, -0.2];
|
|
14
|
+
interface RenderOptions {
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
fov: number;
|
|
18
|
+
cull: boolean;
|
|
19
|
+
gamma: boolean;
|
|
20
|
+
ambient: number;
|
|
21
|
+
lightDir: readonly [number, number, number];
|
|
22
|
+
camPos?: readonly [number, number, number] | null;
|
|
23
|
+
lookAt?: readonly [number, number, number] | null;
|
|
24
|
+
}
|
|
25
|
+
type RenderOptionsInput = Partial<RenderOptions>;
|
|
26
|
+
declare const DEFAULT_RENDER_OPTIONS: RenderOptions;
|
|
27
|
+
declare function getDefaultRenderOptions(): RenderOptions;
|
|
28
|
+
|
|
29
|
+
interface Material {
|
|
30
|
+
baseColorFactor: [number, number, number, number];
|
|
31
|
+
baseColorTexture: BitmapLike | null;
|
|
32
|
+
}
|
|
33
|
+
interface DrawCall {
|
|
34
|
+
positions: Float32Array;
|
|
35
|
+
normals: Float32Array | null;
|
|
36
|
+
uvs: Float32Array | null;
|
|
37
|
+
indices: Uint32Array | null;
|
|
38
|
+
model: mat4;
|
|
39
|
+
material: Material;
|
|
40
|
+
}
|
|
41
|
+
interface GLTFResources {
|
|
42
|
+
buffers: Uint8Array[];
|
|
43
|
+
images: BitmapLike[];
|
|
44
|
+
}
|
|
45
|
+
interface GLTFScene {
|
|
46
|
+
drawCalls: DrawCall[];
|
|
47
|
+
gltf: any;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface Camera {
|
|
51
|
+
view: mat4;
|
|
52
|
+
proj: mat4;
|
|
53
|
+
}
|
|
54
|
+
declare function buildCamera(drawCalls: DrawCall[], width: number, height: number, fovDeg: number, camPos: readonly [number, number, number] | null | undefined, lookAt: readonly [number, number, number] | null | undefined): Camera;
|
|
55
|
+
|
|
56
|
+
interface RenderResult {
|
|
57
|
+
bitmap: BitmapLike;
|
|
58
|
+
camera: Camera;
|
|
59
|
+
options: RenderOptions;
|
|
60
|
+
}
|
|
61
|
+
declare function renderDrawCalls(drawCalls: DrawCall[], optionsInput?: RenderOptionsInput, imageFactory?: ImageFactory): RenderResult;
|
|
62
|
+
|
|
63
|
+
declare function resolveRenderOptions(options?: RenderOptionsInput): RenderOptions;
|
|
64
|
+
|
|
65
|
+
type GLTF = any;
|
|
66
|
+
declare function createSceneFromGLTF(gltf: GLTF, resources: GLTFResources): GLTFScene;
|
|
67
|
+
|
|
68
|
+
declare function computeSmoothNormals(positions: Float32Array, indices: Uint32Array | null): Float32Array;
|
|
69
|
+
|
|
70
|
+
declare function computeWorldAABB(drawCalls: DrawCall[]): {
|
|
71
|
+
min: number[];
|
|
72
|
+
max: number[];
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
interface FetchLikeResponse {
|
|
76
|
+
ok: boolean;
|
|
77
|
+
status: number;
|
|
78
|
+
statusText: string;
|
|
79
|
+
url?: string;
|
|
80
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
81
|
+
}
|
|
82
|
+
type FetchLike = (input: string, init?: Record<string, unknown>) => Promise<FetchLikeResponse>;
|
|
83
|
+
interface LoadGLTFWithResourcesFromURLOptions {
|
|
84
|
+
fetchImpl?: FetchLike;
|
|
85
|
+
}
|
|
86
|
+
declare function loadGLTFWithResourcesFromURL(url: string, options?: LoadGLTFWithResourcesFromURLOptions): Promise<{
|
|
87
|
+
gltf: any;
|
|
88
|
+
resources: GLTFResources;
|
|
89
|
+
}>;
|
|
90
|
+
|
|
91
|
+
declare function bufferFromDataURI(uri: string): Uint8Array;
|
|
92
|
+
declare function isPNG(filenameOrUri: string): boolean;
|
|
93
|
+
declare function isJPG(filenameOrUri: string): boolean;
|
|
94
|
+
declare function decodeImageFromBuffer(buf: Uint8Array, mimeType?: string | null): Promise<BitmapLike>;
|
|
95
|
+
|
|
96
|
+
interface LightSettings {
|
|
97
|
+
dir: readonly [number, number, number];
|
|
98
|
+
ambient: number;
|
|
99
|
+
}
|
|
100
|
+
declare class SoftwareRenderer {
|
|
101
|
+
readonly width: number;
|
|
102
|
+
readonly height: number;
|
|
103
|
+
readonly bitmap: BitmapLike;
|
|
104
|
+
readonly depth: Float32Array;
|
|
105
|
+
constructor(width: number, height: number, imageFactory?: ImageFactory);
|
|
106
|
+
get buffer(): Uint8Array<ArrayBufferLike> | Uint8ClampedArray<ArrayBufferLike>;
|
|
107
|
+
clear(colorRGBA?: [number, number, number, number]): void;
|
|
108
|
+
setPixel(x: number, y: number, r: number, g: number, b: number, a: number): void;
|
|
109
|
+
sampleTextureNearest(img: BitmapLike | null, u: number, v: number): MutableRGBA;
|
|
110
|
+
perspInterp(attrs: number[][], invWs: number[], lambdas: number[]): number[];
|
|
111
|
+
drawMesh(mesh: DrawCall, camera: Camera, light: LightSettings, material: Material, cullBackFaces?: boolean, gammaOut?: boolean): void;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
declare const pureImageFactory: ImageFactory;
|
|
115
|
+
|
|
116
|
+
declare function encodePNGToBuffer(image: BitmapLike): Promise<Buffer>;
|
|
117
|
+
|
|
118
|
+
interface RenderGLTFToPNGBufferFromURLOptions extends RenderOptionsInput, LoadGLTFWithResourcesFromURLOptions {
|
|
119
|
+
}
|
|
120
|
+
declare function renderGLTFToPNGBufferFromURL(url: string, options?: RenderGLTFToPNGBufferFromURLOptions): Promise<Buffer>;
|
|
121
|
+
|
|
122
|
+
type RenderGLTFToPNGBufferFromGLBBufferOptions = RenderOptionsInput;
|
|
123
|
+
declare function renderGLTFToPNGBufferFromGLBBuffer(glb: ArrayBuffer | Uint8Array, options?: RenderGLTFToPNGBufferFromGLBBufferOptions): Promise<Buffer>;
|
|
124
|
+
|
|
125
|
+
declare function renderSceneFromGLTF(scene: GLTFScene, options?: RenderOptionsInput, imageFactory?: ImageFactory): RenderResult;
|
|
126
|
+
|
|
127
|
+
export { type BitmapLike, type Camera, DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, type DrawCall, type FetchLike, type GLTFResources, type GLTFScene, type ImageFactory, type LightSettings, type LoadGLTFWithResourcesFromURLOptions, type Material, type MutableRGBA, type RGBA, type RenderGLTFToPNGBufferFromGLBBufferOptions, type RenderGLTFToPNGBufferFromURLOptions, type RenderOptions, type RenderOptionsInput, type RenderResult, SoftwareRenderer, bufferFromDataURI, buildCamera, computeSmoothNormals, computeWorldAABB, createSceneFromGLTF, createUint8Bitmap, decodeImageFromBuffer, encodePNGToBuffer, getDefaultRenderOptions, isJPG, isPNG, loadGLTFWithResourcesFromURL, pureImageFactory, renderDrawCalls, renderGLTFToPNGBufferFromGLBBuffer, renderGLTFToPNGBufferFromURL, renderSceneFromGLTF, resolveRenderOptions };
|
package/dist/index.js
CHANGED
|
@@ -10,13 +10,7 @@ function computeWorldAABB(drawCalls) {
|
|
|
10
10
|
for (const dc of drawCalls) {
|
|
11
11
|
const { positions, model } = dc;
|
|
12
12
|
for (let i = 0; i < positions.length; i += 3) {
|
|
13
|
-
vec4.set(
|
|
14
|
-
tmp,
|
|
15
|
-
positions[i],
|
|
16
|
-
positions[i + 1],
|
|
17
|
-
positions[i + 2],
|
|
18
|
-
1
|
|
19
|
-
);
|
|
13
|
+
vec4.set(tmp, positions[i], positions[i + 1], positions[i + 2], 1);
|
|
20
14
|
vec4.transformMat4(tmp, tmp, model);
|
|
21
15
|
const x = tmp[0];
|
|
22
16
|
const y = tmp[1];
|
|
@@ -799,7 +793,8 @@ function parseGLB(arrayBuffer) {
|
|
|
799
793
|
const chunkLength = view.getUint32(offset, true);
|
|
800
794
|
const chunkType = view.getUint32(offset + 4, true);
|
|
801
795
|
offset += 8;
|
|
802
|
-
if (offset + chunkLength > length)
|
|
796
|
+
if (offset + chunkLength > length)
|
|
797
|
+
throw new Error("Truncated GLB chunk data.");
|
|
803
798
|
const chunkData = new Uint8Array(arrayBuffer, offset, chunkLength);
|
|
804
799
|
offset += chunkLength;
|
|
805
800
|
if (chunkType === JSON_CHUNK_TYPE) {
|
|
@@ -817,7 +812,8 @@ function parseGLB(arrayBuffer) {
|
|
|
817
812
|
// lib/gltf/loadGLTFWithResourcesFromURL.ts
|
|
818
813
|
function ensureFetch(fetchImpl) {
|
|
819
814
|
const impl = fetchImpl ?? globalThis.fetch;
|
|
820
|
-
if (!impl)
|
|
815
|
+
if (!impl)
|
|
816
|
+
throw new Error("Global fetch API is not available; provide fetchImpl.");
|
|
821
817
|
return impl;
|
|
822
818
|
}
|
|
823
819
|
async function fetchBinary(fetchImpl, url) {
|
|
@@ -832,7 +828,9 @@ async function loadGLTFWithResourcesFromURL(url, options = {}) {
|
|
|
832
828
|
const fetchImpl = ensureFetch(options.fetchImpl);
|
|
833
829
|
const response = await fetchImpl(url);
|
|
834
830
|
if (!response.ok)
|
|
835
|
-
throw new Error(
|
|
831
|
+
throw new Error(
|
|
832
|
+
`Failed to fetch ${url}: ${response.status} ${response.statusText}`
|
|
833
|
+
);
|
|
836
834
|
const resolvedURL = new URL(response.url || url);
|
|
837
835
|
const baseURL = resolvedURL;
|
|
838
836
|
const sourceBuffer = await response.arrayBuffer();
|
|
@@ -867,7 +865,9 @@ async function loadGLTFWithResourcesFromURL(url, options = {}) {
|
|
|
867
865
|
buffers[index] = buf;
|
|
868
866
|
return buf;
|
|
869
867
|
}
|
|
870
|
-
throw new Error(
|
|
868
|
+
throw new Error(
|
|
869
|
+
`Buffer ${index} is missing a uri and no GLB chunk was provided.`
|
|
870
|
+
);
|
|
871
871
|
}
|
|
872
872
|
await Promise.all(
|
|
873
873
|
(gltf.buffers || []).map(async (entry, idx) => {
|
|
@@ -892,7 +892,10 @@ async function loadGLTFWithResourcesFromURL(url, options = {}) {
|
|
|
892
892
|
const bufferView = gltf.bufferViews?.[img.bufferView];
|
|
893
893
|
if (!bufferView)
|
|
894
894
|
throw new Error(`Invalid image bufferView index ${img.bufferView}`);
|
|
895
|
-
const buffer = await resolveBuffer(
|
|
895
|
+
const buffer = await resolveBuffer(
|
|
896
|
+
bufferView.buffer,
|
|
897
|
+
gltf.buffers?.[bufferView.buffer]
|
|
898
|
+
);
|
|
896
899
|
if (!buffer)
|
|
897
900
|
throw new Error(`Missing buffer for image bufferView ${img.bufferView}`);
|
|
898
901
|
const byteOffset = bufferView.byteOffset ?? 0;
|
|
@@ -981,7 +984,9 @@ async function renderGLTFToPNGBufferFromGLBBuffer(glb, options = {}) {
|
|
|
981
984
|
continue;
|
|
982
985
|
}
|
|
983
986
|
if (!binaryChunk) {
|
|
984
|
-
throw new Error(
|
|
987
|
+
throw new Error(
|
|
988
|
+
`GLB is missing the binary chunk required for buffer ${index}.`
|
|
989
|
+
);
|
|
985
990
|
}
|
|
986
991
|
buffers[index] = binaryChunk;
|
|
987
992
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poppygl",
|
|
3
3
|
"main": "dist/index.js",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.6",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/tscircuit/poppygl.git"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"start": "cosmos",
|
|
14
14
|
"build:site": "cosmos-export",
|
|
15
|
-
"build": "tsup-node ./lib/index.ts --format esm",
|
|
15
|
+
"build": "tsup-node ./lib/index.ts --format esm --dts",
|
|
16
16
|
"format": "biome format --write .",
|
|
17
17
|
"format:check": "biome format .",
|
|
18
18
|
"test": "bun test"
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@biomejs/biome": "^2.2.4",
|
|
23
23
|
"@types/bun": "^1.2.23",
|
|
24
|
+
"@types/readable-stream": "^4.0.21",
|
|
24
25
|
"looks-same": "^10.0.1",
|
|
25
26
|
"react": "^19.1.1",
|
|
26
27
|
"react-cosmos": "^7.0.0",
|