From 6ce09c0e9c3699606968ed684b78111d646570c6 Mon Sep 17 00:00:00 2001 From: Aiden Date: Tue, 5 May 2026 23:51:02 +1000 Subject: [PATCH] making text pretty --- .../OpenGLComposite.cpp | 62 +++++++++++++++++-- shaders/text-overlay/shader.slang | 8 ++- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/apps/LoopThroughWithOpenGLCompositing/OpenGLComposite.cpp b/apps/LoopThroughWithOpenGLCompositing/OpenGLComposite.cpp index cfa3a2c..4bea15e 100644 --- a/apps/LoopThroughWithOpenGLCompositing/OpenGLComposite.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/OpenGLComposite.cpp @@ -68,9 +68,12 @@ constexpr GLuint kSourceHistoryTextureUnitBase = 2; constexpr GLuint kPackedVideoTextureUnit = 2; constexpr GLuint kGlobalParamsBindingPoint = 0; constexpr unsigned kPrerollFrameCount = 8; -constexpr unsigned kTextTextureWidth = 1024; -constexpr unsigned kTextTextureHeight = 128; -constexpr int kTextSdfSpread = 10; +constexpr unsigned kTextTextureWidth = 2048; +constexpr unsigned kTextTextureHeight = 256; +constexpr int kTextSdfSpread = 20; +constexpr unsigned kTextSdfBlurPasses = 1; +constexpr float kTextFontPixelSize = 144.0f; +constexpr float kTextLayoutPadding = 48.0f; const char* kVertexShaderSource = "#version 430 core\n" "out vec2 vTexCoord;\n" @@ -230,6 +233,48 @@ std::vector FlipTextTextureForShaderUv(const std::vector BlurTextSdf(const std::vector& pixels, unsigned width, unsigned height, unsigned passes) +{ + std::vector current = pixels; + std::vector next(pixels.size(), 0); + for (unsigned pass = 0; pass < passes; ++pass) + { + for (unsigned y = 0; y < height; ++y) + { + for (unsigned x = 0; x < width; ++x) + { + unsigned weightedTotal = 0; + unsigned weightSum = 0; + for (int oy = -1; oy <= 1; ++oy) + { + const int sy = static_cast(y) + oy; + if (sy < 0 || sy >= static_cast(height)) + continue; + for (int ox = -1; ox <= 1; ++ox) + { + const int sx = static_cast(x) + ox; + if (sx < 0 || sx >= static_cast(width)) + continue; + const unsigned weight = (ox == 0 && oy == 0) ? 4u : ((ox == 0 || oy == 0) ? 2u : 1u); + const std::size_t sample = (static_cast(sy) * width + sx) * 4; + weightedTotal += static_cast(current[sample]) * weight; + weightSum += weight; + } + } + + const unsigned char value = static_cast((weightedTotal + weightSum / 2) / weightSum); + const std::size_t out = (static_cast(y) * width + x) * 4; + next[out + 0] = value; + next[out + 1] = value; + next[out + 2] = value; + next[out + 3] = value; + } + } + current.swap(next); + } + return current; +} + void WriteTextMaskDebugDump(const std::string& text, const std::vector& alpha, const std::vector& sdf, unsigned width, unsigned height) { try @@ -338,15 +383,19 @@ bool RasterizeTextSdf(const std::string& text, const std::filesystem::path& font graphics.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); graphics.Clear(Gdiplus::Color(255, 0, 0, 0)); graphics.SetCompositingMode(Gdiplus::CompositingModeSourceOver); - graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit); + graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias); graphics.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); - Gdiplus::Font font(fontFamily, 72.0f, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel); + Gdiplus::Font font(fontFamily, kTextFontPixelSize, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel); Gdiplus::SolidBrush brush(Gdiplus::Color(255, 255, 255, 255)); Gdiplus::StringFormat format; format.SetAlignment(Gdiplus::StringAlignmentNear); format.SetLineAlignment(Gdiplus::StringAlignmentCenter); format.SetFormatFlags(Gdiplus::StringFormatFlagsNoWrap | Gdiplus::StringFormatFlagsMeasureTrailingSpaces); - const Gdiplus::RectF layout(24.0f, 0.0f, static_cast(kTextTextureWidth - 48), static_cast(kTextTextureHeight)); + const Gdiplus::RectF layout( + kTextLayoutPadding, + 0.0f, + static_cast(kTextTextureWidth) - (kTextLayoutPadding * 2.0f), + static_cast(kTextTextureHeight)); const std::wstring wideText = Utf8ToWide(text); graphics.DrawString(wideText.c_str(), -1, &font, layout, &format, &brush); @@ -366,6 +415,7 @@ bool RasterizeTextSdf(const std::string& text, const std::filesystem::path& font } } sdf = BuildLocalSdf(alpha, kTextTextureWidth, kTextTextureHeight); + sdf = BlurTextSdf(sdf, kTextTextureWidth, kTextTextureHeight, kTextSdfBlurPasses); sdf = FlipTextTextureForShaderUv(sdf, kTextTextureWidth, kTextTextureHeight); WriteTextMaskDebugDump(text, alpha, sdf, kTextTextureWidth, kTextTextureHeight); return true; diff --git a/shaders/text-overlay/shader.slang b/shaders/text-overlay/shader.slang index 118d47e..98dc8c2 100644 --- a/shaders/text-overlay/shader.slang +++ b/shaders/text-overlay/shader.slang @@ -20,8 +20,12 @@ float4 shadeVideo(ShaderContext context) bool insideTextRect = textUv.x >= 0.0 && textUv.x <= 1.0 && textUv.y >= 0.0 && textUv.y <= 1.0; float mask = insideTextRect ? sampleTitleText(textUv) : 0.0; - float fill = smoothstep(0.48, 0.54, mask); - float outline = smoothstep(0.48 - outlineWidth, 0.54 - outlineWidth, mask); + float edge = 0.5; + float aa = max(fwidth(mask) * 1.5, 0.006); + float outlineAmount = min(outlineWidth * 0.25, 0.24); + float fill = smoothstep(edge - aa, edge + aa, mask); + float outlineField = smoothstep(edge - outlineAmount - aa, edge - outlineAmount + aa, mask); + float outline = saturate(outlineField - fill); float textAlpha = max(fill * fillColor.a, outline * outlineColor.a); if (textAlpha <= 0.0001) return context.sourceColor;