From ec24ba22effae045fb8e3cbeba19636994dbbedf Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Sun, 26 Jan 2025 19:31:59 +0300 Subject: [PATCH] Fix SVG bitmap and optimize rendering --- .../logic/CClientVectorGraphicDisplay.cpp | 52 ++++++++++++++----- .../logic/CClientVectorGraphicDisplay.h | 4 ++ 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp b/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp index 8e3b7c89e8..280fa1def6 100644 --- a/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp +++ b/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp @@ -10,7 +10,6 @@ #include "StdInc.h" #include "CClientVectorGraphicDisplay.h" #include "CClientVectorGraphic.h" -#include using namespace lunasvg; @@ -45,6 +44,37 @@ void CClientVectorGraphicDisplay::Render() } } +void CClientVectorGraphicDisplay::UnpremultiplyBitmap(Bitmap& bitmap) +{ + auto width = bitmap.width(); + auto height = bitmap.height(); + auto stride = bitmap.stride(); + auto rowData = bitmap.data(); + + for (std::uint32_t y = 0; y < height; y++) + { + auto data = rowData; + for (std::uint32_t x = 0; x < width; x++) + { + auto& b = data[0]; + auto& g = data[1]; + auto& r = data[2]; + auto& a = data[3]; + + if (a != 0) + { + r = (r * 255) / a; + g = (g * 255) / a; + b = (b * 255) / a; + } + + data += 4; + } + + rowData += stride; + } +} + void CClientVectorGraphicDisplay::UpdateTexture() { if (!m_pVectorGraphic || m_pVectorGraphic->IsDestroyed()) @@ -62,25 +92,19 @@ void CClientVectorGraphicDisplay::UpdateTexture() if (!surface) return; - Bitmap bitmap = svgDocument->renderToBitmap(pVectorGraphicItem->m_uiSizeX, pVectorGraphicItem->m_uiSizeY); - if (!bitmap.valid()) - return; + // SVG has a predefined width and height. We need transform it to the requested size + const Matrix transformationMatrix(pVectorGraphicItem->m_uiSizeX / svgDocument->width(), 0, 0, pVectorGraphicItem->m_uiSizeY / svgDocument->height(), 0, 0); // Lock surface D3DLOCKED_RECT LockedRect; if (SUCCEEDED(surface->LockRect(&LockedRect, nullptr, D3DLOCK_DISCARD))) { - auto surfaceData = static_cast(LockedRect.pBits); - auto sourceData = static_cast(bitmap.data()); + auto surfaceData = static_cast(LockedRect.pBits); + auto stride = static_cast(LockedRect.Pitch); - for (uint32_t y = 0; y < bitmap.height(); ++y) - { - memcpy(surfaceData, sourceData, bitmap.width() * 4); // 4 bytes per pixel - - // advance row pointers - sourceData += bitmap.stride(); - surfaceData += LockedRect.Pitch; - } + Bitmap bitmap{surfaceData, pVectorGraphicItem->m_uiSizeX, pVectorGraphicItem->m_uiSizeY, stride}; + svgDocument->render(bitmap, transformationMatrix); + UnpremultiplyBitmap(bitmap); // Unlock surface surface->UnlockRect(); diff --git a/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.h b/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.h index 924330d481..40da0d46f2 100644 --- a/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.h +++ b/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.h @@ -13,6 +13,7 @@ class CClientVectorGraphicDisplay; #include "CClientDisplay.h" #include "CClientDisplayManager.h" +#include class CClientVectorGraphicDisplay final : public CClientDisplay { @@ -34,6 +35,9 @@ class CClientVectorGraphicDisplay final : public CClientDisplay void Update(); +private: + void UnpremultiplyBitmap(lunasvg::Bitmap& bitmap); + private: CClientVectorGraphic* m_pVectorGraphic;