From fb3855ad6588d5d8ed5cfb5991a13fd858af9a29 Mon Sep 17 00:00:00 2001 From: Davide Tantillo Date: Mon, 11 Nov 2024 15:44:02 +0100 Subject: [PATCH] [ts][pixi-v8] Clean up SpinePipe after Spine object is destroyed. Closes #2678. --- spine-ts/spine-pixi-v8/src/SpinePipe.ts | 29 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/spine-ts/spine-pixi-v8/src/SpinePipe.ts b/spine-ts/spine-pixi-v8/src/SpinePipe.ts index 2c2b10322..fc76615c6 100644 --- a/spine-ts/spine-pixi-v8/src/SpinePipe.ts +++ b/spine-ts/spine-pixi-v8/src/SpinePipe.ts @@ -31,20 +31,24 @@ import { collectAllRenderables, extensions, ExtensionType, InstructionSet, + type BLEND_MODES, + type Container, type Renderer, type RenderPipe, } from 'pixi.js'; import { BatchableSpineSlot } from './BatchableSpineSlot'; import { Spine } from './Spine'; -import { MeshAttachment, RegionAttachment, SkeletonClipping } from '@esotericsoftware/spine-core'; +import { MeshAttachment, RegionAttachment } from '@esotericsoftware/spine-core'; -const spineBlendModeMap = { +const spineBlendModeMap : Record = { 0: 'normal', 1: 'add', 2: 'multiply', 3: 'screen' }; +type GpuSpineDataElement = { slotBatches: Record }; + // eslint-disable-next-line max-len export class SpinePipe implements RenderPipe { /** @ignore */ @@ -59,7 +63,8 @@ export class SpinePipe implements RenderPipe { renderer: Renderer; - private gpuSpineData: Record = {}; + private gpuSpineData: Record = {}; + private readonly _destroyRenderableBound = this.destroyRenderable.bind(this) as (renderable: Container) => void; constructor (renderer: Renderer) { this.renderer = renderer; @@ -68,10 +73,11 @@ export class SpinePipe implements RenderPipe { validateRenderable (spine: Spine): boolean { spine._validateAndTransformAttachments(); - // if pine attachments have changed, we need to rebuild the batch! + // if spine attachments have changed or destroyed, we need to rebuild the batch! if (spine.spineAttachmentsDirty) { return true; } + // if the textures have changed, we need to rebuild the batch, but only if the texture is not already in the batch else if (spine.spineTexturesDirty) { // loop through and see if the textures have changed.. @@ -101,7 +107,7 @@ export class SpinePipe implements RenderPipe { } addRenderable (spine: Spine, instructionSet: InstructionSet) { - const gpuSpine = this.gpuSpineData[spine.uid] ||= { slotBatches: { } }; + const gpuSpine = this._getSpineData(spine); const batcher = this.renderer.renderPipes.batch; @@ -145,7 +151,6 @@ export class SpinePipe implements RenderPipe { } updateRenderable (spine: Spine) { - // we assume that spine will always change its verts size.. const gpuSpine = this.gpuSpineData[spine.uid]; spine._validateAndTransformAttachments(); @@ -169,14 +174,24 @@ export class SpinePipe implements RenderPipe { } destroyRenderable (spine: Spine) { - // TODO remove the renderable from the batcher this.gpuSpineData[spine.uid] = null as any; + spine.off('destroyed', this._destroyRenderableBound); } destroy () { this.gpuSpineData = null as any; this.renderer = null as any; } + + private _getSpineData(spine: Spine): GpuSpineDataElement { + return this.gpuSpineData[spine.uid] || this._initMeshData(spine); + } + + private _initMeshData(spine: Spine): GpuSpineDataElement { + this.gpuSpineData[spine.uid] = { slotBatches: { } }; + spine.on('destroyed', this._destroyRenderableBound); + return this.gpuSpineData[spine.uid]; + } } extensions.add(SpinePipe);