@@ -27,6 +27,40 @@ extern std::atomic<bool> g_bInMTAScene;
2727
2828using namespace std ;
2929
30+ namespace
31+ {
32+ // Convert a straight-alpha ARGB tint into its premultiplied form:
33+ //
34+ // (R, G, B, A) -> (R*A/255, G*A/255, B*A/255, A)
35+ //
36+ // Needed when routing a translucent draw onto the (ONE, INVSRCALPHA)
37+ // pipeline. That pipeline computes
38+ //
39+ // out.rgb = src.rgb + dst.rgb * (1 - src.a)
40+ //
41+ // with src.rgb = tex.rgb * diff.rgb and src.a = tex.a * diff.a, so
42+ // diff.a never enters the source rgb term. For a PM texel tex.rgb =
43+ // R*A_tex, that leaves
44+ //
45+ // out.rgb = R * A_tex * diff.rgb + dst.rgb * (1 - A_tex * diff.a)
46+ //
47+ // which is brighter than the correct PM composite by a factor of
48+ // 1/diff.a during a fade. Premultiplying the diffuse here
49+ // (diff.rgb *= diff.a) restores the missing factor and the equation
50+ // reduces exactly to the PM "over" operator.
51+ inline SColor PremultiplyAlpha (SColor c) noexcept
52+ {
53+ if (c.A == 0xFF )
54+ return c;
55+
56+ const uint a = c.A ;
57+ c.R = static_cast <unsigned char >((c.R * a + 127 ) / 255 );
58+ c.G = static_cast <unsigned char >((c.G * a + 127 ) / 255 );
59+ c.B = static_cast <unsigned char >((c.B * a + 127 ) / 255 );
60+ return c;
61+ }
62+ } // namespace
63+
3064template <>
3165CGraphics* CSingleton<CGraphics>::m_pSingleton = NULL ;
3266
@@ -1080,6 +1114,15 @@ void CGraphics::DrawMaterialPrimitiveQueued(std::vector<PrimitiveMaterialVertice
10801114 sDrawQueueItem Item;
10811115 Item.eType = QUEUE_PRIMITIVEMATERIAL;
10821116 Item.blendMode = m_ActiveBlendMode;
1117+ // Same PM auto-route as DrawTextureQueued, so dxDrawMaterialPrimitive
1118+ // composites SVG (premultiplied) textures correctly under default blend.
1119+ if (Item.blendMode == EBlendMode::BLEND && pMaterial && pMaterial->m_bPremultipliedAlpha )
1120+ {
1121+ Item.blendMode = EBlendMode::ADD;
1122+ // See PremultiplyAlpha for the diffuse premultiply rationale (#3828).
1123+ for (auto & vert : *pVecVertices)
1124+ vert.Color = PremultiplyAlpha (vert.Color );
1125+ }
10831126 Item.PrimitiveMaterial .eType = eType;
10841127 Item.PrimitiveMaterial .pMaterial = pMaterial;
10851128 Item.PrimitiveMaterial .pVecVertices = pVecVertices;
@@ -1134,6 +1177,16 @@ void CGraphics::DrawTextureQueued(float fX, float fY, float fWidth, float fHeigh
11341177 // Set up a queue item
11351178 sDrawQueueItem Item;
11361179 Item.blendMode = m_ActiveBlendMode;
1180+ // Premultiplied-alpha textures (SVG) need the (ONE, INVSRCALPHA) pipeline,
1181+ // not the straight-alpha BLEND mode. Route the default blend to ADD when
1182+ // the script hasn't asked for a specific mode (issue #4891), and convert
1183+ // the diffuse tint to PM so a translucent dxDrawImage call still fades
1184+ // correctly through that pipeline (issue #3828).
1185+ if (Item.blendMode == EBlendMode::BLEND && pMaterial && pMaterial->m_bPremultipliedAlpha )
1186+ {
1187+ Item.blendMode = EBlendMode::ADD;
1188+ ulColor = PremultiplyAlpha (ulColor);
1189+ }
11371190 Item.Texture .fX = fX ;
11381191 Item.Texture .fY = fY ;
11391192 Item.Texture .fWidth = fWidth ;
0 commit comments