diff --git a/spine-ts/spine-construct3/spine-construct3-lib/src/C3SkeletonRenderer.ts b/spine-ts/spine-construct3/spine-construct3-lib/src/C3SkeletonRenderer.ts index eaa3994df..42b0ecfc7 100644 --- a/spine-ts/spine-construct3/spine-construct3-lib/src/C3SkeletonRenderer.ts +++ b/spine-ts/spine-construct3/spine-construct3-lib/src/C3SkeletonRenderer.ts @@ -27,7 +27,7 @@ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -import { type BlendMode, type Bone, ClippingAttachment, MathUtils, MeshAttachment, PathAttachment, RegionAttachment, type Skeleton, SkeletonRendererCore, Utils, Vector2 } from "@esotericsoftware/spine-core"; +import { type BlendMode, type Bone, ClippingAttachment, MathUtils, MeshAttachment, PathAttachment, RegionAttachment, RenderCommand, type Skeleton, SkeletonRendererCore, Utils, Vector2 } from "@esotericsoftware/spine-core"; import type { C3Matrix } from "./C3Matrix"; import { BlendingModeSpineToC3, type C3TextureEditor, type C3TextureRuntime } from "./C3Texture"; @@ -40,6 +40,7 @@ abstract class C3SkeletonRenderer< Texture extends C3Texture, > extends SkeletonRendererCore { + private command?: RenderCommand; private tempVertices = new Float32Array(4096); private tempColors = new Float32Array(4096); private tempPoint = new Vector2(); @@ -53,10 +54,15 @@ abstract class C3SkeletonRenderer< super(); } - draw (skeleton: Skeleton, inColors: [number, number, number], opacity = 1) { + draw (skeleton: Skeleton, inColors: [number, number, number], opacity = 1, isPlaying = true, fromUpdate = true) { const { matrix, inv255 } = this; - let command = this.render(skeleton, true, [...inColors, opacity]); + this.command = (isPlaying || !this.command) + ? this.render(skeleton, true, [...inColors, opacity]) + : this.command; + let command = this.command; + + const { a, b, c, d, tx, ty } = matrix; while (command) { const { numVertices, positions, uvs, colors, indices, numIndices, blendMode } = command; @@ -70,11 +76,11 @@ abstract class C3SkeletonRenderer< for (let i = 0; i < numVertices; i++) { const srcIndex = i * 2; - const { x, y } = matrix.skeletonToGame(positions[srcIndex], positions[srcIndex + 1]); - const dstIndex = i * 3; - vertices[dstIndex] = x; - vertices[dstIndex + 1] = y; + const x = positions[srcIndex]; + const y = positions[srcIndex + 1]; + vertices[dstIndex] = a * x + c * y + tx; + vertices[dstIndex + 1] = b * x + d * y + ty; vertices[dstIndex + 2] = 0; const color = colors[i]; diff --git a/spine-ts/spine-construct3/src/c3runtime/instance.ts b/spine-ts/spine-construct3/src/c3runtime/instance.ts index d33d919e7..22389ddf1 100644 --- a/spine-ts/spine-construct3/src/c3runtime/instance.ts +++ b/spine-ts/spine-construct3/src/c3runtime/instance.ts @@ -19,7 +19,7 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase { propDebugSkeleton = false; isFlippedX = false; - isPlaying = true; + isPlaying = false; animationSpeed = 1.0; physicsMode = spine.Physics.update; customSkins: Record = {}; @@ -111,12 +111,19 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase { return; } - if (!this.isPlaying) return; + this.matrix.update( + this.x + this.propOffsetX, + this.y + this.propOffsetY, + this.angle + this.propOffsetAngle); - this.update(this.dt); - this.runtime.sdk.updateRender(); + if (this.isPlaying) { + this.update(this.dt); + this.runtime.sdk.updateRender(); + } } + private fromUpdate = false; + private update (delta: number) { const { state, skeleton, animationSpeed, physicsMode, matrix } = this; @@ -126,16 +133,14 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase { state.update(adjustedDelta); skeleton.update(adjustedDelta); state.apply(skeleton); - matrix.update( - this.x + this.propOffsetX, - this.y + this.propOffsetY, - this.angle + this.propOffsetAngle); this.updateHandles(skeleton, matrix); skeleton.updateWorldTransform(physicsMode); - this.updateBoneFollowers(); + this.updateBoneFollowers(matrix); + + this.fromUpdate = true; } _draw (renderer: IRenderer) { @@ -148,7 +153,8 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase { if (!skeleton) return; this.skeletonRenderer ||= new spine.C3RendererRuntime(renderer, this.matrix); - this.skeletonRenderer.draw(skeleton, this.colorRgb, this.opacity); + this.skeletonRenderer.draw(skeleton, this.colorRgb, this.opacity, this.isPlaying, this.fromUpdate); + this.fromUpdate = false; if (this.propDebugSkeleton) this.skeletonRenderer.drawDebug(skeleton, this.x, this.y, this.getBoundingQuad(false)); this.renderDragHandles(); @@ -187,6 +193,7 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase { this.runtime.addEventListener("pointermove", this.dragHandleMove); this.runtime.addEventListener("pointerup", this.dragHandleUp); } + this.isPlaying = true; } private dragHandleDown = (event: ConstructPointerEvent) => { @@ -394,6 +401,7 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase { if (this.propAnimation) { this.setAnimation(0, this.propAnimation, true); + this.isPlaying = true; } this._setSkin(); @@ -402,6 +410,7 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase { this.skeleton.scaleY = this.propScaleY; this.update(0); + this.runtime.sdk.updateRender(); this.skeletonLoaded = true; this._trigger(C3.Plugins.EsotericSoftware_SpineConstruct3.Cnds.OnSkeletonLoaded); @@ -582,7 +591,6 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase { } skeleton.setupPose(); - this.update(0); } public createCustomSkin (skinName: string) { @@ -691,13 +699,14 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase { } this.boneFollowers.set(boneName, { uid, offsetX, offsetY, offsetAngle }); + this.isPlaying = true; } public detachInstanceFromBone (boneName: string) { this.boneFollowers.delete(boneName); } - private updateBoneFollowers () { + private updateBoneFollowers (matrix: C3Matrix) { if (this.boneFollowers.size === 0) return; for (const [boneName, follower] of this.boneFollowers) { @@ -707,7 +716,7 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase { const instance = this.runtime.getInstanceByUid(follower.uid) as IWorldInstance; if (!instance) continue; - const { x, y } = this.matrix.boneToGame(bone); + const { x, y } = matrix.boneToGame(bone); const boneRotation = bone.applied.getWorldRotationX(); // Apply rotation to offset diff --git a/spine-ts/spine-core/src/SkeletonRendererCore.ts b/spine-ts/spine-core/src/SkeletonRendererCore.ts index 79c6d3d91..06adc6299 100644 --- a/spine-ts/spine-core/src/SkeletonRendererCore.ts +++ b/spine-ts/spine-core/src/SkeletonRendererCore.ts @@ -292,7 +292,7 @@ export class SkeletonRendererCore { // values with under score is the original sized array, bigger than necessary // values without under score is a view of the orignal array, sized as needed -interface RenderCommand { +export interface RenderCommand { positions: Float32Array; uvs: Float32Array; colors: Uint32Array;