#pragma once #include #include namespace XCEngine { namespace Rendering { inline Containers::String NormalizeBuiltinPassMetadataValue(const Containers::String& value) { return value.Trim().ToLower(); } inline const char* GetBuiltinPassCanonicalName(BuiltinMaterialPass pass) { switch (pass) { case BuiltinMaterialPass::ForwardLit: return "forwardlit"; case BuiltinMaterialPass::Unlit: return "unlit"; case BuiltinMaterialPass::DepthOnly: return "depthonly"; case BuiltinMaterialPass::ShadowCaster: return "shadowcaster"; case BuiltinMaterialPass::ObjectId: return "objectid"; case BuiltinMaterialPass::Skybox: return "skybox"; case BuiltinMaterialPass::Volumetric: return "volumetric"; case BuiltinMaterialPass::PostProcess: return "colorscale"; case BuiltinMaterialPass::FinalColor: return "finalcolor"; default: return nullptr; } } inline bool MatchesBuiltinPassName( const Containers::String& value, BuiltinMaterialPass pass) { const char* canonicalName = GetBuiltinPassCanonicalName(pass); return canonicalName != nullptr && NormalizeBuiltinPassMetadataValue(value) == Containers::String(canonicalName); } inline bool ShaderPassHasExplicitBuiltinMetadata(const Resources::ShaderPass& shaderPass) { if (!shaderPass.name.Empty() && shaderPass.name != Containers::String("Default")) { return true; } for (const Resources::ShaderPassTagEntry& tag : shaderPass.tags) { if (NormalizeBuiltinPassMetadataValue(tag.name) == Containers::String("lightmode")) { return true; } } return false; } inline bool ShaderHasExplicitBuiltinMetadata(const Resources::Shader& shader) { for (const Resources::ShaderPass& shaderPass : shader.GetPasses()) { if (ShaderPassHasExplicitBuiltinMetadata(shaderPass)) { return true; } } return false; } inline bool ShaderPassMatchesBuiltinPass( const Resources::ShaderPass& shaderPass, BuiltinMaterialPass pass) { bool hasMetadata = false; if (!shaderPass.name.Empty() && shaderPass.name != Containers::String("Default")) { hasMetadata = true; if (!MatchesBuiltinPassName(shaderPass.name, pass)) { return false; } } for (const Resources::ShaderPassTagEntry& tag : shaderPass.tags) { if (NormalizeBuiltinPassMetadataValue(tag.name) != Containers::String("lightmode")) { continue; } hasMetadata = true; if (!MatchesBuiltinPassName(tag.value, pass)) { return false; } } return hasMetadata; } inline BuiltinPassResourceSemantic ResolveBuiltinPassResourceSemantic( const Resources::ShaderResourceBindingDesc& binding) { Containers::String semantic = NormalizeBuiltinPassMetadataValue(binding.semantic); if (semantic.Empty()) { semantic = NormalizeBuiltinPassMetadataValue(binding.name); } if (semantic == Containers::String("perobject") || semantic == Containers::String("perobjectconstants")) { return BuiltinPassResourceSemantic::PerObject; } if (semantic == Containers::String("material") || semantic == Containers::String("materialconstants")) { return BuiltinPassResourceSemantic::Material; } if (semantic == Containers::String("materialbuffer")) { return BuiltinPassResourceSemantic::MaterialBuffer; } if (semantic == Containers::String("lighting") || semantic == Containers::String("lightingconstants")) { return BuiltinPassResourceSemantic::Lighting; } if (semantic == Containers::String("shadowreceiver") || semantic == Containers::String("shadowreceiverconstants")) { return BuiltinPassResourceSemantic::ShadowReceiver; } if (semantic == Containers::String("environment") || semantic == Containers::String("environmentconstants")) { return BuiltinPassResourceSemantic::Environment; } if (semantic == Containers::String("passconstants") || semantic == Containers::String("finalcolorconstants") || semantic == Containers::String("postprocessconstants")) { return BuiltinPassResourceSemantic::PassConstants; } if (semantic == Containers::String("volumefield") || semantic == Containers::String("volumedata")) { return BuiltinPassResourceSemantic::VolumeField; } if (semantic == Containers::String("basecolortexture") || semantic == Containers::String("maintex")) { return BuiltinPassResourceSemantic::BaseColorTexture; } if (semantic == Containers::String("sourcecolortexture")) { return BuiltinPassResourceSemantic::SourceColorTexture; } if (semantic == Containers::String("skyboxpanoramictexture")) { return BuiltinPassResourceSemantic::SkyboxPanoramicTexture; } if (semantic == Containers::String("skyboxtexture")) { return BuiltinPassResourceSemantic::SkyboxTexture; } if (semantic == Containers::String("shadowmaptexture") || semantic == Containers::String("shadowmap")) { return BuiltinPassResourceSemantic::ShadowMapTexture; } if (semantic == Containers::String("linearclampsampler")) { return BuiltinPassResourceSemantic::LinearClampSampler; } if (semantic == Containers::String("shadowmapsampler") || semantic == Containers::String("shadowsampler")) { return BuiltinPassResourceSemantic::ShadowMapSampler; } switch (binding.type) { case Resources::ShaderResourceType::StructuredBuffer: case Resources::ShaderResourceType::RawBuffer: case Resources::ShaderResourceType::RWStructuredBuffer: case Resources::ShaderResourceType::RWRawBuffer: return BuiltinPassResourceSemantic::MaterialBuffer; default: break; } return BuiltinPassResourceSemantic::Unknown; } inline const char* BuiltinPassResourceSemanticToString(BuiltinPassResourceSemantic semantic) { switch (semantic) { case BuiltinPassResourceSemantic::PerObject: return "PerObject"; case BuiltinPassResourceSemantic::Material: return "Material"; case BuiltinPassResourceSemantic::MaterialBuffer: return "MaterialBuffer"; case BuiltinPassResourceSemantic::Lighting: return "Lighting"; case BuiltinPassResourceSemantic::ShadowReceiver: return "ShadowReceiver"; case BuiltinPassResourceSemantic::Environment: return "Environment"; case BuiltinPassResourceSemantic::PassConstants: return "PassConstants"; case BuiltinPassResourceSemantic::VolumeField: return "VolumeField"; case BuiltinPassResourceSemantic::BaseColorTexture: return "BaseColorTexture"; case BuiltinPassResourceSemantic::SourceColorTexture: return "SourceColorTexture"; case BuiltinPassResourceSemantic::SkyboxPanoramicTexture: return "SkyboxPanoramicTexture"; case BuiltinPassResourceSemantic::SkyboxTexture: return "SkyboxTexture"; case BuiltinPassResourceSemantic::ShadowMapTexture: return "ShadowMapTexture"; case BuiltinPassResourceSemantic::LinearClampSampler: return "LinearClampSampler"; case BuiltinPassResourceSemantic::ShadowMapSampler: return "ShadowMapSampler"; case BuiltinPassResourceSemantic::Unknown: default: return "Unknown"; } } inline const char* ShaderResourceTypeToString(Resources::ShaderResourceType type) { switch (type) { case Resources::ShaderResourceType::ConstantBuffer: return "ConstantBuffer"; case Resources::ShaderResourceType::Texture2D: return "Texture2D"; case Resources::ShaderResourceType::TextureCube: return "TextureCube"; case Resources::ShaderResourceType::Sampler: return "Sampler"; case Resources::ShaderResourceType::StructuredBuffer: return "StructuredBuffer"; case Resources::ShaderResourceType::RawBuffer: return "RawBuffer"; case Resources::ShaderResourceType::RWStructuredBuffer: return "RWStructuredBuffer"; case Resources::ShaderResourceType::RWRawBuffer: return "RWRawBuffer"; default: return "Unknown"; } } inline Containers::String DescribeShaderResourceBinding( const Resources::ShaderResourceBindingDesc& binding) { const BuiltinPassResourceSemantic resolvedSemantic = ResolveBuiltinPassResourceSemantic(binding); return Containers::String("name=") + binding.name + ", semantic=" + binding.semantic + ", resolvedSemantic=" + Containers::String(BuiltinPassResourceSemanticToString(resolvedSemantic)) + ", type=" + Containers::String(ShaderResourceTypeToString(binding.type)) + ", set=" + Containers::String(std::to_string(binding.set).c_str()) + ", binding=" + Containers::String(std::to_string(binding.binding).c_str()); } inline Containers::String DescribeShaderResourceBindings( const Containers::Array& bindings) { Containers::String description; for (size_t bindingIndex = 0; bindingIndex < bindings.Size(); ++bindingIndex) { if (!description.Empty()) { description += " | "; } description += "[" + Containers::String(std::to_string(bindingIndex).c_str()) + "] "; description += DescribeShaderResourceBinding(bindings[bindingIndex]); } return description; } inline bool IsBuiltinPassResourceTypeCompatible( BuiltinPassResourceSemantic semantic, Resources::ShaderResourceType type) { switch (semantic) { case BuiltinPassResourceSemantic::PerObject: case BuiltinPassResourceSemantic::Material: case BuiltinPassResourceSemantic::Lighting: case BuiltinPassResourceSemantic::ShadowReceiver: case BuiltinPassResourceSemantic::Environment: case BuiltinPassResourceSemantic::PassConstants: return type == Resources::ShaderResourceType::ConstantBuffer; case BuiltinPassResourceSemantic::MaterialBuffer: return type == Resources::ShaderResourceType::StructuredBuffer || type == Resources::ShaderResourceType::RawBuffer || type == Resources::ShaderResourceType::RWStructuredBuffer || type == Resources::ShaderResourceType::RWRawBuffer; case BuiltinPassResourceSemantic::VolumeField: return type == Resources::ShaderResourceType::StructuredBuffer || type == Resources::ShaderResourceType::RawBuffer; case BuiltinPassResourceSemantic::BaseColorTexture: case BuiltinPassResourceSemantic::SourceColorTexture: case BuiltinPassResourceSemantic::SkyboxPanoramicTexture: case BuiltinPassResourceSemantic::ShadowMapTexture: return type == Resources::ShaderResourceType::Texture2D; case BuiltinPassResourceSemantic::SkyboxTexture: return type == Resources::ShaderResourceType::TextureCube; case BuiltinPassResourceSemantic::LinearClampSampler: case BuiltinPassResourceSemantic::ShadowMapSampler: return type == Resources::ShaderResourceType::Sampler; case BuiltinPassResourceSemantic::Unknown: default: return false; } } } // namespace Rendering } // namespace XCEngine