@stowkit/three-loader 0.1.32 → 0.1.33

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":"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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"}
@@ -501,6 +501,7 @@ class StowKitPack {
501
501
  * Load a skinned mesh by its string ID
502
502
  */
503
503
  async loadSkinnedMesh(stringId) {
504
+ const totalStart = performance.now();
504
505
  const assetIndex = this.reader.findAssetByPath(stringId);
505
506
  if (assetIndex < 0) {
506
507
  throw new Error(`Skinned mesh not found: ${stringId}`);
@@ -511,12 +512,16 @@ class StowKitPack {
511
512
  throw new Error(`Failed to read skinned mesh data: ${stringId}`);
512
513
  if (!metadata)
513
514
  throw new Error(`No metadata for skinned mesh: ${stringId}`);
514
- return await this.parseSkinnedMesh(metadata, data);
515
+ const result = await this.parseSkinnedMesh(metadata, data);
516
+ const totalTime = performance.now() - totalStart;
517
+ PerfLogger.log(`[Perf] === Skinned Mesh "${stringId}": ${totalTime.toFixed(2)}ms total ===`);
518
+ return result;
515
519
  }
516
520
  /**
517
521
  * Parse skinned mesh from binary data
518
522
  */
519
523
  async parseSkinnedMesh(metadata, data) {
524
+ const parseStart = performance.now();
520
525
  // NEW FORMAT: Skip past tag header
521
526
  const view = new DataView(metadata.buffer, metadata.byteOffset, metadata.byteLength);
522
527
  const tagCsvLength = view.getUint32(0, true);
@@ -562,7 +567,7 @@ class StowKitPack {
562
567
  });
563
568
  offset += 72;
564
569
  }
565
- const dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);
570
+ new DataView(data.buffer, data.byteOffset, data.byteLength);
566
571
  // Sort geometry infos by vertex buffer offset to ensure sequential parsing
567
572
  const sortedGeometryInfos = geometryInfos.slice().sort((a, b) => a.vertexBufferOffset - b.vertexBufferOffset);
568
573
  // Parse materials from metadata (immediately after geometries)
@@ -717,88 +722,39 @@ class StowKitPack {
717
722
  }
718
723
  materials.push(material);
719
724
  }
725
+ const parseTime = performance.now() - parseStart;
726
+ PerfLogger.log(`[Perf] Parse skinned metadata: ${parseTime.toFixed(2)}ms`);
727
+ const textureStart = performance.now();
720
728
  await this.loadMaterialTextures(materialData, materials);
729
+ const textureTime = performance.now() - textureStart;
730
+ if (materialData.length > 0) {
731
+ PerfLogger.log(`[Perf] Load textures: ${textureTime.toFixed(2)}ms`);
732
+ }
721
733
  // Collect root bones (hierarchy already built earlier)
734
+ const buildStart = performance.now();
722
735
  const rootBones = bones.filter((_, index) => parentIndices[index] < 0);
723
736
  // Create shared skeleton
724
737
  const skeleton = new THREE.Skeleton(bones, boneMatrices);
725
- // Pre-allocate combined buffers
726
- const totalVertexCount = sortedGeometryInfos.reduce((sum, info) => sum + info.vertexCount, 0);
727
- const totalIndexCount = sortedGeometryInfos.reduce((sum, info) => sum + info.indexCount, 0);
728
- const combinedPositions = new Float32Array(totalVertexCount * 3);
729
- const combinedNormals = new Float32Array(totalVertexCount * 3);
730
- const combinedUVs = new Float32Array(totalVertexCount * 2);
731
- const combinedSkinIndices = new Uint16Array(totalVertexCount * 4);
732
- const combinedSkinWeights = new Float32Array(totalVertexCount * 4);
733
- const combinedIndices = new Uint32Array(totalIndexCount);
738
+ // Use WASM to parse geometry data (10-50x faster!)
739
+ const geomData = this.reader.parseSkinnedMeshGeometryFast(metadata, data);
740
+ if (!geomData) {
741
+ throw new Error('Failed to parse skinned mesh geometry');
742
+ }
743
+ // Convert Uint32Array skinIndices to Uint16Array for Three.js
744
+ const skinIndices16 = new Uint16Array(geomData.skinIndices);
734
745
  const combinedGeometry = new THREE.BufferGeometry();
