@domgell/gltf-parser 1.0.0 → 1.0.2

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.
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="AgentMigrationStateService">
4
+ <option name="migrationStatus" value="COMPLETED" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Ask2AgentMigrationStateService">
4
+ <option name="migrationStatus" value="COMPLETED" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="EditMigrationStateService">
4
+ <option name="migrationStatus" value="COMPLETED" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="WEB_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$">
5
+ <excludeFolder url="file://$MODULE_DIR$/.tmp" />
6
+ <excludeFolder url="file://$MODULE_DIR$/temp" />
7
+ <excludeFolder url="file://$MODULE_DIR$/tmp" />
8
+ </content>
9
+ <orderEntry type="inheritedJdk" />
10
+ <orderEntry type="sourceFolder" forTests="false" />
11
+ </component>
12
+ </module>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/gltf-parser.iml" filepath="$PROJECT_DIR$/.idea/gltf-parser.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
package/package.json CHANGED
@@ -1,18 +1,15 @@
1
1
  {
2
2
  "name": "@domgell/gltf-parser",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "main": "src/index.ts",
5
5
  "exports": "./src/index.ts",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
8
- },
9
- "keywords": ["gltf", "glb", "mesh", "parser"],
10
6
  "author": "domgell",
11
7
  "license": "ISC",
12
8
  "description": "Parse .GLTF/.GLF files into JS objects",
9
+ "keywords": ["gltf", "glb", "mesh", "parser", "model"],
13
10
  "dependencies": {
14
- "gltf-types": "file:../gltf-types",
11
+ "@domgell/gltf-types": "*",
12
+ "@domgell/ts-util": "*",
15
13
  "dom-game-math": "*"
16
- },
17
- "devDependencies": {}
14
+ }
18
15
  }
package/src/Parser.ts CHANGED
@@ -1,17 +1,16 @@
1
1
  import {
2
2
  AccessorArrayType,
3
3
  AccessorConstructorType,
4
- assert,
5
4
  chunk,
6
- fail,
7
5
  getTransform,
8
6
  } from "./util.ts";
9
7
  import * as Parsed from "./types.ts";
10
- import * as GLTF from "gltf-types";
8
+ import * as GLTF from "@domgell/gltf-types";
11
9
  import {mat4, TransformOrder} from "dom-game-math";
12
10
  import {Matrix4x4, TextureFilterMap, TextureWrapModeMap} from "./types.ts";
11
+ import {assert, fail} from "@domgell/ts-util";
13
12
 
