diff --git a/include/Nazara/Graphics/UberShader.hpp b/include/Nazara/Graphics/UberShader.hpp index dda35a70b..c1d6a7a63 100644 --- a/include/Nazara/Graphics/UberShader.hpp +++ b/include/Nazara/Graphics/UberShader.hpp @@ -24,6 +24,8 @@ namespace Nz public: struct Config; struct Option; + using ConfigCallback = std::function& vertexBuffers)>; + UberShader(ShaderStageTypeFlags shaderStages, const ShaderAst::StatementPtr& shaderAst); ~UberShader() = default; @@ -33,6 +35,9 @@ namespace Nz inline bool HasOption(const std::string& optionName, Pointer* option = nullptr) const; + inline void UpdateConfig(Config& config, const std::vector& vertexBuffers); + inline void UpdateConfigCallback(ConfigCallback callback); + static constexpr std::size_t MaximumOptionValue = 32; struct Config @@ -60,6 +65,7 @@ namespace Nz std::unordered_map, ConfigHasher, ConfigEqual> m_combinations; std::unordered_map m_optionIndexByName; ShaderAst::StatementPtr m_shaderAst; + ConfigCallback m_configCallback; ShaderStageTypeFlags m_shaderStages; }; } diff --git a/include/Nazara/Graphics/UberShader.inl b/include/Nazara/Graphics/UberShader.inl index f3aed9552..511a8aed2 100644 --- a/include/Nazara/Graphics/UberShader.inl +++ b/include/Nazara/Graphics/UberShader.inl @@ -24,6 +24,17 @@ namespace Nz return true; } + inline void UberShader::UpdateConfig(Config& config, const std::vector& vertexBuffers) + { + if (m_configCallback) + m_configCallback(config, vertexBuffers); + } + + inline void UberShader::UpdateConfigCallback(ConfigCallback callback) + { + m_configCallback = std::move(callback); + } + inline bool UberShader::ConfigEqual::operator()(const Config& lhs, const Config& rhs) const { for (std::size_t i = 0; i < lhs.optionValues.size(); ++i) diff --git a/src/Nazara/Graphics/BasicMaterial.cpp b/src/Nazara/Graphics/BasicMaterial.cpp index 17cabaee5..cf92f7164 100644 --- a/src/Nazara/Graphics/BasicMaterial.cpp +++ b/src/Nazara/Graphics/BasicMaterial.cpp @@ -154,6 +154,66 @@ namespace Nz settings.shaders = std::move(uberShaders); + for (std::shared_ptr uberShader : settings.shaders) + { + constexpr std::size_t InvalidOption = std::numeric_limits::max(); + + auto FetchLocationOption = [&](const std::string& optionName) + { + const UberShader::Option* optionPtr; + if (!uberShader->HasOption(optionName, &optionPtr)) + return InvalidOption; + + if (optionPtr->type != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::Int32 }) + throw std::runtime_error("Location options must be of type i32"); + + return optionPtr->index; + }; + + std::size_t positionLocationIndex = FetchLocationOption("PosLocation"); + std::size_t colorLocationIndex = FetchLocationOption("ColorLocation"); + std::size_t uvLocationIndex = FetchLocationOption("UvLocation"); + + uberShader->UpdateConfigCallback([=](UberShader::Config& config, const std::vector& vertexBuffers) + { + if (vertexBuffers.empty()) + return; + + const VertexDeclaration& vertexDeclaration = *vertexBuffers.front().declaration; + const auto& components = vertexDeclaration.GetComponents(); + + std::size_t locationIndex = 0; + for (const auto& component : components) + { + switch (component.component) + { + case VertexComponent::Unused: + continue; + + case VertexComponent::Position: + if (positionLocationIndex != InvalidOption) + config.optionValues[positionLocationIndex] = static_cast(locationIndex); + + break; + + case VertexComponent::Color: + if (colorLocationIndex != InvalidOption) + config.optionValues[colorLocationIndex] = static_cast(locationIndex); + + break; + + case VertexComponent::TexCoord: + if (uvLocationIndex != InvalidOption) + config.optionValues[uvLocationIndex] = static_cast(locationIndex); + + break; + } + + ++locationIndex; + } + }); + } + // Options // HasDiffuseMap diff --git a/src/Nazara/Graphics/MaterialPipeline.cpp b/src/Nazara/Graphics/MaterialPipeline.cpp index 8ef5a9ddd..a4976450f 100644 --- a/src/Nazara/Graphics/MaterialPipeline.cpp +++ b/src/Nazara/Graphics/MaterialPipeline.cpp @@ -54,6 +54,7 @@ namespace Nz if (shader.uberShader) { UberShader::Config config{ shader.optionValues }; + shader.uberShader->UpdateConfig(config, vertexBuffers); renderPipelineInfo.shaderModules.push_back(shader.uberShader->Get(config)); } diff --git a/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl b/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl index 070ae72aa..bc6e96207 100644 --- a/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl @@ -2,7 +2,13 @@ option HasDiffuseTexture: bool = false; option HasAlphaTexture: bool = false; option AlphaTest: bool = false; -const HasUV = HasDiffuseTexture || HasAlphaTexture; +// Vertex declaration related options +option PosLocation: i32 = -1; +option ColorLocation: i32 = -1; +option UvLocation: i32 = -1; + +const HasVertexColor = (ColorLocation >= 0); +const HasUV = (UvLocation >= 0) && (HasDiffuseTexture || HasAlphaTexture); [layout(std140)] struct BasicSettings @@ -44,7 +50,8 @@ external // Fragment stage struct FragIn { - [location(0), cond(HasUV)] uv: vec2 + [location(0), cond(HasUV)] uv: vec2, + [location(1), cond(HasVertexColor)] color: vec4 } struct FragOut @@ -56,6 +63,11 @@ struct FragOut fn main(input: FragIn) -> FragOut { let diffuseColor = settings.DiffuseColor; + + const if (HasVertexColor) + //TODO: diffuseColor *= input.color; + diffuseColor = diffuseColor * input.color; + const if (HasDiffuseTexture) // TODO: diffuseColor *= MaterialDiffuseMap.Sample(input.uv) diffuseColor = diffuseColor * MaterialDiffuseMap.Sample(input.uv); @@ -78,13 +90,15 @@ fn main(input: FragIn) -> FragOut // Vertex stage struct VertIn { - [location(0)] pos: vec3, - [location(1), cond(HasUV)] uv: vec2 + [location(PosLocation)] pos: vec3, + [location(ColorLocation), cond(HasVertexColor)] color: vec4, + [location(UvLocation), cond(HasUV)] uv: vec2 } struct VertOut { [location(0), cond(HasUV)] uv: vec2, + [location(1), cond(HasVertexColor)] color: vec4, [builtin(position)] position: vec4 } @@ -94,6 +108,9 @@ fn main(input: VertIn) -> VertOut let output: VertOut; output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4(input.pos, 1.0); + const if (HasVertexColor) + output.color = input.color; + const if (HasUV) output.uv = input.uv; diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp index a2243fe0d..14c38fd30 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp @@ -140,7 +140,7 @@ namespace Nz { m_states = states; m_states.sanitized = true; //< Shader is always sanitized (because of keywords) - std::shared_ptr sanitized = GlslWriter::Sanitize(shaderAst, states.enabledOptions); + std::shared_ptr sanitized = GlslWriter::Sanitize(shaderAst, states.optionValues); for (std::size_t i = 0; i < ShaderStageTypeCount; ++i) {