diff --git a/spine-ts/spine-pixi/src/DarkSlotMesh.ts b/spine-ts/spine-pixi/src/DarkSlotMesh.ts index 4a9e02502..1f896eeef 100644 --- a/spine-ts/spine-pixi/src/DarkSlotMesh.ts +++ b/spine-ts/spine-pixi/src/DarkSlotMesh.ts @@ -99,6 +99,7 @@ export class DarkSlotMesh extends DarkTintMesh implements ISlotMesh { this.tint = DarkSlotMesh.auxColor; } this.blendMode = SpineTexture.toPixiBlending(slotBlendMode); + this.alpha = DarkSlotMesh.auxColor[3]; if (this.geometry.indexBuffer.data.length !== finalIndices.length) { this.geometry.indexBuffer.data = new Uint32Array(finalIndices); diff --git a/spine-ts/spine-pixi/src/Spine.ts b/spine-ts/spine-pixi/src/Spine.ts index 2fb82e565..925e95e7c 100644 --- a/spine-ts/spine-pixi/src/Spine.ts +++ b/spine-ts/spine-pixi/src/Spine.ts @@ -338,6 +338,20 @@ export class Spine extends Container { pixiObject.mask = null; } } + + /* + * Colors in pixi are premultiplied. + * Pixi blending modes are modified to work with premultiplied colors. We cannot create custom blending modes. + * Textures are loaded as premultiplied (see assers/atlasLoader.ts: alphaMode: `page.pma ? ALPHA_MODES.PMA : ALPHA_MODES.UNPACK`): + * - textures non premultiplied are premultiplied on GPU on upload + * - textures premultiplied are uploaded on GPU as is since they are already premultiplied + * + * We need to take this into consideration and calculates final colors for both light and dark color as if textures were always premultiplied. + * This implies for example that alpha for dark tint is always 1. This is way in DarkTintRenderer we have only the alpha of the light color. + * We implies alpha of dark color as 1 and just respective alpha byte to 1. + * (see DarkTintRenderer: const darkargb = (0xFF << 24) | darkTintRGB;) + * If we ever want to load texture as non premultiplied on GPU, we must add a new dark alpha parameter to the TintMaterial and set the alpha. + */ private renderMeshes (): void { this.resetMeshes(); @@ -403,15 +417,20 @@ export class Spine extends Container { const slotColor = slot.color; const alpha = skeletonColor.a * slotColor.a * attachmentColor.a; this.lightColor.set( - skeletonColor.r * slotColor.r * attachmentColor.r, - skeletonColor.g * slotColor.g * attachmentColor.g, - skeletonColor.b * slotColor.b * attachmentColor.b, + skeletonColor.r * slotColor.r * attachmentColor.r * alpha, + skeletonColor.g * slotColor.g * attachmentColor.g * alpha, + skeletonColor.b * slotColor.b * attachmentColor.b * alpha, alpha ); if (slot.darkColor != null) { - this.darkColor.setFromColor(slot.darkColor); + this.darkColor.set( + slot.darkColor.r * alpha, + slot.darkColor.g * alpha, + slot.darkColor.b * alpha, + 1, + ); } else { - this.darkColor.set(0, 0, 0, 0); + this.darkColor.set(0, 0, 0, 1); } let finalVertices: NumberArrayLike; @@ -443,6 +462,7 @@ export class Spine extends Container { verts[tempV++] = this.darkColor.r; verts[tempV++] = this.darkColor.g; verts[tempV++] = this.darkColor.b; + verts[tempV++] = this.darkColor.a; } } finalVertices = this.verticesCache; diff --git a/spine-ts/spine-pixi/src/darkTintMesh/DarkTintRenderer.ts b/spine-ts/spine-pixi/src/darkTintMesh/DarkTintRenderer.ts index a3f23637c..1f639f341 100644 --- a/spine-ts/spine-pixi/src/darkTintMesh/DarkTintRenderer.ts +++ b/spine-ts/spine-pixi/src/darkTintMesh/DarkTintRenderer.ts @@ -99,8 +99,13 @@ export class DarkTintRenderer extends BatchRenderer { const vertexData = element.vertexData; const textureId = element._texture.baseTexture._batchLocation; const alpha = Math.min(element.worldAlpha, 1.0); - const argb = Color.shared.setValue(element._tintRGB).toPremultiplied(alpha, (element._texture.baseTexture.alphaMode ?? 0) > 0); - const darkargb = Color.shared.setValue(element._darkTintRGB).toPremultiplied(alpha, (element._texture.baseTexture.alphaMode ?? 0) > 0); + + const alphaInt = Math.round(alpha * 255) & 0xFF; + const tintRGB = element._tintRGB & 0xFFFFFF; + const argb = (alphaInt << 24) | tintRGB; + + const darkTintRGB = element._darkTintRGB & 0xFFFFFF; + const darkargb = (0xFF << 24) | darkTintRGB; // lets not worry about tint! for now.. for (let i = 0; i < vertexData.length; i += 2) {