diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp index 40a6f645e..82148f580 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp @@ -106,6 +106,7 @@ namespace Nz std::optional scissorRegion; std::optional viewportRegion; std::vector vertexBuffers; + bool shouldFlipY = false; }; struct DrawData diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl index 1dd4b4d30..0b281eaa4 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl @@ -142,6 +142,8 @@ namespace Nz std::copy(clearValues.begin(), clearValues.end(), setFramebuffer.clearValues.begin()); m_commands.emplace_back(std::move(setFramebuffer)); + + m_currentStates.shouldFlipY = (framebuffer.GetType() == OpenGLFramebuffer::Type::Window); } inline void OpenGLCommandBuffer::SetScissor(Nz::Recti scissorRegion) diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp index 3c40eca7a..6745b8c5f 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp @@ -24,11 +24,15 @@ namespace Nz void Apply(const GL::Context& context) const; + void FlipY(bool shouldFlipY) const; + inline const RenderPipelineInfo& GetPipelineInfo() const override; private: RenderPipelineInfo m_pipelineInfo; GL::Program m_program; + GLint m_flipYUniformLocation; + mutable bool m_isYFlipped; }; } diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp index 6acc1eb7b..a4c4181ac 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp @@ -26,10 +26,14 @@ namespace Nz::GL inline void AttachShader(GLuint shader); - inline bool GetLinkStatus(std::string* error = nullptr); + inline bool GetLinkStatus(std::string* error = nullptr) const; + inline GLint GetUniformLocation(const char* uniformName) const; + inline GLint GetUniformLocation(const std::string& uniformName) const; inline void Link(); + inline void Uniform(GLint uniformLocation, float value) const; + Program& operator=(const Program&) = delete; Program& operator=(Program&&) noexcept = default; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Program.inl b/include/Nazara/OpenGLRenderer/Wrapper/Program.inl index ca8795d70..fd5e6030b 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Program.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Program.inl @@ -16,7 +16,7 @@ namespace Nz::GL context.glAttachShader(m_objectId, shader); } - inline bool Program::GetLinkStatus(std::string* error) + inline bool Program::GetLinkStatus(std::string* error) const { assert(m_objectId); const Context& context = EnsureDeviceContext(); @@ -45,6 +45,19 @@ namespace Nz::GL return true; } + inline GLint Program::GetUniformLocation(const char* uniformName) const + { + assert(m_objectId); + const Context& context = EnsureDeviceContext(); + + return context.glGetUniformLocation(m_objectId, uniformName); + } + + inline GLint Program::GetUniformLocation(const std::string& uniformName) const + { + return GetUniformLocation(uniformName.c_str()); + } + inline void Program::Link() { assert(m_objectId); @@ -53,6 +66,15 @@ namespace Nz::GL context.glLinkProgram(m_objectId); } + inline void Program::Uniform(GLint uniformLocation, float value) const + { + assert(m_objectId); + + const Context& context = EnsureDeviceContext(); + context.BindProgram(m_objectId); + context.glUniform1f(uniformLocation, value); + } + inline GLuint Program::CreateHelper(OpenGLDevice& /*device*/, const Context& context) { return context.glCreateProgram(); diff --git a/include/Nazara/Shader/GlslWriter.hpp b/include/Nazara/Shader/GlslWriter.hpp index 2584389a2..a74871da4 100644 --- a/include/Nazara/Shader/GlslWriter.hpp +++ b/include/Nazara/Shader/GlslWriter.hpp @@ -43,6 +43,8 @@ namespace Nz bool flipYPosition = false; }; + static const char* GetFlipYUniformName(); + private: void Append(ShaderExpressionType type); void Append(ShaderNodes::BuiltinEntry builtin); diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp index d3378c941..e1511a847 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -14,7 +15,8 @@ namespace Nz { OpenGLRenderPipeline::OpenGLRenderPipeline(OpenGLDevice& device, RenderPipelineInfo pipelineInfo) : - m_pipelineInfo(std::move(pipelineInfo)) + m_pipelineInfo(std::move(pipelineInfo)), + m_isYFlipped(false) { if (!m_program.Create(device)) throw std::runtime_error("failed to create program"); @@ -30,6 +32,10 @@ namespace Nz std::string errLog; if (!m_program.GetLinkStatus(&errLog)) throw std::runtime_error("failed to link program: " + errLog); + + m_flipYUniformLocation = m_program.GetUniformLocation(GlslWriter::GetFlipYUniformName()); + if (m_flipYUniformLocation != -1) + m_program.Uniform(m_flipYUniformLocation, 1.f); } void OpenGLRenderPipeline::Apply(const GL::Context& context) const @@ -37,4 +43,13 @@ namespace Nz context.UpdateStates(m_pipelineInfo); context.BindProgram(m_program.GetObjectId()); //< Bind program after states } + + void OpenGLRenderPipeline::FlipY(bool shouldFlipY) const + { + if (m_isYFlipped != shouldFlipY) + { + m_program.Uniform(m_flipYUniformLocation, (shouldFlipY) ? -1.f : 1.f); + m_isYFlipped = shouldFlipY; + } + } } diff --git a/src/Nazara/Shader/GlslWriter.cpp b/src/Nazara/Shader/GlslWriter.cpp index e1f32d414..f78896a3c 100644 --- a/src/Nazara/Shader/GlslWriter.cpp +++ b/src/Nazara/Shader/GlslWriter.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,8 @@ namespace Nz { namespace { + static const char* flipYUniformName = "_NzFlipValue"; + struct AstAdapter : ShaderAstCloner { void Visit(ShaderNodes::AssignOp& node) override @@ -35,8 +38,11 @@ namespace Nz if (builtinVar.entry != ShaderNodes::BuiltinEntry::VertexPosition) return ShaderAstCloner::Visit(node); - auto fixYConstant = ShaderBuilder::Constant(Nz::Vector4f(1.f, -1.f, 1.f, 1.f)); - auto mulFix = ShaderBuilder::Multiply(CloneExpression(node.right), fixYConstant); + auto flipVar = ShaderBuilder::Uniform(flipYUniformName, ShaderNodes::BasicType::Float1); + + auto oneConstant = ShaderBuilder::Constant(1.f); + auto fixYValue = ShaderBuilder::Cast(oneConstant, ShaderBuilder::Identifier(flipVar), oneConstant, oneConstant); + auto mulFix = ShaderBuilder::Multiply(CloneExpression(node.right), fixYValue); PushExpression(ShaderNodes::AssignOp::Build(node.op, CloneExpression(node.left), mulFix)); } @@ -50,8 +56,21 @@ namespace Nz { } - std::string GlslWriter::Generate(const ShaderAst& shader, const States& conditions) + std::string GlslWriter::Generate(const ShaderAst& inputShader, const States& conditions) { + const ShaderAst* selectedShader = &inputShader; + std::optional modifiedShader; + if (inputShader.GetStage() == ShaderStageType::Vertex && m_environment.flipYPosition) + { + modifiedShader.emplace(inputShader); + + modifiedShader->AddUniform(flipYUniformName, ShaderNodes::BasicType::Float1); + + selectedShader = &modifiedShader.value(); + } + + const ShaderAst& shader = *selectedShader; + std::string error; if (!ValidateShader(shader, &error)) throw std::runtime_error("Invalid shader AST: " + error); @@ -172,9 +191,9 @@ namespace Nz const char* inKeyword = (glslVersion >= 130) ? "in" : "varying"; const char* outKeyword = (glslVersion >= 130) ? "out" : "varying"; - DeclareVariables(shader, shader.GetUniforms(), "uniform", "Uniforms"); - DeclareVariables(shader, shader.GetInputs(), inKeyword, "Inputs"); - DeclareVariables(shader, shader.GetOutputs(), outKeyword, "Outputs"); + DeclareVariables(shader, shader.GetUniforms(), "uniform", "Uniforms"); + DeclareVariables(shader, shader.GetInputs(), inKeyword, "Inputs"); + DeclareVariables(shader, shader.GetOutputs(), outKeyword, "Outputs"); std::size_t functionCount = shader.GetFunctionCount(); if (functionCount > 1) @@ -201,6 +220,11 @@ namespace Nz m_environment = std::move(environment); } + const char* GlslWriter::GetFlipYUniformName() + { + return flipYUniformName; + } + void GlslWriter::Append(ShaderExpressionType type) { std::visit([&](auto&& arg)