diff --git a/include/Nazara/Graphics/Enums.hpp b/include/Nazara/Graphics/Enums.hpp index 76adb8436..55057b343 100644 --- a/include/Nazara/Graphics/Enums.hpp +++ b/include/Nazara/Graphics/Enums.hpp @@ -8,6 +8,7 @@ #define NAZARA_ENUMS_GRAPHICS_HPP #include +#include namespace Nz { @@ -29,6 +30,21 @@ namespace Nz Volume }; + enum class MaterialPassFlag + { + Transparent, + + Max = Transparent + }; + + template<> + struct EnumAsFlags + { + static constexpr MaterialPassFlag max = MaterialPassFlag::Max; + }; + + using MaterialPassFlags = Flags; + enum class ProjectionType { Orthographic, diff --git a/include/Nazara/Graphics/MaterialPass.hpp b/include/Nazara/Graphics/MaterialPass.hpp index 5c800d9d1..16755e465 100644 --- a/include/Nazara/Graphics/MaterialPass.hpp +++ b/include/Nazara/Graphics/MaterialPass.hpp @@ -46,6 +46,7 @@ namespace Nz inline void EnableDepthClamp(bool depthClamp); inline void EnableDepthWrite(bool depthWrite); inline void EnableFaceCulling(bool faceCulling); + inline void EnableFlag(MaterialPassFlag flag, bool enable = true); inline void EnableScissorTest(bool scissorTest); inline void EnableStencilTest(bool stencilTest); @@ -61,6 +62,7 @@ namespace Nz inline FaceSide GetFaceCulling() const; inline FaceFilling GetFaceFilling() const; inline float GetLineWidth() const; + inline MaterialPassFlags GetFlags() const; inline const ShaderAst::ConstantValue& GetOptionValue(std::size_t optionIndex) const; inline const std::shared_ptr& GetPipeline() const; inline const MaterialPipelineInfo& GetPipelineInfo() const; @@ -83,6 +85,7 @@ namespace Nz inline bool IsDepthClampEnabled() const; inline bool IsDepthWriteEnabled() const; inline bool IsFaceCullingEnabled() const; + inline bool IsFlagEnabled(MaterialPassFlag flag) const; inline bool IsScissorTestEnabled() const; inline bool IsStencilTestEnabled() const; @@ -133,6 +136,7 @@ namespace Nz std::vector m_uniformBuffers; mutable std::shared_ptr m_pipeline; mutable MaterialPipelineInfo m_pipelineInfo; + MaterialPassFlags m_flags; ShaderBindingPtr m_shaderBinding; bool m_forceCommandBufferRegeneration; mutable bool m_pipelineUpdated; diff --git a/include/Nazara/Graphics/MaterialPass.inl b/include/Nazara/Graphics/MaterialPass.inl index 491a55018..aecb90813 100644 --- a/include/Nazara/Graphics/MaterialPass.inl +++ b/include/Nazara/Graphics/MaterialPass.inl @@ -182,6 +182,14 @@ namespace Nz InvalidatePipeline(); } + inline void MaterialPass::EnableFlag(MaterialPassFlag flag, bool enable) + { + if (enable) + m_flags |= flag; + else + m_flags &= ~flag; + } + /*! * \brief Enable/Disable scissor test for this material * @@ -306,6 +314,11 @@ namespace Nz return m_pipelineInfo.lineWidth; } + inline MaterialPassFlags MaterialPass::GetFlags() const + { + return m_flags; + } + inline const ShaderAst::ConstantValue& MaterialPass::GetOptionValue(std::size_t optionIndex) const { assert(optionIndex < m_optionValues.size()); @@ -458,6 +471,11 @@ namespace Nz return m_pipelineInfo.faceCulling; } + inline bool MaterialPass::IsFlagEnabled(MaterialPassFlag flag) const + { + return m_flags.Test(flag); + } + /*! * \brief Checks whether this material has scissor test enabled * \return true If it is the case diff --git a/include/Nazara/Graphics/RenderElement.hpp b/include/Nazara/Graphics/RenderElement.hpp index f2cf2aa56..e253a59f4 100644 --- a/include/Nazara/Graphics/RenderElement.hpp +++ b/include/Nazara/Graphics/RenderElement.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,7 @@ namespace Nz inline RenderElement(UInt8 elementType); virtual ~RenderElement(); - virtual UInt64 ComputeSortingScore(const RenderQueueRegistry& registry) const = 0; + virtual UInt64 ComputeSortingScore(const Nz::Frustumf& frustum, const RenderQueueRegistry& registry) const = 0; inline UInt8 GetElementType() const; diff --git a/include/Nazara/Graphics/RenderSpriteChain.hpp b/include/Nazara/Graphics/RenderSpriteChain.hpp index 59f18193e..d8f1ddf94 100644 --- a/include/Nazara/Graphics/RenderSpriteChain.hpp +++ b/include/Nazara/Graphics/RenderSpriteChain.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -23,10 +24,10 @@ namespace Nz class RenderSpriteChain : public RenderElement { public: - inline RenderSpriteChain(int renderLayer, std::shared_ptr renderPipeline, std::shared_ptr vertexDeclaration, std::shared_ptr textureOverlay, std::size_t spriteCount, const void* spriteData, const ShaderBinding& materialBinding, const ShaderBinding& instanceBinding); + inline RenderSpriteChain(int renderLayer, std::shared_ptr renderPipeline, std::shared_ptr vertexDeclaration, std::shared_ptr textureOverlay, std::size_t spriteCount, const void* spriteData, const ShaderBinding& materialBinding, const WorldInstance& worldInstance, const MaterialPassFlags& matFlags); ~RenderSpriteChain() = default; - inline UInt64 ComputeSortingScore(const RenderQueueRegistry& registry) const override; + inline UInt64 ComputeSortingScore(const Nz::Frustumf& frustum, const RenderQueueRegistry& registry) const override; inline const ShaderBinding& GetInstanceBinding() const; inline const ShaderBinding& GetMaterialBinding() const; @@ -44,8 +45,9 @@ namespace Nz std::shared_ptr m_textureOverlay; std::size_t m_spriteCount; const void* m_spriteData; - const ShaderBinding& m_instanceBinding; + MaterialPassFlags m_matFlags; const ShaderBinding& m_materialBinding; + const WorldInstance& m_worldInstance; int m_renderLayer; }; } diff --git a/include/Nazara/Graphics/RenderSpriteChain.inl b/include/Nazara/Graphics/RenderSpriteChain.inl index 71d0ef9a7..3bf3bc698 100644 --- a/include/Nazara/Graphics/RenderSpriteChain.inl +++ b/include/Nazara/Graphics/RenderSpriteChain.inl @@ -7,42 +7,78 @@ namespace Nz { - inline RenderSpriteChain::RenderSpriteChain(int renderLayer, std::shared_ptr renderPipeline, std::shared_ptr vertexDeclaration, std::shared_ptr textureOverlay, std::size_t spriteCount, const void* spriteData, const ShaderBinding& materialBinding, const ShaderBinding& instanceBinding) : + inline RenderSpriteChain::RenderSpriteChain(int renderLayer, std::shared_ptr renderPipeline, std::shared_ptr vertexDeclaration, std::shared_ptr textureOverlay, std::size_t spriteCount, const void* spriteData, const ShaderBinding& materialBinding, const WorldInstance& worldInstance, const MaterialPassFlags& matFlags) : RenderElement(BasicRenderElement::SpriteChain), m_renderPipeline(std::move(renderPipeline)), m_vertexDeclaration(std::move(vertexDeclaration)), m_textureOverlay(std::move(textureOverlay)), m_spriteCount(spriteCount), m_spriteData(spriteData), - m_instanceBinding(instanceBinding), + m_matFlags(matFlags), + m_worldInstance(worldInstance), m_materialBinding(materialBinding), m_renderLayer(renderLayer) { } - inline UInt64 RenderSpriteChain::ComputeSortingScore(const RenderQueueRegistry& registry) const + inline UInt64 RenderSpriteChain::ComputeSortingScore(const Nz::Frustumf& frustum, const RenderQueueRegistry& registry) const { UInt64 layerIndex = registry.FetchLayerIndex(m_renderLayer); UInt64 elementType = GetElementType(); UInt64 pipelineIndex = registry.FetchPipelineIndex(m_renderPipeline.get()); UInt64 vertexDeclarationIndex = registry.FetchVertexDeclaration(m_vertexDeclaration.get()); - // RQ index: - // - Layer (8bits) - // - Element type (4bits) - // - Pipeline (16bits) - // - VertexDeclaration (8bits) - // - ?? (24bits) - Depth? + if (m_matFlags.Test(MaterialPassFlag::Transparent)) + { + UInt64 matFlags = 1; - return (layerIndex & 0xFF) << 60 | - (elementType & 0xF) << 52 | - (pipelineIndex & 0xFFFF) << 36 | - (vertexDeclarationIndex & 0xFF) << 24; +#if defined(arm) && \ + ((defined(__MAVERICK__) && defined(NAZARA_BIG_ENDIAN)) || \ + (!defined(__SOFTFP__) && !defined(__VFP_FP__) && !defined(__MAVERICK__))) +#error The following code relies on native-endian IEEE-754 representation, which your platform does not guarantee +#endif + + static_assert(sizeof(float) == sizeof(UInt32)); + + float distanceNear = frustum.GetPlane(Nz::FrustumPlane::Near).Distance(m_worldInstance.GetWorldMatrix().GetTranslation()); + UInt32 distanceInt; + std::memcpy(&distanceInt, &distanceNear, sizeof(UInt32)); + + UInt64 distance = ~distanceInt; //< Reverse distance to have back to front + + // Transparent RQ index: + // - Layer (8bits) + // - Transparent flag (1bit) + // - Distance to near plane (32bits) + + return (layerIndex & 0xFF) << 60 | + (matFlags) << 52 | + (distance) << 51; + + } + else + { + UInt64 matFlags = 0; + + // Opaque RQ index: + // - Layer (8bits) + // - Transparent flag (1bit) + // - Element type (4bits) + // - Pipeline (16bits) + // - VertexDeclaration (8bits) + // - ?? (24bits) - Depth? + + return (layerIndex & 0xFF) << 60 | + (matFlags) << 52 | + (elementType & 0xF) << 51 | + (pipelineIndex & 0xFFFF) << 35 | + (vertexDeclarationIndex & 0xFF) << 23; + } } inline const ShaderBinding& RenderSpriteChain::GetInstanceBinding() const { - return m_instanceBinding; + return m_worldInstance.GetShaderBinding(); } inline const ShaderBinding& RenderSpriteChain::GetMaterialBinding() const diff --git a/include/Nazara/Graphics/RenderSubmesh.hpp b/include/Nazara/Graphics/RenderSubmesh.hpp index 4f29e21e7..f3b8ac15b 100644 --- a/include/Nazara/Graphics/RenderSubmesh.hpp +++ b/include/Nazara/Graphics/RenderSubmesh.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -22,10 +23,10 @@ namespace Nz class RenderSubmesh : public RenderElement { public: - inline RenderSubmesh(int renderLayer, std::shared_ptr renderPipeline, std::size_t indexCount, std::shared_ptr indexBuffer, std::shared_ptr vertexBuffer, const ShaderBinding& instanceBinding, const ShaderBinding& materialBinding); + inline RenderSubmesh(int renderLayer, std::shared_ptr renderPipeline, std::size_t indexCount, std::shared_ptr indexBuffer, std::shared_ptr vertexBuffer, const WorldInstance& worldInstance, const ShaderBinding& materialBinding, const MaterialPassFlags& matFlags); ~RenderSubmesh() = default; - inline UInt64 ComputeSortingScore(const RenderQueueRegistry& registry) const override; + inline UInt64 ComputeSortingScore(const Nz::Frustumf& frustum, const RenderQueueRegistry& registry) const override; inline const AbstractBuffer* GetIndexBuffer() const; inline std::size_t GetIndexCount() const; @@ -41,8 +42,9 @@ namespace Nz std::shared_ptr m_vertexBuffer; std::shared_ptr m_renderPipeline; std::size_t m_indexCount; - const ShaderBinding& m_instanceBinding; + MaterialPassFlags m_matFlags; const ShaderBinding& m_materialBinding; + const WorldInstance& m_worldInstance; int m_renderLayer; }; } diff --git a/include/Nazara/Graphics/RenderSubmesh.inl b/include/Nazara/Graphics/RenderSubmesh.inl index e263eb65b..5eafe3731 100644 --- a/include/Nazara/Graphics/RenderSubmesh.inl +++ b/include/Nazara/Graphics/RenderSubmesh.inl @@ -7,36 +7,71 @@ namespace Nz { - inline RenderSubmesh::RenderSubmesh(int renderLayer, std::shared_ptr renderPipeline, std::size_t indexCount, std::shared_ptr indexBuffer, std::shared_ptr vertexBuffer, const ShaderBinding& instanceBinding, const ShaderBinding& materialBinding) : + inline RenderSubmesh::RenderSubmesh(int renderLayer, std::shared_ptr renderPipeline, std::size_t indexCount, std::shared_ptr indexBuffer, std::shared_ptr vertexBuffer, const WorldInstance& worldInstance, const ShaderBinding& materialBinding, const MaterialPassFlags& matFlags) : RenderElement(BasicRenderElement::Submesh), m_indexBuffer(std::move(indexBuffer)), m_vertexBuffer(std::move(vertexBuffer)), m_renderPipeline(std::move(renderPipeline)), m_indexCount(indexCount), - m_instanceBinding(instanceBinding), + m_matFlags(matFlags), + m_worldInstance(worldInstance), m_materialBinding(materialBinding), m_renderLayer(renderLayer) { } - inline UInt64 RenderSubmesh::ComputeSortingScore(const RenderQueueRegistry& registry) const + inline UInt64 RenderSubmesh::ComputeSortingScore(const Nz::Frustumf& frustum, const RenderQueueRegistry& registry) const { UInt64 layerIndex = registry.FetchLayerIndex(m_renderLayer); UInt64 elementType = GetElementType(); UInt64 pipelineIndex = registry.FetchPipelineIndex(m_renderPipeline.get()); UInt64 vertexBufferIndex = registry.FetchVertexBuffer(m_vertexBuffer.get()); + + if (m_matFlags.Test(MaterialPassFlag::Transparent)) + { + UInt64 matFlags = 1; - // RQ index: - // - Layer (8bits) - // - Element type (4bits) - // - Pipeline (16bits) - // - VertexBuffer (8bits) - // - ?? (24bits) - Depth? +#if defined(arm) && \ + ((defined(__MAVERICK__) && defined(NAZARA_BIG_ENDIAN)) || \ + (!defined(__SOFTFP__) && !defined(__VFP_FP__) && !defined(__MAVERICK__))) +#error The following code relies on native-endian IEEE-754 representation, which your platform does not guarantee +#endif - return (layerIndex & 0xFF) << 60 | - (elementType & 0xF) << 52 | - (pipelineIndex & 0xFFFF) << 36 | - (vertexBufferIndex & 0xFF) << 24; + static_assert(sizeof(float) == sizeof(UInt32)); + + float distanceNear = frustum.GetPlane(Nz::FrustumPlane::Near).Distance(m_worldInstance.GetWorldMatrix().GetTranslation()); + UInt32 distanceInt; + std::memcpy(&distanceInt, &distanceNear, sizeof(UInt32)); + + UInt64 distance = ~distanceInt; //< Reverse distance to have back to front + + // Transparent RQ index: + // - Layer (8bits) + // - Transparent flag (1bit) + // - Distance to near plane (32bits) + + return (layerIndex & 0xFF) << 60 | + (matFlags) << 52 | + (distance) << 51; + } + else + { + UInt64 matFlags = 0; + + // Opaque RQ index: + // - Layer (8bits) + // - Transparent flag (1bit) + // - Element type (4bits) + // - Pipeline (16bits) + // - VertexBuffer (8bits) + // - ?? (24bits) - Depth? + + return (layerIndex & 0xFF) << 60 | + (matFlags) << 52 | + (elementType & 0xF) << 51 | + (pipelineIndex & 0xFFFF) << 35 | + (vertexBufferIndex & 0xFF) << 23; + } } inline const AbstractBuffer* RenderSubmesh::GetIndexBuffer() const @@ -56,7 +91,7 @@ namespace Nz inline const ShaderBinding& RenderSubmesh::GetInstanceBinding() const { - return m_instanceBinding; + return m_worldInstance.GetShaderBinding(); } inline const ShaderBinding& RenderSubmesh::GetMaterialBinding() const diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index a3a4d1c71..be0bf3f8a 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -237,7 +237,7 @@ namespace Nz viewerData.depthPrepassRenderQueue.Sort([&](const RenderElement* element) { - return element->ComputeSortingScore(viewerData.depthPrepassRegistry); + return element->ComputeSortingScore(frustum, viewerData.depthPrepassRegistry); }); if (viewerData.rebuildForwardPass) @@ -258,7 +258,7 @@ namespace Nz viewerData.forwardRenderQueue.Sort([&](const RenderElement* element) { - return element->ComputeSortingScore(viewerData.forwardRegistry); + return element->ComputeSortingScore(frustum, viewerData.forwardRegistry); }); } diff --git a/src/Nazara/Graphics/Model.cpp b/src/Nazara/Graphics/Model.cpp index fb967da38..a3a95e770 100644 --- a/src/Nazara/Graphics/Model.cpp +++ b/src/Nazara/Graphics/Model.cpp @@ -45,7 +45,7 @@ namespace Nz const auto& vertexBuffer = m_graphicalMesh->GetVertexBuffer(i); const auto& renderPipeline = materialPass->GetPipeline()->GetRenderPipeline(submeshData.vertexBufferData); - elements.emplace_back(std::make_unique(0, renderPipeline, m_graphicalMesh->GetIndexCount(i), indexBuffer, vertexBuffer, worldInstance.GetShaderBinding(), materialPass->GetShaderBinding())); + elements.emplace_back(std::make_unique(0, renderPipeline, m_graphicalMesh->GetIndexCount(i), indexBuffer, vertexBuffer, worldInstance, materialPass->GetShaderBinding(), materialPass->GetFlags())); } } diff --git a/src/Nazara/Graphics/Sprite.cpp b/src/Nazara/Graphics/Sprite.cpp index 657c7c67d..5a3477d53 100644 --- a/src/Nazara/Graphics/Sprite.cpp +++ b/src/Nazara/Graphics/Sprite.cpp @@ -40,7 +40,7 @@ namespace Nz const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTexture2d; - elements.emplace_back(std::make_unique(0, renderPipeline, vertexDeclaration, whiteTexture, 1, m_vertices.data(), materialPass->GetShaderBinding(), worldInstance.GetShaderBinding())); + elements.emplace_back(std::make_unique(0, renderPipeline, vertexDeclaration, whiteTexture, 1, m_vertices.data(), materialPass->GetShaderBinding(), worldInstance, materialPass->GetFlags())); } const std::shared_ptr& Sprite::GetMaterial(std::size_t i) const diff --git a/src/Nazara/Graphics/TextSprite.cpp b/src/Nazara/Graphics/TextSprite.cpp index 806076ab2..2567eb6e4 100644 --- a/src/Nazara/Graphics/TextSprite.cpp +++ b/src/Nazara/Graphics/TextSprite.cpp @@ -42,7 +42,7 @@ namespace Nz RenderIndices& indices = pair.second; if (indices.count > 0) - elements.emplace_back(std::make_unique(0, renderPipeline, vertexDeclaration, key.texture->shared_from_this(), indices.count, &m_vertices[indices.first * 4], materialPass->GetShaderBinding(), worldInstance.GetShaderBinding())); + elements.emplace_back(std::make_unique(0, renderPipeline, vertexDeclaration, key.texture->shared_from_this(), indices.count, &m_vertices[indices.first * 4], materialPass->GetShaderBinding(), worldInstance, materialPass->GetFlags())); } }