Font selector
This commit is contained in:
@@ -82,13 +82,13 @@ void TestBuildsTextOverlayFontAtlas()
|
||||
Expect(false, ("text overlay font atlas builds: " + error).c_str());
|
||||
return;
|
||||
}
|
||||
Expect(outputs.size() == 1, "one font atlas output is produced");
|
||||
if (!outputs.empty())
|
||||
Expect(outputs.size() == shaderPackage.fontAssets.size(), "one font atlas output is produced for each declared font");
|
||||
for (const RenderCadenceCompositor::FontAtlasBuildOutput& output : outputs)
|
||||
{
|
||||
Expect(std::filesystem::exists(outputs[0].imagePath), "font atlas image exists");
|
||||
Expect(std::filesystem::exists(outputs[0].jsonPath), "font atlas json exists");
|
||||
Expect(std::filesystem::file_size(outputs[0].imagePath) > 0, "font atlas image is not empty");
|
||||
Expect(std::filesystem::file_size(outputs[0].jsonPath) > 0, "font atlas json is not empty");
|
||||
Expect(std::filesystem::exists(output.imagePath), "font atlas image exists");
|
||||
Expect(std::filesystem::exists(output.jsonPath), "font atlas json exists");
|
||||
Expect(std::filesystem::file_size(output.imagePath) > 0, "font atlas image is not empty");
|
||||
Expect(std::filesystem::file_size(output.jsonPath) > 0, "font atlas json is not empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,17 +62,20 @@ std::string AllParametersShaderManifest()
|
||||
"description": "All parameter restore test shader",
|
||||
"category": "Tests",
|
||||
"entryPoint": "shadeVideo",
|
||||
"fonts": [{ "id": "inter", "path": "Inter.ttf" }],
|
||||
"fonts": [
|
||||
{ "id": "inter", "path": "Inter.ttf" },
|
||||
{ "id": "mono", "path": "Mono.ttf" }
|
||||
],
|
||||
"parameters": [
|
||||
{ "id": "gain", "label": "Gain", "type": "float", "default": 0.5, "min": 0.0, "max": 1.0 },
|
||||
{ "id": "offset", "label": "Offset", "type": "vec2", "default": [0.0, 0.0], "min": [-1.0, -1.0], "max": [1.0, 1.0] },
|
||||
{ "id": "tint", "label": "Tint", "type": "color", "default": [1.0, 1.0, 1.0, 1.0], "min": [0.0, 0.0, 0.0, 0.0], "max": [1.0, 1.0, 1.0, 1.0] },
|
||||
{ "id": "enabled", "label": "Enabled", "type": "bool", "default": true },
|
||||
{ "id": "mode", "label": "Mode", "type": "enum", "default": "soft", "options": [
|
||||
{ "value": "soft", "label": "Soft" },
|
||||
{ "value": "hard", "label": "Hard" }
|
||||
{ "id": "mode", "label": "Mode", "type": "enum", "default": "inter", "options": [
|
||||
{ "value": "inter", "label": "Inter" },
|
||||
{ "value": "mono", "label": "Mono" }
|
||||
] },
|
||||
{ "id": "titleText", "label": "Title", "type": "text", "default": "DEFAULT", "font": "inter", "maxLength": 8 },
|
||||
{ "id": "titleText", "label": "Title", "type": "text", "default": "DEFAULT", "font": "inter", "fontParameter": "mode", "maxLength": 8 },
|
||||
{ "id": "drop", "label": "Drop", "type": "trigger" }
|
||||
]
|
||||
})";
|
||||
@@ -94,10 +97,10 @@ RenderCadenceCompositor::SupportedShaderCatalog MakeCatalog(std::filesystem::pat
|
||||
return LoadCatalog(root);
|
||||
}
|
||||
|
||||
RenderCadenceCompositor::FontAtlasBuildOutput MakeFakeFontAtlas()
|
||||
RenderCadenceCompositor::FontAtlasBuildOutput MakeFakeFontAtlas(const std::string& fontId = "inter")
|
||||
{
|
||||
RenderCadenceCompositor::FontAtlasBuildOutput atlas;
|
||||
atlas.fontId = "inter";
|
||||
atlas.fontId = fontId;
|
||||
atlas.width = 2;
|
||||
atlas.height = 2;
|
||||
atlas.ascender = -0.8;
|
||||
@@ -226,6 +229,7 @@ void TestInitializeFromRuntimeStateRestoresLayerStack()
|
||||
WriteFile(root / "solid" / "shader.json", SolidShaderManifest(0.5, false));
|
||||
WriteFile(root / "all-params" / "shader.slang", "float4 shadeVideo(float2 uv) { return float4(uv, 0.0, 1.0); }\n");
|
||||
WriteFile(root / "all-params" / "Inter.ttf", "not a real font, but enough for restore catalog support checks");
|
||||
WriteFile(root / "all-params" / "Mono.ttf", "not a real font, but enough for restore catalog support checks");
|
||||
WriteFile(root / "all-params" / "shader.json", AllParametersShaderManifest());
|
||||
RenderCadenceCompositor::SupportedShaderCatalog catalog = LoadCatalog(root);
|
||||
|
||||
@@ -242,7 +246,7 @@ void TestInitializeFromRuntimeStateRestoresLayerStack()
|
||||
"offset": [0.25, -0.5],
|
||||
"tint": [0.1, 0.2, 0.3, 0.4],
|
||||
"enabled": false,
|
||||
"mode": "hard",
|
||||
"mode": "mono",
|
||||
"titleText": "RESTORED-TEXT",
|
||||
"drop": 4
|
||||
}
|
||||
@@ -275,7 +279,7 @@ void TestInitializeFromRuntimeStateRestoresLayerStack()
|
||||
Expect(snapshot.displayLayers[0].parameterValues.at("offset").numberValues == std::vector<double>({ 0.25, -0.5 }), "restore preserves vec2 parameter values");
|
||||
Expect(snapshot.displayLayers[0].parameterValues.at("tint").numberValues == std::vector<double>({ 0.1, 0.2, 0.3, 0.4 }), "restore preserves color parameter values");
|
||||
Expect(!snapshot.displayLayers[0].parameterValues.at("enabled").booleanValue, "restore preserves boolean parameter values");
|
||||
Expect(snapshot.displayLayers[0].parameterValues.at("mode").enumValue == "hard", "restore preserves enum parameter values");
|
||||
Expect(snapshot.displayLayers[0].parameterValues.at("mode").enumValue == "mono", "restore preserves enum parameter values");
|
||||
Expect(snapshot.displayLayers[0].parameterValues.at("titleText").textValue == "RESTORED", "restore normalizes and preserves text parameter values");
|
||||
Expect(snapshot.displayLayers[0].parameterValues.at("drop").numberValues.front() == 4.0, "restore preserves trigger counts");
|
||||
Expect(snapshot.displayLayers[1].id == "layer-33", "restore preserves later supported layer order");
|
||||
@@ -488,6 +492,7 @@ void TestTextTexturesArePreparedInRuntimeModel()
|
||||
std::filesystem::path root = MakeTestRoot();
|
||||
WriteFile(root / "all-params" / "shader.slang", "float4 shadeVideo(float2 uv) { return float4(uv, 0.0, 1.0); }\n");
|
||||
WriteFile(root / "all-params" / "Inter.ttf", "not a real font, but enough for catalog support checks");
|
||||
WriteFile(root / "all-params" / "Mono.ttf", "not a real font, but enough for catalog support checks");
|
||||
WriteFile(root / "all-params" / "shader.json", AllParametersShaderManifest());
|
||||
RenderCadenceCompositor::SupportedShaderCatalog catalog = LoadCatalog(root);
|
||||
|
||||
@@ -503,6 +508,7 @@ void TestTextTexturesArePreparedInRuntimeModel()
|
||||
artifact.fragmentShaderSource = "void main(){}";
|
||||
artifact.parameterDefinitions = snapshot.displayLayers[0].parameterDefinitions;
|
||||
artifact.fontAtlases.push_back(MakeFakeFontAtlas());
|
||||
artifact.fontAtlases.push_back(MakeFakeFontAtlas("mono"));
|
||||
artifact.message = "build ready";
|
||||
Expect(model.MarkBuildReady(artifact, error), error.empty() ? "ready text artifact prepares textures" : error);
|
||||
|
||||
@@ -520,6 +526,12 @@ void TestTextTexturesArePreparedInRuntimeModel()
|
||||
Expect(preparedUpdated.textValue == "AB", "updated text is prepared before render snapshot");
|
||||
Expect(preparedUpdated.rgbaPixels && preparedUpdated.rgbaPixels != preparedDefault.rgbaPixels, "updated text receives a new prepared pixel payload");
|
||||
|
||||
Expect(model.UpdateParameter(model.FirstLayerId(), "mode", JsonValue("mono"), error), error.empty() ? "font selector update prepares texture" : error);
|
||||
snapshot = model.Snapshot();
|
||||
const RuntimePreparedTextTexture preparedWithNewFont = snapshot.renderLayers[0].artifact.preparedTextTextures[0];
|
||||
Expect(preparedWithNewFont.textValue == "AB", "font selector update preserves current text");
|
||||
Expect(preparedWithNewFont.rgbaPixels && preparedWithNewFont.rgbaPixels != preparedUpdated.rgbaPixels, "font selector update receives a new prepared pixel payload");
|
||||
|
||||
std::filesystem::remove_all(root);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,65 @@ void SupportsTextParametersWithDeclaredFont()
|
||||
Expect(result.reason.empty(), "supported text parameters should not report a rejection reason");
|
||||
}
|
||||
|
||||
void SupportsTextParametersWithFontSelector()
|
||||
{
|
||||
ShaderPackage shaderPackage = MakeSinglePassPackage();
|
||||
ShaderFontAsset roboto;
|
||||
roboto.id = "roboto";
|
||||
shaderPackage.fontAssets.push_back(roboto);
|
||||
ShaderFontAsset mono;
|
||||
mono.id = "mono";
|
||||
shaderPackage.fontAssets.push_back(mono);
|
||||
|
||||
ShaderParameterDefinition fontSelector;
|
||||
fontSelector.id = "font";
|
||||
fontSelector.type = ShaderParameterType::Enum;
|
||||
fontSelector.defaultEnumValue = "roboto";
|
||||
fontSelector.enumOptions = { { "roboto", "Roboto" }, { "mono", "Mono" } };
|
||||
shaderPackage.parameters.push_back(fontSelector);
|
||||
|
||||
ShaderParameterDefinition parameter;
|
||||
parameter.id = "caption";
|
||||
parameter.type = ShaderParameterType::Text;
|
||||
parameter.fontId = "roboto";
|
||||
parameter.fontParameterId = "font";
|
||||
shaderPackage.parameters.push_back(parameter);
|
||||
|
||||
const RenderCadenceCompositor::ShaderSupportResult result =
|
||||
RenderCadenceCompositor::CheckStatelessSinglePassShaderSupport(shaderPackage);
|
||||
|
||||
Expect(result.supported, "text parameters with font selector enum should be supported");
|
||||
Expect(result.reason.empty(), "supported font selector text parameters should not report a rejection reason");
|
||||
}
|
||||
|
||||
void RejectsTextParametersWithFontSelectorUnknownOption()
|
||||
{
|
||||
ShaderPackage shaderPackage = MakeSinglePassPackage();
|
||||
ShaderFontAsset roboto;
|
||||
roboto.id = "roboto";
|
||||
shaderPackage.fontAssets.push_back(roboto);
|
||||
|
||||
ShaderParameterDefinition fontSelector;
|
||||
fontSelector.id = "font";
|
||||
fontSelector.type = ShaderParameterType::Enum;
|
||||
fontSelector.defaultEnumValue = "roboto";
|
||||
fontSelector.enumOptions = { { "roboto", "Roboto" }, { "missing", "Missing" } };
|
||||
shaderPackage.parameters.push_back(fontSelector);
|
||||
|
||||
ShaderParameterDefinition parameter;
|
||||
parameter.id = "caption";
|
||||
parameter.type = ShaderParameterType::Text;
|
||||
parameter.fontId = "roboto";
|
||||
parameter.fontParameterId = "font";
|
||||
shaderPackage.parameters.push_back(parameter);
|
||||
|
||||
const RenderCadenceCompositor::ShaderSupportResult result =
|
||||
RenderCadenceCompositor::CheckStatelessSinglePassShaderSupport(shaderPackage);
|
||||
|
||||
Expect(!result.supported, "font selector enum options must reference declared font assets");
|
||||
Expect(result.reason.find("unknown font asset") != std::string::npos, "font selector rejection mentions unknown font asset");
|
||||
}
|
||||
|
||||
void BuildsDeclaredFontAtlasesDuringCatalogLoad()
|
||||
{
|
||||
std::string msdfReason;
|
||||
@@ -217,6 +276,8 @@ int main()
|
||||
RejectsTextureAssets();
|
||||
RejectsTextParametersWithoutDeclaredFont();
|
||||
SupportsTextParametersWithDeclaredFont();
|
||||
SupportsTextParametersWithFontSelector();
|
||||
RejectsTextParametersWithFontSelectorUnknownOption();
|
||||
BuildsDeclaredFontAtlasesDuringCatalogLoad();
|
||||
|
||||
if (gFailures != 0)
|
||||
|
||||
@@ -49,6 +49,7 @@ void TestValidManifest()
|
||||
const std::filesystem::path root = MakeTestRoot();
|
||||
WriteFile(root / "look" / "mask.png", "not a real png, but enough for existence checks");
|
||||
WriteFile(root / "look" / "Inter.ttf", "not a real font, but enough for existence checks");
|
||||
WriteFile(root / "look" / "Mono.ttf", "not a real font, but enough for existence checks");
|
||||
WriteShaderPackage(root, "look", R"({
|
||||
"id": "look-01",
|
||||
"name": "Look 01",
|
||||
@@ -56,15 +57,18 @@ void TestValidManifest()
|
||||
"category": "Tests",
|
||||
"entryPoint": "shadeVideo",
|
||||
"textures": [{ "id": "maskTex", "path": "mask.png" }],
|
||||
"fonts": [{ "id": "inter", "path": "Inter.ttf" }],
|
||||
"fonts": [
|
||||
{ "id": "inter", "path": "Inter.ttf" },
|
||||
{ "id": "mono", "path": "Mono.ttf" }
|
||||
],
|
||||
"temporal": { "enabled": true, "historySource": "source", "historyLength": 8 },
|
||||
"feedback": { "enabled": true },
|
||||
"parameters": [
|
||||
{ "id": "gain", "label": "Gain", "description": "Scales the output intensity.", "type": "float", "default": 0.5, "min": 0, "max": 1 },
|
||||
{ "id": "titleText", "label": "Title", "type": "text", "default": "LIVE", "font": "inter", "maxLength": 32 },
|
||||
{ "id": "mode", "label": "Mode", "type": "enum", "default": "soft", "options": [
|
||||
{ "value": "soft", "label": "Soft" },
|
||||
{ "value": "hard", "label": "Hard" }
|
||||
{ "id": "titleText", "label": "Title", "type": "text", "default": "LIVE", "font": "inter", "fontParameter": "mode", "maxLength": 32 },
|
||||
{ "id": "mode", "label": "Mode", "type": "enum", "default": "inter", "options": [
|
||||
{ "value": "inter", "label": "Inter" },
|
||||
{ "value": "mono", "label": "Mono" }
|
||||
] },
|
||||
{ "id": "flash", "label": "Flash", "type": "trigger" }
|
||||
]
|
||||
@@ -76,12 +80,13 @@ void TestValidManifest()
|
||||
Expect(registry.ParseManifest(root / "look" / "shader.json", package, error), "valid manifest parses");
|
||||
Expect(package.id == "look-01", "manifest id is preserved");
|
||||
Expect(package.textureAssets.size() == 1 && package.textureAssets[0].id == "maskTex", "texture assets parse");
|
||||
Expect(package.fontAssets.size() == 1 && package.fontAssets[0].id == "inter", "font assets parse");
|
||||
Expect(package.fontAssets.size() == 2 && package.fontAssets[0].id == "inter", "font assets parse");
|
||||
Expect(package.temporal.enabled && package.temporal.effectiveHistoryLength == 4, "temporal history is capped");
|
||||
Expect(package.feedback.enabled && package.feedback.writePassId == "main", "feedback defaults to the implicit main pass");
|
||||
Expect(package.parameters.size() == 4, "parameters parse");
|
||||
Expect(package.parameters[0].description == "Scales the output intensity.", "parameter descriptions parse");
|
||||
Expect(package.parameters[1].type == ShaderParameterType::Text && package.parameters[1].defaultTextValue == "LIVE", "text parameter parses");
|
||||
Expect(package.parameters[1].fontParameterId == "mode", "text font selector parameter parses");
|
||||
Expect(package.parameters[3].type == ShaderParameterType::Trigger, "trigger parameter parses");
|
||||
Expect(package.passes.size() == 1 && package.passes[0].id == "main", "legacy manifests get an implicit main pass");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user