Text-and-Fonts #1

Merged
aiden merged 4 commits from Text-and-Fonts into main 2026-05-05 13:57:24 +00:00
4 changed files with 50 additions and 11 deletions
Showing only changes of commit 7e4ab5cbd8 - Show all commits

View File

@@ -232,7 +232,7 @@ If your Windows runner stores the Blackmagic SDK outside the repo, configure `GP
## Still todo ## Still todo
Audio Audio
Fonts improve text rendering
genlock genlock
Logs Logs
anamorphic desqueeze anamorphic desqueeze
@@ -240,6 +240,6 @@ solid color layer
refactor, cleanup of source files refactor, cleanup of source files
display URL (Maybe clicakable) for control in the windows app (Not on the output) display URL (Maybe clicakable) for control in the windows app (Not on the output)
Sound shader as seperate .slang in shader package? Sound shader as seperate .slang in shader package?
runtime date time runtime date time UTC and offset from PCs internal clock
Add a value control to the color wheels Add a value control to the color wheels
![alt text](image.png) ![alt text](image.png)

View File

@@ -205,6 +205,9 @@ std::vector<unsigned char> BuildLocalSdf(const std::vector<unsigned char>& alpha
const float distance = std::sqrt(static_cast<float>(bestDistanceSq)); const float distance = std::sqrt(static_cast<float>(bestDistanceSq));
const float signedDistance = (inside ? 1.0f : -1.0f) * distance; const float signedDistance = (inside ? 1.0f : -1.0f) * distance;
float normalized = 0.5f + signedDistance / static_cast<float>(kTextSdfSpread * 2); float normalized = 0.5f + signedDistance / static_cast<float>(kTextSdfSpread * 2);
const unsigned char sourceAlpha = alpha[static_cast<std::size_t>(y) * width + x];
if (sourceAlpha > 0 && sourceAlpha < 255)
normalized = static_cast<float>(sourceAlpha) / 255.0f;
if (normalized < 0.0f) if (normalized < 0.0f)
normalized = 0.0f; normalized = 0.0f;
if (normalized > 1.0f) if (normalized > 1.0f)
@@ -220,6 +223,24 @@ std::vector<unsigned char> BuildLocalSdf(const std::vector<unsigned char>& alpha
return sdf; return sdf;
} }
std::vector<unsigned char> BuildTextCoverageTexture(const std::vector<unsigned char>& alpha, unsigned width, unsigned height)
{
std::vector<unsigned char> coverage(static_cast<std::size_t>(width) * height * 4, 0);
for (unsigned y = 0; y < height; ++y)
{
for (unsigned x = 0; x < width; ++x)
{
const unsigned char value = alpha[static_cast<std::size_t>(y) * width + x];
const std::size_t out = (static_cast<std::size_t>(y) * width + x) * 4;
coverage[out + 0] = value;
coverage[out + 1] = value;
coverage[out + 2] = value;
coverage[out + 3] = value;
}
}
return coverage;
}
std::vector<unsigned char> FlipTextTextureForShaderUv(const std::vector<unsigned char>& pixels, unsigned width, unsigned height) std::vector<unsigned char> FlipTextTextureForShaderUv(const std::vector<unsigned char>& pixels, unsigned width, unsigned height)
{ {
std::vector<unsigned char> flipped(pixels.size(), 0); std::vector<unsigned char> flipped(pixels.size(), 0);
@@ -414,7 +435,7 @@ bool RasterizeTextSdf(const std::string& text, const std::filesystem::path& font
alpha[static_cast<std::size_t>(y) * kTextTextureWidth + x] = static_cast<unsigned char>(luminance); alpha[static_cast<std::size_t>(y) * kTextTextureWidth + x] = static_cast<unsigned char>(luminance);
} }
} }
sdf = BuildLocalSdf(alpha, kTextTextureWidth, kTextTextureHeight); sdf = BuildTextCoverageTexture(alpha, kTextTextureWidth, kTextTextureHeight);
sdf = BlurTextSdf(sdf, kTextTextureWidth, kTextTextureHeight, kTextSdfBlurPasses); sdf = BlurTextSdf(sdf, kTextTextureWidth, kTextTextureHeight, kTextSdfBlurPasses);
sdf = FlipTextTextureForShaderUv(sdf, kTextTextureWidth, kTextTextureHeight); sdf = FlipTextTextureForShaderUv(sdf, kTextTextureWidth, kTextTextureHeight);
WriteTextMaskDebugDump(text, alpha, sdf, kTextTextureWidth, kTextTextureHeight); WriteTextMaskDebugDump(text, alpha, sdf, kTextTextureWidth, kTextTextureHeight);

View File

@@ -57,6 +57,15 @@
"min": 0.0, "min": 0.0,
"max": 0.5, "max": 0.5,
"step": 0.01 "step": 0.01
},
{
"id": "softness",
"label": "Softness",
"type": "float",
"default": 0.04,
"min": 0.0,
"max": 0.3,
"step": 0.01
} }
] ]
} }

View File

@@ -20,18 +20,27 @@ float4 shadeVideo(ShaderContext context)
bool insideTextRect = textUv.x >= 0.0 && textUv.x <= 1.0 && textUv.y >= 0.0 && textUv.y <= 1.0; 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 mask = insideTextRect ? sampleTitleText(textUv) : 0.0;
float edge = 0.5; float edge = 0.02;
float aa = max(fwidth(mask) * 1.5, 0.006); float aa = max(fwidth(mask) * 1.5, 0.002);
float outlineAmount = min(outlineWidth * 0.25, 0.24);
float fill = smoothstep(edge - aa, edge + aa, mask); float fill = smoothstep(edge - aa, edge + aa, mask);
float outlineField = smoothstep(edge - outlineAmount - aa, edge - outlineAmount + aa, mask); float shadowRadius = min((outlineWidth + softness) * 0.025, 0.018);
float outline = saturate(outlineField - fill); float shadow = 0.0;
float textAlpha = max(fill * fillColor.a, outline * outlineColor.a); if (shadowRadius > 0.0001)
{
shadow = max(shadow, sampleTitleText(textUv + float2(shadowRadius, shadowRadius)));
shadow = max(shadow, sampleTitleText(textUv + float2(-shadowRadius, shadowRadius)));
shadow = max(shadow, sampleTitleText(textUv + float2(shadowRadius, -shadowRadius)));
shadow = max(shadow, sampleTitleText(textUv + float2(-shadowRadius, -shadowRadius)));
}
shadow = smoothstep(edge - aa, edge + aa, shadow) * (0.35 + softness);
float outlineAlpha = saturate(shadow * (1.0 - fill)) * outlineColor.a;
float fillAlpha = fill * fillColor.a;
float textAlpha = max(fillAlpha, outlineAlpha);
if (textAlpha <= 0.0001) if (textAlpha <= 0.0001)
return context.sourceColor; return context.sourceColor;
float4 base = context.sourceColor; float4 base = context.sourceColor;
float4 outlineLayer = float4(outlineColor.rgb * outlineColor.a, outline * outlineColor.a); float4 outlineLayer = float4(outlineColor.rgb * outlineAlpha, outlineAlpha);
float4 fillLayer = float4(fillColor.rgb * fillColor.a, fill * fillColor.a); float4 fillLayer = float4(fillColor.rgb * fillAlpha, fillAlpha);
return saturate(compositeOver(compositeOver(base, outlineLayer), fillLayer)); return saturate(compositeOver(compositeOver(base, outlineLayer), fillLayer));
} }