[ts][pixi-v8] Clean up SpinePipe after Spine object is destroyed. Closes #2678.

This commit is contained in:
Davide Tantillo 2024-11-11 15:44:02 +01:00
parent 8a8fc74f8e
commit fb3855ad65

View File

@ -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<number, BLEND_MODES> = {
0: 'normal',
1: 'add',
2: 'multiply',
3: 'screen'
};
type GpuSpineDataElement = { slotBatches: Record<string, BatchableSpineSlot> };
// eslint-disable-next-line max-len
export class SpinePipe implements RenderPipe<Spine> {
/** @ignore */
@ -59,7 +63,8 @@ export class SpinePipe implements RenderPipe<Spine> {
renderer: Renderer;
private gpuSpineData: Record<string, any> = {};
private gpuSpineData: Record<string, GpuSpineDataElement> = {};
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<Spine> {
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<Spine> {
}
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<Spine> {
}
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<Spine> {
}
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);