From 8fb691c05434e75361c2190b5d6a81e26f03852f Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Tue, 27 Jun 2023 15:10:53 +0200 Subject: [PATCH] [pixi] Clean-up and improvements. --- examples/export/runtimes.sh | 5 ++ spine-ts/spine-pixi/example/index.html | 2 +- spine-ts/spine-pixi/src/DarkSlotMesh.ts | 4 +- spine-ts/spine-pixi/src/SlotMesh.ts | 4 +- spine-ts/spine-pixi/src/Spine.ts | 86 +++++-------------- spine-ts/spine-pixi/src/SpineDebugRenderer.ts | 28 +++--- spine-ts/spine-pixi/src/SpineTexture.ts | 18 ++-- 7 files changed, 55 insertions(+), 92 deletions(-) diff --git a/examples/export/runtimes.sh b/examples/export/runtimes.sh index ec6e89351..bc5797888 100755 --- a/examples/export/runtimes.sh +++ b/examples/export/runtimes.sh @@ -341,6 +341,11 @@ cp -f ../spineboy/export/spineboy-pro.skel "$ROOT/spine-ts/spine-player/example/ cp -f ../spineboy/export/spineboy-pma.atlas "$ROOT/spine-ts/spine-player/example/assets/" cp -f ../spineboy/export/spineboy-pma.png "$ROOT/spine-ts/spine-player/example/assets/" +cp -f ../spineboy/export/spineboy-pro.json "$ROOT/spine-ts/spine-pixi/example/assets/" +cp -f ../spineboy/export/spineboy-pro.skel "$ROOT/spine-ts/spine-pixi/example/assets/" +cp -f ../spineboy/export/spineboy.atlas "$ROOT/spine-ts/spine-pixi/example/assets/" +cp -f ../spineboy/export/spineboy.png "$ROOT/spine-ts/spine-pixi/example/assets/" + rm "$ROOT/spine-ts/spine-phaser/example/assets/"* cp -f ../raptor/export/raptor-pro.json "$ROOT/spine-ts/spine-phaser/example/assets/" cp -f ../raptor/export/raptor-pma.atlas "$ROOT/spine-ts/spine-phaser/example/assets/" diff --git a/spine-ts/spine-pixi/example/index.html b/spine-ts/spine-pixi/example/index.html index f33de6fd8..b202bf1e6 100644 --- a/spine-ts/spine-pixi/example/index.html +++ b/spine-ts/spine-pixi/example/index.html @@ -54,7 +54,7 @@ ]); // Create the spine display object - const spineBoy = spine.Spine.from("spineboySkeletonJson", "spineboyAtlasPolypack", { scale: 0.5 }); + const spineBoy = spine.Spine.from("spineboySkeletonJson", "spineboyAtlas", { scale: 0.5 }); // .from(...) is a shortcut + cache for creating the skeleton data at a certain scale // Here would be the "long way" of doing it (without cache): diff --git a/spine-ts/spine-pixi/src/DarkSlotMesh.ts b/spine-ts/spine-pixi/src/DarkSlotMesh.ts index a08246f09..f435d3e42 100644 --- a/spine-ts/spine-pixi/src/DarkSlotMesh.ts +++ b/spine-ts/spine-pixi/src/DarkSlotMesh.ts @@ -8,10 +8,10 @@ export class DarkSlotMesh extends DarkTintMesh implements ISlotMesh { private static auxColor = [0, 0, 0, 0]; - constructor() { + constructor () { super(); } - public updateFromSpineData( + public updateFromSpineData ( slotTexture: SpineTexture, slotBlendMode: BlendMode, slotName: string, diff --git a/spine-ts/spine-pixi/src/SlotMesh.ts b/spine-ts/spine-pixi/src/SlotMesh.ts index a9a34318d..87953e0be 100644 --- a/spine-ts/spine-pixi/src/SlotMesh.ts +++ b/spine-ts/spine-pixi/src/SlotMesh.ts @@ -10,7 +10,7 @@ export class SlotMesh extends Mesh implements ISlotMesh { private static readonly auxColor = [0, 0, 0, 0]; private warnedTwoTint: boolean = false; - constructor() { + constructor () { const geometry = new MeshGeometry(); geometry.getBuffer("aVertexPosition").static = false; @@ -19,7 +19,7 @@ export class SlotMesh extends Mesh implements ISlotMesh { const meshMaterial = new MeshMaterial(Texture.EMPTY); super(geometry, meshMaterial); } - public updateFromSpineData( + public updateFromSpineData ( slotTexture: SpineTexture, slotBlendMode: BlendMode, slotName: string, diff --git a/spine-ts/spine-pixi/src/Spine.ts b/spine-ts/spine-pixi/src/Spine.ts index 4edcc2581..c95dfd95a 100644 --- a/spine-ts/spine-pixi/src/Spine.ts +++ b/spine-ts/spine-pixi/src/Spine.ts @@ -24,7 +24,6 @@ import type { IDestroyOptions, DisplayObject } from "@pixi/display"; import { Container } from "@pixi/display"; export interface ISpineOptions { - removeUnusedSlots?: boolean; autoUpdate?: boolean; slotMeshFactory?: () => ISlotMesh; } @@ -43,10 +42,10 @@ export class Spine extends Container { public state: AnimationState; private _debug?: ISpineDebugRenderer | undefined = undefined; - public get debug(): ISpineDebugRenderer | undefined { + public get debug (): ISpineDebugRenderer | undefined { return this._debug; } - public set debug(value: ISpineDebugRenderer | undefined) { + public set debug (value: ISpineDebugRenderer | undefined) { if (this._debug) { this._debug.unregisterSpine(this); } @@ -56,16 +55,14 @@ export class Spine extends Container { this._debug = value; } - // Each slot is a pixi mesh, by default we just visible=false the ones we don't need. This forces a removeChild and addChild every time we need to show a slot. - public removeUnusedSlots: boolean; protected slotMeshFactory: () => ISlotMesh; private autoUpdateWarned: boolean = false; private _autoUpdate: boolean = true; - public get autoUpdate(): boolean { + public get autoUpdate (): boolean { return this._autoUpdate; } - public set autoUpdate(value: boolean) { + public set autoUpdate (value: boolean) { if (value) { Ticker.shared.add(this.internalUpdate, this); this.autoUpdateWarned = false; @@ -88,13 +85,12 @@ export class Spine extends Container { private darkColor = new Color(); - constructor(skeletonData: SkeletonData, options?: ISpineOptions) { + constructor (skeletonData: SkeletonData, options?: ISpineOptions) { super(); this.skeleton = new Skeleton(skeletonData); const animData = new AnimationStateData(skeletonData); this.state = new AnimationState(animData); - this.removeUnusedSlots = options?.removeUnusedSlots ?? false; this.autoUpdate = options?.autoUpdate ?? true; this.slotMeshFactory = options?.slotMeshFactory ?? ((): ISlotMesh => new SlotMesh()); @@ -116,7 +112,7 @@ export class Spine extends Container { */ } - public update(deltaSeconds: number): void { + public update (deltaSeconds: number): void { if (this.autoUpdate && !this.autoUpdateWarned) { console.warn("You are calling update on a Spine instance that has autoUpdate set to true. This is probably not what you want."); this.autoUpdateWarned = true; @@ -124,18 +120,18 @@ export class Spine extends Container { this.internalUpdate(0, deltaSeconds); } - protected internalUpdate(_deltaFrame: number, deltaSeconds?: number): void { + protected internalUpdate (_deltaFrame: number, deltaSeconds?: number): void { // Because reasons, pixi uses deltaFrames at 60fps. We ignore the default deltaFrames and use the deltaSeconds from pixi ticker. this.state.update(deltaSeconds ?? Ticker.shared.deltaMS / 1000); } - public override updateTransform(): void { + public override updateTransform (): void { this.updateSpineTransform(); this.debug?.renderDebug(this); super.updateTransform(); } - protected updateSpineTransform(): void { + protected updateSpineTransform (): void { // if I ever create the linked spines, this will be useful. this.state.apply(this.skeleton); @@ -144,7 +140,7 @@ export class Spine extends Container { this.sortChildren(); } - public override destroy(options?: boolean | IDestroyOptions | undefined): void { + public override destroy (options?: boolean | IDestroyOptions | undefined): void { for (const [, mesh] of this.meshesCache) { mesh?.destroy(); } @@ -154,11 +150,8 @@ export class Spine extends Container { super.destroy(options); } - private recycleMeshes(): void { + private resetMeshes (): void { for (const [, mesh] of this.meshesCache) { - if (this.removeUnusedSlots) { - mesh.parent?.removeChild(mesh); - } mesh.zIndex = -1; mesh.visible = false; } @@ -167,7 +160,7 @@ export class Spine extends Container { /** * If you want to manually handle which meshes go on which slot and how you cache, overwrite this method. */ - protected getMeshForSlot(slot: Slot): ISlotMesh { + protected getMeshForSlot (slot: Slot): ISlotMesh { if (!this.meshesCache.has(slot)) { let mesh = this.slotMeshFactory(); this.addChild(mesh); @@ -175,10 +168,6 @@ export class Spine extends Container { return mesh; } else { let mesh = this.meshesCache.get(slot)!; - - if (this.removeUnusedSlots) { - this.addChild(mesh); - } mesh.visible = true; return mesh; } @@ -186,8 +175,8 @@ export class Spine extends Container { private verticesCache: NumberArrayLike = Utils.newFloatArray(1024); - private updateGeometry(): void { - this.recycleMeshes(); + private updateGeometry (): void { + this.resetMeshes(); let triangles: Array | null = null; let uvs: NumberArrayLike | null = null; @@ -300,46 +289,30 @@ export class Spine extends Container { Spine.clipper.clipEnd(); } - public setBonePosition(bone: string | Bone, position: IPointData): void { + public setBonePosition (bone: string | Bone, position: IPointData): void { const boneAux = bone; if (typeof bone === "string") { bone = this.skeleton.findBone(bone)!; - this.skeleton.findBone; - this.skeleton.findIkConstraint; - this.skeleton.findPathConstraint; - this.skeleton.findSlot; - this.skeleton.findTransformConstraint; - } - - if (!bone) { - console.error(`Cant set bone position! Bone ${String(boneAux)} not found`); - return; } + if (!bone) throw Error(`Cant set bone position, bone ${String(boneAux)} not found`); Spine.vectorAux.set(position.x, position.y); - if (bone.parent) - { + if (bone.parent) { const aux = bone.parent.worldToLocal(Spine.vectorAux); bone.x = aux.x; bone.y = aux.y; } - else - { + else { bone.x = Spine.vectorAux.x; bone.y = Spine.vectorAux.y; } } - public getBonePosition(bone: string | Bone, outPos?: IPointData): IPointData | undefined { + public getBonePosition (bone: string | Bone, outPos?: IPointData): IPointData | undefined { const boneAux = bone; if (typeof bone === "string") { bone = this.skeleton.findBone(bone)!; - this.skeleton.findBone; - this.skeleton.findIkConstraint; - this.skeleton.findPathConstraint; - this.skeleton.findSlot; - this.skeleton.findTransformConstraint; } if (!bone) { @@ -358,34 +331,19 @@ export class Spine extends Container { public static readonly skeletonCache: Record = Object.create(null); - public static from(skeletonAssetName: string, atlasAssetName: string, options?: ISpineOptions & { scale?: number }): Spine { + public static from (skeletonAssetName: string, atlasAssetName: string, options?: ISpineOptions & { scale?: number }): Spine { const cacheKey = `${skeletonAssetName}-${atlasAssetName}-${options?.scale ?? 1}`; - let skeletonData = Spine.skeletonCache[cacheKey]; if (skeletonData) { return new Spine(skeletonData, options); } - const skeletonAsset = Assets.get(skeletonAssetName); - const atlasAsset = Assets.get(atlasAssetName); - - // If you want a custom attachment laoder, you don't use .from(...) const attachmentLoader = new AtlasAttachmentLoader(atlasAsset); - - // What parser do we need? - let parser: SkeletonBinary | SkeletonJson; - if (skeletonAsset instanceof Uint8Array) { - parser = new SkeletonBinary(attachmentLoader); - } else { - parser = new SkeletonJson(attachmentLoader); - } + let parser = skeletonAsset instanceof Uint8Array ? new SkeletonBinary(attachmentLoader) : new SkeletonJson(attachmentLoader); parser.scale = options?.scale ?? 1; - skeletonData = parser.readSkeletonData(skeletonAsset); - Spine.skeletonCache[cacheKey] = skeletonData; - return new this(skeletonData, options); } } @@ -394,7 +352,7 @@ Skeleton.yDown = true; export interface ISlotMesh extends DisplayObject { name: string; - updateFromSpineData( + updateFromSpineData ( slotTexture: SpineTexture, slotBlendMode: BlendMode, slotName: string, diff --git a/spine-ts/spine-pixi/src/SpineDebugRenderer.ts b/spine-ts/spine-pixi/src/SpineDebugRenderer.ts index cc31d3008..a7421e886 100644 --- a/spine-ts/spine-pixi/src/SpineDebugRenderer.ts +++ b/spine-ts/spine-pixi/src/SpineDebugRenderer.ts @@ -13,17 +13,17 @@ export interface ISpineDebugRenderer { /** * This will be called every frame, after the spine has been updated. */ - renderDebug(spine: Spine): void; + renderDebug (spine: Spine): void; /** * This is called when the `spine.debug` object is set to null or when the spine is destroyed. */ - unregisterSpine(spine: Spine): void; + unregisterSpine (spine: Spine): void; /** * This is called when the `spine.debug` object is set to a new instance of a debug renderer. */ - registerSpine(spine: Spine): void; + registerSpine (spine: Spine): void; } type DebugDisplayObjects = { @@ -77,7 +77,7 @@ export class SpineDebugRenderer implements ISpineDebugRenderer { /** * The debug is attached by force to each spine object. So we need to create it inside the spine when we get the first update */ - public registerSpine(spine: Spine): void { + public registerSpine (spine: Spine): void { if (this.registeredSpines.has(spine)) { console.warn("SpineDebugRenderer.registerSpine() - this spine is already registered!", spine); return; @@ -128,11 +128,11 @@ export class SpineDebugRenderer implements ISpineDebugRenderer { debugDisplayObjects.parentDebugContainer.addChild(debugDisplayObjects.eventText); debugDisplayObjects.parentDebugContainer.zIndex = 9999999; - + // Disable screen reader and mouse input on debug objects. (debugDisplayObjects.parentDebugContainer as any).accessibleChildren = false; (debugDisplayObjects.parentDebugContainer as any).eventMode = "none"; - (debugDisplayObjects.parentDebugContainer as any ).interactiveChildren = false; + (debugDisplayObjects.parentDebugContainer as any).interactiveChildren = false; spine.addChild(debugDisplayObjects.parentDebugContainer); @@ -140,7 +140,7 @@ export class SpineDebugRenderer implements ISpineDebugRenderer { this.registeredSpines.set(spine, debugDisplayObjects); } - public renderDebug(spine: Spine): void { + public renderDebug (spine: Spine): void { if (!this.registeredSpines.has(spine)) { // This should never happen. Spines are registered when you assign spine.debug this.registerSpine(spine); @@ -203,7 +203,7 @@ export class SpineDebugRenderer implements ISpineDebugRenderer { } } - private drawBonesFunc(spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number, scale: number): void { + private drawBonesFunc (spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number, scale: number): void { const skeleton = spine.skeleton; const skeletonX = skeleton.x; const skeletonY = skeleton.y; @@ -300,7 +300,7 @@ export class SpineDebugRenderer implements ISpineDebugRenderer { debugDisplayObjects.skeletonXY.lineTo(skeletonX - startDotSize, skeletonY + startDotSize); } - private drawRegionAttachmentsFunc(spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number): void { + private drawRegionAttachmentsFunc (spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number): void { const skeleton = spine.skeleton; const slots = skeleton.slots; @@ -323,7 +323,7 @@ export class SpineDebugRenderer implements ISpineDebugRenderer { } } - private drawMeshHullAndMeshTriangles(spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number): void { + private drawMeshHullAndMeshTriangles (spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number): void { const skeleton = spine.skeleton; const slots = skeleton.slots; @@ -381,7 +381,7 @@ export class SpineDebugRenderer implements ISpineDebugRenderer { } } - private drawClippingFunc(spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number): void { + private drawClippingFunc (spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number): void { const skeleton = spine.skeleton; const slots = skeleton.slots; @@ -408,7 +408,7 @@ export class SpineDebugRenderer implements ISpineDebugRenderer { } } - private drawBoundingBoxesFunc(spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number): void { + private drawBoundingBoxesFunc (spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number): void { // draw the total outline of the bounding box debugDisplayObjects.boundingBoxesRect.lineStyle(lineWidth, this.boundingBoxesRectColor, 5); @@ -453,7 +453,7 @@ export class SpineDebugRenderer implements ISpineDebugRenderer { } } - private drawPathsFunc(spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number): void { + private drawPathsFunc (spine: Spine, debugDisplayObjects: DebugDisplayObjects, lineWidth: number): void { const skeleton = spine.skeleton; const slots = skeleton.slots; @@ -525,7 +525,7 @@ export class SpineDebugRenderer implements ISpineDebugRenderer { } } - public unregisterSpine(spine: Spine): void { + public unregisterSpine (spine: Spine): void { if (!this.registeredSpines.has(spine)) { console.warn("SpineDebugRenderer.unregisterSpine() - spine is not registered, can't unregister!", spine); } diff --git a/spine-ts/spine-pixi/src/SpineTexture.ts b/spine-ts/spine-pixi/src/SpineTexture.ts index 08e103f7e..f10488560 100644 --- a/spine-ts/spine-pixi/src/SpineTexture.ts +++ b/spine-ts/spine-pixi/src/SpineTexture.ts @@ -5,7 +5,7 @@ import { Texture as PixiTexture, SCALE_MODES, MIPMAP_MODES, WRAP_MODES, BLEND_MO export class SpineTexture extends Texture { private static textureMap: Map = new Map(); - public static from(texture: PixiBaseTexture): SpineTexture { + public static from (texture: PixiBaseTexture): SpineTexture { if (SpineTexture.textureMap.has(texture)) { return SpineTexture.textureMap.get(texture)!; } @@ -14,31 +14,31 @@ export class SpineTexture extends Texture { public readonly texture: PixiTexture; - private constructor(image: PixiBaseTexture) { + private constructor (image: PixiBaseTexture) { // Todo: maybe add error handling if you feed a video texture to spine? super((image.resource as BaseImageResource).source as any); this.texture = PixiTexture.from(image); } - public setFilters(minFilter: TextureFilter, _magFilter: TextureFilter): void { + public setFilters (minFilter: TextureFilter, _magFilter: TextureFilter): void { this.texture.baseTexture.scaleMode = SpineTexture.toPixiTextureFilter(minFilter); this.texture.baseTexture.mipmap = SpineTexture.toPixiMipMap(minFilter); // pixi only has one filter for both min and mag, too bad } - public setWraps(uWrap: TextureWrap, _vWrap: TextureWrap): void { + public setWraps (uWrap: TextureWrap, _vWrap: TextureWrap): void { this.texture.baseTexture.wrapMode = SpineTexture.toPixiTextureWrap(uWrap); // Pixi only has one setting } - public dispose(): void { + public dispose (): void { // I am not entirely sure about this... this.texture.destroy(); } - private static toPixiTextureFilter(filter: TextureFilter): SCALE_MODES { + private static toPixiTextureFilter (filter: TextureFilter): SCALE_MODES { switch (filter) { case TextureFilter.Nearest: case TextureFilter.MipMapNearestLinear: @@ -55,7 +55,7 @@ export class SpineTexture extends Texture { } } - private static toPixiMipMap(filter: TextureFilter): MIPMAP_MODES { + private static toPixiMipMap (filter: TextureFilter): MIPMAP_MODES { switch (filter) { case TextureFilter.Nearest: case TextureFilter.Linear: @@ -72,7 +72,7 @@ export class SpineTexture extends Texture { } } - private static toPixiTextureWrap(wrap: TextureWrap): WRAP_MODES { + private static toPixiTextureWrap (wrap: TextureWrap): WRAP_MODES { switch (wrap) { case TextureWrap.ClampToEdge: return WRAP_MODES.CLAMP; @@ -88,7 +88,7 @@ export class SpineTexture extends Texture { } } - public static toPixiBlending(blend: BlendMode): BLEND_MODES { + public static toPixiBlending (blend: BlendMode): BLEND_MODES { switch (blend) { case BlendMode.Normal: return BLEND_MODES.NORMAL;