@loaders.gl/obj 4.0.0-beta.2 → 4.0.0-beta.3

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.
Files changed (56) hide show
  1. package/dist/dist.dev.js +759 -0
  2. package/dist/index.cjs +610 -0
  3. package/dist/{esm/index.js → index.js} +4 -4
  4. package/dist/index.js.map +1 -0
  5. package/dist/lib/get-obj-schema.js.map +1 -0
  6. package/dist/{es5/lib → lib}/obj-types.js.map +1 -1
  7. package/dist/lib/parse-mtl.js.map +1 -0
  8. package/dist/{esm/lib → lib}/parse-obj-meshes.js +1 -1
  9. package/dist/lib/parse-obj-meshes.js.map +1 -0
  10. package/dist/{esm/lib → lib}/parse-obj.js +2 -2
  11. package/dist/lib/parse-obj.js.map +1 -0
  12. package/dist/{esm/mtl-loader.js → mtl-loader.js} +1 -1
  13. package/dist/mtl-loader.js.map +1 -0
  14. package/dist/{esm/obj-loader.js → obj-loader.js} +1 -1
  15. package/dist/obj-loader.js.map +1 -0
  16. package/dist/obj-worker.js +20 -4
  17. package/dist/{esm/workers → workers}/obj-worker.js +1 -1
  18. package/dist/workers/obj-worker.js.map +1 -0
  19. package/package.json +16 -8
  20. package/dist/bundle.d.ts +0 -2
  21. package/dist/bundle.d.ts.map +0 -1
  22. package/dist/dist.min.js +0 -740
  23. package/dist/es5/bundle.js +0 -6
  24. package/dist/es5/bundle.js.map +0 -1
  25. package/dist/es5/index.js +0 -69
  26. package/dist/es5/index.js.map +0 -1
  27. package/dist/es5/lib/get-obj-schema.js +0 -54
  28. package/dist/es5/lib/get-obj-schema.js.map +0 -1
  29. package/dist/es5/lib/obj-types.js +0 -2
  30. package/dist/es5/lib/parse-mtl.js +0 -86
  31. package/dist/es5/lib/parse-mtl.js.map +0 -1
  32. package/dist/es5/lib/parse-obj-meshes.js +0 -486
  33. package/dist/es5/lib/parse-obj-meshes.js.map +0 -1
  34. package/dist/es5/lib/parse-obj.js +0 -100
  35. package/dist/es5/lib/parse-obj.js.map +0 -1
  36. package/dist/es5/mtl-loader.js +0 -24
  37. package/dist/es5/mtl-loader.js.map +0 -1
  38. package/dist/es5/obj-loader.js +0 -25
  39. package/dist/es5/obj-loader.js.map +0 -1
  40. package/dist/es5/workers/obj-worker.js +0 -6
  41. package/dist/es5/workers/obj-worker.js.map +0 -1
  42. package/dist/esm/bundle.js +0 -4
  43. package/dist/esm/bundle.js.map +0 -1
  44. package/dist/esm/index.js.map +0 -1
  45. package/dist/esm/lib/get-obj-schema.js.map +0 -1
  46. package/dist/esm/lib/obj-types.js.map +0 -1
  47. package/dist/esm/lib/parse-mtl.js.map +0 -1
  48. package/dist/esm/lib/parse-obj-meshes.js.map +0 -1
  49. package/dist/esm/lib/parse-obj.js.map +0 -1
  50. package/dist/esm/mtl-loader.js.map +0 -1
  51. package/dist/esm/obj-loader.js.map +0 -1
  52. package/dist/esm/workers/obj-worker.js.map +0 -1
  53. package/src/bundle.ts +0 -4
  54. /package/dist/{esm/lib → lib}/get-obj-schema.js +0 -0
  55. /package/dist/{esm/lib → lib}/obj-types.js +0 -0
  56. /package/dist/{esm/lib → lib}/parse-mtl.js +0 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,610 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ MTLLoader: () => MTLLoader2,
