Skip to content

Commit 3f53ccf

Browse files
committed
Fix SVG texture color banding (#4891)
1 parent 2239a7b commit 3f53ccf

5 files changed

Lines changed: 22 additions & 35 deletions

File tree

Client/core/Graphics/CGraphics.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,10 @@ void CGraphics::DrawMaterialPrimitiveQueued(std::vector<PrimitiveMaterialVertice
10801080
sDrawQueueItem Item;
10811081
Item.eType = QUEUE_PRIMITIVEMATERIAL;
10821082
Item.blendMode = m_ActiveBlendMode;
1083+
// Same PM auto-route as DrawTextureQueued, so dxDrawMaterialPrimitive
1084+
// composites SVG (premultiplied) textures correctly under default blend.
1085+
if (Item.blendMode == EBlendMode::BLEND && pMaterial && pMaterial->m_bPremultipliedAlpha)
1086+
Item.blendMode = EBlendMode::ADD;
10831087
Item.PrimitiveMaterial.eType = eType;
10841088
Item.PrimitiveMaterial.pMaterial = pMaterial;
10851089
Item.PrimitiveMaterial.pVecVertices = pVecVertices;
@@ -1134,6 +1138,11 @@ void CGraphics::DrawTextureQueued(float fX, float fY, float fWidth, float fHeigh
11341138
// Set up a queue item
11351139
sDrawQueueItem Item;
11361140
Item.blendMode = m_ActiveBlendMode;
1141+
// Premultiplied-alpha textures (SVG) need the (ONE, INVSRCALPHA) pipeline,
1142+
// not the straight-alpha BLEND mode. Route the default blend to ADD when
1143+
// the script hasn't asked for a specific mode (issue #4891).
1144+
if (Item.blendMode == EBlendMode::BLEND && pMaterial && pMaterial->m_bPremultipliedAlpha)
1145+
Item.blendMode = EBlendMode::ADD;
11371146
Item.Texture.fX = fX;
11381147
Item.Texture.fY = fY;
11391148
Item.Texture.fWidth = fWidth;

Client/core/Graphics/CRenderItem.VectorGraphic.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ void CVectorGraphicItem::PostConstruct(CRenderItemManager* pManager, uint width,
2424
m_uiSizeY = height;
2525
m_uiSurfaceSizeX = width;
2626
m_uiSurfaceSizeY = height;
27+
// lunasvg writes premultiplied ARGB into the surface; let the draw
28+
// path use a PM-aware blend instead of unpremultiplying per pixel.
29+
m_bPremultipliedAlpha = true;
2730

2831
CreateUnderlyingData();
2932
}

Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -56,37 +56,6 @@ void CClientVectorGraphicDisplay::Render()
5656
}
5757
}
5858

59-
void CClientVectorGraphicDisplay::UnpremultiplyBitmap(Bitmap& bitmap)
60-
{
61-
auto width = bitmap.width();
62-
auto height = bitmap.height();
63-
auto stride = bitmap.stride();
64-
auto rowData = bitmap.data();
65-
66-
for (decltype(height) y = 0; y < height; y++)
67-
{
68-
auto data = rowData;
69-
for (decltype(width) x = 0; x < width; x++)
70-
{
71-
auto& b = data[0];
72-
auto& g = data[1];
73-
auto& r = data[2];
74-
auto& a = data[3];
75-
76-
if (a != 0)
77-
{
78-
r = (r * 255) / a;
79-
g = (g * 255) / a;
80-
b = (b * 255) / a;
81-
}
82-
83-
data += 4;
84-
}
85-
86-
rowData += stride;
87-
}
88-
}
89-
9059
void CClientVectorGraphicDisplay::UpdateTexture()
9160
{
9261
if (!m_pVectorGraphic || m_pVectorGraphic->IsDestroyed())
@@ -144,7 +113,10 @@ void CClientVectorGraphicDisplay::UpdateTexture()
144113
return;
145114
}
146115

147-
UnpremultiplyBitmap(bitmap);
116+
// The surface stays in lunasvg's native premultiplied ARGB layout.
117+
// CGraphics::DrawTextureQueued routes the draw to a PM blend so we
118+
// avoid the precision loss caused by an integer unpremultiply
119+
// (see issue #4891 banding on translucent SVG gradients).
148120

149121
// Unlock surface
150122
surface->UnlockRect();

Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ class CClientVectorGraphicDisplay final : public CClientDisplay
3636
void Update();
3737

3838
private:
39-
void UnpremultiplyBitmap(lunasvg::Bitmap& bitmap);
40-
4139
CClientVectorGraphic* m_pVectorGraphic;
4240

4341
bool m_bIsCleared;

Client/sdk/core/CRenderItemManagerInterface.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,12 +351,17 @@ class CEffectWrap : public CRenderItem
351351
class CMaterialItem : public CRenderItem
352352
{
353353
DECLARE_CLASS(CMaterialItem, CRenderItem)
354-
CMaterialItem() : ClassInit(this), m_TextureAddress(TADDRESS_WRAP), m_uiBorderColor(0) {}
354+
CMaterialItem() : ClassInit(this), m_TextureAddress(TADDRESS_WRAP), m_uiBorderColor(0), m_bPremultipliedAlpha(false) {}
355355

356356
uint m_uiSizeX;
357357
uint m_uiSizeY;
358358
ETextureAddress m_TextureAddress;
359359
uint m_uiBorderColor;
360+
// True if the texture pixels are stored with premultiplied alpha. When set,
361+
// the default dxDrawImage blend ("blend") is internally routed through the
362+
// (ONE, INVSRCALPHA) pipeline so compositing is mathematically correct
363+
// without losing precision to a per-pixel integer unpremultiply.
364+
bool m_bPremultipliedAlpha;
360365
};
361366

362367
////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)