@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.
@@ -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;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;IAwCrI;;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"}
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"}
@@ -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":"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"}
1
+ {"version":3,"file":"StowKitPack.d.ts","sourceRoot":"","sources":["../src/StowKitPack.ts"],"names":[],"mappings":"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"}
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
@@ -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
- // UVs are pre-flipped in the packer now
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
- // Find asset by path
670
- const assetIndex = this.reader.findAssetByPath(assetPath);
671
- if (assetIndex < 0) {
672
- throw new Error(`Texture not found: ${assetPath}`);
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
- // Read texture data
675
- const data = this.reader.readAssetData(assetIndex);
676
- if (!data) {
677
- throw new Error(`Failed to read texture data: ${assetPath}`);
678
- }
679
- // Load as KTX2
680
- return await this.loadKTX2Texture(data);
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
- try {
971
- const texture = await this.loadTexture(textureId);
972
- this.applyTextureToMaterial(material, prop.fieldName, texture);
973
- }
974
- catch (error) {
975
- console.error(`Failed to load texture "${textureId}":`, error);
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) => {