diff --git a/spine-ts/spine-core/src/AssetManagerBase.ts b/spine-ts/spine-core/src/AssetManagerBase.ts index e5ea26a5e..52ec70562 100644 --- a/spine-ts/spine-core/src/AssetManagerBase.ts +++ b/spine-ts/spine-core/src/AssetManagerBase.ts @@ -176,7 +176,7 @@ export class AssetManagerBase implements Disposable { return blob ? createImageBitmap(blob, { premultiplyAlpha: "none", colorSpaceConversion: "none" }) : null; }).then((bitmap) => { if (bitmap) { - const texture = this.textureLoader(bitmap); + const texture = this.createTexture(path, bitmap); this.success(success, path, texture); resolve(texture); }; @@ -185,7 +185,7 @@ export class AssetManagerBase implements Disposable { let image = new Image(); image.crossOrigin = "anonymous"; image.onload = () => { - const texture = this.textureLoader(image); + const texture = this.createTexture(path, image); this.success(success, path, texture); resolve(texture); }; @@ -214,7 +214,7 @@ export class AssetManagerBase implements Disposable { this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { this.downloader.downloadText(path, (atlasText: string): void => { try { - let atlas = new TextureAtlas(atlasText); + const atlas = this.createTextureAtlas(path, atlasText); let toLoad = atlas.pages.length, abort = false; for (let page of atlas.pages) { this.loadTexture(!fileAlias ? parent + page.name : fileAlias[page.name!], @@ -262,7 +262,7 @@ export class AssetManagerBase implements Disposable { this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { this.downloader.downloadText(path, (atlasText: string): void => { try { - const atlas = new TextureAtlas(atlasText); + const atlas = this.createTextureAtlas(path, atlasText); this.success(success, path, atlas); resolve(atlas); } catch (e) { @@ -378,9 +378,12 @@ export class AssetManagerBase implements Disposable { // dispose asset only if it's not used by others disposeAsset (path: string) { - if (--this.cache.assetsRefCount[path] === 0) { - this.remove(path) + const asset = this.cache.assets[path]; + if (asset instanceof TextureAtlas) { + asset.dispose(); + return; } + this.disposeAssetInternal(path); } hasErrors () { @@ -390,6 +393,33 @@ export class AssetManagerBase implements Disposable { getErrors () { return this.errors; } + + private disposeAssetInternal (path: string) { + if (this.cache.assetsRefCount[path] > 0 && --this.cache.assetsRefCount[path] === 0) { + return this.remove(path); + } + } + + private createTextureAtlas (path: string, atlasText: string): TextureAtlas { + const atlas = new TextureAtlas(atlasText); + atlas.dispose = () => { + if (this.cache.assetsRefCount[path] <= 0) return; + this.disposeAssetInternal(path); + for (const page of atlas.pages) { + page.texture?.dispose(); + } + } + return atlas; + } + + private createTexture (path: string, image: HTMLImageElement | ImageBitmap): Texture { + const texture = this.textureLoader(image); + const textureDispose = texture.dispose.bind(texture); + texture.dispose = () => { + if (this.disposeAssetInternal(path)) textureDispose(); + } + return texture; + } } export class AssetCache { diff --git a/spine-ts/spine-webcomponents/src/SpineWebComponentSkeleton.ts b/spine-ts/spine-webcomponents/src/SpineWebComponentSkeleton.ts index 0248c189e..42e898038 100644 --- a/spine-ts/spine-webcomponents/src/SpineWebComponentSkeleton.ts +++ b/spine-ts/spine-webcomponents/src/SpineWebComponentSkeleton.ts @@ -32,27 +32,27 @@ import { AnimationState, AnimationStateData, AtlasAttachmentLoader, + Bone, Disposable, LoadingScreen, + MeshAttachment, MixBlend, MixDirection, + NumberArrayLike, Physics, + RegionAttachment, + Skeleton, SkeletonBinary, SkeletonData, SkeletonJson, - Skeleton, - TextureAtlas, - Vector2, - Utils, - NumberArrayLike, - Slot, - RegionAttachment, - MeshAttachment, - Bone, Skin, + Slot, + TextureAtlas, + Utils, + Vector2, } from "@esotericsoftware/spine-webgl"; -import { AttributeTypes, castValue, isBase64, Rectangle } from "./wcUtils.js"; import { SpineWebComponentOverlay } from "./SpineWebComponentOverlay.js"; +import { AttributeTypes, castValue, isBase64, Rectangle } from "./wcUtils.js"; type UpdateSpineWidgetFunction = (delta: number, skeleton: Skeleton, state: AnimationState) => void; @@ -1318,7 +1318,6 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable const { assetManager } = this.overlay; if (this.lastAtlasPath) assetManager.disposeAsset(this.lastAtlasPath); if (this.lastSkelPath) assetManager.disposeAsset(this.lastSkelPath); - for (const texturePath of this.lastTexturePaths) assetManager.disposeAsset(texturePath); } }