Text rendering
This commit is contained in:
@@ -46,7 +46,7 @@
|
|||||||
"id": "scale",
|
"id": "scale",
|
||||||
"label": "Scale",
|
"label": "Scale",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default": 0.42,
|
"default": 1,
|
||||||
"min": 0.1,
|
"min": 0.1,
|
||||||
"max": 3,
|
"max": 3,
|
||||||
"step": 0.01,
|
"step": 0.01,
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0.8
|
1
|
||||||
],
|
],
|
||||||
"description": "Text outline color and alpha."
|
"description": "Text outline color and alpha."
|
||||||
},
|
},
|
||||||
@@ -80,10 +80,10 @@
|
|||||||
"id": "outlineWidth",
|
"id": "outlineWidth",
|
||||||
"label": "Outline Width",
|
"label": "Outline Width",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default": 0.12,
|
"default": 0.22,
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 0.5,
|
"max": 1,
|
||||||
"step": 0.01,
|
"step": 0.02,
|
||||||
"description": "Width of the SDF outline around the text."
|
"description": "Width of the SDF outline around the text."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,11 +16,18 @@ float sdfCoverage(float2 uv, float edge, float aa)
|
|||||||
return smoothstep(edge - aa, edge + aa, distance);
|
return smoothstep(edge - aa, edge + aa, distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float coverage(float distance, float edge, float aa)
|
||||||
|
{
|
||||||
|
return smoothstep(edge - aa, edge + aa, distance);
|
||||||
|
}
|
||||||
|
|
||||||
float4 shadeVideo(ShaderContext context)
|
float4 shadeVideo(ShaderContext context)
|
||||||
{
|
{
|
||||||
float2 resolution = max(context.outputResolution, float2(1.0, 1.0));
|
float2 resolution = max(context.outputResolution, float2(1.0, 1.0));
|
||||||
float aspect = resolution.x / resolution.y;
|
float aspect = resolution.x / resolution.y;
|
||||||
float2 textSize = float2(0.72 * scale, 0.09 * scale * aspect);
|
float textHeight = 0.09 * scale * aspect;
|
||||||
|
float textWidth = textHeight * max(titleTextTextureAspect, 0.01) / aspect;
|
||||||
|
float2 textSize = float2(textWidth, textHeight);
|
||||||
float2 safeTextSize = max(textSize, float2(0.0001, 0.0001));
|
float2 safeTextSize = max(textSize, float2(0.0001, 0.0001));
|
||||||
float2 textUv = (context.uv - position) / safeTextSize;
|
float2 textUv = (context.uv - position) / safeTextSize;
|
||||||
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;
|
||||||
@@ -30,20 +37,15 @@ float4 shadeVideo(ShaderContext context)
|
|||||||
float aa = max(fwidth(distance) * (1.75 + softness * 5.0), 0.0025);
|
float aa = max(fwidth(distance) * (1.75 + softness * 5.0), 0.0025);
|
||||||
float2 pixelTextUv = (1.0 / resolution) / safeTextSize;
|
float2 pixelTextUv = (1.0 / resolution) / safeTextSize;
|
||||||
float2 sampleOffset = pixelTextUv * 0.38;
|
float2 sampleOffset = pixelTextUv * 0.38;
|
||||||
|
float msdfDistance = sampleTitleTextMsdf(textUv);
|
||||||
float fill = (
|
float fill = (
|
||||||
sdfCoverage(textUv, edge, aa) * 2.0 +
|
coverage(msdfDistance, edge, aa) * 2.0 +
|
||||||
sdfCoverage(textUv + float2(sampleOffset.x, sampleOffset.y), edge, aa) +
|
coverage(sampleTitleTextMsdf(textUv + float2(sampleOffset.x, sampleOffset.y)), edge, aa) +
|
||||||
sdfCoverage(textUv + float2(-sampleOffset.x, sampleOffset.y), edge, aa) +
|
coverage(sampleTitleTextMsdf(textUv + float2(-sampleOffset.x, sampleOffset.y)), edge, aa) +
|
||||||
sdfCoverage(textUv + float2(sampleOffset.x, -sampleOffset.y), edge, aa) +
|
coverage(sampleTitleTextMsdf(textUv + float2(sampleOffset.x, -sampleOffset.y)), edge, aa) +
|
||||||
sdfCoverage(textUv + float2(-sampleOffset.x, -sampleOffset.y), edge, aa)) / 6.0;
|
coverage(sampleTitleTextMsdf(textUv + float2(-sampleOffset.x, -sampleOffset.y)), edge, aa)) / 6.0;
|
||||||
float outlineDistance = outlineWidth * 0.16;
|
float outlineEdge = edge - min(outlineWidth * 0.7, 0.48);
|
||||||
float outlineEdge = edge - outlineDistance;
|
float outline = coverage(distance, outlineEdge, aa);
|
||||||
float outline = (
|
|
||||||
sdfCoverage(textUv, outlineEdge, aa) * 2.0 +
|
|
||||||
sdfCoverage(textUv + float2(sampleOffset.x, sampleOffset.y), outlineEdge, aa) +
|
|
||||||
sdfCoverage(textUv + float2(-sampleOffset.x, sampleOffset.y), outlineEdge, aa) +
|
|
||||||
sdfCoverage(textUv + float2(sampleOffset.x, -sampleOffset.y), outlineEdge, aa) +
|
|
||||||
sdfCoverage(textUv + float2(-sampleOffset.x, -sampleOffset.y), outlineEdge, aa)) / 6.0;
|
|
||||||
float outlineAlpha = saturate(outline - fill) * outlineColor.a;
|
float outlineAlpha = saturate(outline - fill) * outlineColor.a;
|
||||||
float fillAlpha = fill * fillColor.a;
|
float fillAlpha = fill * fillColor.a;
|
||||||
float textAlpha = max(fillAlpha, outlineAlpha);
|
float textAlpha = max(fillAlpha, outlineAlpha);
|
||||||
|
|||||||
@@ -111,8 +111,12 @@ std::vector<unsigned char> BuildRuntimeShaderGlobalParamsStd140(
|
|||||||
break;
|
break;
|
||||||
case ShaderParameterType::Text:
|
case ShaderParameterType::Text:
|
||||||
{
|
{
|
||||||
const auto scaleIt = artifact.textTextureWidthScales.find(definition.id);
|
const auto metricsIt = artifact.textTextureMetrics.find(definition.id);
|
||||||
AppendStd140Float(buffer, scaleIt == artifact.textTextureWidthScales.end() ? 1.0f : scaleIt->second);
|
const RuntimeTextTextureMetrics metrics = metricsIt == artifact.textTextureMetrics.end()
|
||||||
|
? RuntimeTextTextureMetrics()
|
||||||
|
: metricsIt->second;
|
||||||
|
AppendStd140Float(buffer, metrics.activeWidthScale);
|
||||||
|
AppendStd140Float(buffer, metrics.aspect);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ShaderParameterType::Trigger:
|
case ShaderParameterType::Trigger:
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr GLuint kFirstTextTextureUnit = 8;
|
constexpr GLuint kFirstTextTextureUnit = 8;
|
||||||
constexpr unsigned kTextTextureHeight = 128;
|
constexpr unsigned kTextTextureHeight = 256;
|
||||||
constexpr unsigned kTextTexturePadding = 8;
|
constexpr unsigned kTextTexturePadding = 16;
|
||||||
constexpr double kFontPixelsPerEm = 96.0;
|
constexpr double kFontPixelsPerEm = 192.0;
|
||||||
|
|
||||||
std::string ReadTextFile(const std::filesystem::path& path)
|
std::string ReadTextFile(const std::filesystem::path& path)
|
||||||
{
|
{
|
||||||
@@ -105,16 +105,20 @@ void RuntimeTextTextureCache::UpdateArtifactState(const RuntimeShaderArtifact& a
|
|||||||
void RuntimeTextTextureCache::RefreshTextTextures(RuntimeShaderArtifact* artifactState)
|
void RuntimeTextTextureCache::RefreshTextTextures(RuntimeShaderArtifact* artifactState)
|
||||||
{
|
{
|
||||||
if (artifactState)
|
if (artifactState)
|
||||||
artifactState->textTextureWidthScales.clear();
|
artifactState->textTextureMetrics.clear();
|
||||||
for (TextTexture& textTexture : mTextTextures)
|
for (TextTexture& textTexture : mTextTextures)
|
||||||
{
|
{
|
||||||
EnsureTextTexture(textTexture);
|
EnsureTextTexture(textTexture);
|
||||||
if (artifactState)
|
if (artifactState)
|
||||||
{
|
{
|
||||||
const float scale = textTexture.width == 0
|
RuntimeTextTextureMetrics metrics;
|
||||||
|
metrics.activeWidthScale = textTexture.width == 0
|
||||||
? 1.0f
|
? 1.0f
|
||||||
: static_cast<float>(textTexture.liveWidth) / static_cast<float>(textTexture.width);
|
: static_cast<float>(textTexture.liveWidth) / static_cast<float>(textTexture.width);
|
||||||
artifactState->textTextureWidthScales[textTexture.parameterId] = scale;
|
metrics.aspect = textTexture.height == 0
|
||||||
|
? 1.0f
|
||||||
|
: static_cast<float>(textTexture.liveWidth) / static_cast<float>(textTexture.height);
|
||||||
|
artifactState->textTextureMetrics[textTexture.parameterId] = metrics;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,7 +340,7 @@ bool RuntimeTextTextureCache::EnsureTextTexture(TextTexture& texture)
|
|||||||
unsigned width = 0;
|
unsigned width = 0;
|
||||||
unsigned height = 0;
|
unsigned height = 0;
|
||||||
unsigned liveWidth = 1;
|
unsigned liveWidth = 1;
|
||||||
std::vector<unsigned char> pixels = ComposeTextMask(*atlas, texture, text, width, height, liveWidth);
|
std::vector<unsigned char> pixels = ComposeTextTexture(*atlas, texture, text, width, height, liveWidth);
|
||||||
if (pixels.empty() || width == 0 || height == 0)
|
if (pixels.empty() || width == 0 || height == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -353,11 +357,11 @@ bool RuntimeTextTextureCache::EnsureTextTexture(TextTexture& texture)
|
|||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, static_cast<GLsizei>(width), static_cast<GLsizei>(height), 0, GL_RED, GL_UNSIGNED_BYTE, pixels.data());
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, static_cast<GLsizei>(width), static_cast<GLsizei>(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height), GL_RED, GL_UNSIGNED_BYTE, pixels.data());
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height), GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
|
||||||
}
|
}
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, previousUnpackAlignment);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, previousUnpackAlignment);
|
||||||
@@ -370,7 +374,7 @@ bool RuntimeTextTextureCache::EnsureTextTexture(TextTexture& texture)
|
|||||||
return texture.texture != 0;
|
return texture.texture != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned char> RuntimeTextTextureCache::ComposeTextMask(const Atlas& atlas, const TextTexture& texture, const std::string& text, unsigned& width, unsigned& height, unsigned& liveWidth) const
|
std::vector<unsigned char> RuntimeTextTextureCache::ComposeTextTexture(const Atlas& atlas, const TextTexture& texture, const std::string& text, unsigned& width, unsigned& height, unsigned& liveWidth) const
|
||||||
{
|
{
|
||||||
double advance = 0.0;
|
double advance = 0.0;
|
||||||
for (unsigned char character : text)
|
for (unsigned char character : text)
|
||||||
@@ -384,7 +388,7 @@ std::vector<unsigned char> RuntimeTextTextureCache::ComposeTextMask(const Atlas&
|
|||||||
liveWidth = (std::max)(1u, static_cast<unsigned>(std::ceil(advance * kFontPixelsPerEm)) + kTextTexturePadding * 2u);
|
liveWidth = (std::max)(1u, static_cast<unsigned>(std::ceil(advance * kFontPixelsPerEm)) + kTextTexturePadding * 2u);
|
||||||
width = (std::max)(fixedWidth, liveWidth);
|
width = (std::max)(fixedWidth, liveWidth);
|
||||||
height = kTextTextureHeight;
|
height = kTextTextureHeight;
|
||||||
std::vector<unsigned char> mask(static_cast<std::size_t>(width) * height, 0);
|
std::vector<unsigned char> texturePixels(static_cast<std::size_t>(width) * height * 4u, 0);
|
||||||
|
|
||||||
const double baseline = kTextTexturePadding + (-atlas.ascender * kFontPixelsPerEm);
|
const double baseline = kTextTexturePadding + (-atlas.ascender * kFontPixelsPerEm);
|
||||||
double penX = static_cast<double>(kTextTexturePadding);
|
double penX = static_cast<double>(kTextTexturePadding);
|
||||||
@@ -417,8 +421,11 @@ std::vector<unsigned char> RuntimeTextTextureCache::ComposeTextMask(const Atlas&
|
|||||||
const double u = (static_cast<double>(x) + 0.5 - destLeft) / destWidth;
|
const double u = (static_cast<double>(x) + 0.5 - destLeft) / destWidth;
|
||||||
const double atlasX = glyph.atlasLeft + u * (glyph.atlasRight - glyph.atlasLeft);
|
const double atlasX = glyph.atlasLeft + u * (glyph.atlasRight - glyph.atlasLeft);
|
||||||
const double atlasY = glyph.atlasTop + v * (glyph.atlasBottom - glyph.atlasTop);
|
const double atlasY = glyph.atlasTop + v * (glyph.atlasBottom - glyph.atlasTop);
|
||||||
unsigned char& destination = mask[static_cast<std::size_t>(y) * width + static_cast<std::size_t>(x)];
|
unsigned char sample[4] = {};
|
||||||
destination = (std::max)(destination, SampleAtlasAlpha(atlas, atlasX, atlasY));
|
SampleAtlasPixel(atlas, atlasX, atlasY, sample);
|
||||||
|
unsigned char* destination = texturePixels.data() + (static_cast<std::size_t>(y) * width + static_cast<std::size_t>(x)) * 4u;
|
||||||
|
for (unsigned channel = 0; channel < 4u; ++channel)
|
||||||
|
destination[channel] = (std::max)(destination[channel], sample[channel]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -428,13 +435,13 @@ std::vector<unsigned char> RuntimeTextTextureCache::ComposeTextMask(const Atlas&
|
|||||||
|
|
||||||
for (unsigned y = 0; y < height / 2u; ++y)
|
for (unsigned y = 0; y < height / 2u; ++y)
|
||||||
{
|
{
|
||||||
unsigned char* topRow = mask.data() + static_cast<std::size_t>(y) * width;
|
unsigned char* topRow = texturePixels.data() + static_cast<std::size_t>(y) * width * 4u;
|
||||||
unsigned char* bottomRow = mask.data() + static_cast<std::size_t>(height - 1u - y) * width;
|
unsigned char* bottomRow = texturePixels.data() + static_cast<std::size_t>(height - 1u - y) * width * 4u;
|
||||||
for (unsigned x = 0; x < width; ++x)
|
for (unsigned x = 0; x < width * 4u; ++x)
|
||||||
std::swap(topRow[x], bottomRow[x]);
|
std::swap(topRow[x], bottomRow[x]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mask;
|
return texturePixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RuntimeTextTextureCache::Atlas* RuntimeTextTextureCache::FindAtlas(const std::string& fontId) const
|
const RuntimeTextTextureCache::Atlas* RuntimeTextTextureCache::FindAtlas(const std::string& fontId) const
|
||||||
@@ -463,12 +470,28 @@ std::string RuntimeTextTextureCache::DefaultTextValue(const RuntimeShaderArtifac
|
|||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char RuntimeTextTextureCache::SampleAtlasAlpha(const Atlas& atlas, double x, double y)
|
void RuntimeTextTextureCache::SampleAtlasPixel(const Atlas& atlas, double x, double y, unsigned char* rgba)
|
||||||
{
|
{
|
||||||
const int ix = (std::max)(0, (std::min)(static_cast<int>(atlas.width) - 1, static_cast<int>(std::floor(x))));
|
const double clampedX = (std::max)(0.0, (std::min)(static_cast<double>(atlas.width) - 1.0, x));
|
||||||
const int iy = (std::max)(0, (std::min)(static_cast<int>(atlas.height) - 1, static_cast<int>(std::floor(y))));
|
const double clampedY = (std::max)(0.0, (std::min)(static_cast<double>(atlas.height) - 1.0, y));
|
||||||
const std::size_t pixelOffset = (static_cast<std::size_t>(iy) * atlas.width + static_cast<std::size_t>(ix)) * 4u;
|
const int x0 = static_cast<int>(std::floor(clampedX));
|
||||||
return atlas.rgbaPixels[pixelOffset + 3u];
|
const int y0 = static_cast<int>(std::floor(clampedY));
|
||||||
|
const int x1 = (std::min)(static_cast<int>(atlas.width) - 1, x0 + 1);
|
||||||
|
const int y1 = (std::min)(static_cast<int>(atlas.height) - 1, y0 + 1);
|
||||||
|
const double tx = clampedX - static_cast<double>(x0);
|
||||||
|
const double ty = clampedY - static_cast<double>(y0);
|
||||||
|
|
||||||
|
const auto channelAt = [&atlas](int sx, int sy, unsigned channel) {
|
||||||
|
const std::size_t pixelOffset = (static_cast<std::size_t>(sy) * atlas.width + static_cast<std::size_t>(sx)) * 4u;
|
||||||
|
return static_cast<double>(atlas.rgbaPixels[pixelOffset + channel]);
|
||||||
|
};
|
||||||
|
for (unsigned channel = 0; channel < 4u; ++channel)
|
||||||
|
{
|
||||||
|
const double top = channelAt(x0, y0, channel) * (1.0 - tx) + channelAt(x1, y0, channel) * tx;
|
||||||
|
const double bottom = channelAt(x0, y1, channel) * (1.0 - tx) + channelAt(x1, y1, channel) * tx;
|
||||||
|
const double value = top * (1.0 - ty) + bottom * ty;
|
||||||
|
rgba[channel] = static_cast<unsigned char>((std::max)(0.0, (std::min)(255.0, std::round(value))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeTextTextureCache::DestroyTexture(TextTexture& texture)
|
void RuntimeTextTextureCache::DestroyTexture(TextTexture& texture)
|
||||||
|
|||||||
@@ -66,11 +66,11 @@ private:
|
|||||||
bool LoadAtlasJson(const RenderCadenceCompositor::FontAtlasBuildOutput& output, Atlas& atlas, std::string& error) const;
|
bool LoadAtlasJson(const RenderCadenceCompositor::FontAtlasBuildOutput& output, Atlas& atlas, std::string& error) const;
|
||||||
bool LoadAtlasImage(const RenderCadenceCompositor::FontAtlasBuildOutput& output, Atlas& atlas, std::string& error) const;
|
bool LoadAtlasImage(const RenderCadenceCompositor::FontAtlasBuildOutput& output, Atlas& atlas, std::string& error) const;
|
||||||
bool EnsureTextTexture(TextTexture& texture);
|
bool EnsureTextTexture(TextTexture& texture);
|
||||||
std::vector<unsigned char> ComposeTextMask(const Atlas& atlas, const TextTexture& texture, const std::string& text, unsigned& width, unsigned& height, unsigned& liveWidth) const;
|
std::vector<unsigned char> ComposeTextTexture(const Atlas& atlas, const TextTexture& texture, const std::string& text, unsigned& width, unsigned& height, unsigned& liveWidth) const;
|
||||||
const Atlas* FindAtlas(const std::string& fontId) const;
|
const Atlas* FindAtlas(const std::string& fontId) const;
|
||||||
static const ShaderParameterValue* FindParameterValue(const RuntimeShaderArtifact& artifact, const std::string& parameterId);
|
static const ShaderParameterValue* FindParameterValue(const RuntimeShaderArtifact& artifact, const std::string& parameterId);
|
||||||
static std::string DefaultTextValue(const RuntimeShaderArtifact& artifact, const std::string& parameterId);
|
static std::string DefaultTextValue(const RuntimeShaderArtifact& artifact, const std::string& parameterId);
|
||||||
static unsigned char SampleAtlasAlpha(const Atlas& atlas, double x, double y);
|
static void SampleAtlasPixel(const Atlas& atlas, double x, double y, unsigned char* rgba);
|
||||||
static void DestroyTexture(TextTexture& texture);
|
static void DestroyTexture(TextTexture& texture);
|
||||||
|
|
||||||
RuntimeShaderArtifact mArtifact;
|
RuntimeShaderArtifact mArtifact;
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ struct FontAtlasBuildConfig
|
|||||||
{
|
{
|
||||||
std::filesystem::path repoRoot;
|
std::filesystem::path repoRoot;
|
||||||
std::filesystem::path cacheRoot;
|
std::filesystem::path cacheRoot;
|
||||||
double sizePixelsPerEm = 64.0;
|
double sizePixelsPerEm = 128.0;
|
||||||
double pixelRange = 4.0;
|
double pixelRange = 8.0;
|
||||||
std::string atlasType = "mtsdf";
|
std::string atlasType = "mtsdf";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ struct RuntimeShaderPassArtifact
|
|||||||
std::string outputName;
|
std::string outputName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RuntimeTextTextureMetrics
|
||||||
|
{
|
||||||
|
float activeWidthScale = 1.0f;
|
||||||
|
float aspect = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
struct RuntimeShaderArtifact
|
struct RuntimeShaderArtifact
|
||||||
{
|
{
|
||||||
std::string layerId;
|
std::string layerId;
|
||||||
@@ -25,6 +31,6 @@ struct RuntimeShaderArtifact
|
|||||||
std::string message;
|
std::string message;
|
||||||
std::vector<ShaderParameterDefinition> parameterDefinitions;
|
std::vector<ShaderParameterDefinition> parameterDefinitions;
|
||||||
std::map<std::string, ShaderParameterValue> parameterValues;
|
std::map<std::string, ShaderParameterValue> parameterValues;
|
||||||
std::map<std::string, float> textTextureWidthScales;
|
std::map<std::string, RuntimeTextTextureMetrics> textTextureMetrics;
|
||||||
std::vector<RenderCadenceCompositor::FontAtlasBuildOutput> fontAtlases;
|
std::vector<RenderCadenceCompositor::FontAtlasBuildOutput> fontAtlases;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ std::string BuildParameterUniforms(const std::vector<ShaderParameterDefinition>&
|
|||||||
{
|
{
|
||||||
if (definition.type == ShaderParameterType::Text)
|
if (definition.type == ShaderParameterType::Text)
|
||||||
{
|
{
|
||||||
source << "\tfloat " << definition.id << "TextureWidthScale;\n";
|
source << "\tfloat " << definition.id << "TextureActiveWidthScale;\n";
|
||||||
|
source << "\tfloat " << definition.id << "TextureAspect;\n";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (definition.type == ShaderParameterType::Trigger)
|
if (definition.type == ShaderParameterType::Trigger)
|
||||||
@@ -102,17 +103,36 @@ std::string BuildTextSamplerDeclarations(const std::vector<ShaderParameterDefini
|
|||||||
std::string BuildTextHelpers(const std::vector<ShaderParameterDefinition>& parameters)
|
std::string BuildTextHelpers(const std::vector<ShaderParameterDefinition>& parameters)
|
||||||
{
|
{
|
||||||
std::ostringstream source;
|
std::ostringstream source;
|
||||||
|
bool emittedMedian = false;
|
||||||
for (const ShaderParameterDefinition& definition : parameters)
|
for (const ShaderParameterDefinition& definition : parameters)
|
||||||
{
|
{
|
||||||
if (definition.type != ShaderParameterType::Text)
|
if (definition.type != ShaderParameterType::Text)
|
||||||
continue;
|
continue;
|
||||||
|
if (!emittedMedian)
|
||||||
|
{
|
||||||
|
source
|
||||||
|
<< "float median(float r, float g, float b)\n"
|
||||||
|
<< "{\n"
|
||||||
|
<< "\treturn max(min(r, g), min(max(r, g), b));\n"
|
||||||
|
<< "}\n\n";
|
||||||
|
emittedMedian = true;
|
||||||
|
}
|
||||||
const std::string suffix = CapitalizeIdentifier(definition.id);
|
const std::string suffix = CapitalizeIdentifier(definition.id);
|
||||||
source
|
source
|
||||||
<< "float sample" << suffix << "(float2 uv)\n"
|
<< "float4 sample" << suffix << "Mtsdf(float2 uv)\n"
|
||||||
<< "{\n"
|
<< "{\n"
|
||||||
<< "\tif (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0)\n"
|
<< "\tif (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0)\n"
|
||||||
<< "\t\treturn 0.0;\n"
|
<< "\t\treturn float4(0.0, 0.0, 0.0, 0.0);\n"
|
||||||
<< "\treturn " << definition.id << "Texture.Sample(float2(uv.x * " << definition.id << "TextureWidthScale, uv.y)).r;\n"
|
<< "\treturn " << definition.id << "Texture.Sample(float2(uv.x * " << definition.id << "TextureActiveWidthScale, uv.y));\n"
|
||||||
|
<< "}\n\n"
|
||||||
|
<< "float sample" << suffix << "Msdf(float2 uv)\n"
|
||||||
|
<< "{\n"
|
||||||
|
<< "\tfloat4 mtsdf = sample" << suffix << "Mtsdf(uv);\n"
|
||||||
|
<< "\treturn median(mtsdf.r, mtsdf.g, mtsdf.b);\n"
|
||||||
|
<< "}\n\n"
|
||||||
|
<< "float sample" << suffix << "(float2 uv)\n"
|
||||||
|
<< "{\n"
|
||||||
|
<< "\treturn sample" << suffix << "Mtsdf(uv).a;\n"
|
||||||
<< "}\n\n"
|
<< "}\n\n"
|
||||||
<< "float4 draw" << suffix << "(float2 uv, float4 fillColor)\n"
|
<< "float4 draw" << suffix << "(float2 uv, float4 fillColor)\n"
|
||||||
<< "{\n"
|
<< "{\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user