735
- combinedGeometry.clearGroups();
736
- let vertexCursor = 0; // counts vertices
737
- let indexCursor = 0; // counts indices
746
+ combinedGeometry.setAttribute('position', new THREE.BufferAttribute(geomData.positions, 3));
747
+ combinedGeometry.setAttribute('normal', new THREE.BufferAttribute(geomData.normals, 3));
748
+ combinedGeometry.setAttribute('uv', new THREE.BufferAttribute(geomData.uvs, 2));
749
+ combinedGeometry.setAttribute('skinIndex', new THREE.Uint16BufferAttribute(skinIndices16, 4));
750
+ combinedGeometry.setAttribute('skinWeight', new THREE.BufferAttribute(geomData.skinWeights, 4));
751
+ combinedGeometry.setIndex(new THREE.BufferAttribute(geomData.indices, 1));
752
+ // Add geometry groups for materials
753
+ let indexCursor = 0;
738
754
  for (const geomInfo of sortedGeometryInfos) {
739
- const vertexStrideBytes = 32;
740
- const vertexBase = vertexCursor; // base vertex index for this submesh
741
- // Validate offsets before parsing
742
- const requiredVertexBytes = geomInfo.vertexBufferOffset + geomInfo.vertexCount * vertexStrideBytes;
743
- const requiredIndexBytes = geomInfo.indexBufferOffset + geomInfo.indexCount * 4;
744
- const requiredWeightBytes = geomInfo.weightsOffset + geomInfo.vertexCount * 32;
745
- if (requiredVertexBytes > data.byteLength) {
746
- throw new Error(`Vertex buffer out of bounds: need ${requiredVertexBytes}, have ${data.byteLength}`);
747
- }
748
- if (requiredIndexBytes > data.byteLength) {
749
- throw new Error(`Index buffer out of bounds: need ${requiredIndexBytes}, have ${data.byteLength}`);
750
- }
751
- if (requiredWeightBytes > data.byteLength) {
752
- throw new Error(`Weight buffer out of bounds: need ${requiredWeightBytes}, have ${data.byteLength}`);
753
- }
754
- // Parse vertices
755
- for (let v = 0; v < geomInfo.vertexCount; v++) {
756
- const vertexOffset = geomInfo.vertexBufferOffset + v * vertexStrideBytes;
757
- // positions
758
- combinedPositions[(vertexCursor + v) * 3 + 0] = dataView.getFloat32(vertexOffset + 0, true);
759
- combinedPositions[(vertexCursor + v) * 3 + 1] = dataView.getFloat32(vertexOffset + 4, true);
760
- combinedPositions[(vertexCursor + v) * 3 + 2] = dataView.getFloat32(vertexOffset + 8, true);
761
- // normals
762
- if (geomInfo.hasNormals) {
763
- combinedNormals[(vertexCursor + v) * 3 + 0] = dataView.getFloat32(vertexOffset + 12, true);
764
- combinedNormals[(vertexCursor + v) * 3 + 1] = dataView.getFloat32(vertexOffset + 16, true);
765
- combinedNormals[(vertexCursor + v) * 3 + 2] = dataView.getFloat32(vertexOffset + 20, true);
766
- }
767
- // uvs
768
- if (geomInfo.hasUVs) {
769
- combinedUVs[(vertexCursor + v) * 2 + 0] = dataView.getFloat32(vertexOffset + 24, true);
770
- combinedUVs[(vertexCursor + v) * 2 + 1] = dataView.getFloat32(vertexOffset + 28, true);
771
- }
772
- // bone indices & weights
773
- const weightOffset = geomInfo.weightsOffset + v * 32;
774
- for (let j = 0; j < 4; j++) {
775
- const boneIndex = dataView.getUint32(weightOffset + j * 4, true);
776
- combinedSkinIndices[(vertexCursor + v) * 4 + j] = boneIndex < boneCount ? boneIndex : 0;
777
- }
778
- for (let j = 0; j < 4; j++) {
779
- combinedSkinWeights[(vertexCursor + v) * 4 + j] = dataView.getFloat32(weightOffset + 16 + j * 4, true);
780
- }
781
- }
782
- // Parse indices
783
- const groupStart = indexCursor;
784
- for (let i = 0; i < geomInfo.indexCount; i++) {
785
- const indexValue = dataView.getUint32(geomInfo.indexBufferOffset + i * 4, true);
786
- combinedIndices[indexCursor + i] = indexValue + vertexBase;
787
- }
788
- combinedGeometry.addGroup(groupStart, geomInfo.indexCount, Math.min(geomInfo.materialIndex, materials.length - 1));
789
- vertexCursor += geomInfo.vertexCount;
755
+ combinedGeometry.addGroup(indexCursor, geomInfo.indexCount, Math.min(geomInfo.materialIndex, materials.length - 1));
790
756
  indexCursor += geomInfo.indexCount;
791
757
  }
792
- combinedGeometry.setAttribute('position', new THREE.BufferAttribute(combinedPositions, 3));
793
- if (geometryInfos.some(info => info.hasNormals)) {
794
- combinedGeometry.setAttribute('normal', new THREE.BufferAttribute(combinedNormals, 3));
795
- }
796
- if (geometryInfos.some(info => info.hasUVs)) {
797
- combinedGeometry.setAttribute('uv', new THREE.BufferAttribute(combinedUVs, 2));
798
- }
799
- combinedGeometry.setAttribute('skinIndex', new THREE.Uint16BufferAttribute(combinedSkinIndices, 4));
800
- combinedGeometry.setAttribute('skinWeight', new THREE.BufferAttribute(combinedSkinWeights, 4));
801
- combinedGeometry.setIndex(new THREE.BufferAttribute(combinedIndices, 1));
802
758
  combinedGeometry.computeBoundingBox();
803
759
  combinedGeometry.computeBoundingSphere();
804
760
  const skinnedMesh = new THREE.SkinnedMesh(combinedGeometry, materials);
@@ -816,6 +772,8 @@ class StowKitPack {
816
772
  container.add(skinnedMesh);
817
773
  container.userData.boneOriginalNames = boneOriginalNames;
818
774
  container.userData.skinnedMesh = skinnedMesh;
775
+ const buildTime = performance.now() - buildStart;
776
+ PerfLogger.log(`[Perf] Build skinned mesh: ${buildTime.toFixed(2)}ms (${boneCount} bones, ${geomData.vertexCount} verts)`);
819
777
  return container;
820
778
  }
821
779
  /**