Font selector

This commit is contained in:
2026-05-22 17:22:57 +10:00
parent c5f0a9df0e
commit 283f38dddb
15 changed files with 276 additions and 34 deletions

View File

@@ -236,6 +236,8 @@ inline void WriteParameterDefinitionJson(JsonWriter& writer, const ShaderParamet
writer.KeyUInt("maxLength", parameter.maxLength);
if (!parameter.fontId.empty())
writer.KeyString("font", parameter.fontId);
if (!parameter.fontParameterId.empty())
writer.KeyString("fontParameter", parameter.fontParameterId);
}
writer.EndObject();
}

View File

@@ -8,6 +8,29 @@
namespace RenderCadenceCompositor
{
namespace
{
const ShaderParameterDefinition* FindParameterDefinition(const ShaderPackage& shaderPackage, const std::string& parameterId)
{
for (const ShaderParameterDefinition& parameter : shaderPackage.parameters)
{
if (parameter.id == parameterId)
return &parameter;
}
return nullptr;
}
bool HasFontAsset(const ShaderPackage& shaderPackage, const std::string& fontId)
{
for (const ShaderFontAsset& fontAsset : shaderPackage.fontAssets)
{
if (fontAsset.id == fontId)
return true;
}
return false;
}
}
ShaderSupportResult CheckStatelessSinglePassShaderSupport(const ShaderPackage& shaderPackage)
{
if (shaderPackage.passes.empty())
@@ -27,20 +50,24 @@ ShaderSupportResult CheckStatelessSinglePassShaderSupport(const ShaderPackage& s
if (parameter.type != ShaderParameterType::Text)
continue;
if (parameter.fontId.empty())
if (parameter.fontId.empty() && parameter.fontParameterId.empty())
return { false, "Text parameter '" + parameter.id + "' must reference a declared font asset." };
bool hasFontAsset = false;
for (const ShaderFontAsset& fontAsset : shaderPackage.fontAssets)
if (!parameter.fontId.empty() && !HasFontAsset(shaderPackage, parameter.fontId))
return { false, "Text parameter '" + parameter.id + "' references unknown font asset '" + parameter.fontId + "'." };
if (!parameter.fontParameterId.empty())
{
if (fontAsset.id == parameter.fontId)
const ShaderParameterDefinition* fontParameter = FindParameterDefinition(shaderPackage, parameter.fontParameterId);
if (fontParameter == nullptr || fontParameter->type != ShaderParameterType::Enum)
return { false, "Text parameter '" + parameter.id + "' references unknown font enum parameter '" + parameter.fontParameterId + "'." };
for (const ShaderParameterOption& option : fontParameter->enumOptions)
{
hasFontAsset = true;
break;
if (!HasFontAsset(shaderPackage, option.value))
return { false, "Font enum parameter '" + fontParameter->id + "' references unknown font asset '" + option.value + "'." };
}
}
if (!hasFontAsset)
return { false, "Text parameter '" + parameter.id + "' references unknown font asset '" + parameter.fontId + "'." };
}
bool writesLayerOutput = false;
@@ -102,6 +129,7 @@ std::string ShaderPackageFingerprint(const ShaderPackage& shaderPackage)
{
source << "param:" << parameter.id << ":" << static_cast<int>(parameter.type) << ":"
<< parameter.label << ":" << parameter.description << ":" << parameter.fontId << ":"
<< parameter.fontParameterId << ":"
<< parameter.defaultTextValue << ":" << parameter.defaultBoolean << ":"
<< parameter.defaultEnumValue << ":" << parameter.maxLength << "\n";
for (double value : parameter.defaultNumbers)

View File

@@ -178,7 +178,17 @@ bool RuntimeLayerModel::UpdateParameter(const std::string& layerId, const std::s
if (layer->renderReady)
{
layer->artifact.parameterValues = layer->parameterValues;
if (definition->type == ShaderParameterType::Text && !PrepareRuntimeTextTextures(layer->artifact, error))
bool textTexturesDependOnParameter = false;
for (const ShaderParameterDefinition& textDefinition : layer->parameterDefinitions)
{
if (textDefinition.type == ShaderParameterType::Text &&
(textDefinition.id == parameterId || textDefinition.fontParameterId == parameterId))
{
textTexturesDependOnParameter = true;
break;
}
}
if (textTexturesDependOnParameter && !PrepareRuntimeTextTextures(layer->artifact, error))
return false;
}
error.clear();

View File

@@ -27,12 +27,38 @@ const ShaderParameterValue* FindParameterValue(const RuntimeShaderArtifact& arti
return valueIt == artifact.parameterValues.end() ? nullptr : &valueIt->second;
}
const ShaderParameterDefinition* FindParameterDefinition(const RuntimeShaderArtifact& artifact, const std::string& parameterId)
{
for (const ShaderParameterDefinition& definition : artifact.parameterDefinitions)
{
if (definition.id == parameterId)
return &definition;
}
return nullptr;
}
std::string TextValueForDefinition(const RuntimeShaderArtifact& artifact, const ShaderParameterDefinition& definition)
{
const ShaderParameterValue* value = FindParameterValue(artifact, definition.id);
return value ? value->textValue : definition.defaultTextValue;
}
std::string FontIdForTextDefinition(const RuntimeShaderArtifact& artifact, const ShaderParameterDefinition& definition)
{
if (definition.fontParameterId.empty())
return definition.fontId;
const ShaderParameterValue* fontValue = FindParameterValue(artifact, definition.fontParameterId);
if (fontValue != nullptr && !fontValue->enumValue.empty())
return fontValue->enumValue;
const ShaderParameterDefinition* fontDefinition = FindParameterDefinition(artifact, definition.fontParameterId);
if (fontDefinition != nullptr && !fontDefinition->defaultEnumValue.empty())
return fontDefinition->defaultEnumValue;
return definition.fontId;
}
void SampleAtlasPixel(const FontAtlasBuildOutput& atlas, double x, double y, unsigned char* rgba)
{
const double clampedX = (std::max)(0.0, (std::min)(static_cast<double>(atlas.width) - 1.0, x));
@@ -145,7 +171,8 @@ bool PrepareRuntimeTextTextures(RuntimeShaderArtifact& artifact, std::string& er
if (definition.type != ShaderParameterType::Text)
continue;
const FontAtlasBuildOutput* atlas = FindAtlas(artifact, definition.fontId);
const std::string fontId = FontIdForTextDefinition(artifact, definition);
const FontAtlasBuildOutput* atlas = FindAtlas(artifact, fontId);
if (atlas == nullptr)
{
error = "No prepared font atlas is available for text parameter '" + definition.id + "'.";
@@ -153,7 +180,7 @@ bool PrepareRuntimeTextTextures(RuntimeShaderArtifact& artifact, std::string& er
}
if (atlas->width == 0 || atlas->height == 0 || atlas->rgbaPixels.empty() || atlas->glyphsByCodepoint.empty())
{
error = "Prepared font atlas data is empty for font '" + definition.fontId + "'.";
error = "Prepared font atlas data is empty for font '" + fontId + "'.";
return false;
}

View File

@@ -189,6 +189,17 @@ bool ParseParameterDefinition(const JsonValue& parameterJson, ShaderParameterDef
if (!definition.fontId.empty() && !ValidateShaderIdentifier(definition.fontId, "parameters[].font", manifestPath, error))
return false;
}
if (const JsonValue* fontParameterValue = parameterJson.find("fontParameter"))
{
if (!fontParameterValue->isString())
{
error = "Text parameter 'fontParameter' must be a string for: " + definition.id;
return false;
}
definition.fontParameterId = fontParameterValue->asString();
if (!definition.fontParameterId.empty() && !ValidateShaderIdentifier(definition.fontParameterId, "parameters[].fontParameter", manifestPath, error))
return false;
}
if (const JsonValue* maxLengthValue = parameterJson.find("maxLength"))
{
if (!maxLengthValue->isNumber() || maxLengthValue->asNumber() < 1.0 || maxLengthValue->asNumber() > 256.0)

View File

@@ -36,6 +36,7 @@ struct ShaderParameterDefinition
std::string defaultEnumValue;
std::string defaultTextValue;
std::string fontId;
std::string fontParameterId;
unsigned maxLength = 64;
std::vector<ShaderParameterOption> enumOptions;
};