@threepipe/plugin-blend-importer 0.0.9 → 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/CHANGELOG.md +51 -2
- package/README.md +25 -1
- package/dist/BlendLoadPlugin.d.ts +63 -3
- package/dist/BlendLoadPlugin.d.ts.map +1 -1
- package/dist/decompress.d.ts +10 -0
- package/dist/decompress.d.ts.map +1 -0
- package/dist/dependencies.txt +31 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1351 -89
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1349 -87
- package/dist/index.mjs.map +1 -1
- package/dist/loader/camera.d.ts +1 -1
- package/dist/loader/ctx.d.ts +9 -1
- package/dist/loader/ctx.d.ts.map +1 -1
- package/dist/loader/geometry.d.ts +2 -2
- package/dist/loader/geometry.d.ts.map +1 -1
- package/dist/loader/index.d.ts +1 -1
- package/dist/loader/light.d.ts +1 -1
- package/dist/loader/material.d.ts +4 -1
- package/dist/loader/material.d.ts.map +1 -1
- package/dist/loader/mesh.d.ts +1 -1
- package/dist/loader/mesh.d.ts.map +1 -1
- package/docs/assets/highlight.css +49 -0
- package/docs/assets/icons.js +1 -1
- package/docs/assets/icons.svg +1 -1
- package/docs/assets/main.js +2 -2
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/assets/style.css +3 -3
- package/docs/classes/BlendLoadPlugin.html +6 -3
- package/docs/index.html +1 -1
- package/docs/interfaces/BlendFile.html +18 -0
- package/docs/interfaces/BlendLoadOptions.html +12 -0
- package/package.json +4 -3
- package/src/BlendLoadPlugin.ts +204 -13
- package/src/decompress.ts +59 -0
- package/src/index.ts +1 -0
- package/src/js-blend/main.js +4 -1
- package/src/js-blend/parser/parser.js +192 -52
- package/src/loader/ctx.ts +9 -0
- package/src/loader/geometry.ts +270 -13
- package/src/loader/material.ts +324 -8
- package/src/loader/mesh.ts +34 -8
- package/tsconfig.json +42 -0
- package/docs/.nojekyll +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @license
|
|
3
|
-
* @threepipe/plugin-blend-importer v0.0.9
|
|
4
|
-
* Copyright 2022-2025 repalash <palash@shaders.app>
|
|
5
|
-
* Apache-2.0 License
|
|
6
|
-
* See ./dependencies.txt for any bundled third-party dependencies and licenses.
|
|
7
|
-
*/
|
|
8
|
-
import { Quaternion, Euler, Vector3, BaseImporterPlugin, Importer, FileLoader, Object3D, Object3D2, PerspectiveCamera0, OrthographicCamera0, PointLight2, PhysicalMaterial, Mesh2, BufferGeometry2, BufferAttribute } from "threepipe";
|
|
1
|
+
import { FrontSide, DoubleSide, Texture, SRGBColorSpace, ClampToEdgeWrapping, MirroredRepeatWrapping, RepeatWrapping, Quaternion, Euler, Vector3, gunzipSync, BaseImporterPlugin, Importer, FileLoader, Object3D, Object3D2, Source, BufferAttribute, BufferGeometry2, AmbientLight2, SpotLight2, DirectionalLight2, PointLight2, OrthographicCamera0, PerspectiveCamera0, UnlitMaterial, PhysicalMaterial, Mesh2, DataTexture } from "threepipe";
|
|
9
2
|
let worker = null;
|
|
10
3
|
const return_object = {
|
|
11
4
|
loadBlendFromArrayBuffer: function(array_buffer) {
|
|
@@ -38,6 +31,7 @@ function worker_code() {
|
|
|
38
31
|
struct_names = [];
|
|
39
32
|
offset = 0;
|
|
40
33
|
current_SDNA_template = null;
|
|
34
|
+
ERROR = null;
|
|
41
35
|
_data = msg.data;
|
|
42
36
|
AB = _data.slice();
|
|
43
37
|
data = new DataView(_data);
|
|
@@ -72,13 +66,30 @@ function worker_code() {
|
|
|
72
66
|
} else {
|
|
73
67
|
return pointerLow;
|
|
74
68
|
}
|
|
69
|
+
},
|
|
70
|
+
// Alignment-safe TypedArray read over the file buffer. Consumers (e.g. loader/geometry.ts)
|
|
71
|
+
// that reach into `__blender_file__.AB` at a datablock's `__data_address__` MUST use this
|
|
72
|
+
// instead of `new Ctor(AB, byteOffset, n)` — Blender packs blocks with no padding, so on
|
|
73
|
+
// v1 (17-byte header) and some v0 files the payload lands at an offset that isn't a multiple
|
|
74
|
+
// of the element size, where a direct view throws RangeError. All supported files are
|
|
75
|
+
// little-endian (big-endian is rejected at header parse), so a raw byte copy is correct.
|
|
76
|
+
readTypedArray: function(Ctor, byteOffset, length) {
|
|
77
|
+
return alignedTypedArray(Ctor, this.AB, byteOffset, length);
|
|
75
78
|
}
|
|
76
79
|
};
|
|
77
80
|
self.onmessage = parseFile;
|
|
81
|
+
function alignedTypedArray(Ctor, buffer, byteOffset, length) {
|
|
82
|
+
if (byteOffset % Ctor.BYTES_PER_ELEMENT === 0) {
|
|
83
|
+
return new Ctor(buffer, byteOffset, length);
|
|
84
|
+
}
|
|
85
|
+
const out = new Ctor(length);
|
|
86
|
+
new Uint8Array(out.buffer).set(new Uint8Array(buffer, byteOffset, length * Ctor.BYTES_PER_ELEMENT));
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
78
89
|
function float64Prop(offset2, Blender_Array_Length, length) {
|
|
79
90
|
return {
|
|
80
91
|
get: function() {
|
|
81
|
-
return Blender_Array_Length > 1 ?
|
|
92
|
+
return Blender_Array_Length > 1 ? alignedTypedArray(Float64Array, this.__blender_file__.AB, this.__data_address__ + offset2, length) : this.__blender_file__.dv.getFloat64(this.__data_address__ + offset2, this.__blender_file__.template.endianess);
|
|
82
93
|
},
|
|
83
94
|
set: function(float) {
|
|
84
95
|
if (Blender_Array_Length > 1) ;
|
|
@@ -93,7 +104,7 @@ function worker_code() {
|
|
|
93
104
|
function floatProp(offset2, Blender_Array_Length, length) {
|
|
94
105
|
return {
|
|
95
106
|
get: function() {
|
|
96
|
-
return Blender_Array_Length > 1 ?
|
|
107
|
+
return Blender_Array_Length > 1 ? alignedTypedArray(Float32Array, this.__blender_file__.AB, this.__data_address__ + offset2, length) : this.__blender_file__.dv.getFloat32(this.__data_address__ + offset2, this.__blender_file__.template.endianess);
|
|
97
108
|
},
|
|
98
109
|
set: function(float) {
|
|
99
110
|
if (Blender_Array_Length > 1) ;
|
|
@@ -108,7 +119,7 @@ function worker_code() {
|
|
|
108
119
|
function intProp(offset2, Blender_Array_Length, length) {
|
|
109
120
|
return {
|
|
110
121
|
get: function() {
|
|
111
|
-
return Blender_Array_Length > 1 ?
|
|
122
|
+
return Blender_Array_Length > 1 ? alignedTypedArray(Int32Array, this.__blender_file__.AB, this.__data_address__ + offset2, length) : this.__blender_file__.dv.getInt32(this.__data_address__ + offset2, this.__blender_file__.template.endianess);
|
|
112
123
|
},
|
|
113
124
|
set: function(float) {
|
|
114
125
|
if (Blender_Array_Length > 1) ;
|
|
@@ -120,10 +131,25 @@ function worker_code() {
|
|
|
120
131
|
configurable: true
|
|
121
132
|
};
|
|
122
133
|
}
|
|
134
|
+
function uIntProp(offset2, Blender_Array_Length, length) {
|
|
135
|
+
return {
|
|
136
|
+
get: function() {
|
|
137
|
+
return Blender_Array_Length > 1 ? alignedTypedArray(Uint32Array, this.__blender_file__.AB, this.__data_address__ + offset2, length) : this.__blender_file__.dv.getUint32(this.__data_address__ + offset2, this.__blender_file__.template.endianess);
|
|
138
|
+
},
|
|
139
|
+
set: function(float) {
|
|
140
|
+
if (Blender_Array_Length > 1) ;
|
|
141
|
+
else {
|
|
142
|
+
this.__blender_file__.dv.setUint32(this.__data_address__ + offset2, float, this.__blender_file__.template.endianess);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
enumerable: true,
|
|
146
|
+
configurable: true
|
|
147
|
+
};
|
|
148
|
+
}
|
|
123
149
|
function shortProp(offset2, Blender_Array_Length, length) {
|
|
124
150
|
return {
|
|
125
151
|
get: function() {
|
|
126
|
-
return Blender_Array_Length > 1 ?
|
|
152
|
+
return Blender_Array_Length > 1 ? alignedTypedArray(Int16Array, this.__blender_file__.AB, this.__data_address__ + offset2, length) : this.__blender_file__.dv.getInt16(this.__data_address__ + offset2, this.__blender_file__.template.endianess);
|
|
127
153
|
},
|
|
128
154
|
set: function(float) {
|
|
129
155
|
if (Blender_Array_Length > 1) ;
|
|
@@ -138,7 +164,7 @@ function worker_code() {
|
|
|
138
164
|
const uShortProp = (offset2, Blender_Array_Length, length) => {
|
|
139
165
|
return {
|
|
140
166
|
get: function() {
|
|
141
|
-
return Blender_Array_Length > 1 ?
|
|
167
|
+
return Blender_Array_Length > 1 ? alignedTypedArray(Uint16Array, this.__blender_file__.AB, this.__data_address__ + offset2, length) : this.__blender_file__.dv.getUint16(this.__data_address__ + offset2, this.__blender_file__.template.endianess);
|
|
142
168
|
},
|
|
143
169
|
set: function(float) {
|
|
144
170
|
if (Blender_Array_Length > 1) ;
|
|
@@ -186,18 +212,28 @@ function worker_code() {
|
|
|
186
212
|
function pointerProp2(offset2) {
|
|
187
213
|
return {
|
|
188
214
|
get: function() {
|
|
189
|
-
|
|
190
|
-
|
|
215
|
+
const bf = this.__blender_file__;
|
|
216
|
+
let pointer = bf.getPointer(this.__data_address__ + offset2, bf);
|
|
217
|
+
const link = bf.memory_lookup[pointer];
|
|
191
218
|
const results = [];
|
|
192
219
|
if (link) {
|
|
193
220
|
const address = link.__data_address__;
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
let
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
221
|
+
const ps = bf.template && bf.template.pointer_size || 8;
|
|
222
|
+
const count = typeof link.__byte_length__ === "number" && link.__byte_length__ > 0 ? Math.floor(link.__byte_length__ / ps) : 0;
|
|
223
|
+
if (count > 0) {
|
|
224
|
+
for (let j = 0; j < count; j++) {
|
|
225
|
+
pointer = bf.getPointer(address + j * ps, bf);
|
|
226
|
+
results.push(bf.memory_lookup[pointer] || null);
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
let j = 0;
|
|
230
|
+
while (true) {
|
|
231
|
+
pointer = bf.getPointer(address + j * ps, bf);
|
|
232
|
+
const obj = bf.memory_lookup[pointer];
|
|
233
|
+
if (!obj) break;
|
|
234
|
+
results.push(obj);
|
|
235
|
+
j++;
|
|
236
|
+
}
|
|
201
237
|
}
|
|
202
238
|
}
|
|
203
239
|
return results;
|
|
@@ -233,6 +269,33 @@ function worker_code() {
|
|
|
233
269
|
configurable: true
|
|
234
270
|
};
|
|
235
271
|
}
|
|
272
|
+
function int8Prop(offset2, Blender_Array_Length, length) {
|
|
273
|
+
return {
|
|
274
|
+
get: function() {
|
|
275
|
+
return Blender_Array_Length > 1 ? alignedTypedArray(Int8Array, this.__blender_file__.AB, this.__data_address__ + offset2, length) : this.__blender_file__.dv.getInt8(this.__data_address__ + offset2);
|
|
276
|
+
},
|
|
277
|
+
set: function(v) {
|
|
278
|
+
if (Blender_Array_Length <= 1) this.__blender_file__.dv.setInt8(this.__data_address__ + offset2, v);
|
|
279
|
+
},
|
|
280
|
+
enumerable: true,
|
|
281
|
+
configurable: true
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function int64Prop(offset2, Blender_Array_Length, length, unsigned) {
|
|
285
|
+
return {
|
|
286
|
+
get: function() {
|
|
287
|
+
if (Blender_Array_Length > 1) {
|
|
288
|
+
return alignedTypedArray(unsigned ? BigUint64Array : BigInt64Array, this.__blender_file__.AB, this.__data_address__ + offset2, length);
|
|
289
|
+
}
|
|
290
|
+
const dv = this.__blender_file__.dv, le = this.__blender_file__.template.endianess;
|
|
291
|
+
return Number(unsigned ? dv.getBigUint64(this.__data_address__ + offset2, le) : dv.getBigInt64(this.__data_address__ + offset2, le));
|
|
292
|
+
},
|
|
293
|
+
set: function() {
|
|
294
|
+
},
|
|
295
|
+
enumerable: true,
|
|
296
|
+
configurable: true
|
|
297
|
+
};
|
|
298
|
+
}
|
|
236
299
|
function compileProp(obj, name, type, offset2, array_size, IS_POINTER, pointer_size2, length) {
|
|
237
300
|
if (!IS_POINTER) {
|
|
238
301
|
switch (type) {
|
|
@@ -243,18 +306,34 @@ function worker_code() {
|
|
|
243
306
|
Object.defineProperty(obj, name, floatProp(offset2, array_size, length >> 2));
|
|
244
307
|
break;
|
|
245
308
|
case "int":
|
|
309
|
+
case "int32_t":
|
|
246
310
|
Object.defineProperty(obj, name, intProp(offset2, array_size, length >> 2));
|
|
247
311
|
break;
|
|
312
|
+
case "uint32_t":
|
|
313
|
+
Object.defineProperty(obj, name, uIntProp(offset2, array_size, length >> 2));
|
|
314
|
+
break;
|
|
248
315
|
case "short":
|
|
316
|
+
case "int16_t":
|
|
249
317
|
Object.defineProperty(obj, name, shortProp(offset2, array_size, length >> 1));
|
|
250
318
|
break;
|
|
251
319
|
case "ushort":
|
|
320
|
+
case "uint16_t":
|
|
252
321
|
Object.defineProperty(obj, name, uShortProp(offset2, array_size, length >> 1));
|
|
253
322
|
break;
|
|
323
|
+
case "int8_t":
|
|
324
|
+
Object.defineProperty(obj, name, int8Prop(offset2, array_size, length));
|
|
325
|
+
break;
|
|
254
326
|
case "char":
|
|
255
327
|
case "uchar":
|
|
328
|
+
case "uint8_t":
|
|
256
329
|
Object.defineProperty(obj, name, charProp(offset2, array_size, length));
|
|
257
330
|
break;
|
|
331
|
+
case "int64_t":
|
|
332
|
+
Object.defineProperty(obj, name, int64Prop(offset2, array_size, length >> 3, false));
|
|
333
|
+
break;
|
|
334
|
+
case "uint64_t":
|
|
335
|
+
Object.defineProperty(obj, name, int64Prop(offset2, array_size, length >> 3, true));
|
|
336
|
+
break;
|
|
258
337
|
default:
|
|
259
338
|
obj[name] = {};
|
|
260
339
|
obj.__list__.push(name, type, length, offset2, array_size, IS_POINTER);
|
|
@@ -330,7 +409,7 @@ function worker_code() {
|
|
|
330
409
|
offset2 = compileProp(blen_struct.prototype, array_name_, type, offset2, Blender_Array_Length, Pointer_Match, pointer_size, array_length);
|
|
331
410
|
}
|
|
332
411
|
Object.defineProperty(blen_struct.prototype, _name, {
|
|
333
|
-
get: /* @__PURE__ */ function(array_names2) {
|
|
412
|
+
get: /* @__PURE__ */ (function(array_names2) {
|
|
334
413
|
return function() {
|
|
335
414
|
const array = [];
|
|
336
415
|
for (let i2 = 0; i2 < array_names2.length; i2++) {
|
|
@@ -338,7 +417,7 @@ function worker_code() {
|
|
|
338
417
|
}
|
|
339
418
|
return array;
|
|
340
419
|
};
|
|
341
|
-
}(array_names),
|
|
420
|
+
})(array_names),
|
|
342
421
|
enumerable: true,
|
|
343
422
|
configurable: true
|
|
344
423
|
});
|
|
@@ -372,6 +451,7 @@ function worker_code() {
|
|
|
372
451
|
if (this.__list__ === null) return this;
|
|
373
452
|
BLENDER_FILE2.addObject(this);
|
|
374
453
|
this.__blender_file__ = BLENDER_FILE2;
|
|
454
|
+
this.__byte_length__ = data_block_length - _data_offset;
|
|
375
455
|
const struct = this.__list__;
|
|
376
456
|
let j = 0, i = 0, name = "", type, length, Blender_Array_Length, offset2, constructor;
|
|
377
457
|
this.__data_address__ = _data_offset;
|
|
@@ -434,25 +514,53 @@ function worker_code() {
|
|
|
434
514
|
offset = 0;
|
|
435
515
|
const magic = toString(_data, offset, 7);
|
|
436
516
|
if (magic !== "BLENDER") return ERROR = "File supplied is not a .blend compatible Blender file.";
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
517
|
+
let version, large_bhead = false;
|
|
518
|
+
const fmtByte = toString(_data, 7, 8);
|
|
519
|
+
if (fmtByte === "_" || fmtByte === "-") {
|
|
520
|
+
pointer_size = fmtByte === "_" ? 4 : 8;
|
|
521
|
+
BIG_ENDIAN = toString(_data, 8, 9) !== "V";
|
|
522
|
+
version = toString(_data, 9, 12);
|
|
523
|
+
offset = 12;
|
|
524
|
+
} else {
|
|
525
|
+
const headerSize = parseInt(toString(_data, 7, 9), 10);
|
|
526
|
+
if (headerSize !== 17) return ERROR = "Unsupported new-style blend header size: " + headerSize;
|
|
527
|
+
pointer_size = 8;
|
|
528
|
+
BIG_ENDIAN = true;
|
|
529
|
+
large_bhead = true;
|
|
530
|
+
version = toString(_data, 13, 17);
|
|
531
|
+
offset = headerSize;
|
|
532
|
+
}
|
|
533
|
+
if (!BIG_ENDIAN) {
|
|
534
|
+
return ERROR = "Big-endian .blend files are not supported";
|
|
443
535
|
}
|
|
444
|
-
|
|
536
|
+
const BLOCK_HDR = large_bhead ? 32 : 16 + pointer_size;
|
|
537
|
+
const SDNA_OFF = large_bhead ? 4 : 8 + pointer_size;
|
|
538
|
+
const LEN_OFF = large_bhead ? 16 : 4;
|
|
539
|
+
const NR_OFF = large_bhead ? 24 : 12 + pointer_size;
|
|
540
|
+
const LEN_I64 = large_bhead;
|
|
541
|
+
const NR_I64 = large_bhead;
|
|
542
|
+
const readLen = (o) => LEN_I64 ? Number(data.getBigInt64(o + LEN_OFF, true)) : data.getInt32(o + LEN_OFF, true);
|
|
543
|
+
const readSdna = (o) => data.getInt32(o + SDNA_OFF, BIG_ENDIAN);
|
|
544
|
+
const readNr = (o) => NR_I64 ? Number(data.getBigInt64(o + NR_OFF, true)) : data.getInt32(o + NR_OFF, BIG_ENDIAN);
|
|
545
|
+
const templateKey = (large_bhead ? "v1:" : "v0:") + version;
|
|
546
|
+
if (!templates[templateKey]) {
|
|
547
|
+
templates[templateKey] = new MASTER_SDNA_SCHEMA(version);
|
|
548
|
+
}
|
|
549
|
+
current_SDNA_template = templates[templateKey];
|
|
445
550
|
FILE.template = current_SDNA_template;
|
|
446
|
-
offset += 3;
|
|
447
551
|
if (!current_SDNA_template.SDNA_SET) {
|
|
448
552
|
current_SDNA_template.endianess = BIG_ENDIAN;
|
|
449
553
|
current_SDNA_template.pointer_size = pointer_size;
|
|
450
554
|
offset2 = offset;
|
|
451
555
|
while (true) {
|
|
452
|
-
|
|
556
|
+
if (offset2 + BLOCK_HDR > data.byteLength) {
|
|
557
|
+
ERROR = "Unexpected end of file while searching for DNA1";
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
sdna_index = readSdna(offset2);
|
|
453
561
|
code = toString(_data, offset2, offset2 + 4).replace(/\u0000/g, "");
|
|
454
|
-
block_length =
|
|
455
|
-
offset2 +=
|
|
562
|
+
block_length = readLen(offset2);
|
|
563
|
+
offset2 += BLOCK_HDR;
|
|
456
564
|
if (code === "DNA1") {
|
|
457
565
|
count = 0;
|
|
458
566
|
let types = [], names = [], lengths = [], curr_name = "";
|
|
@@ -550,27 +658,24 @@ function worker_code() {
|
|
|
550
658
|
}
|
|
551
659
|
break;
|
|
552
660
|
}
|
|
553
|
-
if (data.getInt8(offset) === 0) {
|
|
554
|
-
debugger;
|
|
555
|
-
}
|
|
556
661
|
data_offset = offset;
|
|
557
|
-
if (offset +
|
|
662
|
+
if (offset + BLOCK_HDR > data.byteLength) {
|
|
558
663
|
ERROR = "Unexpected end of file while parsing";
|
|
559
664
|
break;
|
|
560
665
|
}
|
|
561
|
-
sdna_index =
|
|
666
|
+
sdna_index = readSdna(offset);
|
|
562
667
|
const code_str = toString(_data, offset, offset + 4);
|
|
563
|
-
offset2 = offset +
|
|
564
|
-
const blockLength =
|
|
565
|
-
if (blockLength < 0 || offset + blockLength +
|
|
668
|
+
offset2 = offset + BLOCK_HDR;
|
|
669
|
+
const blockLength = readLen(offset);
|
|
670
|
+
if (blockLength < 0 || offset + blockLength + BLOCK_HDR > data.byteLength) {
|
|
566
671
|
ERROR = "Invalid block length detected";
|
|
567
672
|
break;
|
|
568
673
|
}
|
|
569
|
-
offset += blockLength +
|
|
674
|
+
offset += blockLength + BLOCK_HDR;
|
|
570
675
|
if (code_str === "DNA1") ;
|
|
571
676
|
else if (code_str === "ENDB") break;
|
|
572
677
|
else if (code_str === "TEST") {
|
|
573
|
-
const data_start = data_offset +
|
|
678
|
+
const data_start = data_offset + BLOCK_HDR;
|
|
574
679
|
const width = data.getInt32(data_start, BIG_ENDIAN);
|
|
575
680
|
const height = data.getInt32(data_start + 4, BIG_ENDIAN);
|
|
576
681
|
if (width * height > 0) {
|
|
@@ -579,7 +684,7 @@ function worker_code() {
|
|
|
579
684
|
ERROR = "Invalid TEST block length detected";
|
|
580
685
|
break;
|
|
581
686
|
}
|
|
582
|
-
const image_data =
|
|
687
|
+
const image_data = alignedTypedArray(Uint32Array, _data, data_start + 8, data_len >> 2);
|
|
583
688
|
const image = {
|
|
584
689
|
width,
|
|
585
690
|
height,
|
|
@@ -588,10 +693,10 @@ function worker_code() {
|
|
|
588
693
|
FILE.thumbnail = image;
|
|
589
694
|
}
|
|
590
695
|
} else {
|
|
591
|
-
const data_start = data_offset +
|
|
696
|
+
const data_start = data_offset + BLOCK_HDR;
|
|
592
697
|
const constructor = current_SDNA_template.getSDNAStructureConstructor(current_SDNA_template.SDNA_NAMES[sdna_index]);
|
|
593
|
-
const size =
|
|
594
|
-
count =
|
|
698
|
+
const size = readLen(data_offset);
|
|
699
|
+
count = readNr(data_offset);
|
|
595
700
|
if (count > 0 && constructor) {
|
|
596
701
|
let obj = new constructor();
|
|
597
702
|
const length = constructor.prototype._length;
|
|
@@ -616,18 +721,9 @@ function worker_code() {
|
|
|
616
721
|
}
|
|
617
722
|
}
|
|
618
723
|
worker = new worker_code();
|
|
619
|
-
worker.postMessage = function(message,
|
|
620
|
-
return_object.onParseReady(message,
|
|
724
|
+
worker.postMessage = function(message, err2) {
|
|
725
|
+
return_object.onParseReady(message, err2);
|
|
621
726
|
};
|
|
622
|
-
/**
|
|
623
|
-
* JS.Blend
|
|
624
|
-
* Original Repo: https://github.com/acweathersby/js.blend
|
|
625
|
-
* Slightly modified for three.js and js updates, minor refactor.
|
|
626
|
-
* Object-creation part re-written for latest three.js and typescript
|
|
627
|
-
* MIT License
|
|
628
|
-
* Copyright (c) 2020 Anthony C, Weathersby
|
|
629
|
-
* @license
|
|
630
|
-
*/
|
|
631
727
|
async function parseBlend(buffer, name = "") {
|
|
632
728
|
return new Promise((res, rej) => {
|
|
633
729
|
return_object.onParseReady = (file, error) => {
|
|
@@ -716,14 +812,147 @@ function getLayer(layers, i) {
|
|
|
716
812
|
if (!Array.isArray(layers)) return layers;
|
|
717
813
|
return layers[i];
|
|
718
814
|
}
|
|
815
|
+
function readCString(block) {
|
|
816
|
+
if (!block || block.__data_address__ === void 0 || !block.__blender_file__) return null;
|
|
817
|
+
const u82 = block.__blender_file__.byte;
|
|
818
|
+
let s = "", o = block.__data_address__;
|
|
819
|
+
while (o < u82.length && u82[o] !== 0 && s.length < 256) s += String.fromCharCode(u82[o++]);
|
|
820
|
+
return s;
|
|
821
|
+
}
|
|
822
|
+
const ATTR_TYPE_INT32 = 3, ATTR_TYPE_FLOAT2 = 6, ATTR_TYPE_FLOAT3 = 7;
|
|
823
|
+
const ATTR_DOMAIN_CORNER = 3;
|
|
824
|
+
function getAttributes(meshData) {
|
|
825
|
+
const as = meshData.attribute_storage;
|
|
826
|
+
if (!as) return [];
|
|
827
|
+
let attrs = as.dna_attributes;
|
|
828
|
+
if (!attrs) return [];
|
|
829
|
+
attrs = Array.isArray(attrs) || attrs.length !== void 0 ? Array.from(attrs) : [attrs];
|
|
830
|
+
return attrs;
|
|
831
|
+
}
|
|
832
|
+
function findAttribute(attrs, name, type) {
|
|
833
|
+
for (const a of attrs) {
|
|
834
|
+
if (readCString(a.name) === name && (type === void 0 || a.data_type === type)) return a;
|
|
835
|
+
}
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
838
|
+
function attrSize(attr) {
|
|
839
|
+
const arr = attr && attr.data;
|
|
840
|
+
const n = arr && arr.size !== void 0 ? Number(arr.size) : 0;
|
|
841
|
+
return Number.isFinite(n) && n >= 0 ? n : 0;
|
|
842
|
+
}
|
|
843
|
+
function readAttrArray(attr, Ctor, count) {
|
|
844
|
+
const arr = attr && attr.data;
|
|
845
|
+
const block = arr && arr.data;
|
|
846
|
+
if (!block || block.__data_address__ === void 0 || !block.__blender_file__) return null;
|
|
847
|
+
return block.__blender_file__.readTypedArray(Ctor, block.__data_address__, count);
|
|
848
|
+
}
|
|
849
|
+
function mergeGroupRun(runs, start, count, mat) {
|
|
850
|
+
if (count <= 0) return;
|
|
851
|
+
const last = runs[runs.length - 1];
|
|
852
|
+
if (last && last.mat === mat && last.start + last.count === start) last.count += count;
|
|
853
|
+
else runs.push({ start, count, mat });
|
|
854
|
+
}
|
|
855
|
+
function readFaceMaterialIndex(meshData, faceCount) {
|
|
856
|
+
const pd = meshData.pdata;
|
|
857
|
+
if (!pd || !pd.layers || !pd.totlayer) return null;
|
|
858
|
+
for (let i = 0; i < pd.totlayer; i++) {
|
|
859
|
+
const l = getLayer(pd.layers, i);
|
|
860
|
+
if (l && l.name === "material_index" && l.data) {
|
|
861
|
+
const data = Array.isArray(l.data) ? l.data : l.data.length !== void 0 ? Array.from(l.data) : null;
|
|
862
|
+
if (!data) return null;
|
|
863
|
+
const out = new Array(faceCount);
|
|
864
|
+
for (let f = 0; f < faceCount; f++) {
|
|
865
|
+
const e = data[f];
|
|
866
|
+
out[f] = e && typeof e === "object" ? e.i ?? e.value ?? 0 : e || 0;
|
|
867
|
+
}
|
|
868
|
+
return out;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
return null;
|
|
872
|
+
}
|
|
873
|
+
function createBufferGeometryFromAttributes(meshData, ctx) {
|
|
874
|
+
const attrs = getAttributes(meshData);
|
|
875
|
+
if (!attrs.length) return null;
|
|
876
|
+
const posAttr = findAttribute(attrs, "position", ATTR_TYPE_FLOAT3);
|
|
877
|
+
const vertCount = attrSize(posAttr);
|
|
878
|
+
const posRaw = vertCount > 0 && readAttrArray(posAttr, Float32Array, vertCount * 3);
|
|
879
|
+
if (!posRaw) return null;
|
|
880
|
+
const geometry = new ctx.BufferGeometry();
|
|
881
|
+
geometry.name = meshData.aname || "";
|
|
882
|
+
const positions = new Float32Array(vertCount * 3);
|
|
883
|
+
for (let j = 0; j < vertCount; j++) {
|
|
884
|
+
const x = posRaw[j * 3], y = posRaw[j * 3 + 1], z = posRaw[j * 3 + 2];
|
|
885
|
+
positions[j * 3] = Number.isFinite(x) ? x : 0;
|
|
886
|
+
positions[j * 3 + 1] = Number.isFinite(z) ? z : 0;
|
|
887
|
+
positions[j * 3 + 2] = Number.isFinite(y) ? -y : 0;
|
|
888
|
+
}
|
|
889
|
+
geometry.setAttribute("position", new ctx.BufferAttribute(positions, 3));
|
|
890
|
+
const cvAttr = findAttribute(attrs, ".corner_vert", ATTR_TYPE_INT32);
|
|
891
|
+
const loopCount = attrSize(cvAttr);
|
|
892
|
+
const cornerVerts = loopCount > 0 && readAttrArray(cvAttr, Int32Array, loopCount);
|
|
893
|
+
const poi = meshData.poly_offset_indices;
|
|
894
|
+
const faceOffsetCount = poi && poi.__byte_length__ ? poi.__byte_length__ >> 2 : 0;
|
|
895
|
+
if (cornerVerts && faceOffsetCount > 1 && poi) {
|
|
896
|
+
const faceIndices = poi.__blender_file__.readTypedArray(Int32Array, poi.__data_address__, faceOffsetCount);
|
|
897
|
+
const faceCount = faceIndices.length - 1;
|
|
898
|
+
let totalTriangles = 0;
|
|
899
|
+
for (let i = 0; i < faceCount; i++) totalTriangles += Math.max(0, faceIndices[i + 1] - faceIndices[i] - 2);
|
|
900
|
+
const indexes = new Uint32Array(totalTriangles * 3);
|
|
901
|
+
const inRange = (v) => v >= 0 && v < vertCount;
|
|
902
|
+
const matAttr = (meshData.totcol || 0) > 1 ? findAttribute(attrs, "material_index", ATTR_TYPE_INT32) : null;
|
|
903
|
+
const faceMat = matAttr && attrSize(matAttr) >= faceCount ? readAttrArray(matAttr, Int32Array, faceCount) : null;
|
|
904
|
+
const groupRuns = [];
|
|
905
|
+
let t = 0;
|
|
906
|
+
for (let i = 0; i < faceCount; i++) {
|
|
907
|
+
const faceStart = faceIndices[i], faceVertCount = faceIndices[i + 1] - faceStart;
|
|
908
|
+
const triStart = t;
|
|
909
|
+
if (faceVertCount >= 3 && faceStart >= 0 && faceStart + faceVertCount <= loopCount) {
|
|
910
|
+
const firstVert = cornerVerts[faceStart];
|
|
911
|
+
for (let k = 1; k < faceVertCount - 1; k++) {
|
|
912
|
+
const b = cornerVerts[faceStart + k], c = cornerVerts[faceStart + k + 1];
|
|
913
|
+
if (inRange(firstVert) && inRange(b) && inRange(c)) {
|
|
914
|
+
indexes[t++] = firstVert;
|
|
915
|
+
indexes[t++] = b;
|
|
916
|
+
indexes[t++] = c;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
if (faceMat) mergeGroupRun(groupRuns, triStart, t - triStart, faceMat[i] || 0);
|
|
921
|
+
}
|
|
922
|
+
geometry.setIndex(new ctx.BufferAttribute(t === indexes.length ? indexes : indexes.slice(0, t), 1));
|
|
923
|
+
if (faceMat) for (const g of groupRuns) geometry.addGroup(g.start, g.count, g.mat);
|
|
924
|
+
const uvAttr = attrs.find((a) => a.data_type === ATTR_TYPE_FLOAT2 && a.domain === ATTR_DOMAIN_CORNER && !(readCString(a.name) || ".").startsWith("."));
|
|
925
|
+
const uvRaw = uvAttr && attrSize(uvAttr) >= loopCount && readAttrArray(uvAttr, Float32Array, loopCount * 2);
|
|
926
|
+
if (uvRaw) {
|
|
927
|
+
const uvs = new Float32Array(vertCount * 2);
|
|
928
|
+
for (let i = 0; i < loopCount; i++) {
|
|
929
|
+
const v = cornerVerts[i];
|
|
930
|
+
if (v >= 0 && v < vertCount) {
|
|
931
|
+
const u = uvRaw[i * 2], vv = uvRaw[i * 2 + 1];
|
|
932
|
+
uvs[v * 2] = Number.isFinite(u) ? u : 0;
|
|
933
|
+
uvs[v * 2 + 1] = Number.isFinite(vv) ? vv : 0;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
geometry.setAttribute("uv", new ctx.BufferAttribute(uvs, 2));
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
if (geometry.attributes.position && !geometry.attributes.normal)
|
|
940
|
+
geometry.computeVertexNormals();
|
|
941
|
+
return geometry;
|
|
942
|
+
}
|
|
719
943
|
function createBufferGeometry(meshData, ctx) {
|
|
720
944
|
if (meshData.mpoly) return createBufferGeometryOld(meshData, ctx);
|
|
945
|
+
if (meshData.attribute_storage) {
|
|
946
|
+
const g = createBufferGeometryFromAttributes(meshData, ctx);
|
|
947
|
+
if (g) return g;
|
|
948
|
+
}
|
|
721
949
|
const geometry = new ctx.BufferGeometry();
|
|
722
950
|
geometry.name = meshData.aname || "";
|
|
723
951
|
let vertices;
|
|
724
952
|
let verticesData;
|
|
725
953
|
let indices;
|
|
726
954
|
let indicesData;
|
|
955
|
+
let uvLayerData = null;
|
|
727
956
|
if (meshData.vdata && meshData.vdata.layers && meshData.vdata.totlayer > 0) {
|
|
728
957
|
for (let i = 0; i < meshData.vdata.totlayer; i++) {
|
|
729
958
|
const layer = getLayer(meshData.vdata.layers, i);
|
|
@@ -742,7 +971,12 @@ function createBufferGeometry(meshData, ctx) {
|
|
|
742
971
|
const layer = getLayer(meshData.ldata.layers, i);
|
|
743
972
|
const data = layer.data || [];
|
|
744
973
|
if (data.length === meshData.totloop) {
|
|
745
|
-
|
|
974
|
+
const lname = layer.name || "";
|
|
975
|
+
if (!uvLayerData && (layer.type === 49 || lname[0] !== "." && /uv/i.test(lname))) {
|
|
976
|
+
uvLayerData = data;
|
|
977
|
+
continue;
|
|
978
|
+
}
|
|
979
|
+
if (indices && (lname !== ".corner_vert" || indices.name === ".corner_vert")) {
|
|
746
980
|
continue;
|
|
747
981
|
}
|
|
748
982
|
indices = layer;
|
|
@@ -752,9 +986,44 @@ function createBufferGeometry(meshData, ctx) {
|
|
|
752
986
|
}
|
|
753
987
|
let faceIndices = [];
|
|
754
988
|
if (meshData.poly_offset_indices && meshData.totpoly > 0) {
|
|
755
|
-
faceIndices = [...
|
|
989
|
+
faceIndices = [...meshData.poly_offset_indices.__blender_file__.readTypedArray(Int32Array, meshData.poly_offset_indices.__data_address__, meshData.totpoly + 1)];
|
|
990
|
+
}
|
|
991
|
+
const vco = (vd) => vd?.x !== void 0 ? [vd.x, vd.y, vd.z] : vd?.co ? [vd.co[0], vd.co[1], vd.co[2]] : [0, 0, 0];
|
|
992
|
+
let cornerToVert = null;
|
|
993
|
+
let expandedPos = null;
|
|
994
|
+
let expandedUv = null;
|
|
995
|
+
if (uvLayerData && indicesData && verticesData && verticesData.length) {
|
|
996
|
+
cornerToVert = new Int32Array(indicesData.length);
|
|
997
|
+
const seen = /* @__PURE__ */ new Map();
|
|
998
|
+
const ps = [], us = [];
|
|
999
|
+
const uvN = uvLayerData.length;
|
|
1000
|
+
for (let i = 0; i < indicesData.length; i++) {
|
|
1001
|
+
const bv = indicesData[i]?.i;
|
|
1002
|
+
if (!(bv >= 0 && bv < verticesData.length)) {
|
|
1003
|
+
cornerToVert[i] = 0;
|
|
1004
|
+
continue;
|
|
1005
|
+
}
|
|
1006
|
+
const e = i < uvN ? uvLayerData[i] : null;
|
|
1007
|
+
const u = e && Number.isFinite(e.x) ? e.x : 0;
|
|
1008
|
+
const w = e && Number.isFinite(e.y) ? e.y : 0;
|
|
1009
|
+
const key = bv + "|" + Math.round(u * 4096) + "|" + Math.round(w * 4096);
|
|
1010
|
+
let ev = seen.get(key);
|
|
1011
|
+
if (ev === void 0) {
|
|
1012
|
+
ev = us.length / 2;
|
|
1013
|
+
seen.set(key, ev);
|
|
1014
|
+
const [x, y, z] = vco(verticesData[bv]);
|
|
1015
|
+
ps.push(x, z, -y);
|
|
1016
|
+
us.push(u, w);
|
|
1017
|
+
}
|
|
1018
|
+
cornerToVert[i] = ev;
|
|
1019
|
+
}
|
|
1020
|
+
expandedPos = new Float32Array(ps);
|
|
1021
|
+
expandedUv = new Float32Array(us);
|
|
756
1022
|
}
|
|
757
|
-
|
|
1023
|
+
const vAt = (corner) => cornerToVert ? cornerToVert[corner] : indicesData[corner].i;
|
|
1024
|
+
if (expandedPos) {
|
|
1025
|
+
geometry.setAttribute("position", new ctx.BufferAttribute(expandedPos, 3));
|
|
1026
|
+
} else if (verticesData && verticesData.length > 0) {
|
|
758
1027
|
const positions = new Float32Array(verticesData.length * 3);
|
|
759
1028
|
for (let j = 0; j < verticesData.length; j++) {
|
|
760
1029
|
const { x, y, z, co } = verticesData[j] || {};
|
|
@@ -773,44 +1042,50 @@ function createBufferGeometry(meshData, ctx) {
|
|
|
773
1042
|
}
|
|
774
1043
|
geometry.setAttribute("position", new ctx.BufferAttribute(positions, 3));
|
|
775
1044
|
}
|
|
776
|
-
if (indicesData && indicesData.length > 0 &&
|
|
1045
|
+
if (indicesData && indicesData.length > 0 && verticesData?.length) {
|
|
777
1046
|
const faceSize = meshData.totloop / meshData.totpoly;
|
|
778
1047
|
if (faceIndices.length > 0) {
|
|
1048
|
+
const faceCount = faceIndices.length - 1;
|
|
779
1049
|
let totalTriangles = 0;
|
|
780
|
-
for (let i = 0; i <
|
|
1050
|
+
for (let i = 0; i < faceCount; i++) {
|
|
781
1051
|
const faceVertCount = faceIndices[i + 1] - faceIndices[i];
|
|
782
1052
|
totalTriangles += Math.max(0, faceVertCount - 2);
|
|
783
1053
|
}
|
|
784
1054
|
const indexes = new Uint32Array(totalTriangles * 3);
|
|
785
1055
|
let t = 0;
|
|
786
|
-
|
|
1056
|
+
const faceMat = (meshData.totcol || 0) > 1 ? readFaceMaterialIndex(meshData, faceCount) : null;
|
|
1057
|
+
const groupRuns = [];
|
|
1058
|
+
for (let i = 0; i < faceCount; i++) {
|
|
787
1059
|
const faceStart = faceIndices[i];
|
|
788
1060
|
const faceEnd = faceIndices[i + 1];
|
|
789
1061
|
const faceVertCount = faceEnd - faceStart;
|
|
1062
|
+
const triStart = t;
|
|
790
1063
|
if (faceVertCount >= 3) {
|
|
791
|
-
const firstVert =
|
|
1064
|
+
const firstVert = vAt(faceStart);
|
|
792
1065
|
for (let k = 1; k < faceVertCount - 1; k++) {
|
|
793
1066
|
indexes[t++] = firstVert;
|
|
794
|
-
indexes[t++] =
|
|
795
|
-
indexes[t++] =
|
|
1067
|
+
indexes[t++] = vAt(faceStart + k);
|
|
1068
|
+
indexes[t++] = vAt(faceStart + k + 1);
|
|
796
1069
|
}
|
|
797
1070
|
}
|
|
1071
|
+
if (faceMat) mergeGroupRun(groupRuns, triStart, t - triStart, faceMat[i] || 0);
|
|
798
1072
|
}
|
|
799
1073
|
geometry.setIndex(new ctx.BufferAttribute(indexes, 1));
|
|
1074
|
+
if (faceMat) for (const g of groupRuns) geometry.addGroup(g.start, g.count, g.mat);
|
|
800
1075
|
} else if (faceSize === 3 || faceSize === 4) {
|
|
801
1076
|
const isQuad = faceSize === 4;
|
|
802
1077
|
const faceCount = indices.length / faceSize;
|
|
803
1078
|
const indexes = new Uint32Array(faceCount * 3 * (isQuad ? 2 : 1));
|
|
804
1079
|
if (faceSize !== 3 && faceSize !== 4) return geometry;
|
|
805
1080
|
for (let j = 0, t = 0; j < indices.length; j += faceSize) {
|
|
806
|
-
const a =
|
|
807
|
-
const b =
|
|
808
|
-
const c =
|
|
1081
|
+
const a = vAt(j);
|
|
1082
|
+
const b = vAt(j + 1);
|
|
1083
|
+
const c = vAt(j + 2);
|
|
809
1084
|
indexes[t++] = a;
|
|
810
1085
|
indexes[t++] = b;
|
|
811
1086
|
indexes[t++] = c;
|
|
812
1087
|
if (isQuad) {
|
|
813
|
-
const d =
|
|
1088
|
+
const d = vAt(j + 3);
|
|
814
1089
|
indexes[t++] = a;
|
|
815
1090
|
indexes[t++] = c;
|
|
816
1091
|
indexes[t++] = d;
|
|
@@ -821,6 +1096,9 @@ function createBufferGeometry(meshData, ctx) {
|
|
|
821
1096
|
} else if (faceIndices) {
|
|
822
1097
|
console.error("BlendLoader - no indices data found, but face indices are present", faceIndices);
|
|
823
1098
|
}
|
|
1099
|
+
if (expandedUv && !geometry.attributes.uv) {
|
|
1100
|
+
geometry.setAttribute("uv", new ctx.BufferAttribute(expandedUv, 2));
|
|
1101
|
+
}
|
|
824
1102
|
if (geometry.attributes.position && !geometry.attributes.normal)
|
|
825
1103
|
geometry.computeVertexNormals();
|
|
826
1104
|
return geometry;
|
|
@@ -836,9 +1114,12 @@ function createBufferGeometryOld(mesh, ctx) {
|
|
|
836
1114
|
const positions = new Float32Array(size * 3);
|
|
837
1115
|
let currentIndex = 0;
|
|
838
1116
|
let computeNormals = false;
|
|
1117
|
+
const useGroups = (mesh.totcol || 0) > 1;
|
|
1118
|
+
const groupRuns = [];
|
|
839
1119
|
for (const face of faces) {
|
|
840
1120
|
const len = face.totloop;
|
|
841
1121
|
const start = face.loopstart;
|
|
1122
|
+
const faceStartIndex = currentIndex;
|
|
842
1123
|
let indexi = 1;
|
|
843
1124
|
while (indexi < len) {
|
|
844
1125
|
let index = 0;
|
|
@@ -870,34 +1151,294 @@ function createBufferGeometryOld(mesh, ctx) {
|
|
|
870
1151
|
}
|
|
871
1152
|
indexi += 2;
|
|
872
1153
|
}
|
|
1154
|
+
if (useGroups) mergeGroupRun(groupRuns, faceStartIndex, currentIndex - faceStartIndex, face.mat_nr || 0);
|
|
873
1155
|
}
|
|
874
1156
|
geometry.setAttribute("position", new ctx.BufferAttribute(positions, 3));
|
|
875
1157
|
geometry.setIndex(new ctx.BufferAttribute(indices, 1));
|
|
876
1158
|
geometry.setAttribute("normal", new ctx.BufferAttribute(normals, 3));
|
|
877
1159
|
geometry.setAttribute("uv", new ctx.BufferAttribute(uvs, 2));
|
|
1160
|
+
if (useGroups && groupRuns.length)
|
|
1161
|
+
for (const g of groupRuns) geometry.addGroup(g.start, g.count, g.mat);
|
|
878
1162
|
if (computeNormals) {
|
|
879
1163
|
geometry.computeVertexNormals();
|
|
880
1164
|
}
|
|
881
1165
|
return geometry;
|
|
882
1166
|
}
|
|
1167
|
+
const MA_BL_CULL_BACKFACE = 1 << 2;
|
|
1168
|
+
const MA_BM_CLIP = 3;
|
|
1169
|
+
function listBaseToArray(lb) {
|
|
1170
|
+
const out = [];
|
|
1171
|
+
if (!lb) return out;
|
|
1172
|
+
let n = lb.first, guard = 0;
|
|
1173
|
+
while (n && guard++ < 8192) {
|
|
1174
|
+
out.push(n);
|
|
1175
|
+
n = n.next;
|
|
1176
|
+
}
|
|
1177
|
+
return out;
|
|
1178
|
+
}
|
|
1179
|
+
const idnameOf = (n) => n && typeof n.idname === "string" ? n.idname : "";
|
|
1180
|
+
const nameOf = (s) => s && typeof s.name === "string" ? s.name : "";
|
|
1181
|
+
function socketByName(sockets, ...names) {
|
|
1182
|
+
for (const name of names) {
|
|
1183
|
+
const s = sockets.find((x) => nameOf(x) === name);
|
|
1184
|
+
if (s) return s;
|
|
1185
|
+
}
|
|
1186
|
+
return null;
|
|
1187
|
+
}
|
|
1188
|
+
function inputsOf(node) {
|
|
1189
|
+
return node ? listBaseToArray(node.inputs) : [];
|
|
1190
|
+
}
|
|
1191
|
+
function socketConst(sock) {
|
|
1192
|
+
const dv = sock && sock.default_value;
|
|
1193
|
+
return dv ? dv.value : void 0;
|
|
1194
|
+
}
|
|
1195
|
+
const num = (v) => typeof v === "number" ? v : void 0;
|
|
1196
|
+
const clamp01 = (c) => Math.max(0, Math.min(1, c));
|
|
1197
|
+
function nodeFeeding(links, socket) {
|
|
1198
|
+
if (!socket) return null;
|
|
1199
|
+
let link = links.find((l) => l.tosock === socket);
|
|
1200
|
+
let guard = 0;
|
|
1201
|
+
while (link && idnameOf(link.fromnode).includes("Reroute") && guard++ < 32) {
|
|
1202
|
+
const re = inputsOf(link.fromnode)[0];
|
|
1203
|
+
link = links.find((l) => l.tosock === re);
|
|
1204
|
+
}
|
|
1205
|
+
return link ? link.fromnode : null;
|
|
1206
|
+
}
|
|
1207
|
+
function imageMime(b) {
|
|
1208
|
+
if (b[0] === 137 && b[1] === 80 && b[2] === 78 && b[3] === 71) return "image/png";
|
|
1209
|
+
if (b[0] === 255 && b[1] === 216 && b[2] === 255) return "image/jpeg";
|
|
1210
|
+
if (b[0] === 66 && b[1] === 77) return "image/bmp";
|
|
1211
|
+
if (b[0] === 82 && b[1] === 73 && b[2] === 70 && b[3] === 70 && b[8] === 87 && b[9] === 69) return "image/webp";
|
|
1212
|
+
return null;
|
|
1213
|
+
}
|
|
1214
|
+
function packedTexture(imageNode, srgb) {
|
|
1215
|
+
const img = imageNode && imageNode.id;
|
|
1216
|
+
if (!img) return null;
|
|
1217
|
+
const pf = img.packedfile || img.packedfiles && img.packedfiles.first && img.packedfiles.first.packedfile;
|
|
1218
|
+
const block = pf && pf.data;
|
|
1219
|
+
const size = pf && typeof pf.size === "number" ? pf.size : 0;
|
|
1220
|
+
if (!block || block.__data_address__ === void 0 || size <= 0) return null;
|
|
1221
|
+
const buf = block.__blender_file__.byte.buffer;
|
|
1222
|
+
if (block.__data_address__ + size > buf.byteLength) return null;
|
|
1223
|
+
const bytes = new Uint8Array(buf, block.__data_address__, size).slice();
|
|
1224
|
+
const mime = imageMime(bytes);
|
|
1225
|
+
if (!mime || typeof Blob === "undefined" || typeof URL === "undefined" || typeof Image === "undefined") return null;
|
|
1226
|
+
const url = URL.createObjectURL(new Blob([bytes], { type: mime }));
|
|
1227
|
+
const el = new Image();
|
|
1228
|
+
const texture = new Texture(el);
|
|
1229
|
+
if (srgb) texture.colorSpace = SRGBColorSpace;
|
|
1230
|
+
texture.name = (typeof img.aname === "string" ? img.aname : "") || "blendTexture";
|
|
1231
|
+
el.onload = () => {
|
|
1232
|
+
texture.needsUpdate = true;
|
|
1233
|
+
URL.revokeObjectURL(url);
|
|
1234
|
+
};
|
|
1235
|
+
el.onerror = () => {
|
|
1236
|
+
URL.revokeObjectURL(url);
|
|
1237
|
+
};
|
|
1238
|
+
el.src = url;
|
|
1239
|
+
return texture;
|
|
1240
|
+
}
|
|
1241
|
+
const IMA_SRC_GENERATED = 4, IMA_SRC_VIEWER = 5;
|
|
1242
|
+
function applyWrap(tex, imageNode) {
|
|
1243
|
+
if (!tex) return tex;
|
|
1244
|
+
const ext = imageNode?.storage?.extension;
|
|
1245
|
+
tex.wrapS = tex.wrapT = ext === 1 || ext === 2 ? ClampToEdgeWrapping : ext === 3 ? MirroredRepeatWrapping : RepeatWrapping;
|
|
1246
|
+
tex.needsUpdate = true;
|
|
1247
|
+
return tex;
|
|
1248
|
+
}
|
|
1249
|
+
function imageNodeTexture(imageNode, srgb, ctx) {
|
|
1250
|
+
const packed = packedTexture(imageNode, srgb);
|
|
1251
|
+
if (packed) return applyWrap(packed, imageNode);
|
|
1252
|
+
const img = imageNode && imageNode.id;
|
|
1253
|
+
if (img && img.source !== IMA_SRC_GENERATED && img.source !== IMA_SRC_VIEWER && typeof img.name === "string" && img.name && ctx.loadExternalTexture) {
|
|
1254
|
+
return applyWrap(ctx.loadExternalTexture(img.name, srgb), imageNode);
|
|
1255
|
+
}
|
|
1256
|
+
return null;
|
|
1257
|
+
}
|
|
1258
|
+
function imageNodeFeeding(links, socket) {
|
|
1259
|
+
let src = nodeFeeding(links, socket);
|
|
1260
|
+
if (src && idnameOf(src).includes("NormalMap")) src = nodeFeeding(links, socketByName(inputsOf(src), "Color"));
|
|
1261
|
+
return src && idnameOf(src).includes("TexImage") ? src : null;
|
|
1262
|
+
}
|
|
1263
|
+
function textureFromSocket(links, socket, srgb, ctx) {
|
|
1264
|
+
const src = imageNodeFeeding(links, socket);
|
|
1265
|
+
return src ? imageNodeTexture(src, srgb, ctx) : null;
|
|
1266
|
+
}
|
|
1267
|
+
function resolveShaders(nodes, links) {
|
|
1268
|
+
const outputs = nodes.filter((n) => idnameOf(n).includes("OutputMaterial"));
|
|
1269
|
+
const activeOut = outputs.find((n) => n.is_active_output) || outputs[0];
|
|
1270
|
+
let principled = null, emission = null;
|
|
1271
|
+
if (activeOut) {
|
|
1272
|
+
let surf = nodeFeeding(links, socketByName(inputsOf(activeOut), "Surface"));
|
|
1273
|
+
let guard = 0;
|
|
1274
|
+
while (surf && !idnameOf(surf).includes("BsdfPrincipled") && guard++ < 4) {
|
|
1275
|
+
if (idnameOf(surf).includes("Emission") && !emission) emission = surf;
|
|
1276
|
+
const next = inputsOf(surf).map((s) => nodeFeeding(links, s)).find((n) => n && idnameOf(n).includes("BsdfPrincipled"));
|
|
1277
|
+
if (!next) break;
|
|
1278
|
+
surf = next;
|
|
1279
|
+
}
|
|
1280
|
+
if (surf && idnameOf(surf).includes("BsdfPrincipled")) principled = surf;
|
|
1281
|
+
}
|
|
1282
|
+
if (!principled) principled = nodes.find((n) => idnameOf(n).includes("BsdfPrincipled"));
|
|
1283
|
+
if (!emission) emission = nodes.find((n) => idnameOf(n) === "ShaderNodeEmission");
|
|
1284
|
+
return { principled, emission };
|
|
1285
|
+
}
|
|
883
1286
|
function createMaterial(mat, ctx) {
|
|
884
1287
|
const material = new ctx.MeshPhysicalMaterial();
|
|
885
|
-
material.
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
1288
|
+
material.side = typeof mat.blend_flag === "number" && mat.blend_flag & MA_BL_CULL_BACKFACE ? FrontSide : DoubleSide;
|
|
1289
|
+
const nodes = mat.nodetree ? listBaseToArray(mat.nodetree.nodes) : [];
|
|
1290
|
+
const links = mat.nodetree ? listBaseToArray(mat.nodetree.links) : [];
|
|
1291
|
+
const { principled, emission } = resolveShaders(nodes, links);
|
|
1292
|
+
let applied = false;
|
|
1293
|
+
if (principled) {
|
|
1294
|
+
const inp = inputsOf(principled);
|
|
1295
|
+
applied = true;
|
|
1296
|
+
const baseSock = socketByName(inp, "Base Color", "BaseColor");
|
|
1297
|
+
const baseImgNode = imageNodeFeeding(links, baseSock);
|
|
1298
|
+
const baseTex = baseImgNode ? imageNodeTexture(baseImgNode, true, ctx) : null;
|
|
1299
|
+
if (baseTex) {
|
|
1300
|
+
material.map = baseTex;
|
|
1301
|
+
material.color.setRGB(1, 1, 1);
|
|
1302
|
+
} else {
|
|
1303
|
+
const base = socketConst(baseSock);
|
|
1304
|
+
if (base && base.length >= 3) material.color.setRGB(clamp01(base[0]), clamp01(base[1]), clamp01(base[2]));
|
|
1305
|
+
}
|
|
1306
|
+
const roughSock = socketByName(inp, "Roughness");
|
|
1307
|
+
const roughTex = textureFromSocket(links, roughSock, false, ctx);
|
|
1308
|
+
if (roughTex) material.roughnessMap = roughTex;
|
|
1309
|
+
else {
|
|
1310
|
+
const r = num(socketConst(roughSock));
|
|
1311
|
+
if (r !== void 0) material.roughness = r;
|
|
1312
|
+
}
|
|
1313
|
+
const metalSock = socketByName(inp, "Metallic");
|
|
1314
|
+
const metalTex = textureFromSocket(links, metalSock, false, ctx);
|
|
1315
|
+
if (metalTex) material.metalnessMap = metalTex;
|
|
1316
|
+
else {
|
|
1317
|
+
const m = num(socketConst(metalSock));
|
|
1318
|
+
if (m !== void 0) material.metalness = m;
|
|
1319
|
+
}
|
|
1320
|
+
const normSrc = nodeFeeding(links, socketByName(inp, "Normal"));
|
|
1321
|
+
if (normSrc) {
|
|
1322
|
+
const normTex = textureFromSocket(links, socketByName(inp, "Normal"), false, ctx);
|
|
1323
|
+
if (normTex) {
|
|
1324
|
+
material.normalMap = normTex;
|
|
1325
|
+
const strength = num(socketConst(socketByName(inputsOf(normSrc), "Strength")));
|
|
1326
|
+
if (strength !== void 0 && material.normalScale) material.normalScale.set(strength, strength);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
const alphaSock = socketByName(inp, "Alpha");
|
|
1330
|
+
const alphaImgNode = imageNodeFeeding(links, alphaSock);
|
|
1331
|
+
const alphaFromBase = !!(alphaImgNode && baseImgNode && alphaImgNode === baseImgNode);
|
|
1332
|
+
const alphaTex = alphaImgNode && !alphaFromBase ? imageNodeTexture(alphaImgNode, false, ctx) : null;
|
|
1333
|
+
const alphaC = num(socketConst(alphaSock));
|
|
1334
|
+
const hasAlpha = !!alphaTex || alphaFromBase || alphaC !== void 0 && alphaC < 1;
|
|
1335
|
+
if (alphaTex) material.alphaMap = alphaTex;
|
|
1336
|
+
else if (!alphaFromBase && alphaC !== void 0 && alphaC < 1) material.opacity = alphaC;
|
|
1337
|
+
if (hasAlpha) {
|
|
1338
|
+
if (mat.blend_method === MA_BM_CLIP) {
|
|
1339
|
+
const thr = num(mat.alpha_threshold);
|
|
1340
|
+
material.alphaTest = thr !== void 0 && thr > 0 ? thr : 0.5;
|
|
1341
|
+
} else material.transparent = true;
|
|
1342
|
+
}
|
|
1343
|
+
const ior = num(socketConst(socketByName(inp, "IOR")));
|
|
1344
|
+
if (ior !== void 0 && material.ior !== void 0) material.ior = ior;
|
|
1345
|
+
const trans = num(socketConst(socketByName(inp, "Transmission Weight", "Transmission")));
|
|
1346
|
+
if (trans !== void 0 && trans > 0 && material.transmission !== void 0) {
|
|
1347
|
+
material.transmission = trans;
|
|
1348
|
+
}
|
|
1349
|
+
const coat = num(socketConst(socketByName(inp, "Coat Weight", "Clearcoat")));
|
|
1350
|
+
if (coat !== void 0 && coat > 0 && material.clearcoat !== void 0) {
|
|
1351
|
+
material.clearcoat = coat;
|
|
1352
|
+
const cr = num(socketConst(socketByName(inp, "Coat Roughness", "Clearcoat Roughness")));
|
|
1353
|
+
if (cr !== void 0) material.clearcoatRoughness = cr;
|
|
1354
|
+
}
|
|
1355
|
+
const sheen = num(socketConst(socketByName(inp, "Sheen Weight", "Sheen")));
|
|
1356
|
+
if (sheen !== void 0 && sheen > 0 && material.sheen !== void 0) {
|
|
1357
|
+
material.sheen = sheen;
|
|
1358
|
+
const stint = socketConst(socketByName(inp, "Sheen Tint"));
|
|
1359
|
+
if (stint && stint.length >= 3 && material.sheenColor) material.sheenColor.setRGB(stint[0], stint[1], stint[2]);
|
|
1360
|
+
const sr = num(socketConst(socketByName(inp, "Sheen Roughness")));
|
|
1361
|
+
if (sr !== void 0) material.sheenRoughness = sr;
|
|
1362
|
+
}
|
|
1363
|
+
const spec = num(socketConst(socketByName(inp, "Specular IOR Level", "Specular")));
|
|
1364
|
+
if (spec !== void 0 && material.specularIntensity !== void 0) {
|
|
1365
|
+
material.specularIntensity = Math.min(1, spec * 2);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
const matOutput = nodes.find((n) => idnameOf(n).includes("OutputMaterial") && n.is_active_output) || nodes.find((n) => idnameOf(n).includes("OutputMaterial"));
|
|
1369
|
+
const dispNode = matOutput ? nodeFeeding(links, socketByName(inputsOf(matOutput), "Displacement")) : null;
|
|
1370
|
+
if (dispNode && idnameOf(dispNode).includes("Displacement")) {
|
|
1371
|
+
const heightTex = textureFromSocket(links, socketByName(inputsOf(dispNode), "Height"), false, ctx);
|
|
1372
|
+
if (heightTex) {
|
|
1373
|
+
const scale = num(socketConst(socketByName(inputsOf(dispNode), "Scale")));
|
|
1374
|
+
const s = scale !== void 0 && scale > 0 ? scale : 1;
|
|
1375
|
+
const mid = num(socketConst(socketByName(inputsOf(dispNode), "Midlevel")));
|
|
1376
|
+
if (material.displacementMap !== void 0) {
|
|
1377
|
+
material.displacementMap = heightTex;
|
|
1378
|
+
material.displacementScale = s;
|
|
1379
|
+
material.displacementBias = -(mid ?? 0.5) * s;
|
|
1380
|
+
}
|
|
1381
|
+
if (!material.normalMap && material.bumpMap !== void 0) {
|
|
1382
|
+
material.bumpMap = heightTex;
|
|
1383
|
+
material.bumpScale = s;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
const emSock = emission ? socketByName(inputsOf(emission), "Color") : principled ? socketByName(inputsOf(principled), "Emission Color", "Emission") : null;
|
|
1388
|
+
const emStrSock = emission ? socketByName(inputsOf(emission), "Strength") : principled ? socketByName(inputsOf(principled), "Emission Strength") : null;
|
|
1389
|
+
const emTex = textureFromSocket(links, emSock, true, ctx);
|
|
1390
|
+
let emCol = socketConst(emSock);
|
|
1391
|
+
if (emTex && (!emCol || emCol.length < 3 || !emCol[0] && !emCol[1] && !emCol[2])) emCol = [1, 1, 1];
|
|
1392
|
+
if (emCol && emCol.length >= 3 && (emCol[0] || emCol[1] || emCol[2] || emTex)) {
|
|
1393
|
+
const f = [emCol[0], emCol[1], emCol[2]];
|
|
1394
|
+
const strength = num(socketConst(emStrSock));
|
|
1395
|
+
if (typeof strength === "number") for (let i = 0; i < 3; i++) f[i] *= strength;
|
|
1396
|
+
const peak = Math.max(f[0], f[1], f[2]);
|
|
1397
|
+
if (peak > 1) {
|
|
1398
|
+
material.emissiveIntensity = peak;
|
|
1399
|
+
material.emissive.setRGB(f[0] / peak, f[1] / peak, f[2] / peak);
|
|
1400
|
+
} else material.emissive.setRGB(f[0], f[1], f[2]);
|
|
1401
|
+
}
|
|
1402
|
+
if (!applied) {
|
|
1403
|
+
if (mat.r !== void 0) material.color.setRGB(mat.r, mat.g, mat.b);
|
|
1404
|
+
material.roughness = mat.roughness !== void 0 ? mat.roughness : 0.4;
|
|
1405
|
+
material.metalness = mat.metallic !== void 0 ? mat.metallic : 0;
|
|
1406
|
+
}
|
|
890
1407
|
return material;
|
|
891
1408
|
}
|
|
892
1409
|
function createMesh(object, loaded, ctx) {
|
|
893
1410
|
if (!object.data) {
|
|
894
1411
|
return void 0;
|
|
895
1412
|
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1413
|
+
let geometry = loaded.get(object.data);
|
|
1414
|
+
if (!geometry) {
|
|
1415
|
+
geometry = createBufferGeometry(object.data, ctx);
|
|
1416
|
+
loaded.set(object.data, geometry);
|
|
1417
|
+
}
|
|
1418
|
+
const matData = object.data.mat;
|
|
1419
|
+
const slots = Array.isArray(matData) ? matData : matData ? [matData] : [];
|
|
1420
|
+
const buildMaterial = (m) => {
|
|
1421
|
+
if (!m) {
|
|
1422
|
+
const d = new ctx.MeshPhysicalMaterial();
|
|
1423
|
+
d.side = DoubleSide;
|
|
1424
|
+
return d;
|
|
1425
|
+
}
|
|
1426
|
+
const cached = loaded.get(m);
|
|
1427
|
+
if (cached) return cached;
|
|
1428
|
+
const created = createMaterial(m, ctx);
|
|
1429
|
+
loaded.set(m, created);
|
|
1430
|
+
return created;
|
|
1431
|
+
};
|
|
1432
|
+
const hasGroups = !!(geometry.groups && geometry.groups.length);
|
|
1433
|
+
let material;
|
|
1434
|
+
if (hasGroups) {
|
|
1435
|
+
material = slots.map(buildMaterial);
|
|
1436
|
+
let maxIdx = 0;
|
|
1437
|
+
for (const g of geometry.groups) if (g.materialIndex > maxIdx) maxIdx = g.materialIndex;
|
|
1438
|
+
while (material.length <= maxIdx) material.push(buildMaterial(null));
|
|
1439
|
+
} else {
|
|
1440
|
+
material = buildMaterial(slots[0]);
|
|
1441
|
+
}
|
|
901
1442
|
const mesh = new ctx.Mesh(geometry, material);
|
|
902
1443
|
mesh.castShadow = true;
|
|
903
1444
|
mesh.receiveShadow = true;
|
|
@@ -997,25 +1538,743 @@ function setTransform(object, obj) {
|
|
|
997
1538
|
obj.updateMatrix();
|
|
998
1539
|
if (obj.setDirty) obj.setDirty();
|
|
999
1540
|
}
|
|
1541
|
+
var ab = ArrayBuffer, u8 = Uint8Array, u16 = Uint16Array, i16 = Int16Array, i32 = Int32Array;
|
|
1542
|
+
var slc = function(v, s, e) {
|
|
1543
|
+
if (u8.prototype.slice)
|
|
1544
|
+
return u8.prototype.slice.call(v, s, e);
|
|
1545
|
+
if (s == null || s < 0)
|
|
1546
|
+
s = 0;
|
|
1547
|
+
if (e == null || e > v.length)
|
|
1548
|
+
e = v.length;
|
|
1549
|
+
var n = new u8(e - s);
|
|
1550
|
+
n.set(v.subarray(s, e));
|
|
1551
|
+
return n;
|
|
1552
|
+
};
|
|
1553
|
+
var fill = function(v, n, s, e) {
|
|
1554
|
+
if (u8.prototype.fill)
|
|
1555
|
+
return u8.prototype.fill.call(v, n, s, e);
|
|
1556
|
+
if (s == null || s < 0)
|
|
1557
|
+
s = 0;
|
|
1558
|
+
if (e == null || e > v.length)
|
|
1559
|
+
e = v.length;
|
|
1560
|
+
for (; s < e; ++s)
|
|
1561
|
+
v[s] = n;
|
|
1562
|
+
return v;
|
|
1563
|
+
};
|
|
1564
|
+
var cpw = function(v, t, s, e) {
|
|
1565
|
+
if (u8.prototype.copyWithin)
|
|
1566
|
+
return u8.prototype.copyWithin.call(v, t, s, e);
|
|
1567
|
+
if (s == null || s < 0)
|
|
1568
|
+
s = 0;
|
|
1569
|
+
if (e == null || e > v.length)
|
|
1570
|
+
e = v.length;
|
|
1571
|
+
while (s < e) {
|
|
1572
|
+
v[t++] = v[s++];
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
var ec = [
|
|
1576
|
+
"invalid zstd data",
|
|
1577
|
+
"window size too large (>2046MB)",
|
|
1578
|
+
"invalid block type",
|
|
1579
|
+
"FSE accuracy too high",
|
|
1580
|
+
"match distance too far back",
|
|
1581
|
+
"unexpected EOF"
|
|
1582
|
+
];
|
|
1583
|
+
var err = function(ind, msg, nt) {
|
|
1584
|
+
var e = new Error(msg || ec[ind]);
|
|
1585
|
+
e.code = ind;
|
|
1586
|
+
if (Error.captureStackTrace)
|
|
1587
|
+
Error.captureStackTrace(e, err);
|
|
1588
|
+
if (!nt)
|
|
1589
|
+
throw e;
|
|
1590
|
+
return e;
|
|
1591
|
+
};
|
|
1592
|
+
var rb = function(d, b, n) {
|
|
1593
|
+
var i = 0, o = 0;
|
|
1594
|
+
for (; i < n; ++i)
|
|
1595
|
+
o |= d[b++] << (i << 3);
|
|
1596
|
+
return o;
|
|
1597
|
+
};
|
|
1598
|
+
var b4 = function(d, b) {
|
|
1599
|
+
return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
|
|
1600
|
+
};
|
|
1601
|
+
var rzfh = function(dat, w) {
|
|
1602
|
+
var n3 = dat[0] | dat[1] << 8 | dat[2] << 16;
|
|
1603
|
+
if (n3 == 3126568 && dat[3] == 253) {
|
|
1604
|
+
var flg = dat[4];
|
|
1605
|
+
var ss = flg >> 5 & 1, cc = flg >> 2 & 1, df = flg & 3, fcf = flg >> 6;
|
|
1606
|
+
if (flg & 8)
|
|
1607
|
+
err(0);
|
|
1608
|
+
var bt = 6 - ss;
|
|
1609
|
+
var db = df == 3 ? 4 : df;
|
|
1610
|
+
var di = rb(dat, bt, db);
|
|
1611
|
+
bt += db;
|
|
1612
|
+
var fsb = fcf ? 1 << fcf : ss;
|
|
1613
|
+
var fss = rb(dat, bt, fsb) + (fcf == 1 && 256);
|
|
1614
|
+
var ws = fss;
|
|
1615
|
+
if (!ss) {
|
|
1616
|
+
var wb = 1 << 10 + (dat[5] >> 3);
|
|
1617
|
+
ws = wb + (wb >> 3) * (dat[5] & 7);
|
|
1618
|
+
}
|
|
1619
|
+
if (ws > 2145386496)
|
|
1620
|
+
err(1);
|
|
1621
|
+
var buf = new u8((w == 1 ? fss || ws : w ? 0 : ws) + 12);
|
|
1622
|
+
buf[0] = 1, buf[4] = 4, buf[8] = 8;
|
|
1623
|
+
return {
|
|
1624
|
+
b: bt + fsb,
|
|
1625
|
+
y: 0,
|
|
1626
|
+
l: 0,
|
|
1627
|
+
d: di,
|
|
1628
|
+
w: w && w != 1 ? w : buf.subarray(12),
|
|
1629
|
+
e: ws,
|
|
1630
|
+
o: new i32(buf.buffer, 0, 3),
|
|
1631
|
+
u: fss,
|
|
1632
|
+
c: cc,
|
|
1633
|
+
m: Math.min(131072, ws)
|
|
1634
|
+
};
|
|
1635
|
+
} else if ((n3 >> 4 | dat[3] << 20) == 25481893) {
|
|
1636
|
+
return b4(dat, 4) + 8;
|
|
1637
|
+
}
|
|
1638
|
+
err(0);
|
|
1639
|
+
};
|
|
1640
|
+
var msb = function(val) {
|
|
1641
|
+
var bits = 0;
|
|
1642
|
+
for (; 1 << bits <= val; ++bits)
|
|
1643
|
+
;
|
|
1644
|
+
return bits - 1;
|
|
1645
|
+
};
|
|
1646
|
+
var rfse = function(dat, bt, mal) {
|
|
1647
|
+
var tpos = (bt << 3) + 4;
|
|
1648
|
+
var al = (dat[bt] & 15) + 5;
|
|
1649
|
+
if (al > mal)
|
|
1650
|
+
err(3);
|
|
1651
|
+
var sz = 1 << al;
|
|
1652
|
+
var probs = sz, sym = -1, re = -1, i = -1, ht = sz;
|
|
1653
|
+
var buf = new ab(512 + (sz << 2));
|
|
1654
|
+
var freq = new i16(buf, 0, 256);
|
|
1655
|
+
var dstate = new u16(buf, 0, 256);
|
|
1656
|
+
var nstate = new u16(buf, 512, sz);
|
|
1657
|
+
var bb1 = 512 + (sz << 1);
|
|
1658
|
+
var syms = new u8(buf, bb1, sz);
|
|
1659
|
+
var nbits = new u8(buf, bb1 + sz);
|
|
1660
|
+
while (sym < 255 && probs > 0) {
|
|
1661
|
+
var bits = msb(probs + 1);
|
|
1662
|
+
var cbt = tpos >> 3;
|
|
1663
|
+
var msk = (1 << bits + 1) - 1;
|
|
1664
|
+
var val = (dat[cbt] | dat[cbt + 1] << 8 | dat[cbt + 2] << 16) >> (tpos & 7) & msk;
|
|
1665
|
+
var msk1fb = (1 << bits) - 1;
|
|
1666
|
+
var msv = msk - probs - 1;
|
|
1667
|
+
var sval = val & msk1fb;
|
|
1668
|
+
if (sval < msv)
|
|
1669
|
+
tpos += bits, val = sval;
|
|
1670
|
+
else {
|
|
1671
|
+
tpos += bits + 1;
|
|
1672
|
+
if (val > msk1fb)
|
|
1673
|
+
val -= msv;
|
|
1674
|
+
}
|
|
1675
|
+
freq[++sym] = --val;
|
|
1676
|
+
if (val == -1) {
|
|
1677
|
+
probs += val;
|
|
1678
|
+
syms[--ht] = sym;
|
|
1679
|
+
} else
|
|
1680
|
+
probs -= val;
|
|
1681
|
+
if (!val) {
|
|
1682
|
+
do {
|
|
1683
|
+
var rbt = tpos >> 3;
|
|
1684
|
+
re = (dat[rbt] | dat[rbt + 1] << 8) >> (tpos & 7) & 3;
|
|
1685
|
+
tpos += 2;
|
|
1686
|
+
sym += re;
|
|
1687
|
+
} while (re == 3);
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
if (sym > 255 || probs)
|
|
1691
|
+
err(0);
|
|
1692
|
+
var sympos = 0;
|
|
1693
|
+
var sstep = (sz >> 1) + (sz >> 3) + 3;
|
|
1694
|
+
var smask = sz - 1;
|
|
1695
|
+
for (var s = 0; s <= sym; ++s) {
|
|
1696
|
+
var sf = freq[s];
|
|
1697
|
+
if (sf < 1) {
|
|
1698
|
+
dstate[s] = -sf;
|
|
1699
|
+
continue;
|
|
1700
|
+
}
|
|
1701
|
+
for (i = 0; i < sf; ++i) {
|
|
1702
|
+
syms[sympos] = s;
|
|
1703
|
+
do {
|
|
1704
|
+
sympos = sympos + sstep & smask;
|
|
1705
|
+
} while (sympos >= ht);
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
if (sympos)
|
|
1709
|
+
err(0);
|
|
1710
|
+
for (i = 0; i < sz; ++i) {
|
|
1711
|
+
var ns = dstate[syms[i]]++;
|
|
1712
|
+
var nb = nbits[i] = al - msb(ns);
|
|
1713
|
+
nstate[i] = (ns << nb) - sz;
|
|
1714
|
+
}
|
|
1715
|
+
return [tpos + 7 >> 3, {
|
|
1716
|
+
b: al,
|
|
1717
|
+
s: syms,
|
|
1718
|
+
n: nbits,
|
|
1719
|
+
t: nstate
|
|
1720
|
+
}];
|
|
1721
|
+
};
|
|
1722
|
+
var rhu = function(dat, bt) {
|
|
1723
|
+
var i = 0, wc = -1;
|
|
1724
|
+
var buf = new u8(292), hb = dat[bt];
|
|
1725
|
+
var hw = buf.subarray(0, 256);
|
|
1726
|
+
var rc = buf.subarray(256, 268);
|
|
1727
|
+
var ri = new u16(buf.buffer, 268);
|
|
1728
|
+
if (hb < 128) {
|
|
1729
|
+
var _a = rfse(dat, bt + 1, 6), ebt = _a[0], fdt = _a[1];
|
|
1730
|
+
bt += hb;
|
|
1731
|
+
var epos = ebt << 3;
|
|
1732
|
+
var lb = dat[bt];
|
|
1733
|
+
if (!lb)
|
|
1734
|
+
err(0);
|
|
1735
|
+
var st1 = 0, st2 = 0, btr1 = fdt.b, btr2 = btr1;
|
|
1736
|
+
var fpos = (++bt << 3) - 8 + msb(lb);
|
|
1737
|
+
for (; ; ) {
|
|
1738
|
+
fpos -= btr1;
|
|
1739
|
+
if (fpos < epos)
|
|
1740
|
+
break;
|
|
1741
|
+
var cbt = fpos >> 3;
|
|
1742
|
+
st1 += (dat[cbt] | dat[cbt + 1] << 8) >> (fpos & 7) & (1 << btr1) - 1;
|
|
1743
|
+
hw[++wc] = fdt.s[st1];
|
|
1744
|
+
fpos -= btr2;
|
|
1745
|
+
if (fpos < epos)
|
|
1746
|
+
break;
|
|
1747
|
+
cbt = fpos >> 3;
|
|
1748
|
+
st2 += (dat[cbt] | dat[cbt + 1] << 8) >> (fpos & 7) & (1 << btr2) - 1;
|
|
1749
|
+
hw[++wc] = fdt.s[st2];
|
|
1750
|
+
btr1 = fdt.n[st1];
|
|
1751
|
+
st1 = fdt.t[st1];
|
|
1752
|
+
btr2 = fdt.n[st2];
|
|
1753
|
+
st2 = fdt.t[st2];
|
|
1754
|
+
}
|
|
1755
|
+
if (++wc > 255)
|
|
1756
|
+
err(0);
|
|
1757
|
+
} else {
|
|
1758
|
+
wc = hb - 127;
|
|
1759
|
+
for (; i < wc; i += 2) {
|
|
1760
|
+
var byte = dat[++bt];
|
|
1761
|
+
hw[i] = byte >> 4;
|
|
1762
|
+
hw[i + 1] = byte & 15;
|
|
1763
|
+
}
|
|
1764
|
+
++bt;
|
|
1765
|
+
}
|
|
1766
|
+
var wes = 0;
|
|
1767
|
+
for (i = 0; i < wc; ++i) {
|
|
1768
|
+
var wt = hw[i];
|
|
1769
|
+
if (wt > 11)
|
|
1770
|
+
err(0);
|
|
1771
|
+
wes += wt && 1 << wt - 1;
|
|
1772
|
+
}
|
|
1773
|
+
var mb = msb(wes) + 1;
|
|
1774
|
+
var ts = 1 << mb;
|
|
1775
|
+
var rem = ts - wes;
|
|
1776
|
+
if (rem & rem - 1)
|
|
1777
|
+
err(0);
|
|
1778
|
+
hw[wc++] = msb(rem) + 1;
|
|
1779
|
+
for (i = 0; i < wc; ++i) {
|
|
1780
|
+
var wt = hw[i];
|
|
1781
|
+
++rc[hw[i] = wt && mb + 1 - wt];
|
|
1782
|
+
}
|
|
1783
|
+
var hbuf = new u8(ts << 1);
|
|
1784
|
+
var syms = hbuf.subarray(0, ts), nb = hbuf.subarray(ts);
|
|
1785
|
+
ri[mb] = 0;
|
|
1786
|
+
for (i = mb; i > 0; --i) {
|
|
1787
|
+
var pv = ri[i];
|
|
1788
|
+
fill(nb, i, pv, ri[i - 1] = pv + rc[i] * (1 << mb - i));
|
|
1789
|
+
}
|
|
1790
|
+
if (ri[0] != ts)
|
|
1791
|
+
err(0);
|
|
1792
|
+
for (i = 0; i < wc; ++i) {
|
|
1793
|
+
var bits = hw[i];
|
|
1794
|
+
if (bits) {
|
|
1795
|
+
var code = ri[bits];
|
|
1796
|
+
fill(syms, i, code, ri[bits] = code + (1 << mb - bits));
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
return [bt, {
|
|
1800
|
+
n: nb,
|
|
1801
|
+
b: mb,
|
|
1802
|
+
s: syms
|
|
1803
|
+
}];
|
|
1804
|
+
};
|
|
1805
|
+
var dllt = rfse(/* @__PURE__ */ new u8([
|
|
1806
|
+
81,
|
|
1807
|
+
16,
|
|
1808
|
+
99,
|
|
1809
|
+
140,
|
|
1810
|
+
49,
|
|
1811
|
+
198,
|
|
1812
|
+
24,
|
|
1813
|
+
99,
|
|
1814
|
+
12,
|
|
1815
|
+
33,
|
|
1816
|
+
196,
|
|
1817
|
+
24,
|
|
1818
|
+
99,
|
|
1819
|
+
102,
|
|
1820
|
+
102,
|
|
1821
|
+
134,
|
|
1822
|
+
70,
|
|
1823
|
+
146,
|
|
1824
|
+
4
|
|
1825
|
+
]), 0, 6)[1];
|
|
1826
|
+
var dmlt = rfse(/* @__PURE__ */ new u8([
|
|
1827
|
+
33,
|
|
1828
|
+
20,
|
|
1829
|
+
196,
|
|
1830
|
+
24,
|
|
1831
|
+
99,
|
|
1832
|
+
140,
|
|
1833
|
+
33,
|
|
1834
|
+
132,
|
|
1835
|
+
16,
|
|
1836
|
+
66,
|
|
1837
|
+
8,
|
|
1838
|
+
33,
|
|
1839
|
+
132,
|
|
1840
|
+
16,
|
|
1841
|
+
66,
|
|
1842
|
+
8,
|
|
1843
|
+
33,
|
|
1844
|
+
68,
|
|
1845
|
+
68,
|
|
1846
|
+
68,
|
|
1847
|
+
68,
|
|
1848
|
+
68,
|
|
1849
|
+
68,
|
|
1850
|
+
68,
|
|
1851
|
+
68,
|
|
1852
|
+
36,
|
|
1853
|
+
9
|
|
1854
|
+
]), 0, 6)[1];
|
|
1855
|
+
var doct = rfse(/* @__PURE__ */ new u8([
|
|
1856
|
+
32,
|
|
1857
|
+
132,
|
|
1858
|
+
16,
|
|
1859
|
+
66,
|
|
1860
|
+
102,
|
|
1861
|
+
70,
|
|
1862
|
+
68,
|
|
1863
|
+
68,
|
|
1864
|
+
68,
|
|
1865
|
+
68,
|
|
1866
|
+
36,
|
|
1867
|
+
73,
|
|
1868
|
+
2
|
|
1869
|
+
]), 0, 5)[1];
|
|
1870
|
+
var b2bl = function(b, s) {
|
|
1871
|
+
var len = b.length, bl = new i32(len);
|
|
1872
|
+
for (var i = 0; i < len; ++i) {
|
|
1873
|
+
bl[i] = s;
|
|
1874
|
+
s += 1 << b[i];
|
|
1875
|
+
}
|
|
1876
|
+
return bl;
|
|
1877
|
+
};
|
|
1878
|
+
var llb = /* @__PURE__ */ new u8((/* @__PURE__ */ new i32([
|
|
1879
|
+
0,
|
|
1880
|
+
0,
|
|
1881
|
+
0,
|
|
1882
|
+
0,
|
|
1883
|
+
16843009,
|
|
1884
|
+
50528770,
|
|
1885
|
+
134678020,
|
|
1886
|
+
202050057,
|
|
1887
|
+
269422093
|
|
1888
|
+
])).buffer, 0, 36);
|
|
1889
|
+
var llbl = /* @__PURE__ */ b2bl(llb, 0);
|
|
1890
|
+
var mlb = /* @__PURE__ */ new u8((/* @__PURE__ */ new i32([
|
|
1891
|
+
0,
|
|
1892
|
+
0,
|
|
1893
|
+
0,
|
|
1894
|
+
0,
|
|
1895
|
+
0,
|
|
1896
|
+
0,
|
|
1897
|
+
0,
|
|
1898
|
+
0,
|
|
1899
|
+
16843009,
|
|
1900
|
+
50528770,
|
|
1901
|
+
117769220,
|
|
1902
|
+
185207048,
|
|
1903
|
+
252579084,
|
|
1904
|
+
16
|
|
1905
|
+
])).buffer, 0, 53);
|
|
1906
|
+
var mlbl = /* @__PURE__ */ b2bl(mlb, 3);
|
|
1907
|
+
var dhu = function(dat, out, hu) {
|
|
1908
|
+
var len = dat.length, ss = out.length, lb = dat[len - 1], msk = (1 << hu.b) - 1, eb = -hu.b;
|
|
1909
|
+
if (!lb)
|
|
1910
|
+
err(0);
|
|
1911
|
+
var st = 0, btr = hu.b, pos = (len << 3) - 8 + msb(lb) - btr, i = -1;
|
|
1912
|
+
for (; pos > eb && i < ss; ) {
|
|
1913
|
+
var cbt = pos >> 3;
|
|
1914
|
+
var val = (dat[cbt] | dat[cbt + 1] << 8 | dat[cbt + 2] << 16) >> (pos & 7);
|
|
1915
|
+
st = (st << btr | val) & msk;
|
|
1916
|
+
out[++i] = hu.s[st];
|
|
1917
|
+
pos -= btr = hu.n[st];
|
|
1918
|
+
}
|
|
1919
|
+
if (pos != eb || i + 1 != ss)
|
|
1920
|
+
err(0);
|
|
1921
|
+
};
|
|
1922
|
+
var dhu4 = function(dat, out, hu) {
|
|
1923
|
+
var bt = 6;
|
|
1924
|
+
var ss = out.length, sz1 = ss + 3 >> 2, sz2 = sz1 << 1, sz3 = sz1 + sz2;
|
|
1925
|
+
dhu(dat.subarray(bt, bt += dat[0] | dat[1] << 8), out.subarray(0, sz1), hu);
|
|
1926
|
+
dhu(dat.subarray(bt, bt += dat[2] | dat[3] << 8), out.subarray(sz1, sz2), hu);
|
|
1927
|
+
dhu(dat.subarray(bt, bt += dat[4] | dat[5] << 8), out.subarray(sz2, sz3), hu);
|
|
1928
|
+
dhu(dat.subarray(bt), out.subarray(sz3), hu);
|
|
1929
|
+
};
|
|
1930
|
+
var rzb = function(dat, st, out) {
|
|
1931
|
+
var _a;
|
|
1932
|
+
var bt = st.b;
|
|
1933
|
+
var b0 = dat[bt], btype = b0 >> 1 & 3;
|
|
1934
|
+
st.l = b0 & 1;
|
|
1935
|
+
var sz = b0 >> 3 | dat[bt + 1] << 5 | dat[bt + 2] << 13;
|
|
1936
|
+
var ebt = (bt += 3) + sz;
|
|
1937
|
+
if (btype == 1) {
|
|
1938
|
+
if (bt >= dat.length)
|
|
1939
|
+
return;
|
|
1940
|
+
st.b = bt + 1;
|
|
1941
|
+
if (out) {
|
|
1942
|
+
fill(out, dat[bt], st.y, st.y += sz);
|
|
1943
|
+
return out;
|
|
1944
|
+
}
|
|
1945
|
+
return fill(new u8(sz), dat[bt]);
|
|
1946
|
+
}
|
|
1947
|
+
if (ebt > dat.length)
|
|
1948
|
+
return;
|
|
1949
|
+
if (btype == 0) {
|
|
1950
|
+
st.b = ebt;
|
|
1951
|
+
if (out) {
|
|
1952
|
+
out.set(dat.subarray(bt, ebt), st.y);
|
|
1953
|
+
st.y += sz;
|
|
1954
|
+
return out;
|
|
1955
|
+
}
|
|
1956
|
+
return slc(dat, bt, ebt);
|
|
1957
|
+
}
|
|
1958
|
+
if (btype == 2) {
|
|
1959
|
+
var b3 = dat[bt], lbt = b3 & 3, sf = b3 >> 2 & 3;
|
|
1960
|
+
var lss = b3 >> 4, lcs = 0, s4 = 0;
|
|
1961
|
+
if (lbt < 2) {
|
|
1962
|
+
if (sf & 1)
|
|
1963
|
+
lss |= dat[++bt] << 4 | (sf & 2 && dat[++bt] << 12);
|
|
1964
|
+
else
|
|
1965
|
+
lss = b3 >> 3;
|
|
1966
|
+
} else {
|
|
1967
|
+
s4 = sf;
|
|
1968
|
+
if (sf < 2)
|
|
1969
|
+
lss |= (dat[++bt] & 63) << 4, lcs = dat[bt] >> 6 | dat[++bt] << 2;
|
|
1970
|
+
else if (sf == 2)
|
|
1971
|
+
lss |= dat[++bt] << 4 | (dat[++bt] & 3) << 12, lcs = dat[bt] >> 2 | dat[++bt] << 6;
|
|
1972
|
+
else
|
|
1973
|
+
lss |= dat[++bt] << 4 | (dat[++bt] & 63) << 12, lcs = dat[bt] >> 6 | dat[++bt] << 2 | dat[++bt] << 10;
|
|
1974
|
+
}
|
|
1975
|
+
++bt;
|
|
1976
|
+
var buf = out ? out.subarray(st.y, st.y + st.m) : new u8(st.m);
|
|
1977
|
+
var spl = buf.length - lss;
|
|
1978
|
+
if (lbt == 0)
|
|
1979
|
+
buf.set(dat.subarray(bt, bt += lss), spl);
|
|
1980
|
+
else if (lbt == 1)
|
|
1981
|
+
fill(buf, dat[bt++], spl);
|
|
1982
|
+
else {
|
|
1983
|
+
var hu = st.h;
|
|
1984
|
+
if (lbt == 2) {
|
|
1985
|
+
var hud = rhu(dat, bt);
|
|
1986
|
+
lcs += bt - (bt = hud[0]);
|
|
1987
|
+
st.h = hu = hud[1];
|
|
1988
|
+
} else if (!hu)
|
|
1989
|
+
err(0);
|
|
1990
|
+
(s4 ? dhu4 : dhu)(dat.subarray(bt, bt += lcs), buf.subarray(spl), hu);
|
|
1991
|
+
}
|
|
1992
|
+
var ns = dat[bt++];
|
|
1993
|
+
if (ns) {
|
|
1994
|
+
if (ns == 255)
|
|
1995
|
+
ns = (dat[bt++] | dat[bt++] << 8) + 32512;
|
|
1996
|
+
else if (ns > 127)
|
|
1997
|
+
ns = ns - 128 << 8 | dat[bt++];
|
|
1998
|
+
var scm = dat[bt++];
|
|
1999
|
+
if (scm & 3)
|
|
2000
|
+
err(0);
|
|
2001
|
+
var dts = [dmlt, doct, dllt];
|
|
2002
|
+
for (var i = 2; i > -1; --i) {
|
|
2003
|
+
var md = scm >> (i << 1) + 2 & 3;
|
|
2004
|
+
if (md == 1) {
|
|
2005
|
+
var rbuf = new u8([0, 0, dat[bt++]]);
|
|
2006
|
+
dts[i] = {
|
|
2007
|
+
s: rbuf.subarray(2, 3),
|
|
2008
|
+
n: rbuf.subarray(0, 1),
|
|
2009
|
+
t: new u16(rbuf.buffer, 0, 1),
|
|
2010
|
+
b: 0
|
|
2011
|
+
};
|
|
2012
|
+
} else if (md == 2) {
|
|
2013
|
+
_a = rfse(dat, bt, 9 - (i & 1)), bt = _a[0], dts[i] = _a[1];
|
|
2014
|
+
} else if (md == 3) {
|
|
2015
|
+
if (!st.t)
|
|
2016
|
+
err(0);
|
|
2017
|
+
dts[i] = st.t[i];
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
var _b = st.t = dts, mlt = _b[0], oct = _b[1], llt = _b[2];
|
|
2021
|
+
var lb = dat[ebt - 1];
|
|
2022
|
+
if (!lb)
|
|
2023
|
+
err(0);
|
|
2024
|
+
var spos = (ebt << 3) - 8 + msb(lb) - llt.b, cbt = spos >> 3, oubt = 0;
|
|
2025
|
+
var lst = (dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << llt.b) - 1;
|
|
2026
|
+
cbt = (spos -= oct.b) >> 3;
|
|
2027
|
+
var ost = (dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << oct.b) - 1;
|
|
2028
|
+
cbt = (spos -= mlt.b) >> 3;
|
|
2029
|
+
var mst = (dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << mlt.b) - 1;
|
|
2030
|
+
for (++ns; --ns; ) {
|
|
2031
|
+
var llc = llt.s[lst];
|
|
2032
|
+
var lbtr = llt.n[lst];
|
|
2033
|
+
var mlc = mlt.s[mst];
|
|
2034
|
+
var mbtr = mlt.n[mst];
|
|
2035
|
+
var ofc = oct.s[ost];
|
|
2036
|
+
var obtr = oct.n[ost];
|
|
2037
|
+
cbt = (spos -= ofc) >> 3;
|
|
2038
|
+
var ofp = 1 << ofc;
|
|
2039
|
+
var off = ofp + ((dat[cbt] | dat[cbt + 1] << 8 | dat[cbt + 2] << 16 | dat[cbt + 3] << 24) >>> (spos & 7) & ofp - 1);
|
|
2040
|
+
cbt = (spos -= mlb[mlc]) >> 3;
|
|
2041
|
+
var ml = mlbl[mlc] + ((dat[cbt] | dat[cbt + 1] << 8 | dat[cbt + 2] << 16) >> (spos & 7) & (1 << mlb[mlc]) - 1);
|
|
2042
|
+
cbt = (spos -= llb[llc]) >> 3;
|
|
2043
|
+
var ll = llbl[llc] + ((dat[cbt] | dat[cbt + 1] << 8 | dat[cbt + 2] << 16) >> (spos & 7) & (1 << llb[llc]) - 1);
|
|
2044
|
+
cbt = (spos -= lbtr) >> 3;
|
|
2045
|
+
lst = llt.t[lst] + ((dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << lbtr) - 1);
|
|
2046
|
+
cbt = (spos -= mbtr) >> 3;
|
|
2047
|
+
mst = mlt.t[mst] + ((dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << mbtr) - 1);
|
|
2048
|
+
cbt = (spos -= obtr) >> 3;
|
|
2049
|
+
ost = oct.t[ost] + ((dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << obtr) - 1);
|
|
2050
|
+
if (off > 3) {
|
|
2051
|
+
st.o[2] = st.o[1];
|
|
2052
|
+
st.o[1] = st.o[0];
|
|
2053
|
+
st.o[0] = off -= 3;
|
|
2054
|
+
} else {
|
|
2055
|
+
var idx = off - (ll != 0);
|
|
2056
|
+
if (idx) {
|
|
2057
|
+
off = idx == 3 ? st.o[0] - 1 : st.o[idx];
|
|
2058
|
+
if (idx > 1)
|
|
2059
|
+
st.o[2] = st.o[1];
|
|
2060
|
+
st.o[1] = st.o[0];
|
|
2061
|
+
st.o[0] = off;
|
|
2062
|
+
} else
|
|
2063
|
+
off = st.o[0];
|
|
2064
|
+
}
|
|
2065
|
+
for (var i = 0; i < ll; ++i) {
|
|
2066
|
+
buf[oubt + i] = buf[spl + i];
|
|
2067
|
+
}
|
|
2068
|
+
oubt += ll, spl += ll;
|
|
2069
|
+
var stin = oubt - off;
|
|
2070
|
+
if (stin < 0) {
|
|
2071
|
+
var len = -stin;
|
|
2072
|
+
var bs = st.e + stin;
|
|
2073
|
+
if (len > ml)
|
|
2074
|
+
len = ml;
|
|
2075
|
+
for (var i = 0; i < len; ++i) {
|
|
2076
|
+
buf[oubt + i] = st.w[bs + i];
|
|
2077
|
+
}
|
|
2078
|
+
oubt += len, ml -= len, stin = 0;
|
|
2079
|
+
}
|
|
2080
|
+
for (var i = 0; i < ml; ++i) {
|
|
2081
|
+
buf[oubt + i] = buf[stin + i];
|
|
2082
|
+
}
|
|
2083
|
+
oubt += ml;
|
|
2084
|
+
}
|
|
2085
|
+
if (oubt != spl) {
|
|
2086
|
+
while (spl < buf.length) {
|
|
2087
|
+
buf[oubt++] = buf[spl++];
|
|
2088
|
+
}
|
|
2089
|
+
} else
|
|
2090
|
+
oubt = buf.length;
|
|
2091
|
+
if (out)
|
|
2092
|
+
st.y += oubt;
|
|
2093
|
+
else
|
|
2094
|
+
buf = slc(buf, 0, oubt);
|
|
2095
|
+
} else if (out) {
|
|
2096
|
+
st.y += lss;
|
|
2097
|
+
if (spl) {
|
|
2098
|
+
for (var i = 0; i < lss; ++i) {
|
|
2099
|
+
buf[i] = buf[spl + i];
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
} else if (spl)
|
|
2103
|
+
buf = slc(buf, spl);
|
|
2104
|
+
st.b = ebt;
|
|
2105
|
+
return buf;
|
|
2106
|
+
}
|
|
2107
|
+
err(2);
|
|
2108
|
+
};
|
|
2109
|
+
var cct = function(bufs, ol) {
|
|
2110
|
+
if (bufs.length == 1)
|
|
2111
|
+
return bufs[0];
|
|
2112
|
+
var buf = new u8(ol);
|
|
2113
|
+
for (var i = 0, b = 0; i < bufs.length; ++i) {
|
|
2114
|
+
var chk = bufs[i];
|
|
2115
|
+
buf.set(chk, b);
|
|
2116
|
+
b += chk.length;
|
|
2117
|
+
}
|
|
2118
|
+
return buf;
|
|
2119
|
+
};
|
|
2120
|
+
function decompress(dat, buf) {
|
|
2121
|
+
var bufs = [], nb = +!buf;
|
|
2122
|
+
var bt = 0, ol = 0;
|
|
2123
|
+
for (; dat.length; ) {
|
|
2124
|
+
var st = rzfh(dat, nb || buf);
|
|
2125
|
+
if (typeof st == "object") {
|
|
2126
|
+
if (nb) {
|
|
2127
|
+
buf = null;
|
|
2128
|
+
if (st.w.length == st.u) {
|
|
2129
|
+
bufs.push(buf = st.w);
|
|
2130
|
+
ol += st.u;
|
|
2131
|
+
}
|
|
2132
|
+
} else {
|
|
2133
|
+
bufs.push(buf);
|
|
2134
|
+
st.e = 0;
|
|
2135
|
+
}
|
|
2136
|
+
for (; !st.l; ) {
|
|
2137
|
+
var blk = rzb(dat, st, buf);
|
|
2138
|
+
if (!blk)
|
|
2139
|
+
err(5);
|
|
2140
|
+
if (buf)
|
|
2141
|
+
st.e = st.y;
|
|
2142
|
+
else {
|
|
2143
|
+
bufs.push(blk);
|
|
2144
|
+
ol += blk.length;
|
|
2145
|
+
cpw(st.w, 0, blk.length);
|
|
2146
|
+
st.w.set(blk, st.w.length - blk.length);
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
bt = st.b + st.c * 4;
|
|
2150
|
+
} else
|
|
2151
|
+
bt = st;
|
|
2152
|
+
dat = dat.subarray(bt);
|
|
2153
|
+
}
|
|
2154
|
+
return cct(bufs, ol);
|
|
2155
|
+
}
|
|
2156
|
+
function detectBlendCompression(u82) {
|
|
2157
|
+
if (u82.length >= 3 && u82[0] === 31 && u82[1] === 139 && u82[2] === 8) return "gzip";
|
|
2158
|
+
if (u82.length >= 4) {
|
|
2159
|
+
if (u82[0] === 40 && u82[1] === 181 && u82[2] === 47 && u82[3] === 253) return "zstd";
|
|
2160
|
+
if ((u82[0] & 240) === 80 && u82[1] === 42 && u82[2] === 77 && u82[3] === 24) return "zstd";
|
|
2161
|
+
}
|
|
2162
|
+
if (u82.length >= 7 && u82[0] === 66 && u82[1] === 76 && u82[2] === 69 && u82[3] === 78 && u82[4] === 68 && u82[5] === 69 && u82[6] === 82) return "none";
|
|
2163
|
+
return "unknown";
|
|
2164
|
+
}
|
|
2165
|
+
function toArrayBuffer(u82) {
|
|
2166
|
+
if (u82.byteOffset === 0 && u82.byteLength === u82.buffer.byteLength) return u82.buffer;
|
|
2167
|
+
return u82.buffer.slice(u82.byteOffset, u82.byteOffset + u82.byteLength);
|
|
2168
|
+
}
|
|
2169
|
+
function decompressBlend(buf) {
|
|
2170
|
+
const u82 = new Uint8Array(buf);
|
|
2171
|
+
const kind = detectBlendCompression(u82);
|
|
2172
|
+
if (kind === "none") return buf;
|
|
2173
|
+
let out;
|
|
2174
|
+
if (kind === "gzip") out = toArrayBuffer(gunzipSync(u82));
|
|
2175
|
+
else if (kind === "zstd") out = toArrayBuffer(decompress(u82));
|
|
2176
|
+
else {
|
|
2177
|
+
const hex = [u82[0], u82[1], u82[2], u82[3]].map((b) => (b ?? 0).toString(16).padStart(2, "0")).join(" ");
|
|
2178
|
+
throw new Error(`BlendLoadPlugin: unrecognised file magic (first 4 bytes: ${hex}). Expected 'BLENDER' literal, gzip, or zstd.`);
|
|
2179
|
+
}
|
|
2180
|
+
if (out.byteLength < 12) {
|
|
2181
|
+
throw new Error(`BlendLoadPlugin: ${kind} decompression produced ${out.byteLength} bytes, too short to be a valid .blend file.`);
|
|
2182
|
+
}
|
|
2183
|
+
return out;
|
|
2184
|
+
}
|
|
2185
|
+
function resolveExternalTexture(blenderPath, srgb, importer, blendUrl) {
|
|
2186
|
+
if (typeof document === "undefined") return null;
|
|
2187
|
+
const path = blenderPath.replace(/^\/\//, "").replace(/\\/g, "/").replace(/^\.\//, "");
|
|
2188
|
+
if (!path) return null;
|
|
2189
|
+
let url = importer.resolveURL(path);
|
|
2190
|
+
if (url === path && !/^([a-z][a-z0-9+.-]*:|\/|blob:|data:)/i.test(url)) {
|
|
2191
|
+
url = blendUrl.replace(/[?#].*$/, "").replace(/[^/]*$/, "") + path;
|
|
2192
|
+
}
|
|
2193
|
+
const isData = /\.(exr|hdr|rgbe)$/i.test(path.split(/[?#]/)[0]);
|
|
2194
|
+
let texture;
|
|
2195
|
+
if (isData) {
|
|
2196
|
+
texture = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);
|
|
2197
|
+
} else {
|
|
2198
|
+
const canvas = document.createElement("canvas");
|
|
2199
|
+
canvas.width = canvas.height = 1;
|
|
2200
|
+
const c2d = canvas.getContext("2d");
|
|
2201
|
+
if (c2d) {
|
|
2202
|
+
c2d.fillStyle = "#ffffff";
|
|
2203
|
+
c2d.fillRect(0, 0, 1, 1);
|
|
2204
|
+
}
|
|
2205
|
+
texture = new Texture(canvas);
|
|
2206
|
+
}
|
|
2207
|
+
texture.needsUpdate = true;
|
|
2208
|
+
if (srgb) texture.colorSpace = SRGBColorSpace;
|
|
2209
|
+
return { texture, url, srgb, path };
|
|
2210
|
+
}
|
|
2211
|
+
function flipDataTextureRowsY(tex) {
|
|
2212
|
+
const img = tex.image;
|
|
2213
|
+
const data = img?.data;
|
|
2214
|
+
if (!data?.length || !img.width || !img.height) return;
|
|
2215
|
+
const { width, height } = img;
|
|
2216
|
+
const elemsPerRow = data.length / height;
|
|
2217
|
+
if (!Number.isInteger(elemsPerRow)) return;
|
|
2218
|
+
const flipped = new data.constructor(data.length);
|
|
2219
|
+
for (let y = 0; y < height; y++) {
|
|
2220
|
+
flipped.set(data.subarray(y * elemsPerRow, (y + 1) * elemsPerRow), (height - 1 - y) * elemsPerRow);
|
|
2221
|
+
}
|
|
2222
|
+
const newImage = { data: flipped, width, height };
|
|
2223
|
+
tex.image = newImage;
|
|
2224
|
+
tex.source = new Source(newImage);
|
|
2225
|
+
tex.needsUpdate = true;
|
|
2226
|
+
}
|
|
2227
|
+
async function importExternalTexture(req, importer) {
|
|
2228
|
+
try {
|
|
2229
|
+
const imported = await importer.importSingle(req.url);
|
|
2230
|
+
if (imported && imported.isTexture && imported.image) {
|
|
2231
|
+
const wrapS = req.texture.wrapS, wrapT = req.texture.wrapT;
|
|
2232
|
+
req.texture.copy(imported);
|
|
2233
|
+
req.texture.wrapS = wrapS;
|
|
2234
|
+
req.texture.wrapT = wrapT;
|
|
2235
|
+
req.texture.colorSpace = req.srgb ? SRGBColorSpace : imported.colorSpace;
|
|
2236
|
+
if (imported.isDataTexture && imported.flipY === false) flipDataTextureRowsY(req.texture);
|
|
2237
|
+
req.texture.needsUpdate = true;
|
|
2238
|
+
} else {
|
|
2239
|
+
console.warn("BlendLoadPlugin - external texture not found/unsupported:", req.path);
|
|
2240
|
+
}
|
|
2241
|
+
} catch (e) {
|
|
2242
|
+
console.warn("BlendLoadPlugin - external texture failed:", req.path, e);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
1000
2245
|
const _BlendLoadPlugin = class _BlendLoadPlugin extends BaseImporterPlugin {
|
|
1001
2246
|
constructor() {
|
|
1002
2247
|
super();
|
|
1003
2248
|
this._importer = new Importer(class extends FileLoader {
|
|
1004
2249
|
async loadAsync(url, onProgress) {
|
|
1005
2250
|
this.setResponseType("arraybuffer");
|
|
1006
|
-
|
|
1007
|
-
const
|
|
2251
|
+
let res = await super.loadAsync(url, onProgress);
|
|
2252
|
+
const decompressed = decompressBlend(res);
|
|
2253
|
+
res = null;
|
|
2254
|
+
const blend = await parseBlend(decompressed);
|
|
2255
|
+
const importer = this.assetImporter;
|
|
2256
|
+
const texReqs = [];
|
|
1008
2257
|
const ctx = {
|
|
1009
2258
|
Object3D: Object3D2,
|
|
1010
2259
|
Mesh: Mesh2,
|
|
1011
2260
|
MeshPhysicalMaterial: PhysicalMaterial,
|
|
2261
|
+
MeshBasicMaterial: UnlitMaterial,
|
|
1012
2262
|
PerspectiveCamera: PerspectiveCamera0,
|
|
1013
2263
|
OrthographicCamera: OrthographicCamera0,
|
|
1014
2264
|
PointLight: PointLight2,
|
|
2265
|
+
DirectionalLight: DirectionalLight2,
|
|
2266
|
+
SpotLight: SpotLight2,
|
|
2267
|
+
AmbientLight: AmbientLight2,
|
|
1015
2268
|
BufferGeometry: BufferGeometry2,
|
|
1016
|
-
BufferAttribute
|
|
2269
|
+
BufferAttribute,
|
|
2270
|
+
loadExternalTexture: importer ? (p, srgb) => {
|
|
2271
|
+
const req = resolveExternalTexture(p, srgb, importer, url);
|
|
2272
|
+
if (req) texReqs.push(req);
|
|
2273
|
+
return req ? req.texture : null;
|
|
2274
|
+
} : void 0
|
|
1017
2275
|
};
|
|
1018
2276
|
const objects = await createObjects(blend, ctx);
|
|
2277
|
+
if (importer && texReqs.length) await Promise.all(texReqs.map((r) => importExternalTexture(r, importer)));
|
|
1019
2278
|
const root = new Object3D();
|
|
1020
2279
|
root.add(...objects);
|
|
1021
2280
|
blend.scene = root;
|
|
@@ -1027,7 +2286,10 @@ const _BlendLoadPlugin = class _BlendLoadPlugin extends BaseImporterPlugin {
|
|
|
1027
2286
|
}
|
|
1028
2287
|
return res.scene;
|
|
1029
2288
|
}
|
|
1030
|
-
}, ["blend"], ["application/x-blender"], true)
|
|
2289
|
+
}, ["blend"], ["application/x-blender"], true, (loader, assetImporter) => {
|
|
2290
|
+
if (loader) loader.assetImporter = assetImporter;
|
|
2291
|
+
return loader;
|
|
2292
|
+
});
|
|
1031
2293
|
}
|
|
1032
2294
|
};
|
|
1033
2295
|
_BlendLoadPlugin.PluginType = "BlendLoadPlugin";
|