From 0f49503abd96bd24b5737ff335574c0d5425c2da Mon Sep 17 00:00:00 2001 From: fibref Date: Thu, 19 Feb 2026 15:41:48 +0800 Subject: [PATCH] add native MSDF font support for Render2D --- Source/Engine/Render2D/Render2D.cpp | 26 ++++++++++++++++++++++++-- Source/Shaders/GUI.shader | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Render2D/Render2D.cpp b/Source/Engine/Render2D/Render2D.cpp index 5ae034bc5..21dc829ee 100644 --- a/Source/Engine/Render2D/Render2D.cpp +++ b/Source/Engine/Render2D/Render2D.cpp @@ -2,6 +2,7 @@ #include "Render2D.h" #include "Font.h" +#include "FontAsset.h" #include "FontManager.h" #include "FontTextureAtlas.h" #include "RotatedRectangle.h" @@ -74,6 +75,7 @@ enum class DrawCallType : byte FillTexture, FillTexturePoint, DrawChar, + DrawCharMSDF, DrawCharMaterial, Custom, Material, @@ -164,6 +166,7 @@ struct CachedPSO GPUPipelineState* PS_Color_NoAlpha; GPUPipelineState* PS_Font; + GPUPipelineState* PS_FontMSDF; GPUPipelineState* PS_BlurH; GPUPipelineState* PS_BlurV; @@ -455,6 +458,7 @@ CanDrawCallCallback CanDrawCallBatch[] = CanDrawCallCallbackTexture, // FillTexture, CanDrawCallCallbackTexture, // FillTexturePoint, CanDrawCallCallbackChar, // DrawChar, + CanDrawCallCallbackChar, // DrawCharMSDF, CanDrawCallCallbackCharMaterial, // DrawCharMaterial, CanDrawCallCallbackFalse, // Custom, CanDrawCallCallbackMaterial, // Material, @@ -517,6 +521,12 @@ bool CachedPSO::Init(GPUShader* shader, bool useDepth) if (PS_Font->Init(desc)) return true; // + desc.BlendMode = BlendingMode::AlphaBlend; + desc.PS = shader->GetPS("PS_FontMSDF"); + PS_FontMSDF = GPUDevice::Instance->CreatePipelineState(); + if (PS_FontMSDF->Init(desc)) + return true; + // desc.PS = shader->GetPS("PS_LineAA"); PS_LineAA = GPUDevice::Instance->CreatePipelineState(); if (PS_LineAA->Init(desc)) @@ -994,6 +1004,10 @@ void DrawBatch(int32 startIndex, int32 count) Context->BindSR(0, d.AsChar.Tex); Context->SetState(CurrentPso->PS_Font); break; + case DrawCallType::DrawCharMSDF: + Context->BindSR(0, d.AsChar.Tex); + Context->SetState(CurrentPso->PS_FontMSDF); + break; case DrawCallType::DrawCharMaterial: { // Apply and bind material @@ -1176,6 +1190,10 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color, float scale = 1.0f / FontManager::FontScale; const bool enableFallbackFonts = EnumHasAllFlags(Features, RenderingFeatures::FallbackFonts); + const FontAsset* asset = font->GetAsset(); + const FontOptions& options = asset->GetOptions(); + const bool useMSDF = options.RasterMode == FontRasterMode::MSDF; + // Render all characters FontCharacterEntry entry; Render2DDrawCall drawCall; @@ -1186,7 +1204,7 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color, } else { - drawCall.Type = DrawCallType::DrawChar; + drawCall.Type = useMSDF ? DrawCallType::DrawCharMSDF : DrawCallType::DrawChar; drawCall.AsChar.Mat = nullptr; } Float2 pointer = location; @@ -1291,6 +1309,10 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color, float scale = layout.Scale / FontManager::FontScale; const bool enableFallbackFonts = EnumHasAllFlags(Features, RenderingFeatures::FallbackFonts); + const FontAsset* asset = font->GetAsset(); + const FontOptions& options = asset->GetOptions(); + const bool useMSDF = options.RasterMode == FontRasterMode::MSDF; + // Process text to get lines Lines.Clear(); font->ProcessText(text, Lines, layout); @@ -1305,7 +1327,7 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color, } else { - drawCall.Type = DrawCallType::DrawChar; + drawCall.Type = useMSDF ? DrawCallType::DrawCharMSDF : DrawCallType::DrawChar; drawCall.AsChar.Mat = nullptr; } for (int32 lineIndex = 0; lineIndex < Lines.Count(); lineIndex++) diff --git a/Source/Shaders/GUI.shader b/Source/Shaders/GUI.shader index e9eedd4a6..b09a3474d 100644 --- a/Source/Shaders/GUI.shader +++ b/Source/Shaders/GUI.shader @@ -96,6 +96,30 @@ float4 PS_Font(VS2PS input) : SV_Target0 return color; } +META_PS(true, FEATURE_LEVEL_ES2) +float4 PS_FontMSDF(VS2PS input) : SV_Target0 +{ + PerformClipping(input); + + float4 color = input.Color; + float3 msd = Image.Sample(SamplerLinearClamp, input.TexCoord).rgb; + float sd = max(min(msd.r, msd.g), min(max(msd.r, msd.g), msd.b)); + + uint width, height; + Image.GetDimensions(width, height); + float pxRange = 4.0f; // Must match C++ code + float unitRange = float2(pxRange, pxRange) / float2(width, height); + + float2 dx = ddx(input.TexCoord); + float2 dy = ddy(input.TexCoord); + float2 screenTexSize = rsqrt(dx * dx + dy * dy); + float screenPxRange = max(0.5f * dot(screenTexSize, unitRange), 1.0f); + float screenPxDist = screenPxRange * (sd - 0.5f); + + float opacity = saturate(screenPxDist + 0.5f); + return float4(color.rgb, opacity); +} + float4 GetSample(float weight, float offset, float2 uv) { #if BLUR_V