diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index bbd485dc1..b17e4aab2 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -36,6 +36,7 @@ namespace Nz void Write(const ShaderAst::Branch& node) override; void Write(const ShaderAst::BinaryOp& node) override; void Write(const ShaderAst::BuiltinVariable& node) override; + void Write(const ShaderAst::Cast& node) override; void Write(const ShaderAst::Constant& node) override; void Write(const ShaderAst::ExpressionStatement& node) override; void Write(const ShaderAst::NamedVariable& node) override; diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index d0d502959..eb556ab55 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace Nz @@ -76,6 +77,9 @@ namespace Nz virtual void Register(ShaderWriter& visitor) = 0; virtual void Visit(ShaderWriter& visitor) = 0; + + static inline unsigned int GetComponentCount(ExpressionType type); + static inline ExpressionType GetComponentType(ExpressionType type); }; class Statement; @@ -209,6 +213,19 @@ namespace Nz StatementPtr elseStatement; }; + class NAZARA_RENDERER_API Cast : public Expression + { + public: + inline Cast(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second = nullptr, ExpressionPtr third = nullptr, ExpressionPtr fourth = nullptr); + + ExpressionType GetExpressionType() const override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderWriter& visitor) override; + + ExpressionType exprType; + std::array expressions; + }; + class NAZARA_RENDERER_API Constant : public Expression { public: diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index 3fe505726..4565cfc3d 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -10,6 +10,38 @@ namespace Nz { namespace ShaderAst { + inline unsigned int Node::GetComponentCount(ExpressionType type) + { + switch (type) + { + case ExpressionType::Float2: + return 2; + + case ExpressionType::Float3: + return 3; + + case ExpressionType::Float4: + return 4; + + default: + return 1; + } + } + + inline ExpressionType Node::GetComponentType(ExpressionType type) + { + switch (type) + { + case ExpressionType::Float2: + case ExpressionType::Float3: + case ExpressionType::Float4: + return ExpressionType::Float1; + + default: + return type; + } + } + inline ExpressionStatement::ExpressionStatement(ExpressionPtr expr) : expression(std::move(expr)) { @@ -62,6 +94,25 @@ namespace Nz elseStatement = std::move(falseStatement); } + inline Cast::Cast(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second, ExpressionPtr third, ExpressionPtr fourth) : + exprType(castTo), + expressions({first, second, third, fourth}) + { + unsigned int componentCount = 0; + unsigned int requiredComponents = GetComponentCount(exprType); + for (const auto& exprPtr : expressions) + { + if (!exprPtr) + break; + + componentCount += GetComponentCount(exprPtr->GetExpressionType()); + } + + //TODO: AstParseError + if (componentCount != requiredComponents) + throw std::runtime_error("Component count doesn't match required component count"); + } + inline Constant::Constant(float value) : exprType(ExpressionType::Float1) { diff --git a/include/Nazara/Renderer/ShaderBuilder.hpp b/include/Nazara/Renderer/ShaderBuilder.hpp index 631083fab..b92ad78cb 100644 --- a/include/Nazara/Renderer/ShaderBuilder.hpp +++ b/include/Nazara/Renderer/ShaderBuilder.hpp @@ -58,6 +58,8 @@ namespace Nz { namespace ShaderBuilder constexpr BinOpBuilder Substract; constexpr VarBuilder Uniform; constexpr VarBuilder Variable; + + template std::shared_ptr Cast(Args&&... args); } } #include diff --git a/include/Nazara/Renderer/ShaderBuilder.inl b/include/Nazara/Renderer/ShaderBuilder.inl index c64da3a82..4b62b5483 100644 --- a/include/Nazara/Renderer/ShaderBuilder.inl +++ b/include/Nazara/Renderer/ShaderBuilder.inl @@ -48,6 +48,12 @@ namespace Nz { namespace ShaderBuilder { return std::make_shared(type, std::forward(args)...); } + + template + std::shared_ptr Cast(Args&&... args) + { + return std::make_shared(Type, std::forward(args)...); + } } } #include diff --git a/include/Nazara/Renderer/ShaderWriter.hpp b/include/Nazara/Renderer/ShaderWriter.hpp index aec80855f..3c17bf936 100644 --- a/include/Nazara/Renderer/ShaderWriter.hpp +++ b/include/Nazara/Renderer/ShaderWriter.hpp @@ -30,6 +30,7 @@ namespace Nz virtual void Write(const ShaderAst::Branch& node) = 0; virtual void Write(const ShaderAst::BinaryOp& node) = 0; virtual void Write(const ShaderAst::BuiltinVariable& node) = 0; + virtual void Write(const ShaderAst::Cast& node) = 0; virtual void Write(const ShaderAst::Constant& node) = 0; virtual void Write(const ShaderAst::ExpressionStatement& node) = 0; virtual void Write(const ShaderAst::NamedVariable& node) = 0; diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index ebafb2d7b..9edaeeb0d 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -198,6 +198,28 @@ namespace Nz Append(node.var); } + void GlslWriter::Write(const ShaderAst::Cast& node) + { + Append(node.exprType); + Append("("); + + unsigned int i = 0; + unsigned int requiredComponents = ShaderAst::Node::GetComponentCount(node.exprType); + while (requiredComponents > 0) + { + if (i != 0) + m_currentState->stream << ", "; + + const auto& exprPtr = node.expressions[i++]; + NazaraAssert(exprPtr, "Invalid expression"); + + Write(exprPtr); + requiredComponents -= ShaderAst::Node::GetComponentCount(exprPtr->GetExpressionType()); + } + + Append(")"); + } + void GlslWriter::Write(const ShaderAst::Constant& node) { switch (node.exprType) diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index 7cc3b6313..a1612ebf9 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -139,5 +139,29 @@ namespace Nz { namespace ShaderAst { visitor.Write(*this); } + + ExpressionType Cast::GetExpressionType() const + { + return exprType; + } + + void Cast::Register(ShaderWriter& visitor) + { + auto it = expressions.begin(); + (*it)->Register(visitor); + + for (; it != expressions.end(); ++it) + { + if (!*it) + break; + + (*it)->Register(visitor); + } + } + + void Cast::Visit(ShaderWriter& visitor) + { + visitor.Write(*this); + } } }