24
+ OBJLoader: () => OBJLoader2,
25
+ OBJWorkerLoader: () => OBJLoader
26
+ });
27
+ module.exports = __toCommonJS(src_exports);
28
+
29
+ // src/lib/parse-obj.ts
30
+ var import_schema2 = require("@loaders.gl/schema");
31
+
32
+ // src/lib/parse-obj-meshes.ts
33
+ var OBJECT_RE = /^[og]\s*(.+)?/;
34
+ var MATERIAL_RE = /^mtllib /;
35
+ var MATERIAL_USE_RE = /^usemtl /;
36
+ var MeshMaterial = class {
37
+ constructor({ index, name = "", mtllib, smooth, groupStart }) {
38
+ this.index = index;
39
+ this.name = name;
40
+ this.mtllib = mtllib;
41
+ this.smooth = smooth;
42
+ this.groupStart = groupStart;
43
+ this.groupEnd = -1;
44
+ this.groupCount = -1;
45
+ this.inherited = false;
46
+ }
47
+ clone(index = this.index) {
48
+ return new MeshMaterial({
49
+ index,
50
+ name: this.name,
51
+ mtllib: this.mtllib,
52
+ smooth: this.smooth,
53
+ groupStart: 0
54
+ });
55
+ }
56
+ };
57
+ var MeshObject = class {
58
+ constructor(name = "") {
59
+ this.name = name;
60
+ this.geometry = {
61
+ vertices: [],
62
+ normals: [],
63
+ colors: [],
64
+ uvs: []
65
+ };
66
+ this.materials = [];
67
+ this.smooth = true;
68
+ this.fromDeclaration = null;
69
+ }
70
+ startMaterial(name, libraries) {
71
+ const previous = this._finalize(false);
72
+ if (previous && (previous.inherited || previous.groupCount <= 0)) {
73
+ this.materials.splice(previous.index, 1);
74
+ }
75
+ const material = new MeshMaterial({
76
+ index: this.materials.length,
77
+ name,
78
+ mtllib: Array.isArray(libraries) && libraries.length > 0 ? libraries[libraries.length - 1] : "",
79
+ smooth: previous !== void 0 ? previous.smooth : this.smooth,
80
+ groupStart: previous !== void 0 ? previous.groupEnd : 0
81
+ });
82
+ this.materials.push(material);
83
+ return material;
84
+ }
85
+ currentMaterial() {
86
+ if (this.materials.length > 0) {
87
+ return this.materials[this.materials.length - 1];
88
+ }
89
+ return void 0;
90
+ }
91
+ _finalize(end) {
92
+ const lastMultiMaterial = this.currentMaterial();
93
+ if (lastMultiMaterial && lastMultiMaterial.groupEnd === -1) {
94
+ lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
95
+ lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
96
+ lastMultiMaterial.inherited = false;
97
+ }
98
+ if (end && this.materials.length > 1) {
99
+ for (let mi = this.materials.length - 1; mi >= 0; mi--) {
100
+ if (this.materials[mi].groupCount <= 0) {
101
+ this.materials.splice(mi, 1);
102
+ }
103
+ }
104
+ }
105
+ if (end && this.materials.length === 0) {
106
+ this.materials.push({
107
+ name: "",
108
+ smooth: this.smooth
109
+ });
110
+ }
111
+ return lastMultiMaterial;
112
+ }
113
+ };
114
+ var ParserState = class {
115
+ constructor() {
116
+ this.objects = [];
117
+ this.object = null;
118
+ this.vertices = [];
119
+ this.normals = [];
120
+ this.colors = [];
121
+ this.uvs = [];
122
+ this.materialLibraries = [];
123
+ this.startObject("", false);
124
+ }
125
+ startObject(name, fromDeclaration = true) {
126
+ if (this.object && !this.object.fromDeclaration) {
127
+ this.object.name = name;
128
+ this.object.fromDeclaration = fromDeclaration;
129
+ return;
130
+ }
131
+ const previousMaterial = this.object && typeof this.object.currentMaterial === "function" ? this.object.currentMaterial() : void 0;
132
+ if (this.object && typeof this.object._finalize === "function") {
133
+ this.object._finalize(true);
134
+ }
135
+ this.object = new MeshObject(name);
136
+ this.object.fromDeclaration = fromDeclaration;
137
+ if (previousMaterial && previousMaterial.name && typeof previousMaterial.clone === "function") {
138
+ const declared = previousMaterial.clone(0);
139
+ declared.inherited = true;
140
+ this.object.materials.push(declared);
141
+ }
142
+ this.objects.push(this.object);
143
+ }
144
+ finalize() {
145
+ if (this.object && typeof this.object._finalize === "function") {
146
+ this.object._finalize(true);
147
+ }
148
+ }
149
+ parseVertexIndex(value, len) {
150
+ const index = parseInt(value);
151
+ return (index >= 0 ? index - 1 : index + len / 3) * 3;
152
+ }
153
+ parseNormalIndex(value, len) {
154
+ const index = parseInt(value);
155
+ return (index >= 0 ? index - 1 : index + len / 3) * 3;
156
+ }
157
+ parseUVIndex(value, len) {
158
+ const index = parseInt(value);
159
+ return (index >= 0 ? index - 1 : index + len / 2) * 2;
160
+ }
161
+ addVertex(a, b, c) {
162
+ const src = this.vertices;
163
+ const dst = this.object.geometry.vertices;
164
+ dst.push(src[a + 0], src[a + 1], src[a + 2]);
165
+ dst.push(src[b + 0], src[b + 1], src[b + 2]);
166
+ dst.push(src[c + 0], src[c + 1], src[c + 2]);
167
+ }
168
+ addVertexPoint(a) {
169
+ const src = this.vertices;
170
+ const dst = this.object.geometry.vertices;
171
+ dst.push(src[a + 0], src[a + 1], src[a + 2]);
172
+ }
173
+ addVertexLine(a) {
174
+ const src = this.vertices;
175
+ const dst = this.object.geometry.vertices;
176
+ dst.push(src[a + 0], src[a + 1], src[a + 2]);
177
+ }
178
+ addNormal(a, b, c) {
179
+ const src = this.normals;
180
+ const dst = this.object.geometry.normals;
181
+ dst.push(src[a + 0], src[a + 1], src[a + 2]);
182
+ dst.push(src[b + 0], src[b + 1], src[b + 2]);
183
+ dst.push(src[c + 0], src[c + 1], src[c + 2]);
184
+ }
185
+ addColor(a, b, c) {
186
+ const src = this.colors;
187
+ const dst = this.object.geometry.colors;
188
+ dst.push(src[a + 0], src[a + 1], src[a + 2]);
189
+ dst.push(src[b + 0], src[b + 1], src[b + 2]);
190
+ dst.push(src[c + 0], src[c + 1], src[c + 2]);
191
+ }
192
+ addUV(a, b, c) {
193
+ const src = this.uvs;
194
+ const dst = this.object.geometry.uvs;
195
+ dst.push(src[a + 0], src[a + 1]);
196
+ dst.push(src[b + 0], src[b + 1]);
197
+ dst.push(src[c + 0], src[c + 1]);
198
+ }
199
+ addUVLine(a) {
200
+ const src = this.uvs;
201
+ const dst = this.object.geometry.uvs;
202
+ dst.push(src[a + 0], src[a + 1]);
203
+ }
204
+ // eslint-disable-next-line max-params
205
+ addFace(a, b, c, ua, ub, uc, na, nb, nc) {
206
+ const vLen = this.vertices.length;
207
+ let ia = this.parseVertexIndex(a, vLen);
208
+ let ib = this.parseVertexIndex(b, vLen);
209
+ let ic = this.parseVertexIndex(c, vLen);
210
+ this.addVertex(ia, ib, ic);
211
+ if (ua !== void 0 && ua !== "") {
212
+ const uvLen = this.uvs.length;
213
+ ia = this.parseUVIndex(ua, uvLen);
214
+ ib = this.parseUVIndex(ub, uvLen);
215
+ ic = this.parseUVIndex(uc, uvLen);
216
+ this.addUV(ia, ib, ic);
217
+ }
218
+ if (na !== void 0 && na !== "") {
219
+ const nLen = this.normals.length;
220
+ ia = this.parseNormalIndex(na, nLen);
221
+ ib = na === nb ? ia : this.parseNormalIndex(nb, nLen);
222
+ ic = na === nc ? ia : this.parseNormalIndex(nc, nLen);
223
+ this.addNormal(ia, ib, ic);
224
+ }
225
+ if (this.colors.length > 0) {
226
+ this.addColor(ia, ib, ic);
227
+ }
228
+ }
229
+ addPointGeometry(vertices) {
230
+ this.object.geometry.type = "Points";
231
+ const vLen = this.vertices.length;
232
+ for (const vertex of vertices) {
233
+ this.addVertexPoint(this.parseVertexIndex(vertex, vLen));
234
+ }
235
+ }
236
+ addLineGeometry(vertices, uvs) {
237
+ this.object.geometry.type = "Line";
238
+ const vLen = this.vertices.length;
239
+ const uvLen = this.uvs.length;
240
+ for (const vertex of vertices) {
241
+ this.addVertexLine(this.parseVertexIndex(vertex, vLen));
242
+ }
243
+ for (const uv of uvs) {
244
+ this.addUVLine(this.parseUVIndex(uv, uvLen));
245
+ }
246
+ }
247
+ };
248
+ function parseOBJMeshes(text) {
249
+ const state = new ParserState();
250
+ if (text.indexOf("\r\n") !== -1) {
251
+ text = text.replace(/\r\n/g, "\n");
252
+ }
253
+ if (text.indexOf("\\\n") !== -1) {
254
+ text = text.replace(/\\\n/g, "");
255
+ }
256
+ const lines = text.split("\n");
257
+ let line = "";
258
+ let lineFirstChar = "";
259
+ let lineLength = 0;
260
+ let result = [];
261
+ const trimLeft = typeof "".trimLeft === "function";
262
+ for (let i = 0, l = lines.length; i < l; i++) {
263
+ line = lines[i];
264
+ line = trimLeft ? line.trimLeft() : line.trim();
265
+ lineLength = line.length;
266
+ if (lineLength === 0)
267
+ continue;
268
+ lineFirstChar = line.charAt(0);
269
+ if (lineFirstChar === "#")
270
+ continue;
271
+ if (lineFirstChar === "v") {
272
+ const data = line.split(/\s+/);
273
+ switch (data[0]) {
274
+ case "v":
275
+ state.vertices.push(parseFloat(data[1]), parseFloat(data[2]), parseFloat(data[3]));
276
+ if (data.length >= 7) {
277
+ state.colors.push(parseFloat(data[4]), parseFloat(data[5]), parseFloat(data[6]));
278
+ }
279
+ break;
280
+ case "vn":
281
+ state.normals.push(parseFloat(data[1]), parseFloat(data[2]), parseFloat(data[3]));
282
+ break;
283
+ case "vt":
284
+ state.uvs.push(parseFloat(data[1]), parseFloat(data[2]));
285
+ break;
286
+ default:
287
+ }
288
+ } else if (lineFirstChar === "f") {
289
+ const lineData = line.substr(1).trim();
290
+ const vertexData = lineData.split(/\s+/);
291
+ const faceVertices = [];
292
+ for (let j = 0, jl = vertexData.length; j < jl; j++) {
293
+ const vertex = vertexData[j];
294
+ if (vertex.length > 0) {
295
+ const vertexParts = vertex.split("/");
296
+ faceVertices.push(vertexParts);
297
+ }
298
+ }
299
+ const v1 = faceVertices[0];
300
+ for (let j = 1, jl = faceVertices.length - 1; j < jl; j++) {
301
+ const v2 = faceVertices[j];
302
+ const v3 = faceVertices[j + 1];
303
+ state.addFace(v1[0], v2[0], v3[0], v1[1], v2[1], v3[1], v1[2], v2[2], v3[2]);
304
+ }
305
+ } else if (lineFirstChar === "l") {
306
+ const lineParts = line.substring(1).trim().split(" ");
307
+ let lineVertices;
308
+ const lineUVs = [];
309
+ if (line.indexOf("/") === -1) {
310
+ lineVertices = lineParts;
311
+ } else {
312
+ lineVertices = [];
313
+ for (let li = 0, llen = lineParts.length; li < llen; li++) {
314
+ const parts = lineParts[li].split("/");
315
+ if (parts[0] !== "")
316
+ lineVertices.push(parts[0]);
317
+ if (parts[1] !== "")
318
+ lineUVs.push(parts[1]);
319
+ }
320
+ }
321
+ state.addLineGeometry(lineVertices, lineUVs);
322
+ } else if (lineFirstChar === "p") {
323
+ const lineData = line.substr(1).trim();
324
+ const pointData = lineData.split(" ");
325
+ state.addPointGeometry(pointData);
326
+ } else if ((result = OBJECT_RE.exec(line)) !== null) {
327
+ const name = (" " + result[0].substr(1).trim()).substr(1);
328
+ state.startObject(name);
329
+ } else if (MATERIAL_USE_RE.test(line)) {
330
+ state.object.startMaterial(line.substring(7).trim(), state.materialLibraries);
331
+ } else if (MATERIAL_RE.test(line)) {
332
+ state.materialLibraries.push(line.substring(7).trim());
333
+ } else if (lineFirstChar === "s") {
334
+ result = line.split(" ");
335
+ if (result.length > 1) {
336
+ const value = result[1].trim().toLowerCase();
337
+ state.object.smooth = value !== "0" && value !== "off";
338
+ } else {
339
+ state.object.smooth = true;
340
+ }
341
+ const material = state.object.currentMaterial();
342
+ if (material)
343
+ material.smooth = state.object.smooth;
344
+ } else {
345
+ if (line === "\0")
346
+ continue;
347
+ throw new Error(`Unexpected line: "${line}"`);
348
+ }
349
+ }
350
+ state.finalize();
351
+ const meshes = [];
352
+ const materials = [];
353
+ for (const object of state.objects) {
354
+ const { geometry } = object;
355
+ if (geometry.vertices.length === 0)
356
+ continue;
357
+ const mesh = {
358
+ header: {
359
+ vertexCount: geometry.vertices.length / 3
360
+ },
361
+ attributes: {}
362
+ };
363
+ switch (geometry.type) {
364
+ case "Points":
365
+ mesh.mode = 0;
366
+ break;
367
+ case "Line":
368
+ mesh.mode = 1;
369
+ break;
370
+ default:
371
+ mesh.mode = 4;
372
+ break;
373
+ }
374
+ mesh.attributes.POSITION = { value: new Float32Array(geometry.vertices), size: 3 };
375
+ if (geometry.normals.length > 0) {
376
+ mesh.attributes.NORMAL = { value: new Float32Array(geometry.normals), size: 3 };
377
+ }
378
+ if (geometry.colors.length > 0) {
379
+ mesh.attributes.COLOR_0 = { value: new Float32Array(geometry.colors), size: 3 };
380
+ }
381
+ if (geometry.uvs.length > 0) {
382
+ mesh.attributes.TEXCOORD_0 = { value: new Float32Array(geometry.uvs), size: 2 };
383
+ }
384
+ mesh.materials = [];
385
+ for (const sourceMaterial of object.materials) {
386
+ const _material = {
387
+ name: sourceMaterial.name,
388
+ flatShading: !sourceMaterial.smooth
389
+ };
390
+ mesh.materials.push(_material);
391
+ materials.push(_material);
392
+ }
393
+ mesh.name = object.name;
394
+ meshes.push(mesh);
395
+ }
396
+ return { meshes, materials };
397
+ }
398
+
399
+ // src/lib/get-obj-schema.ts
400
+ var import_schema = require("@loaders.gl/schema");
401
+ function getOBJSchema(attributes, metadata = {}) {
402
+ const stringMetadata = {};
403
+ for (const key in metadata) {
404
+ if (key !== "value") {
405
+ stringMetadata[key] = JSON.stringify(metadata[key]);
406
+ }
407
+ }
408
+ const fields = [];
409
+ for (const attributeName in attributes) {
410
+ const attribute = attributes[attributeName];
411
+ const field = getFieldFromAttribute(attributeName, attribute);
412
+ fields.push(field);
413
+ }
414
+ return { fields, metadata: stringMetadata };
415
+ }
416
+ function getFieldFromAttribute(name, attribute) {
417
+ const metadata = {};
418
+ for (const key in attribute) {
419
+ if (key !== "value") {
420
+ metadata[key] = JSON.stringify(attribute[key]);
421
+ }
422
+ }
423
+ let { type } = (0, import_schema.getDataTypeFromArray)(attribute.value);
424
+ const isSingleValue = attribute.size === 1 || attribute.size === void 0;
425
+ if (!isSingleValue) {
426
+ type = { type: "fixed-size-list", listSize: attribute.size, children: [{ name: "values", type }] };
427
+ }
428
+ return { name, type, nullable: false, metadata };
429
+ }
430
+
431
+ // src/lib/parse-obj.ts
432
+ function parseOBJ(text, options) {
433
+ const { meshes } = parseOBJMeshes(text);
434
+ const vertexCount = meshes.reduce((s, mesh) => s + mesh.header.vertexCount, 0);
435
+ const attributes = mergeAttributes(meshes, vertexCount);
436
+ const header = {
437
+ vertexCount,
438
+ // @ts-ignore Need to export Attributes type
439
+ boundingBox: (0, import_schema2.getMeshBoundingBox)(attributes)
440
+ };
441
+ const schema = getOBJSchema(attributes, {
442
+ mode: 4,
443
+ boundingBox: header.boundingBox
444
+ });
445
+ return {
446
+ // Data return by this loader implementation
447
+ loaderData: {
448
+ header: {}
449
+ },
450
+ // Normalised data
451
+ schema,
452
+ header,
453
+ mode: 4,
454
+ // TRIANGLES
455
+ topology: "point-list",
456
+ attributes
457
+ };
458
+ }
459
+ function mergeAttributes(meshes, vertexCount) {
460
+ const positions = new Float32Array(vertexCount * 3);
461
+ let normals;
462
+ let colors;
463
+ let uvs;
464
+ let i = 0;
465
+ for (const mesh of meshes) {
466
+ const { POSITION, NORMAL, COLOR_0, TEXCOORD_0 } = mesh.attributes;
467
+ positions.set(POSITION.value, i * 3);
468
+ if (NORMAL) {
469
+ normals = normals || new Float32Array(vertexCount * 3);
470
+ normals.set(NORMAL.value, i * 3);
471
+ }
472
+ if (COLOR_0) {
473
+ colors = colors || new Float32Array(vertexCount * 3);
474
+ colors.set(COLOR_0.value, i * 3);
475
+ }
476
+ if (TEXCOORD_0) {
477
+ uvs = uvs || new Float32Array(vertexCount * 2);
478
+ uvs.set(TEXCOORD_0.value, i * 2);
479
+ }
480
+ i += POSITION.value.length / 3;
481
+ }
482
+ const attributes = {};
483
+ attributes.POSITION = { value: positions, size: 3 };
484
+ if (normals) {
485
+ attributes.NORMAL = { value: normals, size: 3 };
486
+ }
487
+ if (colors) {
488
+ attributes.COLOR_0 = { value: colors, size: 3 };
489
+ }
490
+ if (uvs) {
491
+ attributes.TEXCOORD_0 = { value: uvs, size: 2 };
492
+ }
493
+ return attributes;
494
+ }
495
+
496
+ // src/obj-loader.ts
497
+ var VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest";
498
+ var OBJLoader = {
499
+ name: "OBJ",
500
+ id: "obj",
501
+ module: "obj",
502
+ version: VERSION,
503
+ worker: true,
504
+ extensions: ["obj"],
505
+ mimeTypes: ["text/plain"],
506
+ testText: testOBJFile,
507
+ options: {
508
+ obj: {}
509
+ }
510
+ };
511
+ function testOBJFile(text) {
512
+ return text[0] === "v";
513
+ }
514
+
515
+ // src/lib/parse-mtl.ts
516
+ var DELIMITER_PATTERN = /\s+/;
517
+ function parseMTL(text, options) {
518
+ const materials = [];
519
+ let currentMaterial = { name: "placeholder" };
520
+ const lines = text.split("\n");
521
+ for (let line of lines) {
522
+ line = line.trim();
523
+ if (line.length === 0 || line.charAt(0) === "#") {
524
+ continue;
525
+ }
526
+ const pos = line.indexOf(" ");
527
+ let key = pos >= 0 ? line.substring(0, pos) : line;
528
+ key = key.toLowerCase();
529
+ let value = pos >= 0 ? line.substring(pos + 1) : "";
530
+ value = value.trim();
531
+ switch (key) {
532
+ case "newmtl":
533
+ currentMaterial = { name: value };
534
+ materials.push(currentMaterial);
535
+ break;
536
+ case "ka":
537
+ currentMaterial.ambientColor = parseColor(value);
538
+ break;
539
+ case "kd":
540
+ currentMaterial.diffuseColor = parseColor(value);
541
+ break;
542
+ case "map_kd":
543
+ currentMaterial.diffuseTextureUrl = value;
544
+ break;
545
+ case "ks":
546
+ currentMaterial.specularColor = parseColor(value);
547
+ break;
548
+ case "map_ks":
549
+ currentMaterial.specularTextureUrl = value;
550
+ break;
551
+ case "ke":
552
+ currentMaterial.emissiveColor = parseColor(value);
553
+ break;
554
+ case "map_ke":
555
+ currentMaterial.emissiveTextureUrl = value;
556
+ break;
557
+ case "ns":
558
+ currentMaterial.shininess = parseFloat(value);
559
+ break;
560
+ case "map_ns":
561
+ break;
562
+ case "ni":
563
+ currentMaterial.refraction = parseFloat(value);
564
+ break;
565
+ case "illum":
566
+ currentMaterial.illumination = parseFloat(value);
567
+ break;
568
+ default:
569
+ break;
570
+ }
571
+ }
572
+ return materials;
573
+ }
574
+ function parseColor(value, options) {
575
+ const rgb = value.split(DELIMITER_PATTERN, 3);
576
+ const color = [
577
+ parseFloat(rgb[0]),
578
+ parseFloat(rgb[1]),
579
+ parseFloat(rgb[2])
580
+ ];
581
+ return color;
582
+ }
583
+
584
+ // src/mtl-loader.ts
585
+ var VERSION2 = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest";
586
+ var MTLLoader = {
587
+ name: "MTL",
588
+ id: "mtl",
589
+ module: "mtl",
590
+ version: VERSION2,
591
+ worker: true,
592
+ extensions: ["mtl"],
593
+ mimeTypes: ["text/plain"],
594
+ testText: (text) => text.includes("newmtl"),
595
+ options: {
596
+ mtl: {}
597
+ }
598
+ };
599
+
600
+ // src/index.ts
601
+ var OBJLoader2 = {
602
+ ...OBJLoader,
603
+ parse: async (arrayBuffer, options) => parseOBJ(new TextDecoder().decode(arrayBuffer), options),
604
+ parseTextSync: (text, options) => parseOBJ(text, options)
605
+ };
606
+ var MTLLoader2 = {
607
+ ...MTLLoader,
608
+ parse: async (arrayBuffer, options) => parseMTL(new TextDecoder().decode(arrayBuffer), options == null ? void 0 : options.mtl),
609
+ parseTextSync: (text, options) => parseMTL(text, options == null ? void 0 : options.mtl)
610
+ };
@@ -1,7 +1,7 @@
1
- import { parseOBJ } from './lib/parse-obj';
2
- import { OBJLoader as OBJWorkerLoader } from './obj-loader';
3
- import { parseMTL } from './lib/parse-mtl';
4
- import { MTLLoader as MTLWorkerLoader } from './mtl-loader';
1
+ import { parseOBJ } from "./lib/parse-obj.js";
2
+ import { OBJLoader as OBJWorkerLoader } from "./obj-loader.js";
3
+ import { parseMTL } from "./lib/parse-mtl.js";
4
+ import { MTLLoader as MTLWorkerLoader } from "./mtl-loader.js";
5
5
  export { OBJWorkerLoader };
