@stowkit/three-loader 0.1.26 → 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.
@@ -341,6 +341,7 @@ class MeshParser {
341
341
  */
342
342
  class StowKitPack {
343
343
  constructor(reader, ktx2Loader, dracoLoader) {
344
+ this.textureCache = new Map();
344
345
  this.reader = reader;
345
346
  this.ktx2Loader = ktx2Loader;
346
347
  this.dracoLoader = dracoLoader;
@@ -708,18 +709,28 @@ class StowKitPack {
708
709
  * Load a texture by its canonical path/name
709
710
  */
710
711
  async loadTexture(assetPath) {
711
- // Find asset by path
712
- const assetIndex = this.reader.findAssetByPath(assetPath);
713
- if (assetIndex < 0) {
714
- throw new Error(`Texture not found: ${assetPath}`);
712
+ // Check cache first
713
+ if (this.textureCache.has(assetPath)) {
714
+ reader.PerfLogger.log(`[Perf] Texture cache hit: ${assetPath}`);
715
+ return this.textureCache.get(assetPath);
715
716
  }
716
- // Read texture data
717
- const data = this.reader.readAssetData(assetIndex);
718
- if (!data) {
719
- throw new Error(`Failed to read texture data: ${assetPath}`);
720
- }
721
- // Load as KTX2
722
- return await this.loadKTX2Texture(data);
717
+ // Cache the promise to avoid duplicate loads
718
+ const loadPromise = (async () => {
719
+ // Find asset by path
720
+ const assetIndex = this.reader.findAssetByPath(assetPath);
721
+ if (assetIndex < 0) {
722
+ throw new Error(`Texture not found: ${assetPath}`);
723
+ }
724
+ // Read texture data
725
+ const data = this.reader.readAssetData(assetIndex);
726
+ if (!data) {
727
+ throw new Error(`Failed to read texture data: ${assetPath}`);
728
+ }
729
+ // Load as KTX2
730
+ return await this.loadKTX2Texture(data);
731
+ })();
732
+ this.textureCache.set(assetPath, loadPromise);
733
+ return loadPromise;
723
734
  }
724
735
  /**
725
736
  * Load audio by its canonical path/name
@@ -998,27 +1009,40 @@ class StowKitPack {
998
1009
  * Close the pack and free resources
999
1010
  */
1000
1011
  dispose() {
1012
+ this.textureCache.clear();
1001
1013
  this.reader.close();
1002
1014
  }
1003
1015
  // Private methods moved from StowKitLoader
1004
1016
  async loadMaterialTextures(materialData, materials) {
1017
+ // Collect all texture load promises to load in parallel
1018
+ const textureLoads = [];
1005
1019
  for (let i = 0; i < materialData.length; i++) {
1006
1020
  const matData = materialData[i];
1007
- const material = materials[i];
1008
1021
  for (const prop of matData.properties) {
1009
- // Trim and check for truly non-empty texture ID
1010
1022
  const textureId = prop.textureId?.trim();
1011
1023
  if (textureId && textureId.length > 0) {
1012
- try {
1013
- const texture = await this.loadTexture(textureId);
1014
- this.applyTextureToMaterial(material, prop.fieldName, texture);
1015
- }
1016
- catch (error) {
1017
- console.error(`Failed to load texture "${textureId}":`, error);
1018
- }
1024
+ textureLoads.push({
1025
+ materialIndex: i,
1026
+ propertyName: prop.fieldName,
1027
+ texturePromise: this.loadTexture(textureId).catch(error => {
1028
+ console.error(`Failed to load texture "${textureId}":`, error);
1029
+ throw error;
1030
+ })
1031
+ });
1019
1032
  }
1020
1033
  }
1021
1034
  }
1035
+ // Load all textures in parallel
1036
+ const results = await Promise.allSettled(textureLoads.map(load => load.texturePromise));
1037
+ // Apply successfully loaded textures
1038
+ for (let i = 0; i < textureLoads.length; i++) {
1039
+ const result = results[i];
1040
+ if (result.status === 'fulfilled') {
1041
+ const load = textureLoads[i];
1042
+ const material = materials[load.materialIndex];
1043
+ this.applyTextureToMaterial(material, load.propertyName, result.value);
1044
+ }
1045
+ }
1022
1046
  }
1023
1047
  async loadKTX2Texture(data) {
1024
1048
  performance.now();