Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion Extensions/Spine/managers/pixi-spine-atlas-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,38 @@ namespace gdjs {
: 'anonymous',
});
PIXI.Assets.add({ alias, src: url, data: { images } });
return PIXI.Assets.load<spine.TextureAtlas>(alias);
const atlas = await PIXI.Assets.load<spine.TextureAtlas>(alias);

// The spine-pixi-v7 tint shader always samples atlas textures as if they
// were premultiplied (see the runtime comment in `renderMeshes`). When the
// spine loader loads the atlas pages itself, it sets each page texture's
// alpha mode accordingly (`PMA` for premultiplied atlases, `UNPACK`
// otherwise). Here we instead share the textures already loaded by the
// ImageManager, which are uploaded to the GPU with PIXI's default `UNPACK`
// mode (premultiply-on-upload). For atlases exported with premultiplied
// alpha (`pma: true`), this premultiplies the texture a second time, which
// produces dark fringes/halos ("shadows") around the rendered parts.
// Align each shared texture's alpha mode with what the atlas page declares.
const imageNames = Object.keys(images);
for (const page of atlas.pages) {
const baseTexture =
images[page.name] ||
(atlas.pages.length === 1 && imageNames.length === 1
? images[imageNames[0]]
: undefined);
if (!baseTexture) continue;

const expectedAlphaMode = page.pma
? PIXI.ALPHA_MODES.PMA
: PIXI.ALPHA_MODES.UNPACK;
if (baseTexture.alphaMode !== expectedAlphaMode) {
baseTexture.alphaMode = expectedAlphaMode;
// Force a re-upload to the GPU so the new alpha mode takes effect.
baseTexture.update();
}
}

return atlas;
}

/**
Expand Down
18 changes: 13 additions & 5 deletions Extensions/Spine/spineruntimeobject-pixi-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,22 @@ namespace gdjs {
this._rendererObject
);

// Rotation of the point attachment within the skeleton, in degrees.
// `computeWorldRotation` accounts for both the attachment's own rotation
// (the angle set on the point in the Spine editor) and the full bone chain
// it is attached to.
// Note: the previous code returned only `slot.bone.rotation` for the local
// case, which ignored the attachment's own rotation entirely - so a point's
// configured angle had no effect on the "local rotation" expression.
const localRotation = attachment.computeWorldRotation(slot.bone);

if (isWorld) {
return (
gdjs.toDegrees(this._rendererObject.rotation) +
attachment.computeWorldRotation(slot.bone)
);
// Add the object's own rotation to express the angle in scene space, so
// that: world rotation = local rotation + object angle.
return gdjs.toDegrees(this._rendererObject.rotation) + localRotation;
}

return slot.bone.rotation;
return localRotation;
}

getPointAttachmentScale(
Expand Down
26 changes: 26 additions & 0 deletions newIDE/app/src/ObjectsRendering/PixiResourcesLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,32 @@ export default class PixiResourcesLoader {
});
PIXI.Assets.load(spineTextureAtlasName).then(
textureAtlas => {
// The spine-pixi-v7 tint shader always samples atlas textures as if
// they were premultiplied. The shared textures loaded by the engine
// are uploaded with PIXI's default UNPACK mode (premultiply-on-upload),
// so atlases exported with premultiplied alpha (`pma: true`) would be
// premultiplied a second time, producing dark fringes/halos
// ("shadows") around the rendered parts. Align each shared texture's
// alpha mode with what the atlas page declares.
const imageNames = Object.keys(images);
for (const page of textureAtlas.pages) {
const baseTexture =
images[page.name] ||
(textureAtlas.pages.length === 1 && imageNames.length === 1
? images[imageNames[0]]
: undefined);
if (!baseTexture) continue;

const expectedAlphaMode = page.pma
? PIXI.ALPHA_MODES.PMA
: PIXI.ALPHA_MODES.UNPACK;
if (baseTexture.alphaMode !== expectedAlphaMode) {
baseTexture.alphaMode = expectedAlphaMode;
// Force a re-upload to the GPU so the new alpha mode takes effect.
baseTexture.update();
}
}

resolve({
textureAtlas,
atlasAlias: spineTextureAtlasName,
Expand Down
Loading