Add material render state and pipeline caching

This commit is contained in:
2026-03-27 12:18:04 +08:00
parent 4b9a63098e
commit 9a5c187abc
9 changed files with 717 additions and 26 deletions

View File

@@ -109,6 +109,24 @@ bool TryParseIntValue(const std::string& json, const char* key, Core::int32& out
return true;
}
bool TryParseBoolValue(const std::string& json, const char* key, bool& outValue) {
size_t valuePos = 0;
if (!FindValueStart(json, key, valuePos)) {
return false;
}
if (json.compare(valuePos, 4, "true") == 0) {
outValue = true;
return true;
}
if (json.compare(valuePos, 5, "false") == 0) {
outValue = false;
return true;
}
return false;
}
bool TryExtractObject(const std::string& json, const char* key, std::string& outObject) {
size_t valuePos = 0;
if (!FindValueStart(json, key, valuePos) || valuePos >= json.size() || json[valuePos] != '{') {
@@ -234,6 +252,270 @@ bool TryParseTagMap(const std::string& objectText, Material* material) {
return false;
}
bool TryParseCullMode(const Containers::String& value, MaterialCullMode& outMode) {
const Containers::String normalized = value.Trim().ToLower();
if (normalized == "none" || normalized == "off") {
outMode = MaterialCullMode::None;
return true;
}
if (normalized == "front") {
outMode = MaterialCullMode::Front;
return true;
}
if (normalized == "back") {
outMode = MaterialCullMode::Back;
return true;
}
return false;
}
bool TryParseComparisonFunc(const Containers::String& value, MaterialComparisonFunc& outFunc) {
const Containers::String normalized = value.Trim().ToLower();
if (normalized == "never") {
outFunc = MaterialComparisonFunc::Never;
return true;
}
if (normalized == "less") {
outFunc = MaterialComparisonFunc::Less;
return true;
}
if (normalized == "equal") {
outFunc = MaterialComparisonFunc::Equal;
return true;
}
if (normalized == "lessequal" || normalized == "less_equal" || normalized == "lequal") {
outFunc = MaterialComparisonFunc::LessEqual;
return true;
}
if (normalized == "greater") {
outFunc = MaterialComparisonFunc::Greater;
return true;
}
if (normalized == "notequal" || normalized == "not_equal") {
outFunc = MaterialComparisonFunc::NotEqual;
return true;
}
if (normalized == "greaterequal" || normalized == "greater_equal" || normalized == "gequal") {
outFunc = MaterialComparisonFunc::GreaterEqual;
return true;
}
if (normalized == "always") {
outFunc = MaterialComparisonFunc::Always;
return true;
}
return false;
}
bool TryParseBlendFactor(const Containers::String& value, MaterialBlendFactor& outFactor) {
const Containers::String normalized = value.Trim().ToLower();
if (normalized == "zero") {
outFactor = MaterialBlendFactor::Zero;
return true;
}
if (normalized == "one") {
outFactor = MaterialBlendFactor::One;
return true;
}
if (normalized == "srccolor" || normalized == "src_color") {
outFactor = MaterialBlendFactor::SrcColor;
return true;
}
if (normalized == "invsrccolor" || normalized == "inv_src_color" || normalized == "one_minus_src_color") {
outFactor = MaterialBlendFactor::InvSrcColor;
return true;
}
if (normalized == "srcalpha" || normalized == "src_alpha") {
outFactor = MaterialBlendFactor::SrcAlpha;
return true;
}
if (normalized == "invsrcalpha" || normalized == "inv_src_alpha" || normalized == "one_minus_src_alpha") {
outFactor = MaterialBlendFactor::InvSrcAlpha;
return true;
}
if (normalized == "dstalpha" || normalized == "dst_alpha") {
outFactor = MaterialBlendFactor::DstAlpha;
return true;
}
if (normalized == "invdstalpha" || normalized == "inv_dst_alpha" || normalized == "one_minus_dst_alpha") {
outFactor = MaterialBlendFactor::InvDstAlpha;
return true;
}
if (normalized == "dstcolor" || normalized == "dst_color") {
outFactor = MaterialBlendFactor::DstColor;
return true;
}
if (normalized == "invdstcolor" || normalized == "inv_dst_color" || normalized == "one_minus_dst_color") {
outFactor = MaterialBlendFactor::InvDstColor;
return true;
}
if (normalized == "srcalphasat" || normalized == "src_alpha_sat") {
outFactor = MaterialBlendFactor::SrcAlphaSat;
return true;
}
if (normalized == "blendfactor" || normalized == "blend_factor") {
outFactor = MaterialBlendFactor::BlendFactor;
return true;
}
if (normalized == "invblendfactor" || normalized == "inv_blend_factor" || normalized == "one_minus_blend_factor") {
outFactor = MaterialBlendFactor::InvBlendFactor;
return true;
}
if (normalized == "src1color" || normalized == "src1_color") {
outFactor = MaterialBlendFactor::Src1Color;
return true;
}
if (normalized == "invsrc1color" || normalized == "inv_src1_color" || normalized == "one_minus_src1_color") {
outFactor = MaterialBlendFactor::InvSrc1Color;
return true;
}
if (normalized == "src1alpha" || normalized == "src1_alpha") {
outFactor = MaterialBlendFactor::Src1Alpha;
return true;
}
if (normalized == "invsrc1alpha" || normalized == "inv_src1_alpha" || normalized == "one_minus_src1_alpha") {
outFactor = MaterialBlendFactor::InvSrc1Alpha;
return true;
}
return false;
}
bool TryParseBlendOp(const Containers::String& value, MaterialBlendOp& outOp) {
const Containers::String normalized = value.Trim().ToLower();
if (normalized == "add") {
outOp = MaterialBlendOp::Add;
return true;
}
if (normalized == "subtract") {
outOp = MaterialBlendOp::Subtract;
return true;
}
if (normalized == "reversesubtract" || normalized == "reverse_subtract") {
outOp = MaterialBlendOp::ReverseSubtract;
return true;
}
if (normalized == "min") {
outOp = MaterialBlendOp::Min;
return true;
}
if (normalized == "max") {
outOp = MaterialBlendOp::Max;
return true;
}
return false;
}
bool TryParseRenderStateObject(const std::string& objectText, Material* material) {
if (material == nullptr || objectText.empty() || objectText.front() != '{' || objectText.back() != '}') {
return false;
}
MaterialRenderState renderState = material->GetRenderState();
Containers::String enumValue;
if (HasKey(objectText, "cull")) {
if (!TryParseStringValue(objectText, "cull", enumValue) ||
!TryParseCullMode(enumValue, renderState.cullMode)) {
return false;
}
}
bool boolValue = false;
if (HasKey(objectText, "depthTest")) {
if (!TryParseBoolValue(objectText, "depthTest", boolValue)) {
return false;
}
renderState.depthTestEnable = boolValue;
}
if (HasKey(objectText, "depthWrite")) {
if (!TryParseBoolValue(objectText, "depthWrite", boolValue)) {
return false;
}
renderState.depthWriteEnable = boolValue;
}
if (HasKey(objectText, "zWrite")) {
if (!TryParseBoolValue(objectText, "zWrite", boolValue)) {
return false;
}
renderState.depthWriteEnable = boolValue;
}
if (HasKey(objectText, "blend")) {
if (!TryParseBoolValue(objectText, "blend", boolValue)) {
return false;
}
renderState.blendEnable = boolValue;
}
if (HasKey(objectText, "blendEnable")) {
if (!TryParseBoolValue(objectText, "blendEnable", boolValue)) {
return false;
}
renderState.blendEnable = boolValue;
}
if (HasKey(objectText, "depthFunc")) {
if (!TryParseStringValue(objectText, "depthFunc", enumValue) ||
!TryParseComparisonFunc(enumValue, renderState.depthFunc)) {
return false;
}
}
if (HasKey(objectText, "zTest")) {
if (!TryParseStringValue(objectText, "zTest", enumValue) ||
!TryParseComparisonFunc(enumValue, renderState.depthFunc)) {
return false;
}
}
if (HasKey(objectText, "colorWriteMask")) {
Core::int32 colorWriteMask = 0;
if (!TryParseIntValue(objectText, "colorWriteMask", colorWriteMask) ||
colorWriteMask < 0 || colorWriteMask > 0xF) {
return false;
}
renderState.colorWriteMask = static_cast<Core::uint8>(colorWriteMask);
}
if (HasKey(objectText, "srcBlend")) {
if (!TryParseStringValue(objectText, "srcBlend", enumValue) ||
!TryParseBlendFactor(enumValue, renderState.srcBlend)) {
return false;
}
}
if (HasKey(objectText, "dstBlend")) {
if (!TryParseStringValue(objectText, "dstBlend", enumValue) ||
!TryParseBlendFactor(enumValue, renderState.dstBlend)) {
return false;
}
}
if (HasKey(objectText, "srcBlendAlpha")) {
if (!TryParseStringValue(objectText, "srcBlendAlpha", enumValue) ||
!TryParseBlendFactor(enumValue, renderState.srcBlendAlpha)) {
return false;
}
}
if (HasKey(objectText, "dstBlendAlpha")) {
if (!TryParseStringValue(objectText, "dstBlendAlpha", enumValue) ||
!TryParseBlendFactor(enumValue, renderState.dstBlendAlpha)) {
return false;
}
}
if (HasKey(objectText, "blendOp")) {
if (!TryParseStringValue(objectText, "blendOp", enumValue) ||
!TryParseBlendOp(enumValue, renderState.blendOp)) {
return false;
}
}
if (HasKey(objectText, "blendOpAlpha")) {
if (!TryParseStringValue(objectText, "blendOpAlpha", enumValue) ||
!TryParseBlendOp(enumValue, renderState.blendOpAlpha)) {
return false;
}
}
material->SetRenderState(renderState);
return true;
}
ResourceHandle<Shader> LoadShaderHandle(const Containers::String& shaderPath) {
ResourceHandle<Shader> shader = ResourceManager::Get().Load<Shader>(shaderPath);
if (shader.IsValid()) {
@@ -349,6 +631,14 @@ bool MaterialLoader::ParseMaterialData(const Containers::Array<Core::uint8>& dat
}
}
if (HasKey(jsonText, "renderState")) {
std::string renderStateObject;
if (!TryExtractObject(jsonText, "renderState", renderStateObject) ||
!TryParseRenderStateObject(renderStateObject, material)) {
return false;
}
}
return true;
}