6
6
  export const OBJLoader = {
7
7
  ...OBJWorkerLoader,
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["parseOBJ","OBJLoader","OBJWorkerLoader","parseMTL","MTLLoader","MTLWorkerLoader","parse","arrayBuffer","options","TextDecoder","decode","parseTextSync","text","mtl"],"sources":["../src/index.ts"],"sourcesContent":["import type {LoaderWithParser} from '@loaders.gl/loader-utils';\nimport type {Mesh} from '@loaders.gl/schema';\nimport {parseOBJ} from './lib/parse-obj';\nimport type {OBJLoaderOptions} from './obj-loader';\nimport {OBJLoader as OBJWorkerLoader} from './obj-loader';\n\nimport type {MTLMaterial} from './lib/parse-mtl';\nimport {parseMTL} from './lib/parse-mtl';\nimport type {MTLLoaderOptions} from './mtl-loader';\nimport {MTLLoader as MTLWorkerLoader} from './mtl-loader';\n\n// OBJLoader\n\nexport {OBJWorkerLoader};\n\n/**\n * Loader for the OBJ geometry format\n */\nexport const OBJLoader: LoaderWithParser<Mesh, never, OBJLoaderOptions> = {\n ...OBJWorkerLoader,\n parse: async (arrayBuffer: ArrayBuffer, options?: OBJLoaderOptions) =>\n parseOBJ(new TextDecoder().decode(arrayBuffer), options),\n parseTextSync: (text: string, options?: OBJLoaderOptions) => parseOBJ(text, options)\n};\n\n// MTLLoader\n\n/**\n * Loader for the MTL material format\n */\nexport const MTLLoader: LoaderWithParser<MTLMaterial[], never, MTLLoaderOptions> = {\n ...MTLWorkerLoader,\n parse: async (arrayBuffer: ArrayBuffer, options?: MTLLoaderOptions) =>\n parseMTL(new TextDecoder().decode(arrayBuffer), options?.mtl),\n parseTextSync: (text: string, options?: MTLLoaderOptions) => parseMTL(text, options?.mtl)\n};\n"],"mappings":"SAEQA,QAAQ;AAAA,SAERC,SAAS,IAAIC,eAAe;AAAA,SAG5BC,QAAQ;AAAA,SAERC,SAAS,IAAIC,eAAe;AAIpC,SAAQH,eAAe;AAKvB,OAAO,MAAMD,SAA0D,GAAG;EACxE,GAAGC,eAAe;EAClBI,KAAK,EAAE,MAAAA,CAAOC,WAAwB,EAAEC,OAA0B,KAChER,QAAQ,CAAC,IAAIS,WAAW,CAAC,CAAC,CAACC,MAAM,CAACH,WAAW,CAAC,EAAEC,OAAO,CAAC;EAC1DG,aAAa,EAAEA,CAACC,IAAY,EAAEJ,OAA0B,KAAKR,QAAQ,CAACY,IAAI,EAAEJ,OAAO;AACrF,CAAC;AAOD,OAAO,MAAMJ,SAAmE,GAAG;EACjF,GAAGC,eAAe;EAClBC,KAAK,EAAE,MAAAA,CAAOC,WAAwB,EAAEC,OAA0B,KAChEL,QAAQ,CAAC,IAAIM,WAAW,CAAC,CAAC,CAACC,MAAM,CAACH,WAAW,CAAC,EAAEC,OAAO,aAAPA,OAAO,uBAAPA,OAAO,CAAEK,GAAG,CAAC;EAC/DF,aAAa,EAAEA,CAACC,IAAY,EAAEJ,OAA0B,KAAKL,QAAQ,CAACS,IAAI,EAAEJ,OAAO,aAAPA,OAAO,uBAAPA,OAAO,CAAEK,GAAG;AAC1F,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-obj-schema.js","names":["getDataTypeFromArray","getOBJSchema","attributes","metadata","arguments","length","undefined","stringMetadata","key","JSON","stringify","fields","attributeName","attribute","field","getFieldFromAttribute","push","name","type","value","isSingleValue","size","listSize","children","nullable"],"sources":["../../src/lib/get-obj-schema.ts"],"sourcesContent":["// loaders.gl, MIT license\n\nimport type {Schema, SchemaMetadata, Field, MeshAttribute} from '@loaders.gl/schema';\nimport {getDataTypeFromArray} from '@loaders.gl/schema';\n\n/** Get Mesh Schema */\nexport function getOBJSchema(\n attributes: Record<string, MeshAttribute>,\n metadata: Record<string, unknown> = {}\n): Schema {\n const stringMetadata: SchemaMetadata = {};\n for (const key in metadata) {\n if (key !== 'value') {\n stringMetadata[key] = JSON.stringify(metadata[key]);\n }\n }\n\n const fields: Field[] = [];\n for (const attributeName in attributes) {\n const attribute = attributes[attributeName];\n const field = getFieldFromAttribute(attributeName, attribute);\n fields.push(field);\n }\n\n return {fields, metadata: stringMetadata};\n}\n\n/** Get a Field describing the column from an OBJ attribute */\nfunction getFieldFromAttribute(name: string, attribute: MeshAttribute): Field {\n const metadata: Record<string, string> = {};\n for (const key in attribute) {\n if (key !== 'value') {\n metadata[key] = JSON.stringify(attribute[key]);\n }\n }\n\n let {type} = getDataTypeFromArray(attribute.value);\n const isSingleValue = attribute.size === 1 || attribute.size === undefined;\n if (!isSingleValue) {\n type = {type: 'fixed-size-list', listSize: attribute.size, children: [{name: 'values', type}]};\n }\n return {name, type, nullable: false, metadata};\n}\n"],"mappings":"AAGA,SAAQA,oBAAoB,QAAO,oBAAoB;AAGvD,OAAO,SAASC,YAAYA,CAC1BC,UAAyC,EAEjC;EAAA,IADRC,QAAiC,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EAEtC,MAAMG,cAA8B,GAAG,CAAC,CAAC;EACzC,KAAK,MAAMC,GAAG,IAAIL,QAAQ,EAAE;IAC1B,IAAIK,GAAG,KAAK,OAAO,EAAE;MACnBD,cAAc,CAACC,GAAG,CAAC,GAAGC,IAAI,CAACC,SAAS,CAACP,QAAQ,CAACK,GAAG,CAAC,CAAC;IACrD;EACF;EAEA,MAAMG,MAAe,GAAG,EAAE;EAC1B,KAAK,MAAMC,aAAa,IAAIV,UAAU,EAAE;IACtC,MAAMW,SAAS,GAAGX,UAAU,CAACU,aAAa,CAAC;IAC3C,MAAME,KAAK,GAAGC,qBAAqB,CAACH,aAAa,EAAEC,SAAS,CAAC;IAC7DF,MAAM,CAACK,IAAI,CAACF,KAAK,CAAC;EACpB;EAEA,OAAO;IAACH,MAAM;IAAER,QAAQ,EAAEI;EAAc,CAAC;AAC3C;AAGA,SAASQ,qBAAqBA,CAACE,IAAY,EAAEJ,SAAwB,EAAS;EAC5E,MAAMV,QAAgC,GAAG,CAAC,CAAC;EAC3C,KAAK,MAAMK,GAAG,IAAIK,SAAS,EAAE;IAC3B,IAAIL,GAAG,KAAK,OAAO,EAAE;MACnBL,QAAQ,CAACK,GAAG,CAAC,GAAGC,IAAI,CAACC,SAAS,CAACG,SAAS,CAACL,GAAG,CAAC,CAAC;IAChD;EACF;EAEA,IAAI;IAACU;EAAI,CAAC,GAAGlB,oBAAoB,CAACa,SAAS,CAACM,KAAK,CAAC;EAClD,MAAMC,aAAa,GAAGP,SAAS,CAACQ,IAAI,KAAK,CAAC,IAAIR,SAAS,CAACQ,IAAI,KAAKf,SAAS;EAC1E,IAAI,CAACc,aAAa,EAAE;IAClBF,IAAI,GAAG;MAACA,IAAI,EAAE,iBAAiB;MAAEI,QAAQ,EAAET,SAAS,CAACQ,IAAI;MAAEE,QAAQ,EAAE,CAAC;QAACN,IAAI,EAAE,QAAQ;QAAEC;MAAI,CAAC;IAAC,CAAC;EAChG;EACA,OAAO;IAACD,IAAI;IAAEC,IAAI;IAAEM,QAAQ,EAAE,KAAK;IAAErB;EAAQ,CAAC;AAChD"}
@@ -1 +1 @@
1
- {"version":3,"file":"obj-types.js","names":[],"sources":["../../../src/lib/obj-types.ts"],"sourcesContent":[""],"mappings":""}
1
+ {"version":3,"file":"obj-types.js","names":[],"sources":["../../src/lib/obj-types.ts"],"sourcesContent":[""],"mappings":""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-mtl.js","names":["DELIMITER_PATTERN","parseMTL","text","options","materials","currentMaterial","name","lines","split","line","trim","length","charAt","pos","indexOf","key","substring","toLowerCase","value","push","ambientColor","parseColor","diffuseColor","diffuseTextureUrl","specularColor","specularTextureUrl","emissiveColor","emissiveTextureUrl","shininess","parseFloat","refraction","illumination","rgb","color"],"sources":["../../src/lib/parse-mtl.ts"],"sourcesContent":["// loaders.gl, MIT license\n// Forked from THREE.js under MIT license\n// https://github.com/mrdoob/three.js/blob/master/examples/jsm/loaders/MTLLoader.js\n\n// import type {DiffuseMaterial} from '@loaders.gl/schema';\n\nexport type MTLMaterial = {\n name: string;\n ambientColor?: [number, number, number];\n diffuseColor?: [number, number, number];\n specularColor?: [number, number, number];\n emissiveColor?: [number, number, number];\n // specular?: number;\n shininess?: number;\n refraction?: number;\n illumination?: number;\n diffuseTextureUrl?: string;\n emissiveTextureUrl?: string;\n specularTextureUrl?: string;\n};\n\nconst DELIMITER_PATTERN = /\\s+/;\n\n/**\n * Set of options on how to construct materials\n * @param normalizeRGB: RGBs need to be normalized to 0-1 from 0-255 (Default: false, assumed to be already normalized)\n * @param ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's Default: false\n * @param baseUrl - Url relative to which textures are loaded\n */\nexport type ParseMTLOptions = {\n normalizeRGB?: boolean;\n ignoreZeroRGBs?: boolean;\n baseUrl?: string;\n};\n\n/**\n * Parses a MTL file.\n * Parses a Wavefront .mtl file specifying materials\n * http://paulbourke.net/dataformats/mtl/\n * https://www.loc.gov/preservation/digital/formats/fdd/fdd000508.shtml\n *\n * @param text - Content of MTL file\n */\n// eslint-disable-next-line complexity\nexport function parseMTL(text: string, options?: ParseMTLOptions): MTLMaterial[] {\n // const materialsInfo: Record<string, MTLMaterial> = {};\n const materials: MTLMaterial[] = [];\n\n let currentMaterial: MTLMaterial = {name: 'placeholder'};\n\n const lines = text.split('\\n');\n for (let line of lines) {\n line = line.trim();\n\n if (line.length === 0 || line.charAt(0) === '#') {\n // Blank line or comment ignore\n continue; // eslint-disable-line no-continue\n }\n\n const pos = line.indexOf(' ');\n\n let key = pos >= 0 ? line.substring(0, pos) : line;\n key = key.toLowerCase();\n\n let value = pos >= 0 ? line.substring(pos + 1) : '';\n value = value.trim();\n\n switch (key) {\n case 'newmtl':\n // New material\n currentMaterial = {name: value};\n // insert into map\n materials.push(currentMaterial);\n break;\n\n case 'ka': // Ka\n currentMaterial.ambientColor = parseColor(value);\n break;\n\n case 'kd':\n // Kd: Diffuse color (color under white light) using RGB values\n currentMaterial.diffuseColor = parseColor(value);\n break;\n case 'map_kd':\n // Diffuse texture map\n currentMaterial.diffuseTextureUrl = value;\n // setMapForType('map', value);\n break;\n\n case 'ks':\n // Specular color (color when light is reflected from shiny surface) using RGB values\n currentMaterial.specularColor = parseColor(value);\n break;\n case 'map_ks':\n // Specular map\n currentMaterial.specularTextureUrl = value;\n // setMapForType('specularMap', value);\n break;\n\n case 'ke':\n // Emissive using RGB values\n currentMaterial.emissiveColor = parseColor(value);\n break;\n case 'map_ke':\n // Emissive map\n currentMaterial.emissiveTextureUrl = value;\n // setMapForType('emissiveMap', value);\n break;\n\n case 'ns':\n // Ns is material specular exponent (defines the focus of the specular highlight)\n // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.\n currentMaterial.shininess = parseFloat(value);\n break;\n case 'map_ns':\n // Ns is material specular exponent\n // TODO?\n // currentMaterial.shininessMap = parseFloat(value);\n break;\n case 'ni':\n currentMaterial.refraction = parseFloat(value);\n break;\n case 'illum':\n currentMaterial.illumination = parseFloat(value);\n break;\n\n default:\n // log unknown message?\n break;\n\n /*\n case 'norm':\n setMapForType('normalMap', value);\n break;\n\n case 'map_bump':\n case 'bump':\n // Bump texture map\n setMapForType('bumpMap', value);\n break;\n\n case 'd':\n n = parseFloat(value);\n if (n < 1) {\n params.opacity = n;\n params.transparent = true;\n }\n break;\n\n case 'map_d':\n // Alpha map\n setMapForType('alphaMap', value);\n params.transparent = true;\n break;\n\n case 'tr':\n n = parseFloat(value);\n if (this.options && this.options.invertTrProperty) n = 1 - n;\n if (n > 0) {\n params.opacity = 1 - n;\n params.transparent = true;\n }\n */\n }\n }\n\n return materials;\n}\n\nfunction parseColor(value: string, options?: ParseMTLOptions): [number, number, number] {\n const rgb = value.split(DELIMITER_PATTERN, 3);\n const color: [number, number, number] = [\n parseFloat(rgb[0]),\n parseFloat(rgb[1]),\n parseFloat(rgb[2])\n ];\n // TODO auto detect big values?\n // if (this.options && this.options.normalizeRGB) {\n // value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ];\n // }\n\n // if (this.options && this.options.ignoreZeroRGBs) {\n // if (value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 2 ] === 0) {\n // // ignore\n // save = false;\n // }\n // }\n return color;\n}\n\n/* TODO parse url options\nfunction parseTexture(value, matParams) {\n const texParams = {\n scale: new Vector2(1, 1),\n offset: new Vector2(0, 0)\n };\n\n const items = value.split(/\\s+/);\n let pos;\n\n pos = items.indexOf('-bm');\n if (pos >= 0) {\n matParams.bumpScale = parseFloat(items[ pos + 1 ]);\n items.splice(pos, 2);\n }\n\n pos = items.indexOf('-s');\n if (pos >= 0) {\n texParams.scale.set(parseFloat(items[ pos + 1 ]), parseFloat(items[ pos + 2 ]));\n items.splice(pos, 4); // we expect 3 parameters here!\n\n }\n\n pos = items.indexOf('-o');\n\n if (pos >= 0) {\n texParams.offset.set(parseFloat(items[ pos + 1 ]), parseFloat(items[ pos + 2 ]));\n items.splice(pos, 4); // we expect 3 parameters here!\n }\n\n texParams.url = items.join(' ').trim();\n return texParams;\n}\n\n *function resolveURL(baseUrl, url) {\n * baseUrl?: string;\n // Absolute URL\n if (/^https?:\\/\\//i.test(url)) return url;\n return baseUrl + url;\n }\n\n function setMapForType(mapType, value) {\n if (params[ mapType ]) return; // Keep the first encountered texture\n\n const texParams = scope.getTextureParams(value, params);\n const map = scope.loadTexture(resolveURL(scope.baseUrl, texParams.url));\n\n map.repeat.copy(texParams.scale);\n map.offset.copy(texParams.offset);\n\n map.wrapS = scope.wrap;\n map.wrapT = scope.wrap;\n\n params[ mapType ] = map;\n }\n*/\n"],"mappings":"AAqBA,MAAMA,iBAAiB,GAAG,KAAK;AAuB/B,OAAO,SAASC,QAAQA,CAACC,IAAY,EAAEC,OAAyB,EAAiB;EAE/E,MAAMC,SAAwB,GAAG,EAAE;EAEnC,IAAIC,eAA4B,GAAG;IAACC,IAAI,EAAE;EAAa,CAAC;EAExD,MAAMC,KAAK,GAAGL,IAAI,CAACM,KAAK,CAAC,IAAI,CAAC;EAC9B,KAAK,IAAIC,IAAI,IAAIF,KAAK,EAAE;IACtBE,IAAI,GAAGA,IAAI,CAACC,IAAI,CAAC,CAAC;IAElB,IAAID,IAAI,CAACE,MAAM,KAAK,CAAC,IAAIF,IAAI,CAACG,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;MAE/C;IACF;IAEA,MAAMC,GAAG,GAAGJ,IAAI,CAACK,OAAO,CAAC,GAAG,CAAC;IAE7B,IAAIC,GAAG,GAAGF,GAAG,IAAI,CAAC,GAAGJ,IAAI,CAACO,SAAS,CAAC,CAAC,EAAEH,GAAG,CAAC,GAAGJ,IAAI;IAClDM,GAAG,GAAGA,GAAG,CAACE,WAAW,CAAC,CAAC;IAEvB,IAAIC,KAAK,GAAGL,GAAG,IAAI,CAAC,GAAGJ,IAAI,CAACO,SAAS,CAACH,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE;IACnDK,KAAK,GAAGA,KAAK,CAACR,IAAI,CAAC,CAAC;IAEpB,QAAQK,GAAG;MACT,KAAK,QAAQ;QAEXV,eAAe,GAAG;UAACC,IAAI,EAAEY;QAAK,CAAC;QAE/Bd,SAAS,CAACe,IAAI,CAACd,eAAe,CAAC;QAC/B;MAEF,KAAK,IAAI;QACPA,eAAe,CAACe,YAAY,GAAGC,UAAU,CAACH,KAAK,CAAC;QAChD;MAEF,KAAK,IAAI;QAEPb,eAAe,CAACiB,YAAY,GAAGD,UAAU,CAACH,KAAK,CAAC;QAChD;MACF,KAAK,QAAQ;QAEXb,eAAe,CAACkB,iBAAiB,GAAGL,KAAK;QAEzC;MAEF,KAAK,IAAI;QAEPb,eAAe,CAACmB,aAAa,GAAGH,UAAU,CAACH,KAAK,CAAC;QACjD;MACF,KAAK,QAAQ;QAEXb,eAAe,CAACoB,kBAAkB,GAAGP,KAAK;QAE1C;MAEF,KAAK,IAAI;QAEPb,eAAe,CAACqB,aAAa,GAAGL,UAAU,CAACH,KAAK,CAAC;QACjD;MACF,KAAK,QAAQ;QAEXb,eAAe,CAACsB,kBAAkB,GAAGT,KAAK;QAE1C;MAEF,KAAK,IAAI;QAGPb,eAAe,CAACuB,SAAS,GAAGC,UAAU,CAACX,KAAK,CAAC;QAC7C;MACF,KAAK,QAAQ;QAIX;MACF,KAAK,IAAI;QACPb,eAAe,CAACyB,UAAU,GAAGD,UAAU,CAACX,KAAK,CAAC;QAC9C;MACF,KAAK,OAAO;QACVb,eAAe,CAAC0B,YAAY,GAAGF,UAAU,CAACX,KAAK,CAAC;QAChD;MAEF;QAEE;IAmCJ;EACF;EAEA,OAAOd,SAAS;AAClB;AAEA,SAASiB,UAAUA,CAACH,KAAa,EAAEf,OAAyB,EAA4B;EACtF,MAAM6B,GAAG,GAAGd,KAAK,CAACV,KAAK,CAACR,iBAAiB,EAAE,CAAC,CAAC;EAC7C,MAAMiC,KAA+B,GAAG,CACtCJ,UAAU,CAACG,GAAG,CAAC,CAAC,CAAC,CAAC,EAClBH,UAAU,CAACG,GAAG,CAAC,CAAC,CAAC,CAAC,EAClBH,UAAU,CAACG,GAAG,CAAC,CAAC,CAAC,CAAC,CACnB;EAYD,OAAOC,KAAK;AACd"}
@@ -315,7 +315,7 @@ export function parseOBJMeshes(text) {
315
315
  if (material) material.smooth = state.object.smooth;
316
316
  } else {
317
317
  if (line === '\0') continue;
318
- throw new Error("Unexpected line: \"".concat(line, "\""));
318
+ throw new Error(`Unexpected line: "${line}"`);
319
319
  }
320
320
  }
321
321
  state.finalize();