Text-and-Fonts #1
@@ -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<unsigned char> FlipTextTextureForShaderUv(const std::vector<unsigned
|
||||
return flipped;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> BlurTextSdf(const std::vector<unsigned char>& pixels, unsigned width, unsigned height, unsigned passes)
|
||||
{
|
||||
std::vector<unsigned char> current = pixels;
|
||||
std::vector<unsigned char> 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<int>(y) + oy;
|
||||
if (sy < 0 || sy >= static_cast<int>(height))
|
||||
continue;
|
||||
for (int ox = -1; ox <= 1; ++ox)
|
||||
{
|
||||
const int sx = static_cast<int>(x) + ox;
|
||||
if (sx < 0 || sx >= static_cast<int>(width))
|
||||
continue;
|
||||
const unsigned weight = (ox == 0 && oy == 0) ? 4u : ((ox == 0 || oy == 0) ? 2u : 1u);
|
||||
const std::size_t sample = (static_cast<std::size_t>(sy) * width + sx) * 4;
|
||||
weightedTotal += static_cast<unsigned>(current[sample]) * weight;
|
||||
weightSum += weight;
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned char value = static_cast<unsigned char>((weightedTotal + weightSum / 2) / weightSum);
|
||||
const std::size_t out = (static_cast<std::size_t>(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<unsigned char>& alpha, const std::vector<unsigned char>& 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<Gdiplus::REAL>(kTextTextureWidth - 48), static_cast<Gdiplus::REAL>(kTextTextureHeight));
|
||||
const Gdiplus::RectF layout(
|
||||
kTextLayoutPadding,
|
||||
0.0f,
|
||||
static_cast<Gdiplus::REAL>(kTextTextureWidth) - (kTextLayoutPadding * 2.0f),
|
||||
static_cast<Gdiplus::REAL>(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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user