From fecbf42900e367daa9b3f5b2062413e98ad761d8 Mon Sep 17 00:00:00 2001 From: Causeless Date: Sun, 25 Oct 2026 19:59:40 +0000 Subject: [PATCH 1/4] Fix DrawPrimitives transparency drawing nothing on the GPU renderer The Transparency blend mode put its blend amounts straight into the rteColor uniform, including the alpha amount it ignores, which is always 0 from DrawPrimitives(transValue, ...). Every transparent primitive came out fully transparent, so stock callers like Decision Day's region boxes, the Scanner ping and the Automover controller's info box never showed. Use the RGB amounts as the alpha instead, rounded to the blend step as the software renderer did, so 0 is opaque and 100 is invisible. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 2 ++ Source/Managers/PrimitiveMan.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b036f1c72..d8189f34de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -309,6 +309,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Fixed AI actors refusing to fire the Coalition Missile Launcher at anything beyond point-blank range, because the AI took the range of its short-lived dummy round instead of the missile's. +- Fixed `PrimitiveMan:DrawPrimitives(transValue, primitivesTable)`, and the `Transparency` blend mode in general, drawing nothing at all. `transValue` goes from 0 (opaque) to 100 (invisible) again, in steps of 5. +
Removed diff --git a/Source/Managers/PrimitiveMan.cpp b/Source/Managers/PrimitiveMan.cpp index a16bc14beb..12222ff722 100644 --- a/Source/Managers/PrimitiveMan.cpp +++ b/Source/Managers/PrimitiveMan.cpp @@ -254,7 +254,13 @@ void PrimitiveMan::DrawPrimitives(int player, BITMAP* targetBitmap, const Vector rlEnableShader(rlGetShaderCurrent()); g_FrameMan.SetBlendMode(blendMode); GLint colorUniform = glGetUniformLocation(rlGetShaderCurrent(), "rteColor"); - glUniform4f(colorUniform, blendAmounts[0] / static_cast(MaxBlend), blendAmounts[1] / static_cast(MaxBlend), blendAmounts[2] / static_cast(MaxBlend), blendAmounts[3] / static_cast(MaxBlend)); + if (blendMode == BlendTransparency) { + // Transparency uses the RGB amounts, 0 being opaque and 100 invisible. Alpha blending can't do each channel separately, so use their average. + int transAmount = RoundToNearestMultiple((blendAmounts[0] + blendAmounts[1] + blendAmounts[2]) / 3, c_BlendAmountStep); + glUniform4f(colorUniform, 1.0f, 1.0f, 1.0f, 1.0f - transAmount / static_cast(MaxBlend)); + } else { + glUniform4f(colorUniform, blendAmounts[0] / static_cast(MaxBlend), blendAmounts[1] / static_cast(MaxBlend), blendAmounts[2] / static_cast(MaxBlend), blendAmounts[3] / static_cast(MaxBlend)); + } lastBlendMode = blendMode; lastBlendAmounts = blendAmounts; } From 67d62828353ebc637d3da2bbbdc7e5d0a29d3be9 Mon Sep 17 00:00:00 2001 From: Causeless Date: Sun, 25 Oct 2026 20:11:11 +0000 Subject: [PATCH 2/4] Fix translucent drawing coming out darker on the GPU renderer Alpha blending also lowers the backbuffer's alpha wherever something translucent is drawn. Two copies of the frame then blended by that alpha onto a cleared buffer, which darkened those pixels: by 25% for a half-transparent primitive, and twice over in split-screen. - The post-processing copy disabled blending, but its quad was only drawn after blending was enabled again for the glows. Flush it while blending is still off. - The split-screen copy of each player screen into the backbuffer now draws without blending too. Opaque pixels are unchanged. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 2 ++ Source/Managers/FrameMan.cpp | 3 +++ Source/Managers/PostProcessMan.cpp | 2 ++ 3 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8189f34de..1534f76c1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -311,6 +311,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Fixed `PrimitiveMan:DrawPrimitives(transValue, primitivesTable)`, and the `Transparency` blend mode in general, drawing nothing at all. `transValue` goes from 0 (opaque) to 100 (invisible) again, in steps of 5. +- Fixed anything drawn partly transparent during an activity, such as transparent primitives, coming out darker than it should, and darker still in split-screen. +
Removed diff --git a/Source/Managers/FrameMan.cpp b/Source/Managers/FrameMan.cpp index 0799a475c6..57936a4b59 100644 --- a/Source/Managers/FrameMan.cpp +++ b/Source/Managers/FrameMan.cpp @@ -901,8 +901,11 @@ void FrameMan::Draw() { backgroundShader.End(); if (screenCount > 1) { m_BackBuffer->Begin(false); + // Copy without blending, otherwise anything drawn translucent comes out darker. + rlDisableColorBlend(); DrawTextureRec(m_PlayerScreen->GetColorTexture(), {0, 0, static_cast(m_PlayerScreen8->w), -static_cast(m_PlayerScreen8->h)}, {screenOffset.m_X, screenOffset.m_Y}, {255, 255, 255, 255}); m_BackBuffer->End(); + rlEnableColorBlend(); } g_PostProcessMan.AdjustEffectsPosToPlayerScreen(playerScreen, drawScreen, screenOffset, screenRelativeEffects, screenRelativeGlowBoxes); } diff --git a/Source/Managers/PostProcessMan.cpp b/Source/Managers/PostProcessMan.cpp index 7afe820782..bb9b1ccdff 100644 --- a/Source/Managers/PostProcessMan.cpp +++ b/Source/Managers/PostProcessMan.cpp @@ -337,6 +337,8 @@ void PostProcessMan::PostProcess() { rlDisableDepthTest(); DrawTextureRec(g_FrameMan.GetBackBuffer()->GetColorTexture(), {0, 0, g_FrameMan.GetBackBuffer()->GetSize().w, -g_FrameMan.GetBackBuffer()->GetSize().h}, {0.0f, 0.0f}, {255, 255, 255, 255}); //m_Blit8->End(); + // Draw the copy while blending is still off, otherwise anything drawn translucent comes out darker. + rlDrawRenderBatchActive(); // Set the screen blender mode for glows set_screen_blender(128, 128, 128, 128); From 8c313df2a5bdb2b4fa5e193de0a7dfb5b0a861e3 Mon Sep 17 00:00:00 2001 From: Causeless Date: Sun, 25 Oct 2026 20:23:32 +0000 Subject: [PATCH 3/4] Make the other blend modes use their blend amounts as documented The GPU renderer put each blend amount straight into the color uniform, so the modes other than Transparency drew nothing at 0 and their full effect at 100, the reverse of the documented behavior and of 6.2.2. The RGB amounts also scaled the color, where 6.2.2 ignored them for these modes, and Screen ignored the alpha amount altogether. Use only the alpha amount, 0 being the full effect and 100 invisible, rounded to the blend step. Invert and Dissolve are alpha blended and take it as the alpha. The other blend equations take the color premultiplied by it, which mixes the effect into the background by that much. Difference still draws the primitive minus the background rather than their difference, so it doesn't fade out; that's a separate issue. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 2 ++ Source/Managers/PrimitiveMan.cpp | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1534f76c1f..560fbd3714 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -313,6 +313,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Fixed anything drawn partly transparent during an activity, such as transparent primitives, coming out darker than it should, and darker still in split-screen. +- Fixed the other `DrawBlendMode`s using their blend amount backwards. As documented, 0 is the full effect and 100 is invisible, and modes other than `Transparency` only use the alpha amount, as before. +
Removed diff --git a/Source/Managers/PrimitiveMan.cpp b/Source/Managers/PrimitiveMan.cpp index 12222ff722..2fe52b3637 100644 --- a/Source/Managers/PrimitiveMan.cpp +++ b/Source/Managers/PrimitiveMan.cpp @@ -254,12 +254,14 @@ void PrimitiveMan::DrawPrimitives(int player, BITMAP* targetBitmap, const Vector rlEnableShader(rlGetShaderCurrent()); g_FrameMan.SetBlendMode(blendMode); GLint colorUniform = glGetUniformLocation(rlGetShaderCurrent(), "rteColor"); - if (blendMode == BlendTransparency) { - // Transparency uses the RGB amounts, 0 being opaque and 100 invisible. Alpha blending can't do each channel separately, so use their average. - int transAmount = RoundToNearestMultiple((blendAmounts[0] + blendAmounts[1] + blendAmounts[2]) / 3, c_BlendAmountStep); - glUniform4f(colorUniform, 1.0f, 1.0f, 1.0f, 1.0f - transAmount / static_cast(MaxBlend)); + // Blend amounts go from 0 for the full effect to 100 for invisible. Transparency uses the RGB amounts, averaged since alpha blending can't do each channel separately, and the other modes only use the alpha amount. + int blendAmount = (blendMode == BlendTransparency) ? (blendAmounts[0] + blendAmounts[1] + blendAmounts[2]) / 3 : blendAmounts[3]; + float strength = 1.0f - RoundToNearestMultiple(blendAmount, c_BlendAmountStep) / static_cast(MaxBlend); + if (blendMode == BlendTransparency || blendMode == BlendInvert || blendMode == BlendDissolve) { + glUniform4f(colorUniform, 1.0f, 1.0f, 1.0f, strength); } else { - glUniform4f(colorUniform, blendAmounts[0] / static_cast(MaxBlend), blendAmounts[1] / static_cast(MaxBlend), blendAmounts[2] / static_cast(MaxBlend), blendAmounts[3] / static_cast(MaxBlend)); + // The other blend equations take the color premultiplied by its alpha. + glUniform4f(colorUniform, strength, strength, strength, strength); } lastBlendMode = blendMode; lastBlendAmounts = blendAmounts; From 0822b9164089d56b4e17a5f27d0a2ca9e0df5bf5 Mon Sep 17 00:00:00 2001 From: Causeless Date: Sun, 25 Oct 2026 20:28:13 +0000 Subject: [PATCH 4/4] Remove the CHANGELOG entries for these fixes All three bugs came from the GPU renderer, which was written after 6.2.2, so none of them is a change from the last release. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 560fbd3714..2b036f1c72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -309,12 +309,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Fixed AI actors refusing to fire the Coalition Missile Launcher at anything beyond point-blank range, because the AI took the range of its short-lived dummy round instead of the missile's. -- Fixed `PrimitiveMan:DrawPrimitives(transValue, primitivesTable)`, and the `Transparency` blend mode in general, drawing nothing at all. `transValue` goes from 0 (opaque) to 100 (invisible) again, in steps of 5. - -- Fixed anything drawn partly transparent during an activity, such as transparent primitives, coming out darker than it should, and darker still in split-screen. - -- Fixed the other `DrawBlendMode`s using their blend amount backwards. As documented, 0 is the full effect and 100 is invisible, and modes other than `Transparency` only use the alpha amount, as before. -
Removed