Skip to content

Preserve blend modes when flattening/merging layers in indexed color mode - #157

Open
Nidrax wants to merge 3 commits into
trunkfrom
nidrax/156-fix-layers-blending-when-merging
Open

Preserve blend modes when flattening/merging layers in indexed color mode#157
Nidrax wants to merge 3 commits into
trunkfrom
nidrax/156-fix-layers-blending-when-merging

Conversation

@Nidrax

@Nidrax Nidrax commented Aug 26, 2026

Copy link
Copy Markdown
Member

Fixes #156.

Flatten and Merge Down lost special blend modes for anything other than a
fully-opaque backdrop. Three independent gaps, fixed as three commits:

  1. FlattenLayers pre-filled the working buffer with the background
    color before rendering, so flattening onto a visible background layer
    made every pixel look like real content to the blend functions —
    defeating the transparent-backdrop fallback from Blending with transparency should use normal blending #148/Use normal blending when backdrop is fully transparent #154. Now it
    renders onto an empty backdrop and composites the background color in
    underneath afterwards, matching how render.cpp already handles the
    checked background.

  2. MergeDownLayerCommand, when the destination has no cel at all,
    copied the source cel verbatim and silently dropped the source layer's
    blend mode and opacity. Since that case is really "move the source
    layer one step down," the destination now takes over the source's
    blend mode and opacity so layers beneath it keep blending the way they
    did before the merge.

  3. The real bug: BlenderHelper<IndexedTraits, IndexedTraits> in
    render.cpp ignored blend mode entirely and just copied source
    indexes over the destination. The editor/export preview never showed
    this because it composites indexed sprites into an RGB surface (a
    different, blend-aware specialization); Flatten and Merge Down
    composite indexed onto indexed, so on indexed sprites every special
    blend mode was lost outright — the reported "top layer becomes
    Normal-blend and obscures everything beneath it." Fixed by blending in
    RGB through the palette and mapping the result back to the closest
    existing entry via Palette::findBestfit. Normal/SRC keep the plain
    index-copy fast path. The palette itself is never modified, so results
    are only as close as the existing palette allows (documented in the
    test).

Added a regression test in render_tests.cpp covering Normal vs.
Multiply blending between two indexed images, including the
falls-back-to-Normal-over-a-transparent-backdrop case. I could not run
the test suite in this environment — third_party/gtest isn't present in
this checkout — so I verified all assertions by hand-driving the same
call sequence against the built doc/render libraries.

Manually retested in the app in both indexed and RGB color modes.

🤖 Generated with Claude Code

@Nidrax Nidrax changed the title Preserve blend modes when flattening/merging layers Preserve blend modes when flattening/merging layers in indexed color mode Aug 27, 2026
Nidrax and others added 3 commits August 27, 2026 12:20
FlattenLayers pre-filled its working buffer with the background color
before rendering, so when flattening onto a visible background layer
every pixel looked like real content to the layers' blend functions.
Special blend modes then blended against that synthetic backdrop
instead of falling back to Normal where the sprite has no content.

Render the frame onto an empty backdrop and drop the background color
in behind it afterwards, the same way render.cpp handles the checked
background. The temporary image also needs its mask color to match the
sprite's transparent color, as the indexed blender uses it to tell
which source pixels are empty.

Refs #156

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbyTCR1vPETPFq3BhtWfVW
Merging onto a layer without any content of its own copies the source
cels verbatim, which is the right result for the pixels (blending
against an empty backdrop is Normal blending) but silently dropped the
source layer's blend mode and folded its opacity into the cel. The
layers under the destination then stopped blending the way they did
before the merge.

Let the destination take over the source blend mode and opacity when it
holds no cels at all, which is the case where merging is just the source
layer moved one step down.

Refs #156

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbyTCR1vPETPFq3BhtWfVW
Compositing an indexed image onto another indexed image ignored the
blend mode entirely and copied the source indexes over the destination.
The editor hid this because it composites indexed sprites into an RGB
surface, which does blend through the palette; flattening and merging
down composite indexed onto indexed, so every special blend mode was
lost and the top layer simply obscured everything beneath it.

Compute the blend in RGB through the palette and map the result back to
the closest existing entry. Normal and SRC keep the plain index copy, as
indexed pixels are either fully opaque or the transparent index and
there is nothing to interpolate. The palette itself is left untouched,
so the merged result is only as close as its entries allow.

Fixes #156

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbyTCR1vPETPFq3BhtWfVW
@Nidrax
Nidrax force-pushed the nidrax/156-fix-layers-blending-when-merging branch from 0212174 to 6f7f39c Compare August 27, 2026 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flatten/Merge Down loses special blend modes in indexed color mode

1 participant