#include "ShaderAuthoringInternal.h" namespace XCEngine { namespace Resources { namespace Internal { MaterialRenderState BuildDefaultAuthoringFixedFunctionState() { MaterialRenderState state = {}; state.blendEnable = false; state.srcBlend = MaterialBlendFactor::One; state.dstBlend = MaterialBlendFactor::Zero; state.srcBlendAlpha = MaterialBlendFactor::One; state.dstBlendAlpha = MaterialBlendFactor::Zero; state.blendOp = MaterialBlendOp::Add; state.blendOpAlpha = MaterialBlendOp::Add; state.colorWriteMask = 0xF; state.depthTestEnable = true; state.depthWriteEnable = true; state.depthFunc = MaterialComparisonFunc::LessEqual; state.cullMode = MaterialCullMode::Back; return state; } void EnsureAuthoringFixedFunctionStateInitialized( bool& hasFixedFunctionState, MaterialRenderState& fixedFunctionState) { if (!hasFixedFunctionState) { hasFixedFunctionState = true; fixedFunctionState = BuildDefaultAuthoringFixedFunctionState(); } } bool TryParseAuthoringBoolDirectiveToken(const std::string& token, bool& outValue) { const Containers::String normalized = Containers::String(token.c_str()).Trim().ToLower(); if (normalized == "on") { outValue = true; return true; } if (normalized == "off") { outValue = false; return true; } return false; } bool TryParseAuthoringCullMode(const std::string& token, MaterialCullMode& outMode) { const Containers::String normalized = Containers::String(token.c_str()).Trim().ToLower(); if (normalized == "back") { outMode = MaterialCullMode::Back; return true; } if (normalized == "front") { outMode = MaterialCullMode::Front; return true; } if (normalized == "off") { outMode = MaterialCullMode::None; return true; } return false; } bool TryParseAuthoringComparisonFunc(const std::string& token, MaterialComparisonFunc& outFunc) { const Containers::String normalized = Containers::String(token.c_str()).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 == "lequal" || normalized == "lessequal" || normalized == "less_equal") { 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 == "gequal" || normalized == "greaterequal" || normalized == "greater_equal") { outFunc = MaterialComparisonFunc::GreaterEqual; return true; } if (normalized == "always") { outFunc = MaterialComparisonFunc::Always; return true; } return false; } bool TryParseAuthoringBlendFactor(const std::string& token, MaterialBlendFactor& outFactor) { const Containers::String normalized = Containers::String(token.c_str()).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 == "oneminussrccolor" || normalized == "one_minus_src_color" || normalized == "invsrccolor") { outFactor = MaterialBlendFactor::InvSrcColor; return true; } if (normalized == "srcalpha" || normalized == "src_alpha") { outFactor = MaterialBlendFactor::SrcAlpha; return true; } if (normalized == "oneminussrcalpha" || normalized == "one_minus_src_alpha" || normalized == "invsrcalpha") { outFactor = MaterialBlendFactor::InvSrcAlpha; return true; } if (normalized == "dstalpha" || normalized == "dst_alpha") { outFactor = MaterialBlendFactor::DstAlpha; return true; } if (normalized == "oneminusdstalpha" || normalized == "one_minus_dst_alpha" || normalized == "invdstalpha") { outFactor = MaterialBlendFactor::InvDstAlpha; return true; } if (normalized == "dstcolor" || normalized == "dst_color") { outFactor = MaterialBlendFactor::DstColor; return true; } if (normalized == "oneminusdstcolor" || normalized == "one_minus_dst_color" || normalized == "invdstcolor") { outFactor = MaterialBlendFactor::InvDstColor; return true; } if (normalized == "srcalphasaturate" || normalized == "src_alpha_saturate" || normalized == "srcalphasat") { outFactor = MaterialBlendFactor::SrcAlphaSat; return true; } return false; } bool TryParseAuthoringColorMask(const std::string& token, Core::uint8& outMask) { const Containers::String normalized = Containers::String(token.c_str()).Trim().ToUpper(); if (normalized == "0") { outMask = 0u; return true; } Core::uint8 mask = 0u; for (size_t index = 0; index < normalized.Length(); ++index) { switch (normalized[index]) { case 'R': mask |= 0x1u; break; case 'G': mask |= 0x2u; break; case 'B': mask |= 0x4u; break; case 'A': mask |= 0x8u; break; default: return false; } } outMask = mask; return true; } bool TryParseAuthoringBlendDirective( const std::vector& tokens, MaterialRenderState& outState) { std::vector normalizedTokens; normalizedTokens.reserve(tokens.size()); for (const std::string& token : tokens) { if (token == ",") { continue; } std::string normalizedToken = token; while (!normalizedToken.empty() && normalizedToken.back() == ',') { normalizedToken.pop_back(); } if (!normalizedToken.empty()) { normalizedTokens.push_back(std::move(normalizedToken)); } } if (normalizedTokens.size() != 2u && normalizedTokens.size() != 3u && normalizedTokens.size() != 5u) { return false; } if (normalizedTokens.size() == 2u) { bool enabled = false; if (!TryParseAuthoringBoolDirectiveToken(normalizedTokens[1], enabled)) { return false; } outState.blendEnable = enabled; if (!enabled) { outState.srcBlend = MaterialBlendFactor::One; outState.dstBlend = MaterialBlendFactor::Zero; outState.srcBlendAlpha = MaterialBlendFactor::One; outState.dstBlendAlpha = MaterialBlendFactor::Zero; } return true; } MaterialBlendFactor srcBlend = MaterialBlendFactor::One; MaterialBlendFactor dstBlend = MaterialBlendFactor::Zero; if (!TryParseAuthoringBlendFactor(normalizedTokens[1], srcBlend) || !TryParseAuthoringBlendFactor(normalizedTokens[2], dstBlend)) { return false; } outState.blendEnable = true; outState.srcBlend = srcBlend; outState.dstBlend = dstBlend; if (normalizedTokens.size() == 5u) { if (!TryParseAuthoringBlendFactor(normalizedTokens[3], outState.srcBlendAlpha) || !TryParseAuthoringBlendFactor(normalizedTokens[4], outState.dstBlendAlpha)) { return false; } } else { outState.srcBlendAlpha = srcBlend; outState.dstBlendAlpha = dstBlend; } return true; } void SetOrReplaceAuthoringTag( std::vector& tags, const Containers::String& name, const Containers::String& value) { for (ShaderTagIR& tag : tags) { if (tag.name == name) { tag.value = value; return; } } tags.push_back({ name, value }); } bool TryParseShaderKeywordDeclarationPragma( const std::vector& pragmaTokens, ShaderKeywordDeclaration& outDeclaration) { outDeclaration = {}; if (pragmaTokens.size() < 3u) { return false; } if (pragmaTokens[1] == "multi_compile") { outDeclaration.type = ShaderKeywordDeclarationType::MultiCompile; } else if (pragmaTokens[1] == "multi_compile_local") { outDeclaration.type = ShaderKeywordDeclarationType::MultiCompileLocal; } else if (pragmaTokens[1] == "shader_feature") { outDeclaration.type = ShaderKeywordDeclarationType::ShaderFeature; } else if (pragmaTokens[1] == "shader_feature_local") { outDeclaration.type = ShaderKeywordDeclarationType::ShaderFeatureLocal; } else { return false; } for (size_t tokenIndex = 2; tokenIndex < pragmaTokens.size(); ++tokenIndex) { outDeclaration.options.PushBack(pragmaTokens[tokenIndex].c_str()); } return !outDeclaration.options.Empty(); } } // namespace Internal } // namespace Resources } // namespace XCEngine