@stowkit/three-loader 0.1.29 → 0.1.31
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/AssetCache.d.ts +54 -0
- package/dist/AssetCache.d.ts.map +1 -0
- package/dist/MeshParser.d.ts +2 -2
- package/dist/MeshParser.d.ts.map +1 -1
- package/dist/StowKitLoader.d.ts +4 -1
- package/dist/StowKitLoader.d.ts.map +1 -1
- package/dist/StowKitPack.d.ts +3 -1
- package/dist/StowKitPack.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/stowkit-three-loader.esm.js +245 -38
- package/dist/stowkit-three-loader.esm.js.map +1 -1
- package/dist/stowkit-three-loader.js +245 -37
- package/dist/stowkit-three-loader.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent asset cache using IndexedDB
|
|
3
|
+
* Caches decoded Draco geometries and transcoded Basis textures
|
|
4
|
+
* Invalidates when source .stow file changes
|
|
5
|
+
*/
|
|
6
|
+
interface CachedGeometry {
|
|
7
|
+
positions: Float32Array;
|
|
8
|
+
normals?: Float32Array;
|
|
9
|
+
uvs?: Float32Array;
|
|
10
|
+
indices: Uint32Array;
|
|
11
|
+
version: string;
|
|
12
|
+
}
|
|
13
|
+
interface CachedTexture {
|
|
14
|
+
data: Uint8Array;
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
format: number;
|
|
18
|
+
internalFormat: number;
|
|
19
|
+
compressed: boolean;
|
|
20
|
+
version: string;
|
|
21
|
+
}
|
|
22
|
+
export declare class AssetMemoryCache {
|
|
23
|
+
private static db;
|
|
24
|
+
private static initPromise;
|
|
25
|
+
private static DB_NAME;
|
|
26
|
+
private static DB_VERSION;
|
|
27
|
+
private static GEOMETRY_STORE;
|
|
28
|
+
private static TEXTURE_STORE;
|
|
29
|
+
private static init;
|
|
30
|
+
static getGeometry(key: string, version: string): Promise<CachedGeometry | null>;
|
|
31
|
+
static setGeometry(key: string, version: string, geometry: {
|
|
32
|
+
positions: Float32Array;
|
|
33
|
+
normals?: Float32Array;
|
|
34
|
+
uvs?: Float32Array;
|
|
35
|
+
indices: Uint32Array;
|
|
36
|
+
}): Promise<void>;
|
|
37
|
+
static getTexture(key: string, version: string): Promise<CachedTexture | null>;
|
|
38
|
+
static setTexture(key: string, version: string, textureData: {
|
|
39
|
+
data: Uint8Array;
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
format: number;
|
|
43
|
+
internalFormat: number;
|
|
44
|
+
compressed: boolean;
|
|
45
|
+
}): Promise<void>;
|
|
46
|
+
static clear(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Generate a version hash for cache invalidation
|
|
49
|
+
* Based on file size only
|
|
50
|
+
*/
|
|
51
|
+
static generateVersion(fileSize: number): string;
|
|
52
|
+
}
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=AssetCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetCache.d.ts","sourceRoot":"","sources":["../src/AssetCache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,UAAU,cAAc;IACpB,SAAS,EAAE,YAAY,CAAC;IACxB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,aAAa;IACnB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,gBAAgB;IACzB,OAAO,CAAC,MAAM,CAAC,EAAE,CAA4B;IAC7C,OAAO,CAAC,MAAM,CAAC,WAAW,CAA8B;IACxD,OAAO,CAAC,MAAM,CAAC,OAAO,CAAuB;IAC7C,OAAO,CAAC,MAAM,CAAC,UAAU,CAAK;IAC9B,OAAO,CAAC,MAAM,CAAC,cAAc,CAAgB;IAC7C,OAAO,CAAC,MAAM,CAAC,aAAa,CAAc;mBAErB,IAAI;WA6BZ,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;WA0BzE,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC7D,SAAS,EAAE,YAAY,CAAC;QACxB,OAAO,CAAC,EAAE,YAAY,CAAC;QACvB,GAAG,CAAC,EAAE,YAAY,CAAC;QACnB,OAAO,EAAE,WAAW,CAAC;KACxB,GAAG,OAAO,CAAC,IAAI,CAAC;WAmBJ,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;WA0BvE,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE;QAC/D,IAAI,EAAE,UAAU,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,OAAO,CAAC;KACvB,GAAG,OAAO,CAAC,IAAI,CAAC;WAmBJ,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBnC;;;OAGG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAGnD"}
|
package/dist/MeshParser.d.ts
CHANGED
|
@@ -55,11 +55,11 @@ export declare class MeshParser {
|
|
|
55
55
|
/**
|
|
56
56
|
* Create Three.js BufferGeometry from Draco compressed mesh data
|
|
57
57
|
*/
|
|
58
|
-
static createGeometry(geoInfo: MeshGeometryInfo, dataBlob: Uint8Array, dracoLoader: DRACOLoader): Promise<THREE.BufferGeometry>;
|
|
58
|
+
static createGeometry(geoInfo: MeshGeometryInfo, dataBlob: Uint8Array, dracoLoader: DRACOLoader, cacheKey?: string, version?: string): Promise<THREE.BufferGeometry>;
|
|
59
59
|
/**
|
|
60
60
|
* Build Three.js scene from parsed mesh data
|
|
61
61
|
*/
|
|
62
|
-
static buildScene(parsedData: ReturnType<typeof MeshParser.parseMeshData>, dataBlob: Uint8Array, dracoLoader: DRACOLoader): Promise<THREE.Group>;
|
|
62
|
+
static buildScene(parsedData: ReturnType<typeof MeshParser.parseMeshData>, dataBlob: Uint8Array, dracoLoader: DRACOLoader, cacheKeyPrefix?: string, version?: string): Promise<THREE.Group>;
|
|
63
63
|
/**
|
|
64
64
|
* Read null-terminated string from buffer
|
|
65
65
|
*/
|
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;AAIxE,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,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC;IAuE1K;;OAEG;WACU,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAoGjM;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;CAK5B"}
|
package/dist/StowKitLoader.d.ts
CHANGED
|
@@ -38,8 +38,11 @@ export declare class StowKitLoader {
|
|
|
38
38
|
static load(url: string, options?: StowKitLoaderOptions): Promise<StowKitPack>;
|
|
39
39
|
/**
|
|
40
40
|
* Load a .stow pack from memory (ArrayBuffer, Blob, or File)
|
|
41
|
+
* @param data - The .stow file data
|
|
42
|
+
* @param options - Loader options
|
|
43
|
+
* @param cacheKey - Optional unique identifier for caching (e.g., CDN URL). Recommended for files loaded from CDN.
|
|
41
44
|
*/
|
|
42
|
-
static loadFromMemory(data: ArrayBuffer | Blob | File, options?: StowKitLoaderOptions): Promise<StowKitPack>;
|
|
45
|
+
static loadFromMemory(data: ArrayBuffer | Blob | File, options?: StowKitLoaderOptions, cacheKey?: string): Promise<StowKitPack>;
|
|
43
46
|
/**
|
|
44
47
|
* Initialize the loader (called automatically on first load)
|
|
45
48
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StowKitLoader.d.ts","sourceRoot":"","sources":["../src/StowKitLoader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,WAAW,oBAAoB;IACjC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,aAAa;IACtB,OAAO,CAAC,MAAM,CAAC,UAAU,CAA2B;IACpD,OAAO,CAAC,MAAM,CAAC,WAAW,CAA4B;IACtD,OAAO,CAAC,MAAM,CAAC,WAAW,CAAS;IACnC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA0C;IAEjE;;OAEG;WACU,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"StowKitLoader.d.ts","sourceRoot":"","sources":["../src/StowKitLoader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,WAAW,oBAAoB;IACjC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,aAAa;IACtB,OAAO,CAAC,MAAM,CAAC,UAAU,CAA2B;IACpD,OAAO,CAAC,MAAM,CAAC,WAAW,CAA4B;IACtD,OAAO,CAAC,MAAM,CAAC,WAAW,CAAS;IACnC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA0C;IAEjE;;OAEG;WACU,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,CAAC;IA0BpF;;;;;OAKG;WACU,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,oBAAoB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAgCrI;;OAEG;mBACkB,UAAU;CAoBlC"}
|
package/dist/StowKitPack.d.ts
CHANGED
|
@@ -10,7 +10,9 @@ export declare class StowKitPack {
|
|
|
10
10
|
private ktx2Loader;
|
|
11
11
|
private dracoLoader;
|
|
12
12
|
private textureCache;
|
|
13
|
-
|
|
13
|
+
private packVersion;
|
|
14
|
+
private packUrl;
|
|
15
|
+
constructor(reader: StowKitReader, ktx2Loader: KTX2Loader, dracoLoader: DRACOLoader, packUrl?: string, packVersion?: string);
|
|
14
16
|
/**
|
|
15
17
|
* Load a skinned mesh by its string ID
|
|
16
18
|
*/
|
|
@@ -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,EAAc,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"StowKitPack.d.ts","sourceRoot":"","sources":["../src/StowKitPack.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { StowKitLoader } from './StowKitLoader';
|
|
6
6
|
export { StowKitPack } from './StowKitPack';
|
|
7
|
+
export { AssetMemoryCache } from './AssetCache';
|
|
7
8
|
export type { StowKitLoaderOptions } from './StowKitLoader';
|
|
8
9
|
export type { MeshGeometryInfo, MaterialPropertyValue, MaterialData, Node, MeshMetadata } from './MeshParser';
|
|
9
10
|
export { AssetType, PerfLogger } from '@stowkit/reader';
|
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,UAAU,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,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,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"}
|
|
@@ -4,6 +4,154 @@ import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
|
4
4
|
import { PerfLogger, StowKitReader } from '@stowkit/reader';
|
|
5
5
|
export { AssetType, PerfLogger } from '@stowkit/reader';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Persistent asset cache using IndexedDB
|
|
9
|
+
* Caches decoded Draco geometries and transcoded Basis textures
|
|
10
|
+
* Invalidates when source .stow file changes
|
|
11
|
+
*/
|
|
12
|
+
class AssetMemoryCache {
|
|
13
|
+
static async init() {
|
|
14
|
+
if (this.db)
|
|
15
|
+
return;
|
|
16
|
+
if (this.initPromise)
|
|
17
|
+
return this.initPromise;
|
|
18
|
+
this.initPromise = new Promise((resolve, reject) => {
|
|
19
|
+
const request = indexedDB.open(this.DB_NAME, this.DB_VERSION);
|
|
20
|
+
request.onerror = () => reject(request.error);
|
|
21
|
+
request.onsuccess = () => {
|
|
22
|
+
this.db = request.result;
|
|
23
|
+
resolve();
|
|
24
|
+
};
|
|
25
|
+
request.onupgradeneeded = (event) => {
|
|
26
|
+
const db = event.target.result;
|
|
27
|
+
if (!db.objectStoreNames.contains(this.GEOMETRY_STORE)) {
|
|
28
|
+
db.createObjectStore(this.GEOMETRY_STORE);
|
|
29
|
+
}
|
|
30
|
+
if (!db.objectStoreNames.contains(this.TEXTURE_STORE)) {
|
|
31
|
+
db.createObjectStore(this.TEXTURE_STORE);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
return this.initPromise;
|
|
36
|
+
}
|
|
37
|
+
static async getGeometry(key, version) {
|
|
38
|
+
try {
|
|
39
|
+
await this.init();
|
|
40
|
+
if (!this.db)
|
|
41
|
+
return null;
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
const transaction = this.db.transaction([this.GEOMETRY_STORE], 'readonly');
|
|
44
|
+
const store = transaction.objectStore(this.GEOMETRY_STORE);
|
|
45
|
+
const request = store.get(key);
|
|
46
|
+
request.onsuccess = () => {
|
|
47
|
+
const cached = request.result;
|
|
48
|
+
if (cached && cached.version === version) {
|
|
49
|
+
resolve(cached);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
resolve(null);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
request.onerror = () => resolve(null);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
static async setGeometry(key, version, geometry) {
|
|
63
|
+
try {
|
|
64
|
+
await this.init();
|
|
65
|
+
if (!this.db)
|
|
66
|
+
return;
|
|
67
|
+
const cached = { ...geometry, version };
|
|
68
|
+
return new Promise((resolve) => {
|
|
69
|
+
const transaction = this.db.transaction([this.GEOMETRY_STORE], 'readwrite');
|
|
70
|
+
const store = transaction.objectStore(this.GEOMETRY_STORE);
|
|
71
|
+
store.put(cached, key);
|
|
72
|
+
transaction.oncomplete = () => resolve();
|
|
73
|
+
transaction.onerror = () => resolve();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Silently fail if IndexedDB unavailable
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
static async getTexture(key, version) {
|
|
81
|
+
try {
|
|
82
|
+
await this.init();
|
|
83
|
+
if (!this.db)
|
|
84
|
+
return null;
|
|
85
|
+
return new Promise((resolve) => {
|
|
86
|
+
const transaction = this.db.transaction([this.TEXTURE_STORE], 'readonly');
|
|
87
|
+
const store = transaction.objectStore(this.TEXTURE_STORE);
|
|
88
|
+
const request = store.get(key);
|
|
89
|
+
request.onsuccess = () => {
|
|
90
|
+
const cached = request.result;
|
|
91
|
+
if (cached && cached.version === version) {
|
|
92
|
+
resolve(cached);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
resolve(null);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
request.onerror = () => resolve(null);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
static async setTexture(key, version, textureData) {
|
|
106
|
+
try {
|
|
107
|
+
await this.init();
|
|
108
|
+
if (!this.db)
|
|
109
|
+
return;
|
|
110
|
+
const cached = { ...textureData, version };
|
|
111
|
+
return new Promise((resolve) => {
|
|
112
|
+
const transaction = this.db.transaction([this.TEXTURE_STORE], 'readwrite');
|
|
113
|
+
const store = transaction.objectStore(this.TEXTURE_STORE);
|
|
114
|
+
store.put(cached, key);
|
|
115
|
+
transaction.oncomplete = () => resolve();
|
|
116
|
+
transaction.onerror = () => resolve();
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Silently fail if IndexedDB unavailable
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
static async clear() {
|
|
124
|
+
try {
|
|
125
|
+
await this.init();
|
|
126
|
+
if (!this.db)
|
|
127
|
+
return;
|
|
128
|
+
return new Promise((resolve) => {
|
|
129
|
+
const transaction = this.db.transaction([this.GEOMETRY_STORE, this.TEXTURE_STORE], 'readwrite');
|
|
130
|
+
transaction.objectStore(this.GEOMETRY_STORE).clear();
|
|
131
|
+
transaction.objectStore(this.TEXTURE_STORE).clear();
|
|
132
|
+
transaction.oncomplete = () => resolve();
|
|
133
|
+
transaction.onerror = () => resolve();
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// Silently fail
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Generate a version hash for cache invalidation
|
|
142
|
+
* Based on file size only
|
|
143
|
+
*/
|
|
144
|
+
static generateVersion(fileSize) {
|
|
145
|
+
return `${fileSize}`;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
AssetMemoryCache.db = null;
|
|
149
|
+
AssetMemoryCache.initPromise = null;
|
|
150
|
+
AssetMemoryCache.DB_NAME = 'StowKitAssetCache';
|
|
151
|
+
AssetMemoryCache.DB_VERSION = 1;
|
|
152
|
+
AssetMemoryCache.GEOMETRY_STORE = 'geometries';
|
|
153
|
+
AssetMemoryCache.TEXTURE_STORE = 'textures';
|
|
154
|
+
|
|
7
155
|
class MeshParser {
|
|
8
156
|
/**
|
|
9
157
|
* Parse mesh metadata from binary data
|
|
@@ -191,49 +339,75 @@ class MeshParser {
|
|
|
191
339
|
/**
|
|
192
340
|
* Create Three.js BufferGeometry from Draco compressed mesh data
|
|
193
341
|
*/
|
|
194
|
-
static async createGeometry(geoInfo, dataBlob, dracoLoader) {
|
|
195
|
-
|
|
342
|
+
static async createGeometry(geoInfo, dataBlob, dracoLoader, cacheKey, version) {
|
|
343
|
+
// Try loading from IndexedDB cache first
|
|
344
|
+
if (cacheKey && version) {
|
|
345
|
+
const cached = await AssetMemoryCache.getGeometry(cacheKey, version);
|
|
346
|
+
if (cached) {
|
|
347
|
+
PerfLogger.log(`[Perf] Geometry cache hit: ${cacheKey}`);
|
|
348
|
+
const geometry = new THREE.BufferGeometry();
|
|
349
|
+
geometry.setAttribute('position', new THREE.BufferAttribute(cached.positions, 3));
|
|
350
|
+
if (cached.normals) {
|
|
351
|
+
geometry.setAttribute('normal', new THREE.BufferAttribute(cached.normals, 3));
|
|
352
|
+
}
|
|
353
|
+
if (cached.uvs) {
|
|
354
|
+
geometry.setAttribute('uv', new THREE.BufferAttribute(cached.uvs, 2));
|
|
355
|
+
}
|
|
356
|
+
geometry.setIndex(new THREE.BufferAttribute(cached.indices, 1));
|
|
357
|
+
return geometry;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
196
360
|
// Extract the Draco compressed buffer
|
|
197
361
|
if (geoInfo.compressedBufferOffset + geoInfo.compressedBufferSize > dataBlob.length) {
|
|
198
362
|
throw new Error(`Compressed buffer out of bounds: offset=${geoInfo.compressedBufferOffset}, size=${geoInfo.compressedBufferSize}, dataLength=${dataBlob.length}`);
|
|
199
363
|
}
|
|
200
364
|
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)`);
|
|
203
365
|
// Decode using Draco
|
|
204
|
-
// Create a blob URL for the Draco data (DRACOLoader expects a URL)
|
|
205
366
|
const arrayBuffer = compressedData.buffer.slice(compressedData.byteOffset, compressedData.byteOffset + compressedData.byteLength);
|
|
206
367
|
const blob = new Blob([arrayBuffer]);
|
|
207
368
|
const url = URL.createObjectURL(blob);
|
|
208
|
-
const decodeStart = performance.now();
|
|
209
369
|
const geometry = await new Promise((resolve, reject) => {
|
|
210
370
|
dracoLoader.load(url, (decoded) => {
|
|
211
371
|
URL.revokeObjectURL(url);
|
|
212
|
-
const decodeEnd = performance.now();
|
|
213
|
-
PerfLogger.log(`[Perf] Draco decode: ${(decodeEnd - decodeStart).toFixed(2)}ms (vertices: ${geoInfo.vertexCount}, indices: ${geoInfo.indexCount})`);
|
|
214
372
|
resolve(decoded);
|
|
215
373
|
}, undefined, (error) => {
|
|
216
374
|
URL.revokeObjectURL(url);
|
|
217
375
|
reject(new Error(`Failed to decode Draco geometry: ${error}`));
|
|
218
376
|
});
|
|
219
377
|
});
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
|
|
378
|
+
// Cache the decoded geometry
|
|
379
|
+
if (cacheKey && version) {
|
|
380
|
+
const posAttr = geometry.getAttribute('position');
|
|
381
|
+
const normAttr = geometry.getAttribute('normal');
|
|
382
|
+
const uvAttr = geometry.getAttribute('uv');
|
|
383
|
+
const indexAttr = geometry.index;
|
|
384
|
+
if (posAttr && 'array' in posAttr && indexAttr && 'array' in indexAttr) {
|
|
385
|
+
AssetMemoryCache.setGeometry(cacheKey, version, {
|
|
386
|
+
positions: posAttr.array,
|
|
387
|
+
normals: (normAttr && 'array' in normAttr) ? normAttr.array : undefined,
|
|
388
|
+
uvs: (uvAttr && 'array' in uvAttr) ? uvAttr.array : undefined,
|
|
389
|
+
indices: indexAttr.array
|
|
390
|
+
}).catch(() => {
|
|
391
|
+
// Silent fail - caching is optional
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
}
|
|
223
395
|
return geometry;
|
|
224
396
|
}
|
|
225
397
|
/**
|
|
226
398
|
* Build Three.js scene from parsed mesh data
|
|
227
399
|
*/
|
|
228
|
-
static async buildScene(parsedData, dataBlob, dracoLoader) {
|
|
400
|
+
static async buildScene(parsedData, dataBlob, dracoLoader, cacheKeyPrefix, version) {
|
|
229
401
|
const root = new THREE.Group();
|
|
230
402
|
root.name = 'StowKitMesh';
|
|
231
403
|
const { geometries, materials, nodes, meshIndices } = parsedData;
|
|
232
404
|
// Pre-load ALL geometries in parallel for maximum speed
|
|
233
|
-
|
|
234
|
-
const geometryPromises = geometries.map(geoInfo => this.createGeometry(geoInfo, dataBlob, dracoLoader));
|
|
405
|
+
const dracoStart = performance.now();
|
|
406
|
+
const geometryPromises = geometries.map((geoInfo, index) => this.createGeometry(geoInfo, dataBlob, dracoLoader, cacheKeyPrefix ? `${cacheKeyPrefix}_geo${index}` : undefined, version));
|
|
235
407
|
const loadedGeometries = await Promise.all(geometryPromises);
|
|
236
|
-
|
|
408
|
+
const dracoTime = performance.now() - dracoStart;
|
|
409
|
+
const totalVerts = geometries.reduce((sum, g) => sum + g.vertexCount, 0);
|
|
410
|
+
PerfLogger.log(`[Perf] Draco: ${dracoTime.toFixed(2)}ms (${geometries.length} meshes, ${totalVerts} verts)`);
|
|
237
411
|
// Create all Three.js objects for nodes
|
|
238
412
|
const nodeObjects = [];
|
|
239
413
|
for (const node of nodes) {
|
|
@@ -320,11 +494,13 @@ class MeshParser {
|
|
|
320
494
|
* Represents an opened StowKit pack with methods to load assets by name
|
|
321
495
|
*/
|
|
322
496
|
class StowKitPack {
|
|
323
|
-
constructor(reader, ktx2Loader, dracoLoader) {
|
|
497
|
+
constructor(reader, ktx2Loader, dracoLoader, packUrl = '', packVersion = '') {
|
|
324
498
|
this.textureCache = new Map();
|
|
325
499
|
this.reader = reader;
|
|
326
500
|
this.ktx2Loader = ktx2Loader;
|
|
327
501
|
this.dracoLoader = dracoLoader;
|
|
502
|
+
this.packUrl = packUrl;
|
|
503
|
+
this.packVersion = packVersion || Date.now().toString();
|
|
328
504
|
}
|
|
329
505
|
/**
|
|
330
506
|
* Load a skinned mesh by its string ID
|
|
@@ -653,17 +829,13 @@ class StowKitPack {
|
|
|
653
829
|
async loadMesh(assetPath) {
|
|
654
830
|
const totalStart = performance.now();
|
|
655
831
|
// Find asset by path
|
|
656
|
-
const findStart = performance.now();
|
|
657
832
|
const assetIndex = this.reader.findAssetByPath(assetPath);
|
|
658
833
|
if (assetIndex < 0) {
|
|
659
834
|
throw new Error(`Mesh not found: ${assetPath}`);
|
|
660
835
|
}
|
|
661
|
-
PerfLogger.log(`[Perf] Find asset: ${(performance.now() - findStart).toFixed(2)}ms`);
|
|
662
836
|
// Read mesh data and metadata
|
|
663
|
-
const readStart = performance.now();
|
|
664
837
|
const data = this.reader.readAssetData(assetIndex);
|
|
665
838
|
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)`);
|
|
667
839
|
if (!data) {
|
|
668
840
|
throw new Error(`Failed to read mesh data: ${assetPath}`);
|
|
669
841
|
}
|
|
@@ -671,18 +843,19 @@ class StowKitPack {
|
|
|
671
843
|
throw new Error(`No metadata available: ${assetPath}`);
|
|
672
844
|
}
|
|
673
845
|
// Parse mesh data
|
|
674
|
-
const parseStart = performance.now();
|
|
675
846
|
const parsedData = MeshParser.parseMeshData(metadata, data);
|
|
676
|
-
PerfLogger.log(`[Perf] Parse mesh metadata: ${(performance.now() - parseStart).toFixed(2)}ms`);
|
|
677
847
|
// Load textures for materials
|
|
678
848
|
const textureStart = performance.now();
|
|
679
849
|
const textureNames = await this.loadMaterialTextures(parsedData.materialData, parsedData.materials);
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
850
|
+
const textureTime = performance.now() - textureStart;
|
|
851
|
+
if (textureNames.length > 0) {
|
|
852
|
+
PerfLogger.log(`[Perf] Textures: ${textureTime.toFixed(2)}ms (${textureNames.join(', ')})`);
|
|
853
|
+
}
|
|
854
|
+
// Build Three.js scene with Draco decoder (with caching)
|
|
855
|
+
const cacheKey = `${this.packUrl}::${assetPath}`;
|
|
856
|
+
const scene = await MeshParser.buildScene(parsedData, data, this.dracoLoader, cacheKey, this.packVersion);
|
|
857
|
+
const totalTime = performance.now() - totalStart;
|
|
858
|
+
PerfLogger.log(`[Perf] === Mesh "${assetPath}": ${totalTime.toFixed(2)}ms total ===`);
|
|
686
859
|
return scene;
|
|
687
860
|
}
|
|
688
861
|
/**
|
|
@@ -691,7 +864,6 @@ class StowKitPack {
|
|
|
691
864
|
async loadTexture(assetPath) {
|
|
692
865
|
// Check cache first
|
|
693
866
|
if (this.textureCache.has(assetPath)) {
|
|
694
|
-
PerfLogger.log(`[Perf] Texture cache hit: ${assetPath}`);
|
|
695
867
|
return this.textureCache.get(assetPath);
|
|
696
868
|
}
|
|
697
869
|
// Cache the promise to avoid duplicate loads
|
|
@@ -1029,18 +1201,29 @@ class StowKitPack {
|
|
|
1029
1201
|
return Array.from(uniqueTextures);
|
|
1030
1202
|
}
|
|
1031
1203
|
async loadKTX2Texture(data, textureName) {
|
|
1032
|
-
|
|
1204
|
+
// Try IndexedDB cache first
|
|
1205
|
+
const cacheKey = textureName ? `${this.packUrl}::${textureName}` : undefined;
|
|
1206
|
+
if (cacheKey) {
|
|
1207
|
+
const startCache = performance.now();
|
|
1208
|
+
const cached = await AssetMemoryCache.getTexture(cacheKey, this.packVersion);
|
|
1209
|
+
if (cached) {
|
|
1210
|
+
PerfLogger.log(`[Perf] Texture cache hit (IndexedDB): ${textureName} (${(performance.now() - startCache).toFixed(2)}ms)`);
|
|
1211
|
+
const texture = new THREE.CompressedTexture([{ data: cached.data, width: cached.width, height: cached.height }], cached.width, cached.height, cached.format, THREE.UnsignedByteType);
|
|
1212
|
+
texture.needsUpdate = true;
|
|
1213
|
+
return texture;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1033
1216
|
// Create blob URL - KTX2Loader requires a URL, can't use ArrayBuffer directly
|
|
1034
1217
|
const arrayBuffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
1035
1218
|
const blob = new Blob([arrayBuffer]);
|
|
1036
1219
|
const url = URL.createObjectURL(blob);
|
|
1037
1220
|
try {
|
|
1038
|
-
|
|
1039
|
-
|
|
1221
|
+
const decodeStart = performance.now();
|
|
1222
|
+
const texture = await new Promise((resolve, reject) => {
|
|
1040
1223
|
this.ktx2Loader.load(url, (texture) => {
|
|
1041
1224
|
URL.revokeObjectURL(url);
|
|
1042
|
-
const
|
|
1043
|
-
PerfLogger.log(`[Perf] Basis
|
|
1225
|
+
const decodeTime = performance.now() - decodeStart;
|
|
1226
|
+
PerfLogger.log(`[Perf] Basis decode: ${decodeTime.toFixed(2)}ms (${textureName || 'unknown'}, ${texture.image?.width}x${texture.image?.height})`);
|
|
1044
1227
|
texture.needsUpdate = true;
|
|
1045
1228
|
resolve(texture);
|
|
1046
1229
|
}, undefined, (error) => {
|
|
@@ -1048,6 +1231,22 @@ class StowKitPack {
|
|
|
1048
1231
|
reject(error);
|
|
1049
1232
|
});
|
|
1050
1233
|
});
|
|
1234
|
+
// Cache the transcoded texture data to IndexedDB
|
|
1235
|
+
if (cacheKey && texture.mipmaps && texture.mipmaps.length > 0) {
|
|
1236
|
+
const mipmap = texture.mipmaps[0];
|
|
1237
|
+
const dataArray = new Uint8Array(mipmap.data.buffer, mipmap.data.byteOffset, mipmap.data.byteLength);
|
|
1238
|
+
AssetMemoryCache.setTexture(cacheKey, this.packVersion, {
|
|
1239
|
+
data: dataArray,
|
|
1240
|
+
width: mipmap.width,
|
|
1241
|
+
height: mipmap.height,
|
|
1242
|
+
format: texture.format,
|
|
1243
|
+
internalFormat: texture.format,
|
|
1244
|
+
compressed: true
|
|
1245
|
+
}).catch(() => {
|
|
1246
|
+
// Silent fail - caching is optional
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
return texture;
|
|
1051
1250
|
}
|
|
1052
1251
|
catch (error) {
|
|
1053
1252
|
URL.revokeObjectURL(url);
|
|
@@ -1108,17 +1307,22 @@ class StowKitLoader {
|
|
|
1108
1307
|
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
1109
1308
|
}
|
|
1110
1309
|
const arrayBuffer = await response.arrayBuffer();
|
|
1310
|
+
// Generate version for cache invalidation (based on file size)
|
|
1311
|
+
const version = `${arrayBuffer.byteLength}`;
|
|
1111
1312
|
// Create a new reader instance for this pack
|
|
1112
1313
|
const reader = new StowKitReader(this.wasmPath);
|
|
1113
1314
|
await reader.init();
|
|
1114
1315
|
await reader.open(arrayBuffer);
|
|
1115
1316
|
// Return pack wrapper with its own dedicated reader
|
|
1116
|
-
return new StowKitPack(reader, this.ktx2Loader, this.dracoLoader);
|
|
1317
|
+
return new StowKitPack(reader, this.ktx2Loader, this.dracoLoader, url, version);
|
|
1117
1318
|
}
|
|
1118
1319
|
/**
|
|
1119
1320
|
* Load a .stow pack from memory (ArrayBuffer, Blob, or File)
|
|
1321
|
+
* @param data - The .stow file data
|
|
1322
|
+
* @param options - Loader options
|
|
1323
|
+
* @param cacheKey - Optional unique identifier for caching (e.g., CDN URL). Recommended for files loaded from CDN.
|
|
1120
1324
|
*/
|
|
1121
|
-
static async loadFromMemory(data, options) {
|
|
1325
|
+
static async loadFromMemory(data, options, cacheKey) {
|
|
1122
1326
|
// Initialize loaders if needed
|
|
1123
1327
|
if (!this.initialized) {
|
|
1124
1328
|
await this.initialize(options);
|
|
@@ -1137,12 +1341,15 @@ class StowKitLoader {
|
|
|
1137
1341
|
else {
|
|
1138
1342
|
throw new Error('Data must be ArrayBuffer, Blob, or File');
|
|
1139
1343
|
}
|
|
1344
|
+
// Generate version for cache invalidation (based on file size)
|
|
1345
|
+
const version = `${arrayBuffer.byteLength}`;
|
|
1346
|
+
const packUrl = cacheKey || 'memory';
|
|
1140
1347
|
// Create a new reader instance for this pack
|
|
1141
1348
|
const reader = new StowKitReader(this.wasmPath);
|
|
1142
1349
|
await reader.init();
|
|
1143
1350
|
await reader.open(arrayBuffer);
|
|
1144
1351
|
// Return pack wrapper with its own dedicated reader
|
|
1145
|
-
return new StowKitPack(reader, this.ktx2Loader, this.dracoLoader);
|
|
1352
|
+
return new StowKitPack(reader, this.ktx2Loader, this.dracoLoader, packUrl, version);
|
|
1146
1353
|
}
|
|
1147
1354
|
/**
|
|
1148
1355
|
* Initialize the loader (called automatically on first load)
|
|
@@ -1169,5 +1376,5 @@ StowKitLoader.dracoLoader = null;
|
|
|
1169
1376
|
StowKitLoader.initialized = false;
|
|
1170
1377
|
StowKitLoader.wasmPath = '/stowkit/stowkit_reader.wasm';
|
|
1171
1378
|
|
|
1172
|
-
export { StowKitLoader, StowKitPack };
|
|
1379
|
+
export { AssetMemoryCache, StowKitLoader, StowKitPack };
|
|
1173
1380
|
//# sourceMappingURL=stowkit-three-loader.esm.js.map
|