@stowkit/three-loader 0.1.25 → 0.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MeshParser.d.ts.map +1 -1
- package/dist/StowKitPack.d.ts +1 -0
- package/dist/StowKitPack.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/stowkit-three-loader.esm.js +74 -23
- package/dist/stowkit-three-loader.esm.js.map +1 -1
- package/dist/stowkit-three-loader.js +76 -21
- package/dist/stowkit-three-loader.js.map +1 -1
- package/package.json +1 -1
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;
|
|
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;AAGxE,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;IAwLD;;OAEG;WACU,cAAc,CAAC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC;IAqDrI;;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;IAuFtJ;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;CAK5B"}
|
package/dist/StowKitPack.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare class StowKitPack {
|
|
|
9
9
|
reader: StowKitReader;
|
|
10
10
|
private ktx2Loader;
|
|
11
11
|
private dracoLoader;
|
|
12
|
+
private textureCache;
|
|
12
13
|
constructor(reader: StowKitReader, ktx2Loader: KTX2Loader, dracoLoader: DRACOLoader);
|
|
13
14
|
/**
|
|
14
15
|
* Load a skinned mesh by its string ID
|
|
@@ -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,
|
|
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,EAAc,MAAM,iBAAiB,CAAC;AAG5D;;GAEG;AACH,qBAAa,WAAW;IACb,MAAM,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,YAAY,CAA4D;gBAEpE,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;IAkY9B;;OAEG;IACG,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IA4CvD;;OAEG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC;IA6BtE;;OAEG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IA0BvF;;OAEG;IACH,UAAU;IAIV;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG;IAIhC;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAI/C;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAKnD;;OAEG;IACG,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAUjE;;OAEG;IACG,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAY1D;;OAEG;IACG,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC;IAMzE;;OAEG;IACG,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAiBlE;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM;IAMlC;;OAEG;IACH,oBAAoB,CAAC,KAAK,EAAE,MAAM;IAIlC;;OAEG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM;IAKhC;;OAEG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC;IAQvE;;OAEG;IACG,aAAa,CACf,gBAAgB,EAAE,KAAK,CAAC,KAAK,EAC7B,aAAa,EAAE,MAAM,GACtB,OAAO,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC;QAAC,MAAM,EAAE,KAAK,CAAC,eAAe,CAAC;QAAC,IAAI,EAAE,KAAK,CAAC,aAAa,CAAA;KAAE,CAAC;IAUrG;;OAEG;IACG,oBAAoB,CACtB,gBAAgB,EAAE,KAAK,CAAC,KAAK,EAC7B,cAAc,EAAE,MAAM,GACvB,OAAO,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC;QAAC,MAAM,EAAE,KAAK,CAAC,eAAe,CAAC;QAAC,IAAI,EAAE,KAAK,CAAC,aAAa,CAAA;KAAE,CAAC;IAUrG;;OAEG;IACG,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC;IAW3E;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA+H1B;;OAEG;IACH,OAAO,CAAC,cAAc;IAQtB;;OAEG;IACH,OAAO,IAAI,IAAI;YAMD,oBAAoB;YAmDpB,eAAe;IAiC7B,OAAO,CAAC,sBAAsB;IAwB9B,OAAO,CAAC,iBAAiB;CAM5B"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export { StowKitLoader } from './StowKitLoader';
|
|
|
6
6
|
export { StowKitPack } from './StowKitPack';
|
|
7
7
|
export type { StowKitLoaderOptions } from './StowKitLoader';
|
|
8
8
|
export type { MeshGeometryInfo, MaterialPropertyValue, MaterialData, Node, MeshMetadata } from './MeshParser';
|
|
9
|
-
export { AssetType } from '@stowkit/reader';
|
|
9
|
+
export { AssetType, PerfLogger } from '@stowkit/reader';
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EACR,gBAAgB,EAChB,qBAAqB,EACrB,YAAY,EACZ,IAAI,EACJ,YAAY,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EACR,gBAAgB,EAChB,qBAAqB,EACrB,YAAY,EACZ,IAAI,EACJ,YAAY,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
|
|
3
3
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
4
|
-
import { StowKitReader } from '@stowkit/reader';
|
|
5
|
-
export { AssetType } from '@stowkit/reader';
|
|
4
|
+
import { PerfLogger, StowKitReader } from '@stowkit/reader';
|
|
5
|
+
export { AssetType, PerfLogger } from '@stowkit/reader';
|
|
6
6
|
|
|
7
7
|
class MeshParser {
|
|
8
8
|
/**
|
|
@@ -192,20 +192,25 @@ class MeshParser {
|
|
|
192
192
|
* Create Three.js BufferGeometry from Draco compressed mesh data
|
|
193
193
|
*/
|
|
194
194
|
static async createGeometry(geoInfo, dataBlob, dracoLoader) {
|
|
195
|
+
const startTime = performance.now();
|
|
195
196
|
// Extract the Draco compressed buffer
|
|
196
197
|
if (geoInfo.compressedBufferOffset + geoInfo.compressedBufferSize > dataBlob.length) {
|
|
197
198
|
throw new Error(`Compressed buffer out of bounds: offset=${geoInfo.compressedBufferOffset}, size=${geoInfo.compressedBufferSize}, dataLength=${dataBlob.length}`);
|
|
198
199
|
}
|
|
199
200
|
const compressedData = dataBlob.slice(geoInfo.compressedBufferOffset, geoInfo.compressedBufferOffset + geoInfo.compressedBufferSize);
|
|
201
|
+
const extractTime = performance.now();
|
|
202
|
+
PerfLogger.log(`[Perf] Draco extract: ${(extractTime - startTime).toFixed(2)}ms (${geoInfo.compressedBufferSize} bytes)`);
|
|
200
203
|
// Decode using Draco
|
|
201
204
|
// Create a blob URL for the Draco data (DRACOLoader expects a URL)
|
|
202
205
|
const arrayBuffer = compressedData.buffer.slice(compressedData.byteOffset, compressedData.byteOffset + compressedData.byteLength);
|
|
203
206
|
const blob = new Blob([arrayBuffer]);
|
|
204
207
|
const url = URL.createObjectURL(blob);
|
|
208
|
+
const decodeStart = performance.now();
|
|
205
209
|
const geometry = await new Promise((resolve, reject) => {
|
|
206
210
|
dracoLoader.load(url, (decoded) => {
|
|
207
211
|
URL.revokeObjectURL(url);
|
|
208
|
-
|
|
212
|
+
const decodeEnd = performance.now();
|
|
213
|
+
PerfLogger.log(`[Perf] Draco decode: ${(decodeEnd - decodeStart).toFixed(2)}ms (vertices: ${geoInfo.vertexCount}, indices: ${geoInfo.indexCount})`);
|
|
209
214
|
resolve(decoded);
|
|
210
215
|
}, undefined, (error) => {
|
|
211
216
|
URL.revokeObjectURL(url);
|
|
@@ -213,8 +218,13 @@ class MeshParser {
|
|
|
213
218
|
});
|
|
214
219
|
});
|
|
215
220
|
// Compute bounding volumes
|
|
221
|
+
const boundsStart = performance.now();
|
|
216
222
|
geometry.computeBoundingSphere();
|
|
217
223
|
geometry.computeBoundingBox();
|
|
224
|
+
const boundsEnd = performance.now();
|
|
225
|
+
PerfLogger.log(`[Perf] Bounds computation: ${(boundsEnd - boundsStart).toFixed(2)}ms`);
|
|
226
|
+
const totalTime = performance.now();
|
|
227
|
+
PerfLogger.log(`[Perf] Total geometry creation: ${(totalTime - startTime).toFixed(2)}ms`);
|
|
218
228
|
return geometry;
|
|
219
229
|
}
|
|
220
230
|
/**
|
|
@@ -311,6 +321,7 @@ class MeshParser {
|
|
|
311
321
|
*/
|
|
312
322
|
class StowKitPack {
|
|
313
323
|
constructor(reader, ktx2Loader, dracoLoader) {
|
|
324
|
+
this.textureCache = new Map();
|
|
314
325
|
this.reader = reader;
|
|
315
326
|
this.ktx2Loader = ktx2Loader;
|
|
316
327
|
this.dracoLoader = dracoLoader;
|
|
@@ -640,14 +651,19 @@ class StowKitPack {
|
|
|
640
651
|
* Load a mesh by its canonical path/name
|
|
641
652
|
*/
|
|
642
653
|
async loadMesh(assetPath) {
|
|
654
|
+
const totalStart = performance.now();
|
|
643
655
|
// Find asset by path
|
|
656
|
+
const findStart = performance.now();
|
|
644
657
|
const assetIndex = this.reader.findAssetByPath(assetPath);
|
|
645
658
|
if (assetIndex < 0) {
|
|
646
659
|
throw new Error(`Mesh not found: ${assetPath}`);
|
|
647
660
|
}
|
|
661
|
+
PerfLogger.log(`[Perf] Find asset: ${(performance.now() - findStart).toFixed(2)}ms`);
|
|
648
662
|
// Read mesh data and metadata
|
|
663
|
+
const readStart = performance.now();
|
|
649
664
|
const data = this.reader.readAssetData(assetIndex);
|
|
650
665
|
const metadata = this.reader.readAssetMetadata(assetIndex);
|
|
666
|
+
PerfLogger.log(`[Perf] Read mesh data: ${(performance.now() - readStart).toFixed(2)}ms (data: ${data?.byteLength || 0} bytes, metadata: ${metadata?.byteLength || 0} bytes)`);
|
|
651
667
|
if (!data) {
|
|
652
668
|
throw new Error(`Failed to read mesh data: ${assetPath}`);
|
|
653
669
|
}
|
|
@@ -655,29 +671,46 @@ class StowKitPack {
|
|
|
655
671
|
throw new Error(`No metadata available: ${assetPath}`);
|
|
656
672
|
}
|
|
657
673
|
// Parse mesh data
|
|
674
|
+
const parseStart = performance.now();
|
|
658
675
|
const parsedData = MeshParser.parseMeshData(metadata, data);
|
|
676
|
+
PerfLogger.log(`[Perf] Parse mesh metadata: ${(performance.now() - parseStart).toFixed(2)}ms`);
|
|
659
677
|
// Load textures for materials
|
|
678
|
+
const textureStart = performance.now();
|
|
660
679
|
await this.loadMaterialTextures(parsedData.materialData, parsedData.materials);
|
|
680
|
+
PerfLogger.log(`[Perf] Load textures: ${(performance.now() - textureStart).toFixed(2)}ms`);
|
|
661
681
|
// Build Three.js scene with Draco decoder
|
|
682
|
+
const buildStart = performance.now();
|
|
662
683
|
const scene = await MeshParser.buildScene(parsedData, data, this.dracoLoader);
|
|
684
|
+
PerfLogger.log(`[Perf] Build scene: ${(performance.now() - buildStart).toFixed(2)}ms`);
|
|
685
|
+
PerfLogger.log(`[Perf] ===== Total mesh load: ${(performance.now() - totalStart).toFixed(2)}ms =====`);
|
|
663
686
|
return scene;
|
|
664
687
|
}
|
|
665
688
|
/**
|
|
666
689
|
* Load a texture by its canonical path/name
|
|
667
690
|
*/
|
|
668
691
|
async loadTexture(assetPath) {
|
|
669
|
-
//
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
692
|
+
// Check cache first
|
|
693
|
+
if (this.textureCache.has(assetPath)) {
|
|
694
|
+
PerfLogger.log(`[Perf] Texture cache hit: ${assetPath}`);
|
|
695
|
+
return this.textureCache.get(assetPath);
|
|
673
696
|
}
|
|
674
|
-
//
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
697
|
+
// Cache the promise to avoid duplicate loads
|
|
698
|
+
const loadPromise = (async () => {
|
|
699
|
+
// Find asset by path
|
|
700
|
+
const assetIndex = this.reader.findAssetByPath(assetPath);
|
|
701
|
+
if (assetIndex < 0) {
|
|
702
|
+
throw new Error(`Texture not found: ${assetPath}`);
|
|
703
|
+
}
|
|
704
|
+
// Read texture data
|
|
705
|
+
const data = this.reader.readAssetData(assetIndex);
|
|
706
|
+
if (!data) {
|
|
707
|
+
throw new Error(`Failed to read texture data: ${assetPath}`);
|
|
708
|
+
}
|
|
709
|
+
// Load as KTX2
|
|
710
|
+
return await this.loadKTX2Texture(data);
|
|
711
|
+
})();
|
|
712
|
+
this.textureCache.set(assetPath, loadPromise);
|
|
713
|
+
return loadPromise;
|
|
681
714
|
}
|
|
682
715
|
/**
|
|
683
716
|
* Load audio by its canonical path/name
|
|
@@ -956,36 +989,54 @@ class StowKitPack {
|
|
|
956
989
|
* Close the pack and free resources
|
|
957
990
|
*/
|
|
958
991
|
dispose() {
|
|
992
|
+
this.textureCache.clear();
|
|
959
993
|
this.reader.close();
|
|
960
994
|
}
|
|
961
995
|
// Private methods moved from StowKitLoader
|
|
962
996
|
async loadMaterialTextures(materialData, materials) {
|
|
997
|
+
// Collect all texture load promises to load in parallel
|
|
998
|
+
const textureLoads = [];
|
|
963
999
|
for (let i = 0; i < materialData.length; i++) {
|
|
964
1000
|
const matData = materialData[i];
|
|
965
|
-
const material = materials[i];
|
|
966
1001
|
for (const prop of matData.properties) {
|
|
967
|
-
// Trim and check for truly non-empty texture ID
|
|
968
1002
|
const textureId = prop.textureId?.trim();
|
|
969
1003
|
if (textureId && textureId.length > 0) {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1004
|
+
textureLoads.push({
|
|
1005
|
+
materialIndex: i,
|
|
1006
|
+
propertyName: prop.fieldName,
|
|
1007
|
+
texturePromise: this.loadTexture(textureId).catch(error => {
|
|
1008
|
+
console.error(`Failed to load texture "${textureId}":`, error);
|
|
1009
|
+
throw error;
|
|
1010
|
+
})
|
|
1011
|
+
});
|
|
977
1012
|
}
|
|
978
1013
|
}
|
|
979
1014
|
}
|
|
1015
|
+
// Load all textures in parallel
|
|
1016
|
+
const results = await Promise.allSettled(textureLoads.map(load => load.texturePromise));
|
|
1017
|
+
// Apply successfully loaded textures
|
|
1018
|
+
for (let i = 0; i < textureLoads.length; i++) {
|
|
1019
|
+
const result = results[i];
|
|
1020
|
+
if (result.status === 'fulfilled') {
|
|
1021
|
+
const load = textureLoads[i];
|
|
1022
|
+
const material = materials[load.materialIndex];
|
|
1023
|
+
this.applyTextureToMaterial(material, load.propertyName, result.value);
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
980
1026
|
}
|
|
981
1027
|
async loadKTX2Texture(data) {
|
|
1028
|
+
performance.now();
|
|
982
1029
|
const arrayBuffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
983
1030
|
const blob = new Blob([arrayBuffer]);
|
|
984
1031
|
const url = URL.createObjectURL(blob);
|
|
1032
|
+
PerfLogger.log(`[Perf] KTX2/Basis texture size: ${data.byteLength} bytes`);
|
|
985
1033
|
try {
|
|
986
1034
|
return await new Promise((resolve, reject) => {
|
|
1035
|
+
const loadStart = performance.now();
|
|
987
1036
|
this.ktx2Loader.load(url, (texture) => {
|
|
988
1037
|
URL.revokeObjectURL(url);
|
|
1038
|
+
const loadEnd = performance.now();
|
|
1039
|
+
PerfLogger.log(`[Perf] Basis transcode: ${(loadEnd - loadStart).toFixed(2)}ms (resolution: ${texture.image?.width || '?'}x${texture.image?.height || '?'})`);
|
|
989
1040
|
texture.needsUpdate = true;
|
|
990
1041
|
resolve(texture);
|
|
991
1042
|
}, undefined, (error) => {
|