@stowkit/three-loader 0.1.16 → 0.1.18
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/README.md +3 -3
- package/dist/MeshParser.d.ts.map +1 -1
- package/dist/StowKitLoader.d.ts +1 -1
- package/dist/StowKitPack.d.ts.map +1 -1
- package/dist/stowkit-three-loader.esm.js +97 -63
- package/dist/stowkit-three-loader.esm.js.map +1 -1
- package/dist/stowkit-three-loader.js +97 -63
- package/dist/stowkit-three-loader.js.map +1 -1
- package/package.json +36 -36
- package/public/basis/basis_transcoder.wasm +0 -0
- package/public/draco/draco_decoder.wasm +0 -0
- package/scripts/postinstall.js +37 -37
package/README.md
CHANGED
|
@@ -325,12 +325,12 @@ The package automatically copies required files on install:
|
|
|
325
325
|
|
|
326
326
|
```
|
|
327
327
|
public/
|
|
328
|
-
├── stowkit_reader.wasm # WASM reader module
|
|
329
328
|
└── stowkit/
|
|
330
|
-
├──
|
|
329
|
+
├── stowkit_reader.wasm # WASM reader module
|
|
330
|
+
├── basis/ # Basis Universal transcoder
|
|
331
331
|
│ ├── basis_transcoder.js
|
|
332
332
|
│ └── basis_transcoder.wasm
|
|
333
|
-
└── draco/
|
|
333
|
+
└── draco/ # Draco decoder
|
|
334
334
|
├── draco_decoder.js
|
|
335
335
|
├── draco_decoder.wasm
|
|
336
336
|
└── draco_wasm_wrapper.js
|
package/dist/MeshParser.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MeshParser.d.ts","sourceRoot":"","sources":["../src/MeshParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,IAAI;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,qBAAqB,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,UAAU;IAEnB;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,YAAY;
|
|
1
|
+
{"version":3,"file":"MeshParser.d.ts","sourceRoot":"","sources":["../src/MeshParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,IAAI;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,qBAAqB,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,UAAU;IAEnB;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,YAAY;IAyBxD;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,GAAG;QAClE,QAAQ,EAAE,YAAY,CAAC;QACvB,UAAU,EAAE,gBAAgB,EAAE,CAAC;QAC/B,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC5B,YAAY,EAAE,YAAY,EAAE,CAAC;QAC7B,KAAK,EAAE,IAAI,EAAE,CAAC;QACd,WAAW,EAAE,WAAW,CAAC;KAC5B;IA4LD;;OAEG;WACU,cAAc,CAAC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC;IAyCrI;;OAEG;WACU,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IA2FtJ;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;CAK5B"}
|
package/dist/StowKitLoader.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StowKitPack.d.ts","sourceRoot":"","sources":["../src/StowKitPack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD;;GAEG;AACH,qBAAa,WAAW;IACb,MAAM,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAc;gBAErB,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW;IAMnF;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAe7D;;OAEG;YACW,gBAAgB;
|
|
1
|
+
{"version":3,"file":"StowKitPack.d.ts","sourceRoot":"","sources":["../src/StowKitPack.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,13 +9,22 @@ class MeshParser {
|
|
|
9
9
|
* Parse mesh metadata from binary data
|
|
10
10
|
*/
|
|
11
11
|
static parseMeshMetadata(data) {
|
|
12
|
+
// NEW FORMAT: Skip past tag header
|
|
13
|
+
// Format: [4-byte tag_csv_length][CSV string][MeshMetadata struct]
|
|
12
14
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
15
|
+
const tagCsvLength = view.getUint32(0, true);
|
|
16
|
+
const metadataOffset = 4 + tagCsvLength;
|
|
17
|
+
if (metadataOffset >= data.length) {
|
|
18
|
+
throw new Error('Invalid metadata: tag header exceeds bounds');
|
|
19
|
+
}
|
|
20
|
+
const actualMetadata = data.slice(metadataOffset);
|
|
21
|
+
const metaView = new DataView(actualMetadata.buffer, actualMetadata.byteOffset, actualMetadata.byteLength);
|
|
13
22
|
// MeshMetadata structure (140 bytes total when packed)
|
|
14
23
|
const metadata = {
|
|
15
|
-
meshGeometryCount:
|
|
16
|
-
materialCount:
|
|
17
|
-
nodeCount:
|
|
18
|
-
stringId: this.readString(
|
|
24
|
+
meshGeometryCount: metaView.getUint32(0, true),
|
|
25
|
+
materialCount: metaView.getUint32(4, true),
|
|
26
|
+
nodeCount: metaView.getUint32(8, true),
|
|
27
|
+
stringId: this.readString(actualMetadata.slice(12, 140)) // 128 bytes for string
|
|
19
28
|
};
|
|
20
29
|
return metadata;
|
|
21
30
|
}
|
|
@@ -23,21 +32,24 @@ class MeshParser {
|
|
|
23
32
|
* Parse complete mesh data including geometry, materials, and nodes
|
|
24
33
|
*/
|
|
25
34
|
static parseMeshData(metadataBlob, dataBlob) {
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const metadata = this.parseMeshMetadata(metadataBlob);
|
|
31
|
-
// Check if the metadata blob contains
|
|
32
|
-
|
|
35
|
+
// NEW FORMAT: Account for tag header at front
|
|
36
|
+
const view = new DataView(metadataBlob.buffer, metadataBlob.byteOffset, metadataBlob.byteLength);
|
|
37
|
+
const tagCsvLength = view.getUint32(0, true);
|
|
38
|
+
const tagHeaderSize = 4 + tagCsvLength;
|
|
39
|
+
const metadata = this.parseMeshMetadata(metadataBlob); // This already handles tag header
|
|
40
|
+
// Check if the metadata blob contains all the mesh info (shifted by tag header)
|
|
41
|
+
// Total expected size = tagHeaderSize + 140 (MeshMetadata) + geometries + materials + nodes
|
|
42
|
+
const expectedMetadataSize = tagHeaderSize + 140 +
|
|
33
43
|
(metadata.meshGeometryCount * 40) + // Draco compressed (40 bytes each)
|
|
34
44
|
(metadata.materialCount * 196) + // MaterialData header
|
|
35
45
|
(metadata.nodeCount * 116);
|
|
36
46
|
let hasExtendedMetadata = metadataBlob.length >= expectedMetadataSize;
|
|
37
|
-
// If metadata
|
|
47
|
+
// If metadata has everything, read from metadataBlob (accounting for tag header)
|
|
48
|
+
// Otherwise, read from dataBlob (no tag header there)
|
|
38
49
|
const sourceBlob = hasExtendedMetadata ? metadataBlob : dataBlob;
|
|
39
50
|
const metaView = new DataView(sourceBlob.buffer, sourceBlob.byteOffset, sourceBlob.byteLength);
|
|
40
|
-
|
|
51
|
+
// Offset: skip tag header + MeshMetadata struct if reading from metadata blob
|
|
52
|
+
let offset = hasExtendedMetadata ? (tagHeaderSize + 140) : 0;
|
|
41
53
|
// Parse geometry infos (now Draco compressed!)
|
|
42
54
|
const geometries = [];
|
|
43
55
|
for (let i = 0; i < metadata.meshGeometryCount; i++) {
|
|
@@ -156,10 +168,16 @@ class MeshParser {
|
|
|
156
168
|
});
|
|
157
169
|
// Apply properties
|
|
158
170
|
for (const prop of matData.properties) {
|
|
159
|
-
|
|
160
|
-
|
|
171
|
+
const fieldName = prop.fieldName.toLowerCase();
|
|
172
|
+
if (fieldName === 'tint' || fieldName.includes('color')) {
|
|
161
173
|
mat.color = new THREE.Color(prop.value[0], prop.value[1], prop.value[2]);
|
|
162
174
|
}
|
|
175
|
+
else if (fieldName === 'alphatest') {
|
|
176
|
+
if (prop.value[0] > 0) {
|
|
177
|
+
mat.alphaTest = 0.5;
|
|
178
|
+
mat.transparent = true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
163
181
|
}
|
|
164
182
|
materials.push(mat);
|
|
165
183
|
}
|
|
@@ -327,15 +345,20 @@ class StowKitPack {
|
|
|
327
345
|
* Parse skinned mesh from binary data
|
|
328
346
|
*/
|
|
329
347
|
async parseSkinnedMesh(metadata, data) {
|
|
330
|
-
//
|
|
348
|
+
// NEW FORMAT: Skip past tag header
|
|
331
349
|
const view = new DataView(metadata.buffer, metadata.byteOffset, metadata.byteLength);
|
|
350
|
+
const tagCsvLength = view.getUint32(0, true);
|
|
351
|
+
const tagHeaderSize = 4 + tagCsvLength;
|
|
352
|
+
// Skip to actual metadata
|
|
353
|
+
const actualMetadata = metadata.slice(tagHeaderSize);
|
|
354
|
+
const metaView = new DataView(actualMetadata.buffer, actualMetadata.byteOffset, actualMetadata.byteLength);
|
|
332
355
|
const decoder = new TextDecoder();
|
|
333
356
|
// SkinnedMeshMetadata: 4 uint32s (16 bytes) THEN string_id[128] = 144 bytes total
|
|
334
|
-
const meshGeometryCount =
|
|
335
|
-
const materialCount =
|
|
336
|
-
const nodeCount =
|
|
337
|
-
const boneCount =
|
|
338
|
-
const stringIdBytes =
|
|
357
|
+
const meshGeometryCount = metaView.getUint32(0, true);
|
|
358
|
+
const materialCount = metaView.getUint32(4, true);
|
|
359
|
+
const nodeCount = metaView.getUint32(8, true);
|
|
360
|
+
const boneCount = metaView.getUint32(12, true);
|
|
361
|
+
const stringIdBytes = actualMetadata.slice(16, 144);
|
|
339
362
|
const stringIdNullIndex = stringIdBytes.indexOf(0);
|
|
340
363
|
const stringId = decoder
|
|
341
364
|
.decode(stringIdBytes.slice(0, stringIdNullIndex >= 0 ? stringIdNullIndex : 128))
|
|
@@ -348,21 +371,21 @@ class StowKitPack {
|
|
|
348
371
|
// vertex_buffer_offset, vertex_buffer_size, index_buffer_offset, index_buffer_size, weights_offset, weights_size (48 bytes)
|
|
349
372
|
// material_index, _padding (8 bytes)
|
|
350
373
|
for (let g = 0; g < meshGeometryCount; g++) {
|
|
351
|
-
if (offset + 72 >
|
|
374
|
+
if (offset + 72 > actualMetadata.length) {
|
|
352
375
|
throw new Error(`Metadata too small for geometry ${g}`);
|
|
353
376
|
}
|
|
354
377
|
geometryInfos.push({
|
|
355
|
-
vertexCount:
|
|
356
|
-
indexCount:
|
|
357
|
-
hasNormals:
|
|
358
|
-
hasUVs:
|
|
359
|
-
vertexBufferOffset: Number(
|
|
360
|
-
vertexBufferSize: Number(
|
|
361
|
-
indexBufferOffset: Number(
|
|
362
|
-
indexBufferSize: Number(
|
|
363
|
-
weightsOffset: Number(
|
|
364
|
-
weightsSize: Number(
|
|
365
|
-
materialIndex:
|
|
378
|
+
vertexCount: metaView.getUint32(offset, true),
|
|
379
|
+
indexCount: metaView.getUint32(offset + 4, true),
|
|
380
|
+
hasNormals: metaView.getUint32(offset + 8, true),
|
|
381
|
+
hasUVs: metaView.getUint32(offset + 12, true),
|
|
382
|
+
vertexBufferOffset: Number(metaView.getBigUint64(offset + 16, true)),
|
|
383
|
+
vertexBufferSize: Number(metaView.getBigUint64(offset + 24, true)),
|
|
384
|
+
indexBufferOffset: Number(metaView.getBigUint64(offset + 32, true)),
|
|
385
|
+
indexBufferSize: Number(metaView.getBigUint64(offset + 40, true)),
|
|
386
|
+
weightsOffset: Number(metaView.getBigUint64(offset + 48, true)),
|
|
387
|
+
weightsSize: Number(metaView.getBigUint64(offset + 56, true)),
|
|
388
|
+
materialIndex: metaView.getUint32(offset + 64, true)
|
|
366
389
|
// _padding at offset + 68 (ignored)
|
|
367
390
|
});
|
|
368
391
|
offset += 72;
|
|
@@ -375,15 +398,15 @@ class StowKitPack {
|
|
|
375
398
|
const materialData = [];
|
|
376
399
|
// Parse MaterialData headers
|
|
377
400
|
for (let i = 0; i < materialCount; i++) {
|
|
378
|
-
if (metadataOffset + 196 >
|
|
401
|
+
if (metadataOffset + 196 > actualMetadata.length) {
|
|
379
402
|
console.warn('Skinned mesh metadata truncated while reading material headers');
|
|
380
403
|
break;
|
|
381
404
|
}
|
|
382
|
-
const nameBytes =
|
|
383
|
-
const schemaIdBytes =
|
|
405
|
+
const nameBytes = actualMetadata.slice(metadataOffset, metadataOffset + 64);
|
|
406
|
+
const schemaIdBytes = actualMetadata.slice(metadataOffset + 64, metadataOffset + 192);
|
|
384
407
|
const name = decoder.decode(nameBytes.slice(0, nameBytes.indexOf(0) || 64));
|
|
385
408
|
const schemaId = decoder.decode(schemaIdBytes.slice(0, schemaIdBytes.indexOf(0) || 128));
|
|
386
|
-
const propertyCount =
|
|
409
|
+
const propertyCount = metaView.getUint32(metadataOffset + 192, true);
|
|
387
410
|
materialData.push({ name, schemaId, propertyCount, properties: [] });
|
|
388
411
|
metadataOffset += 196;
|
|
389
412
|
}
|
|
@@ -398,20 +421,20 @@ class StowKitPack {
|
|
|
398
421
|
const mat = materialData[i];
|
|
399
422
|
for (let p = 0; p < mat.propertyCount; p++) {
|
|
400
423
|
try {
|
|
401
|
-
if (metadataOffset + PROPERTY_STRIDE >
|
|
424
|
+
if (metadataOffset + PROPERTY_STRIDE > actualMetadata.length) {
|
|
402
425
|
break;
|
|
403
426
|
}
|
|
404
|
-
const fieldNameBytes =
|
|
427
|
+
const fieldNameBytes = actualMetadata.slice(metadataOffset, metadataOffset + 64);
|
|
405
428
|
const fieldName = decoder
|
|
406
429
|
.decode(fieldNameBytes.slice(0, fieldNameBytes.indexOf(0) || 64))
|
|
407
430
|
.trim();
|
|
408
431
|
const value = [
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
432
|
+
metaView.getFloat32(metadataOffset + 64, true),
|
|
433
|
+
metaView.getFloat32(metadataOffset + 68, true),
|
|
434
|
+
metaView.getFloat32(metadataOffset + 72, true),
|
|
435
|
+
metaView.getFloat32(metadataOffset + 76, true)
|
|
413
436
|
];
|
|
414
|
-
const textureIdBytes =
|
|
437
|
+
const textureIdBytes = actualMetadata.slice(metadataOffset + 80, metadataOffset + 144);
|
|
415
438
|
const textureIdNullIndex = textureIdBytes.indexOf(0);
|
|
416
439
|
const textureId = (textureIdNullIndex >= 0
|
|
417
440
|
? decoder.decode(textureIdBytes.slice(0, textureIdNullIndex))
|
|
@@ -433,17 +456,17 @@ class StowKitPack {
|
|
|
433
456
|
const boneOriginalNames = [];
|
|
434
457
|
const bindPoses = [];
|
|
435
458
|
for (let i = 0; i < boneCount; i++) {
|
|
436
|
-
if (metadataOffset + BONE_STRIDE >
|
|
459
|
+
if (metadataOffset + BONE_STRIDE > actualMetadata.length) {
|
|
437
460
|
throw new Error(`Skinned mesh metadata truncated while reading bone ${i}`);
|
|
438
461
|
}
|
|
439
|
-
const nameBytes = new Uint8Array(
|
|
462
|
+
const nameBytes = new Uint8Array(actualMetadata.buffer, actualMetadata.byteOffset + metadataOffset, 64);
|
|
440
463
|
const nullIndex = nameBytes.indexOf(0);
|
|
441
464
|
const rawName = decoder.decode(nameBytes.subarray(0, nullIndex >= 0 ? nullIndex : 64)).trim();
|
|
442
|
-
const parentIndex =
|
|
465
|
+
const parentIndex = metaView.getInt32(metadataOffset + 64, true);
|
|
443
466
|
const offsetMatrix = new THREE.Matrix4();
|
|
444
467
|
const matrixElements = new Float32Array(16);
|
|
445
468
|
for (let j = 0; j < 16; j++) {
|
|
446
|
-
matrixElements[j] =
|
|
469
|
+
matrixElements[j] = metaView.getFloat32(metadataOffset + 68 + j * 4, true);
|
|
447
470
|
}
|
|
448
471
|
offsetMatrix.fromArray(matrixElements);
|
|
449
472
|
const sanitizedName = this.sanitizeTrackName(rawName);
|
|
@@ -504,7 +527,6 @@ class StowKitPack {
|
|
|
504
527
|
// Apply non-texture properties
|
|
505
528
|
for (const prop of mat.properties) {
|
|
506
529
|
const fieldName = prop.fieldName.toLowerCase();
|
|
507
|
-
// Handle color properties
|
|
508
530
|
if (fieldName.includes('color') || fieldName.includes('tint')) {
|
|
509
531
|
material.color.setRGB(prop.value[0], prop.value[1], prop.value[2]);
|
|
510
532
|
}
|
|
@@ -514,6 +536,12 @@ class StowKitPack {
|
|
|
514
536
|
else if (fieldName === 'roughness') {
|
|
515
537
|
material.roughness = prop.value[0];
|
|
516
538
|
}
|
|
539
|
+
else if (fieldName === 'alphatest') {
|
|
540
|
+
if (prop.value[0] > 0) {
|
|
541
|
+
material.alphaTest = 0.5;
|
|
542
|
+
material.transparent = true;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
517
545
|
}
|
|
518
546
|
materials.push(material);
|
|
519
547
|
}
|
|
@@ -833,32 +861,38 @@ class StowKitPack {
|
|
|
833
861
|
* Parse animation clip from binary data
|
|
834
862
|
*/
|
|
835
863
|
parseAnimationClip(metadata, data) {
|
|
864
|
+
// NEW FORMAT: Skip past tag header
|
|
836
865
|
const view = new DataView(metadata.buffer, metadata.byteOffset, metadata.byteLength);
|
|
866
|
+
const tagCsvLength = view.getUint32(0, true);
|
|
867
|
+
const tagHeaderSize = 4 + tagCsvLength;
|
|
868
|
+
// Skip to actual metadata
|
|
869
|
+
const actualMetadata = metadata.slice(tagHeaderSize);
|
|
870
|
+
const metaView = new DataView(actualMetadata.buffer, actualMetadata.byteOffset, actualMetadata.byteLength);
|
|
837
871
|
const decoder = new TextDecoder();
|
|
838
872
|
// Parse AnimationClipMetadata (272 bytes total)
|
|
839
|
-
const stringIdBytes =
|
|
873
|
+
const stringIdBytes = actualMetadata.slice(0, 128);
|
|
840
874
|
const stringIdNullIndex = stringIdBytes.indexOf(0);
|
|
841
875
|
const stringId = decoder.decode(stringIdBytes.slice(0, stringIdNullIndex >= 0 ? stringIdNullIndex : 128));
|
|
842
|
-
const targetMeshIdBytes =
|
|
876
|
+
const targetMeshIdBytes = actualMetadata.slice(128, 256);
|
|
843
877
|
const targetMeshIdNullIndex = targetMeshIdBytes.indexOf(0);
|
|
844
878
|
decoder
|
|
845
879
|
.decode(targetMeshIdBytes.slice(0, targetMeshIdNullIndex >= 0 ? targetMeshIdNullIndex : 128))
|
|
846
880
|
.trim();
|
|
847
|
-
const durationSeconds =
|
|
848
|
-
|
|
849
|
-
const channelCount =
|
|
850
|
-
const boneCount =
|
|
881
|
+
const durationSeconds = metaView.getFloat32(256, true); // Duration in seconds (per C header)
|
|
882
|
+
metaView.getFloat32(260, true); // For custom playback rate if needed
|
|
883
|
+
const channelCount = metaView.getUint32(264, true);
|
|
884
|
+
const boneCount = metaView.getUint32(268, true);
|
|
851
885
|
// Parse AnimationChannel[] (starts at offset 272, each is 28 bytes)
|
|
852
886
|
const channelsOffset = 272;
|
|
853
887
|
const channels = [];
|
|
854
888
|
for (let i = 0; i < channelCount; i++) {
|
|
855
889
|
const chOffset = channelsOffset + i * 28;
|
|
856
890
|
channels.push({
|
|
857
|
-
boneIndex:
|
|
858
|
-
keyframeType:
|
|
859
|
-
keyframeCount:
|
|
860
|
-
keyframeTimesOffset: Number(
|
|
861
|
-
keyframeValuesOffset: Number(
|
|
891
|
+
boneIndex: metaView.getUint32(chOffset, true),
|
|
892
|
+
keyframeType: metaView.getUint32(chOffset + 4, true),
|
|
893
|
+
keyframeCount: metaView.getUint32(chOffset + 8, true),
|
|
894
|
+
keyframeTimesOffset: Number(metaView.getBigUint64(chOffset + 12, true)),
|
|
895
|
+
keyframeValuesOffset: Number(metaView.getBigUint64(chOffset + 20, true))
|
|
862
896
|
});
|
|
863
897
|
}
|
|
864
898
|
// Parse AnimationBoneInfo[] (starts after all channels, each is 68 bytes)
|
|
@@ -866,13 +900,13 @@ class StowKitPack {
|
|
|
866
900
|
const bones = [];
|
|
867
901
|
for (let i = 0; i < boneCount; i++) {
|
|
868
902
|
const boneOffset = bonesOffset + i * 68;
|
|
869
|
-
const nameBytes =
|
|
903
|
+
const nameBytes = actualMetadata.slice(boneOffset, boneOffset + 64);
|
|
870
904
|
const nullIndex = nameBytes.indexOf(0);
|
|
871
905
|
const rawName = decoder
|
|
872
906
|
.decode(nameBytes.slice(0, nullIndex >= 0 ? nullIndex : 64))
|
|
873
907
|
.trim();
|
|
874
908
|
const sanitizedName = this.sanitizeTrackName(rawName);
|
|
875
|
-
const parentIndex =
|
|
909
|
+
const parentIndex = metaView.getInt32(boneOffset + 64, true);
|
|
876
910
|
bones.push({ name: rawName, parentIndex, sanitizedName });
|
|
877
911
|
}
|
|
878
912
|
// Create DataView for keyframe data
|
|
@@ -1065,7 +1099,7 @@ class StowKitLoader {
|
|
|
1065
1099
|
* Initialize the loader (called automatically on first load)
|
|
1066
1100
|
*/
|
|
1067
1101
|
static async initialize(options) {
|
|
1068
|
-
const wasmPath = options?.wasmPath || '/stowkit_reader.wasm';
|
|
1102
|
+
const wasmPath = options?.wasmPath || '/stowkit/stowkit_reader.wasm';
|
|
1069
1103
|
const basisPath = options?.basisPath || '/stowkit/basis/';
|
|
1070
1104
|
const dracoPath = options?.dracoPath || '/stowkit/draco/';
|
|
1071
1105
|
// Initialize reader
|