14
- export type ParserOptions = {
13
+ export interface ParserOptions {
15
14
  transformOrder: TransformOrder,
16
15
  }
17
16
 
@@ -30,7 +29,6 @@ export class Parser {
30
29
 
31
30
  const data = await r.arrayBuffer();
32
31
  const dataView = new DataView(data);
33
-
34
32
  let offset = 12;
35
33
 
36
34
  // Get JSON Header
@@ -39,12 +37,12 @@ export class Parser {
39
37
  const textDecoder = new TextDecoder("utf-8");
40
38
  const json = textDecoder.decode(jsonChunkData);
41
39
  const header = JSON.parse(json);
42
-
43
40
  offset += 8 + jsonChunkLength;
44
41
 
45
42
  // Get binary data
46
43
  const binaryChunkLength = dataView.getUint32(offset, true);
47
44
  const binary = new ArrayBuffer(binaryChunkLength);
45
+
48
46
  const binaryChunkView = new Uint8Array(binary);
49
47
  binaryChunkView.set(new Uint8Array(data, offset + 8, binaryChunkLength));
50
48
 
@@ -53,7 +51,10 @@ export class Parser {
53
51
 
54
52
  // ----------------------------------- Accessor ------------------------------------
55
53
 
56
- accessor<T extends AccessorArrayType, I extends number | undefined>(index: I, type: T): I extends number ? AccessorConstructorType<T> : AccessorConstructorType<T> | undefined {
54
+ accessor<
55
+ T extends AccessorArrayType,
56
+ I extends number | undefined
57
+ >(index: I, type: T): I extends number ? AccessorConstructorType<T> : AccessorConstructorType<T> | undefined {
57
58
  if (index === undefined) return undefined as any;
58
59
 
59
60
  assert(this.header.accessors !== undefined, "Accessors are undefined");
@@ -63,7 +64,6 @@ export class Parser {
63
64
  ?? fail(`Accessor at index ${index} not found`);
64
65
 
65
66
  assert(accessor.bufferView !== undefined, "Accessor bufferView is undefined");
66
-
67
67
  const bufferView = this.header.bufferViews[accessor.bufferView];
68
68
  const byteOffset = (bufferView.byteOffset ?? 0) + (accessor.byteOffset ?? 0);
69
69
 
@@ -79,6 +79,7 @@ export class Parser {
79
79
  5125: Uint32Array,
80
80
  5126: Float32Array,
81
81
  }[accessor.componentType];
82
+
82
83
  assert(assertType.name === type.name, `Mismatched types: requested '${type.name}' but got '${assertType.name}'`);
83
84
 
84
85
  const byteLength = numComponents * accessor.count * type.BYTES_PER_ELEMENT;
@@ -89,6 +90,7 @@ export class Parser {
89
90
 
90
91
  async mesh(gltfMesh: GLTF.Mesh) {
91
92
  const primitives = new Array<Parsed.MeshPrimitive>(gltfMesh.primitives.length);
93
+
92
94
  for (let i = 0; i < primitives.length; i++) {
93
95
  primitives[i] = await this.primitive(gltfMesh.primitives[i]);
94
96
  }
@@ -133,7 +135,7 @@ export class Parser {
133
135
  skin(gltfSkin: GLTF.Skin) {
134
136
  assert(this.header.nodes !== undefined, "`Nodes` is undefined");
135
137
 
136
- // Default: Array of identity matrices with length = number of joints
138
+ // Default to array of identity matrices with length = number of joints
137
139
  const inverseBindMatrices = gltfSkin.inverseBindMatrices
138
140
  ? chunk(this.accessor(gltfSkin.inverseBindMatrices, Float32Array), 16)
139
141
  : gltfSkin.joints.map(() => Array.from(mat4.idt) as Matrix4x4);
@@ -152,11 +154,8 @@ export class Parser {
152
154
 
153
155
  const children = gltfJoint.children?.map(i => this.header.nodes![i].name!) ?? [];
154
156
 
155
- //const inverseBindTransform = inverseBindMatrices[jointIndex];
156
157
  const inverseBindTransform = inverseBindMatrices[i];
157
-
158
158
  joints[gltfJoint.name] = {name: gltfJoint.name, transform, children, inverseBindTransform};
159
-
160
159
  i++;
161
160
  }
162
161
 
@@ -166,6 +165,7 @@ export class Parser {
166
165
  // Set parents
167
166
  for (let name in joints) {
168
167
  const joint = joints[name];
168
+
169
169
  for (let childName of joint.children) {
170
170
  joints[childName].parent = name;
171
171
  }
@@ -183,6 +183,7 @@ export class Parser {
183
183
 
184
184
  // TEMP: Calculate global inverse transform
185
185
  const skinParentNode = this.header.nodes.find(n => n.children?.includes(gltfSkin.joints[0]));
186
+
186
187
  const globalInverseTransform = skinParentNode
187
188
  ? getTransform(skinParentNode, this.options.transformOrder)
188
189
  : Array.from(mat4.idt) as Matrix4x4;
@@ -192,6 +193,7 @@ export class Parser {
192
193
 
193
194
  animation(gltfAnimation: GLTF.Animation): Parsed.Animation {
194
195
  assert(this.header.nodes !== undefined, "`Nodes` is undefined");
196
+
195
197
  const channels: Record<string, Parsed.AnimationChannel> = {};
196
198
  let duration = 0;
197
199
 
@@ -201,18 +203,15 @@ export class Parser {
201
203
 
202
204
  // Init channel if not already present
203
205
  channels[gltfTargetNode.name] ??= {translation: [], rotation: [], scale: []};
204
-
205
206
  const sampler = gltfAnimation.samplers[gltfChannel.sampler];
206
207
  const times = this.accessor(sampler.input, Float32Array);
207
208
  const values = this.accessor(sampler.output, Float32Array);
208
-
209
209
  const numComponents = values.length / times.length;
210
210
  assert(numComponents === 3 || numComponents === 4, `Invalid number of components: '${numComponents}'`);
211
211
 
212
212
  // Set keyframes array of current 'path', e.g. 'translation'
213
213
  const keyframes = chunk(values, numComponents).map((value, i) => ({time: times[i], value}));
214
214
  channels[gltfTargetNode.name][gltfChannel.target.path] = keyframes as any;
215
-
216
215
  duration = Math.max(duration, ...keyframes.map(k => k.time));
217
216
  }
218
217
 
@@ -233,17 +232,17 @@ export class Parser {
233
232
 
234
233
  let normal: Parsed.MaterialNormalInfo | undefined;
235
234
  if (gltfMaterial.normalTexture !== undefined) {
236
- fail("TODO");
235
+ fail("TODO: Normal Texture");
237
236
  }
238
237
 
239
238
  let emissive: Parsed.MaterialEmissiveInfo | undefined;
240
239
  if (gltfMaterial.emissiveTexture !== undefined) {
241
- fail("TODO");
240
+ fail("TODO: Emissive Texture");
242
241
  }
243
242
 
244
243
  let ambientOcclusion: Parsed.MaterialAmbientOcclusionInfo | undefined;
245
244
  if (gltfMaterial.occlusionTexture !== undefined) {
246
- fail("TODO");
245
+ fail("TODO: Occlusion Texture");
247
246
  }
248
247
 
249
248
  const alpha: Parsed.MaterialAlphaInfo = {
@@ -271,6 +270,7 @@ export class Parser {
271
270
 
272
271
  // Parse sampler
273
272
  const sampler: Parsed.Sampler = {wrap: {s: "repeat", t: "repeat"}, filter: {min: "linear", mag: "linear"}};
273
+
274
274
  if (this.header.samplers !== undefined && gltfTexture.sampler !== undefined) {
275
275
  const gltfSampler = this.header.samplers[gltfTexture.sampler];
276
276
 
@@ -290,22 +290,26 @@ export class Parser {
290
290
  const response = await fetch(this.path + gltfImage.uri);
291
291
  assert(response.ok, `Failed to fetch image at URI: '${gltfImage.uri}'`);
292
292
  const blob = await response.blob();
293
+
293
294
  return await createImageBitmap(blob);
294
295
  }
295
296
  // Image from buffer
296
297
  else {
297
298
  assert(this.header.bufferViews !== undefined, "Header `BufferViews` property is undefined");
298
299
  assert(this.header.buffers !== undefined, "Header `Buffers` property is undefined");
300
+
299
301
  const bufferView = this.header.bufferViews[gltfImage.bufferView];
300
302
  const buffer = this.header.buffers[bufferView.buffer];
301
303
 
302
304
  if (buffer.uri !== undefined) {
303
- fail("TODO");
305
+ fail("TODO: Buffer URI");
304
306
  }
305
307
 
306
- // TODO: buffer length + bufferView offset (?)
307
- const data = this.binary.slice(bufferView.byteOffset ?? 0, (bufferView.byteOffset ?? 0) + bufferView.byteLength);
308
+ const dataBegin = bufferView.byteOffset ?? 0;
309
+ const dataEnd = dataBegin + bufferView.byteLength;
310
+ const data = this.binary.slice(dataBegin, dataEnd);
308
311
  const blob = new Blob([new Uint8Array(data)]);
312
+
309
313
  return await createImageBitmap(blob);
310
314
  }
311
315
  }
package/src/index.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from "./types.ts";
2
- export * from "./Parser.ts";
1
+ export * from "./types.ts";
2
+ export * from "./Parser.ts";
package/src/types.ts CHANGED
@@ -1,244 +1,259 @@
1
- import {Tuple} from "./util.ts";
2
-
3
- export type Matrix4x4 = Tuple<number, 16>
4
- export type Vector2 = Tuple<number, 2>
5
- export type Vector3 = Tuple<number, 3>
6
- export type Vector4 = Tuple<number, 4>
7
-
8
- // ------------------------------- Scene -------------------------------
9
-
10
- export type Scene = {
11
- /**
12
- * All nodes in scene
13
- */
14
- nodes: Node[]
15
- cameras: Camera[],
16
- meshes: Mesh[],
17
- skins: Skin[],
18
- }
19
-
20
-
21
- // ------------------------------- Node --------------------------------
22
-
23
- export type Node = {
24
- transform: Matrix4x4,
25
- name?: string,
26
- children: Node[],
27
- parent?: Node,
28
- } & ({ mesh: Mesh, skin?: undefined, camera?: undefined }
29
- | { skin: Skin, mesh?: undefined, camera?: undefined }
30
- | { camera: Camera, mesh?: undefined, skin?: undefined })
31
-
32
-
33
- // ------------------------------ Camera -------------------------------
34
-
35
- export type OrthographicCamera = {
36
- type: "Orthographic"
37
- xmag: number,
38
- ymag: number,
39
- zfar: number,
40
- znear: number,
41
- view: Matrix4x4,
42
- projection: Matrix4x4,
43
- }
44
-
45
- export type PerspectiveCamera = {
46
- type: "Perspective"
47
- aspectRatio: number,
48
- yfov: number,
49
- zfar: number,
50
- znear: number,
51
- view: Matrix4x4,
52
- projection: Matrix4x4,
53
- }
54
-
55
- export type Camera = OrthographicCamera | PerspectiveCamera
56
-
57
-
58
- // ------------------------------- Mesh --------------------------------
59
-
60
- export type MeshPrimitiveAttributes = {
61
- positions: Vector3[],
62
- uvs?: Vector2[],
63
- normals?: Vector3[],
64
- colors?: Vector4[]
65
- weights?: Vector4[],
66
- joints?: Vector4[],
67
- tangents?: Vector4[], // TODO
68
- }
69
-
70
- export type MeshPrimitive = {
71
- /**
72
- * Vertex attributes of the mesh primitive
73
- */
74
- attributes: MeshPrimitiveAttributes,
75
- indices?: Uint32Array,
76
- material?: Material,
77
- }
78
-
79
- export type Mesh = {
80
- primitives: MeshPrimitive[],
81
- name?: string,
82
- }
83
-
84
-
85
- // -------------------------------- Skin -------------------------------
86
-
87
- export type Joint = {
88
- name: string,
89
- transform: Matrix4x4,
90
- inverseBindTransform: Matrix4x4,
91
- children: string[],
92
- parent?: string,
93
- }
94
-
95
- export type Skin = {
96
- root: Joint,
97
- joints: Record<string, Joint>,
98
- animations: Animation[],
99
- globalInverseTransform: Matrix4x4,
100
- name?: string,
101
- }
102
-
103
- // ----------------------------- Animation -----------------------------
104
-
105
- export type Animation = {
106
- duration: number,
107
- name?: string,
108
- channels: Record<string, AnimationChannel>,
109
- }
110
-
111
- export type AnimationChannel = {
112
- translation: AnimationKeyframe<Vector3>[]
113
- rotation: AnimationKeyframe<Vector4>[]
114
- scale: AnimationKeyframe<Vector3>[]
115
- }
116
-
117
- export type AnimationKeyframe<T> = { time: number, value: T }
118
-
119
-
120
- // ----------------------------- Texture -------------------------------
121
-
122
- // TODO: If source is undefined, don't create texture, if sampler is undefined create default sampler
123
- export type Texture = {
124
- source: ImageBitmap,
125
- sampler: Sampler,
126
- name?: string,
127
- }
128
-
129
- export type Sampler = {
130
- wrap: { s: TextureWrapMode, t: TextureWrapMode },
131
- filter: { min: TextureMinFilter, mag: TextureMagFilter },
132
- }
133
-
134
- export type TextureMagFilter = "nearest" | "linear"
135
-
136
- export type TextureMinFilter =
137
- "nearest"
138
- | "linear"
139
- | "nearest-mipmap-nearest"
140
- | "linear-mipmap-nearest"
141
- | "nearest-mipmap-linear"
142
- | "linear-mipmap-linear"
143
-
144
- export type TextureWrapMode =
145
- | "clamp-to-edge"
146
- | "mirrored-repeat"
147
- | "repeat"
148
-
149
- export const TextureWrapModeMap = {
150
- [33071]: "clamp-to-edge",
151
- [33648]: "mirrored-repeat",
152
- [10497]: "repeat",
153
- } as const;
154
-
155
- export const TextureFilterMap = {
156
- [9728]: "nearest",
157
- [9729]: "linear",
158
- [9984]: "nearest-mipmap-nearest",
159
- [9985]: "linear-mipmap-nearest",
160
- [9986]: "nearest-mipmap-linear",
161
- [9987]: "linear-mipmap-linear",
162
- } as const;
163
-
164
- // ----------------------------- Material ------------------------------
165
-
166
- export type Material = {
167
- metallicRoughness: MaterialMetallicRoughnessInfo,
168
- normal?: MaterialNormalInfo,
169
- emissive?: MaterialEmissiveInfo,
170
- ambientOcclusion?: MaterialAmbientOcclusionInfo,
171
- alpha: MaterialAlphaInfo,
172
- /**
173
- * Whether the material is double sided. Default is `false`.
174
- */
175
- doubleSided: boolean,
176
- }
177
-
178
- export type MaterialAlphaInfo = {
179
- /**
180
- * The alpha rendering mode of the material. Default is `"OPAQUE"`.
181
- */
182
- mode: "OPAQUE" | "MASK" | "BLEND",
183
- /**
184
- * The alpha cutoff value of the material. Default is `0.5`.
185
- */
186
- cutoff: number,
187
- }
188
-
189
- export type MaterialMetallicRoughnessInfo = {
190
- /**
191
- * The base color factor of the material. Default is `[1, 1, 1, 1]`.
192
- */
193
- baseColor: Vector4,
194
- /**
195
- * The base color texture of the material.
196
- */
197
- baseColorTexture?: Texture,
198
- /**
199
- * The factor for the metalness of the material. Default is `1`.
200
- */
201
- metallicFactor: number,
202
- /**
203
- * The factor for the roughness of the material. Default is `1`.
204
- */
205
- roughnessFactor: number,
206
- /**
207
- * The metallic roughness texture of the material.
208
- */
209
- metallicRoughnessTexture?: Texture,
210
- }
211
-
212
- export type MaterialNormalInfo = {
213
- /**
214
- * The normal texture of the material.
215
- */
216
- texture: Texture,
217
- /**
218
- * The scale applied to each vector of the normal map. Default is `1`.
219
- */
220
- scale: number,
221
- }
222
-
223
- export type MaterialEmissiveInfo = {
224
- /**
225
- * The emissive texture of the material.
226
- */
227
- texture: Texture,
228
- /**
229
- * The emissive factor of the material. Default is `[0, 0, 0]`.
230
- */
231
- factor: Vector3,
232
- }
233
-
234
- export type MaterialAmbientOcclusionInfo = {
235
- /**
236
- * The occlusion texture of the material.
237
- */
238
- texture: Texture,
239
- /**
240
- * The occlusion strength of the material. Default is `1`.
241
- */
242
- strength: number,
243
- }
244
-
1
+ import {Tuple} from "./util.ts";
2
+
3
+ export type Matrix4x4 = Tuple<number, 16>
4
+ export type Vector2 = Tuple<number, 2>
5
+ export type Vector3 = Tuple<number, 3>
6
+ export type Vector4 = Tuple<number, 4>
7
+
8
+ // ------------------------------- Scene -------------------------------
9
+
10
+ export interface Scene {
11
+ /**
12
+ * All nodes in scene
13
+ */
14
+ nodes: Node[]
15
+ cameras: Camera[],
16
+ meshes: Mesh[],
17
+ skins: Skin[],
18
+ }
19
+
20
+ // ------------------------------- Node --------------------------------
21
+
22
+ export type Node = {
23
+ transform: Matrix4x4,
24
+ name?: string,
25
+ children: Node[],
26
+ parent?: Node,
27
+ } & (MeshNode | SkinNode | CameraNode)
28
+
29
+ interface MeshNode {
30
+ mesh: Mesh,
31
+ skin?: undefined,
32
+ camera?: undefined
33
+ }
34
+
35
+ interface SkinNode {
36
+ skin: Skin,
37
+ mesh?: undefined,
38
+ camera?: undefined
39
+ }
40
+
41
+ interface CameraNode {
42
+ camera: Camera,
43
+ mesh?: undefined,
44
+ skin?: undefined
45
+ }
46
+
47
+ // ------------------------------ Camera -------------------------------
48
+
49
+ export interface OrthographicCamera {
50
+ type: "Orthographic"
51
+ xmag: number,
52
+ ymag: number,
53
+ zfar: number,
54
+ znear: number,
55
+ view: Matrix4x4,
56
+ projection: Matrix4x4,
57
+ }
58
+
59
+ export interface PerspectiveCamera {
60
+ type: "Perspective"
61
+ aspectRatio: number,
62
+ yfov: number,
63
+ zfar: number,
64
+ znear: number,
65
+ view: Matrix4x4,
66
+ projection: Matrix4x4,
67
+ }
68
+
69
+ export type Camera = OrthographicCamera | PerspectiveCamera
70
+
71
+ // ------------------------------- Mesh --------------------------------
72
+
73
+ export interface MeshPrimitiveAttributes {
74
+ positions: Vector3[],
75
+ uvs?: Vector2[],
76
+ normals?: Vector3[],
77
+ colors?: Vector4[]
78
+ weights?: Vector4[],
79
+ joints?: Vector4[],
80
+ tangents?: Vector4[], // TODO
81
+ }
82
+
83
+ export interface MeshPrimitive {
84
+ /**
85
+ * Vertex attributes of the mesh primitive
86
+ */
87
+ attributes: MeshPrimitiveAttributes,
88
+ indices?: Uint32Array,
89
+ material?: Material,
90
+ }
91
+
92
+ export interface Mesh {
93
+ primitives: MeshPrimitive[],
94
+ name?: string,
95
+ }
96
+
97
+ // -------------------------------- Skin -------------------------------
98
+
99
+ export interface Joint {
100
+ name: string,
101
+ transform: Matrix4x4,
102
+ inverseBindTransform: Matrix4x4,
103
+ children: string[],
104
+ parent?: string,
105
+ }
106
+
107
+ export interface Skin {
108
+ root: Joint,
109
+ joints: Record<string, Joint>,
110
+ animations: Animation[],
111
+ globalInverseTransform: Matrix4x4,
112
+ name?: string,
113
+ }
114
+
115
+ // ----------------------------- Animation -----------------------------
116
+
117
+ export interface Animation {
118
+ duration: number,
119
+ name?: string,
120
+ channels: Record<string, AnimationChannel>,
121
+ }
122
+
123
+ export interface AnimationChannel {
124
+ translation: AnimationKeyframe<Vector3>[];
125
+ rotation: AnimationKeyframe<Vector4>[];
126
+ scale: AnimationKeyframe<Vector3>[];
127
+ }
128
+
129
+ export interface AnimationKeyframe<T> {
130
+ time: number,
131
+ value: T
132
+ }
133
+
134
+ // ----------------------------- Texture -------------------------------
135
+
136
+
137
+ // TODO: If source is undefined, don't create texture, if sampler is undefined create default sampler
138
+ export interface Texture {
139
+ source: ImageBitmap,
140
+ sampler: Sampler,
141
+ name?: string,
142
+ }
143
+
144
+ export interface Sampler {
145
+ wrap: { s: TextureWrapMode, t: TextureWrapMode },
146
+ filter: { min: TextureMinFilter, mag: TextureMagFilter },
147
+ }
148
+
149
+ export type TextureMagFilter = "nearest" | "linear"
150
+
151
+ export type TextureMinFilter =
152
+ | "nearest"
153
+ | "linear"
154
+ | "nearest-mipmap-nearest"
155
+ | "linear-mipmap-nearest"
156
+ | "nearest-mipmap-linear"
157
+ | "linear-mipmap-linear"
158
+
159
+ export type TextureWrapMode =
160
+ | "clamp-to-edge"
161
+ | "mirrored-repeat"
162
+ | "repeat"
163
+
164
+ export const TextureWrapModeMap = {
165
+ [33071]: "clamp-to-edge",
166
+ [33648]: "mirrored-repeat",
167
+ [10497]: "repeat",
168
+ } as const;
169
+
170
+ export const TextureFilterMap = {
171
+ [9728]: "nearest",
172
+ [9729]: "linear",
173
+ [9984]: "nearest-mipmap-nearest",
174
+ [9985]: "linear-mipmap-nearest",
175
+ [9986]: "nearest-mipmap-linear",
176
+ [9987]: "linear-mipmap-linear",
177
+ } as const;
178
+
179
+ // ----------------------------- Material ------------------------------
180
+
181
+ export interface Material {
182
+ metallicRoughness: MaterialMetallicRoughnessInfo,
183
+ normal?: MaterialNormalInfo,
184
+ emissive?: MaterialEmissiveInfo,
185
+ ambientOcclusion?: MaterialAmbientOcclusionInfo,
186
+ alpha: MaterialAlphaInfo,
187
+ /**
188
+ * Whether the material is double-sided. Default is `false`.
189
+ */
190
+ doubleSided: boolean,
191
+ }
192
+
193
+ export interface MaterialAlphaInfo {
194
+ /**
195
+ * The alpha rendering mode of the material. Default is `"OPAQUE"`.
196
+ */
197
+ mode: "OPAQUE" | "MASK" | "BLEND",
198
+ /**
199
+ * The alpha cutoff value of the material. Default is `0.5`.
200
+ */
201
+ cutoff: number,
202
+ }
203
+
204
+ export interface MaterialMetallicRoughnessInfo {
205
+ /**
206
+ * The base color factor of the material. Default is `[1, 1, 1, 1]`.
207
+ */
208
+ baseColor: Vector4,
209
+ /**
210
+ * The base color texture of the material.
211
+ */
212
+ baseColorTexture?: Texture,
213
+ /**
214
+ * The factor for the metalness of the material. Default is `1`.
215
+ */
216
+ metallicFactor: number,
217
+ /**
218
+ * The factor for the roughness of the material. Default is `1`.
219
+ */
220
+ roughnessFactor: number,
221
+ /**
222
+ * The metallic roughness texture of the material.
223
+ */
224
+ metallicRoughnessTexture?: Texture,
225
+ }
226
+
227
+ export interface MaterialNormalInfo {
228
+ /**
229
+ * The normal texture of the material.
230
+ */
231
+ texture: Texture,
232
+ /**
233
+ * The scale applied to each vector of the normal map. Default is `1`.
234
+ */
235
+ scale: number,
236
+ }
237
+
238
+ export interface MaterialEmissiveInfo {
239
+ /**
240
+ * The emissive texture of the material.
241
+ */
242
+ texture: Texture,
243
+
244
+ /**
245
+ * The emissive factor of the material. Default is `[0, 0, 0]`.
246
+ */
247
+ factor: Vector3,
248
+ }
249
+
250
+ export interface MaterialAmbientOcclusionInfo {
251
+ /**
252
+ * The occlusion texture of the material.
253
+ */
254
+ texture: Texture,
255
+ /**
256
+ * The occlusion strength of the material. Default is `1`.
257
+ */
258
+ strength: number,
259
+ }
package/src/util.ts CHANGED
@@ -1,67 +1,59 @@
1
- import {TransformOrder, mat4, vec3, quat, Matrix4} from "dom-game-math";
2
- import {Matrix4x4} from "./types.ts";
3
-
4
- // ----------------------------------- fail & assert -----------------------------------
5
-
6
- export function fail(msg: string): never {
7
- throw new Error(msg);
8
- }
9
-
10
- export function assert(condition: boolean, msg: string): asserts condition {
11
- if (!condition) {
12
- throw new Error(msg);
13
- }
14
- }
15
-
16
- // ------------------------------------- Accessor --------------------------------------
17
-
18
- export type AccessorArrayType =
19
- | Float32ArrayConstructor
20
- | Uint32ArrayConstructor
21
- | Uint16ArrayConstructor
22
- | Int16ArrayConstructor
23
- | Uint8ArrayConstructor
24
- | Int8ArrayConstructor
25
-
26
- export type AccessorConstructorType<T extends AccessorArrayType> = ReturnType<T["from"]>
27
-
28
- // --------------------------------------- Tuple ---------------------------------------
29
-
30
- export type Tuple<T, N extends number> = T[] & { length: N };
31
-
32
- export function chunk<T, N extends number>(array: Iterable<T>, size: N): Tuple<T, N>[] {
33
- const result = new Array<T[]>;
34
- let chunk = new Array<T>();
35
-
36
- for (const value of Array.from(array)) {
37
- chunk.push(value);
38
- if (chunk.length === size) {
39
- result.push(chunk);
40
- chunk = [];
41
- }
42
- }
43
-
44
- if (chunk.length) {
45
- result.push(chunk);
46
- }
47
-
48
- return result as Tuple<T, N>[];
49
- }
50
-
51
- export function getTransform(transform: {
52
- translation?: number[],
53
- rotation?: number[],
54
- scale?: number[]
55
- }, order: TransformOrder, out?: Tuple<number, 16>) {
56
- out ??= Array.from(mat4.idt) as Tuple<number, 16>;
57
-
58
- mat4.compose({
59
- translation: transform.translation && vec3.fromArray(transform.translation),
60
- rotation: transform.rotation && quat.fromArray(transform.rotation),
61
- scale: transform.scale && vec3.fromArray(transform.scale),
62
- order,
63
- }, out as Matrix4);
64
-
65
- return out;
66
- }
67
-
1
+ import {TransformOrder, mat4, vec3, quat, Matrix4} from "dom-game-math";
2
+
3
+ // ------------------------------------- Accessor --------------------------------------
4
+
5
+ export type AccessorArrayType =
6
+ | Float32ArrayConstructor
7
+ | Uint32ArrayConstructor
8
+ | Uint16ArrayConstructor
9
+ | Int16ArrayConstructor
10
+ | Uint8ArrayConstructor
11
+ | Int8ArrayConstructor
12
+
13
+ export type AccessorConstructorType<T extends AccessorArrayType> = ReturnType<T["from"]>
14
+
15
+ // --------------------------------------- Tuple ---------------------------------------
16
+
17
+ export type Tuple<T, N extends number> = T[] & { length: N };
18
+
19
+ export function chunk<T, N extends number>(array: Iterable<T>, size: N): Tuple<T, N>[] {
20
+ const result = new Array<T[]>;
21
+ let chunk = new Array<T>();
22
+
23
+ for (const value of Array.from(array)) {
24
+ chunk.push(value);
25
+
26
+ if (chunk.length === size) {
27
+ result.push(chunk);
28
+ chunk = [];
29
+ }
30
+ }
31
+
32
+ if (chunk.length) {
33
+ result.push(chunk);
34
+ }
35
+
36
+ return result as Tuple<T, N>[];
37
+ }
38
+
39
+ export function getTransform(transform: {
40
+ translation?: number[],
41
+ rotation?: number[],
42
+ scale?: number[]
43
+ }, order: TransformOrder, out?: Tuple<number, 16>) {
44
+ out ??= Array.from(mat4.idt) as Tuple<number, 16>;
45
+
46
+ mat4.compose({
47
+
48
+ translation: transform.translation && vec3.fromArray(transform.translation),
49
+
50
+ rotation: transform.rotation && quat.fromArray(transform.rotation),
51
+
52
+ scale: transform.scale && vec3.fromArray(transform.scale),
53
+
54
+ order,
55
+
56
+ }, out as Matrix4);
57
+
58
+ return out;
59
+ }
package/tsconfig.json CHANGED
@@ -1,36 +1,35 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2023",
4
- "module": "ES2022",
5
- "lib": [
6
- "ES2023",
7
- "DOM",
8
- "DOM.Iterable"
9
- ],
10
- "useDefineForClassFields": true,
11
- "skipLibCheck": true,
12
- /* Bundler mode */
13
- "moduleResolution": "bundler",
14
- "allowImportingTsExtensions": true,
15
- "resolveJsonModule": true,
16
- "isolatedModules": false,
17
- "noEmit": true,
18
- "noImplicitAny": false,
19
- /* Linting */
20
- "strict": true,
21
- "noUnusedLocals": false,
22
- "noUnusedParameters": false,
23
- "noFallthroughCasesInSwitch": true,
24
- "declaration": true,
25
- "accessor-pairs": [
26
- "error",
27
- {
28
- "setWithoutGet": true,
29
- "getWithoutSet": true
30
- }
31
- ]
32
- },
33
- "include": [
34
- "src"
35
- ]
36
- }
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "useDefineForClassFields": true,
5
+ "module": "ESNext",
6
+ "lib": [
7
+ "ESNext",
8
+ "DOM"
9
+ ],
10
+ "skipLibCheck": true,
11
+ /* Bundler mode */
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "resolveJsonModule": true,
15
+ "isolatedModules": true,
16
+ "noEmit": true,
17
+ "noImplicitAny": false,
18
+ /* Linting */
19
+ "strict": true,
20
+ "noUnusedLocals": false,
21
+ "noUnusedParameters": false,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "declaration": true,
24
+ "accessor-pairs": [
25
+ "error",
26
+ {
27
+ "setWithoutGet": true,
28
+ "getWithoutSet": true
29
+ }
30
+ ]
31
+ },
32
+ "include": [
33
+ "src"
34
+ ]
35
+ }
package/.gitattributes DELETED
@@ -1,2 +0,0 @@
1
- # Auto detect text files and perform LF normalization
2
- * text=auto
package/gltf-importer.iml DELETED
@@ -1,9 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <module type="GENERAL_MODULE" version="4">
3
- <component name="NewModuleRootManager" inherit-compiler-output="true">
4
- <exclude-output />
5
- <content url="file://$MODULE_DIR$" />
6
- <orderEntry type="sourceFolder" forTests="false" />
7
- <orderEntry type="module" module-name="gltf-types" />
8
- </component>
9
- </module>
package/index.html DELETED
@@ -1,14 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <!-- Get rid of "http://localhost:5173/favicon.ico not found" -->
5
- <link rel="shortcut icon" href="#" />
6
-
7
- <meta charset="UTF-8"/>
8
- <script type="module" src="src/index.ts"></script>
9
- <title></title>
10
- </head>
11
- <body>
12
- <canvas></canvas>
13
- </body>
14
- </html>
package/res/suzanne.glb DELETED
Binary file