From d96bc9db6e5531db5492d68f3a8fc34c0d0826a5 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 May 2020 20:30:24 +0200 Subject: [PATCH] ShaderNode: Add automatic variables --- include/Nazara/Renderer/ShaderAst.hpp | 13 +++- include/Nazara/Renderer/ShaderAst.inl | 7 +- include/Nazara/Renderer/ShaderBuilder.hpp | 2 +- include/Nazara/Renderer/ShaderBuilder.inl | 2 +- src/Nazara/Renderer/GlslWriter.cpp | 2 +- src/Nazara/Renderer/ShaderAst.cpp | 23 +++++- src/ShaderNode/DataModels/InputValue.cpp | 7 ++ src/ShaderNode/DataModels/SampleTexture.cpp | 9 +++ src/ShaderNode/ShaderGraph.cpp | 83 +++++++++++++++++++-- src/ShaderNode/ShaderGraph.hpp | 2 + src/ShaderNode/ShaderGraph.inl | 10 +++ src/ShaderNode/main.cpp | 2 - 12 files changed, 143 insertions(+), 19 deletions(-) diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index d6cc45789..dfe7639e4 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -40,6 +40,12 @@ namespace Nz VertexPosition, // gl_Position }; + enum class ExpressionCategory + { + LValue, + RValue + }; + enum class ExpressionType { Boolean, // bool @@ -104,6 +110,7 @@ namespace Nz class NAZARA_RENDERER_API Expression : public Node { public: + virtual ExpressionCategory GetExpressionCategory() const; virtual ExpressionType GetExpressionType() const = 0; }; @@ -152,6 +159,7 @@ namespace Nz public: inline Variable(VariableType varKind, ExpressionType varType); + ExpressionCategory GetExpressionCategory() const override; ExpressionType GetExpressionType() const override; ExpressionType type; @@ -191,14 +199,14 @@ namespace Nz class NAZARA_RENDERER_API AssignOp : public Expression { public: - inline AssignOp(AssignType Op, VariablePtr Var, ExpressionPtr Right); + inline AssignOp(AssignType Op, ExpressionPtr Left, ExpressionPtr Right); ExpressionType GetExpressionType() const override; void Register(ShaderWriter& visitor) override; void Visit(ShaderWriter& visitor) override; AssignType op; - VariablePtr variable; + ExpressionPtr left; ExpressionPtr right; }; @@ -277,6 +285,7 @@ namespace Nz public: inline SwizzleOp(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents); + ExpressionCategory GetExpressionCategory() const override; ExpressionType GetExpressionType() const override; void Register(ShaderWriter& visitor) override; void Visit(ShaderWriter& visitor) override; diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index cb9024b48..b7d0a42d8 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -82,11 +82,14 @@ namespace Nz { } - inline AssignOp::AssignOp(AssignType Op, VariablePtr Var, ExpressionPtr Right) : + inline AssignOp::AssignOp(AssignType Op, ExpressionPtr Left, ExpressionPtr Right) : op(Op), - variable(std::move(Var)), + left(std::move(Left)), right(std::move(Right)) { + if (left->GetExpressionCategory() != ExpressionCategory::LValue) + //TODO: AstParseError + throw std::runtime_error("Assignation is only possible with lvalues"); } inline BinaryOp::BinaryOp(BinaryType Op, ExpressionPtr Left, ExpressionPtr Right) : diff --git a/include/Nazara/Renderer/ShaderBuilder.hpp b/include/Nazara/Renderer/ShaderBuilder.hpp index b0ba09cc4..b514b9c57 100644 --- a/include/Nazara/Renderer/ShaderBuilder.hpp +++ b/include/Nazara/Renderer/ShaderBuilder.hpp @@ -18,7 +18,7 @@ namespace Nz { namespace ShaderBuilder { constexpr AssignOpBuilder() {} - std::shared_ptr operator()(const ShaderAst::VariablePtr& left, const ShaderAst::ExpressionPtr& right) const; + std::shared_ptr operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const; }; template diff --git a/include/Nazara/Renderer/ShaderBuilder.inl b/include/Nazara/Renderer/ShaderBuilder.inl index 89fa14c35..772c56583 100644 --- a/include/Nazara/Renderer/ShaderBuilder.inl +++ b/include/Nazara/Renderer/ShaderBuilder.inl @@ -15,7 +15,7 @@ namespace Nz { namespace ShaderBuilder } template - std::shared_ptr AssignOpBuilder::operator()(const ShaderAst::VariablePtr& left, const ShaderAst::ExpressionPtr& right) const + std::shared_ptr AssignOpBuilder::operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const { return std::make_shared(op, left, right); } diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 7cb734cc5..685fc64af 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -139,7 +139,7 @@ namespace Nz void GlslWriter::Write(const ShaderAst::AssignOp& node) { - Write(node.variable); + Write(node.left); switch (node.op) { diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index bb64f4475..96dd0c7f3 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -8,6 +8,11 @@ namespace Nz::ShaderAst { + ExpressionCategory Expression::GetExpressionCategory() const + { + return ExpressionCategory::RValue; + } + void ExpressionStatement::Register(ShaderWriter& visitor) { expression->Register(visitor); @@ -43,6 +48,10 @@ namespace Nz::ShaderAst visitor.Write(*this); } + ExpressionCategory Variable::GetExpressionCategory() const + { + return ExpressionCategory::LValue; + } ExpressionType Variable::GetExpressionType() const { @@ -60,7 +69,7 @@ namespace Nz::ShaderAst } - void BuiltinVariable::Register(ShaderWriter& visitor) + void BuiltinVariable::Register(ShaderWriter& /*visitor*/) { } @@ -72,12 +81,12 @@ namespace Nz::ShaderAst ExpressionType AssignOp::GetExpressionType() const { - return variable->GetExpressionType(); + return left->GetExpressionType(); } void AssignOp::Register(ShaderWriter& visitor) { - variable->Register(visitor); + left->Register(visitor); right->Register(visitor); } @@ -102,6 +111,7 @@ namespace Nz::ShaderAst case ShaderAst::BinaryType::Equality: exprType = ExpressionType::Boolean; + break; } NazaraAssert(exprType != ShaderAst::ExpressionType::Void, "Unhandled builtin"); @@ -178,7 +188,12 @@ namespace Nz::ShaderAst } - ExpressionType ShaderAst::SwizzleOp::GetExpressionType() const + ExpressionCategory SwizzleOp::GetExpressionCategory() const + { + return ExpressionCategory::LValue; + } + + ExpressionType SwizzleOp::GetExpressionType() const { return static_cast(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1); } diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index a6044a229..810c2862e 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -13,6 +13,13 @@ ShaderNode(graph) UpdatePreview(); }); + if (graph.GetInputCount() > 0) + { + auto& firstInput = graph.GetInput(0); + m_currentInputIndex = 0; + m_currentInputText = firstInput.name; + } + UpdatePreview(); } diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index f299b6009..7209a69b5 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -14,6 +14,15 @@ ShaderNode(graph) if (m_currentTextureIndex == textureIndex) UpdatePreview(); }); + + if (graph.GetTextureCount() > 0) + { + auto& firstInput = graph.GetTexture(0); + m_currentTextureIndex = 0; + m_currentTextureText = firstInput.name; + } + + UpdateOutput(); } unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index bc9d643fd..5bdfe0284 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -40,13 +40,28 @@ m_flowScene(BuildRegistry()) OnSelectedNodeUpdate(this, nullptr); }); - auto& node1 = m_flowScene.createNode(std::make_unique(*this)); - node1.nodeGraphicsObject().setPos(200, 200); + // Test + AddInput("UV", InputType::Float2, InputRole::TexCoord, 0); + AddTexture("Potato", TextureType::Sampler2D); - auto& node2 = m_flowScene.createNode(std::make_unique(*this)); - node2.nodeGraphicsObject().setPos(500, 300); + UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)")); + + auto& node1 = m_flowScene.createNode(std::make_unique(*this)); + node1.nodeGraphicsObject().setPos(0, 200); + + auto& node2 = m_flowScene.createNode(std::make_unique(*this)); + node2.nodeGraphicsObject().setPos(200, 200); + + auto& node3 = m_flowScene.createNode(std::make_unique(*this)); + node3.nodeGraphicsObject().setPos(400, 200); + + auto& node4 = m_flowScene.createNode(std::make_unique(*this)); + node4.nodeGraphicsObject().setPos(600, 300); m_flowScene.createConnection(node2, 0, node1, 0); + m_flowScene.createConnection(node3, 0, node2, 0); + m_flowScene.createConnection(node3, 1, node2, 0); + m_flowScene.createConnection(node4, 0, node3, 0); } ShaderGraph::~ShaderGraph() @@ -83,13 +98,51 @@ std::size_t ShaderGraph::AddTexture(std::string name, TextureType type) Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() { std::vector statements; + QHash usageCount; + + unsigned int varCount = 0; + + std::function DetectVariables; + DetectVariables = [&](QtNodes::Node* node) + { + ShaderNode* shaderNode = static_cast(node->nodeDataModel()); + + qDebug() << shaderNode->name() << node->id(); + auto it = usageCount.find(node->id()); + if (it == usageCount.end()) + it = usageCount.insert(node->id(), 0); + + (*it)++; + + for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) + { + for (const auto& [uuid, conn] : connectionSet) + { + DetectVariables(conn->getNode(QtNodes::PortType::Out)); + } + } + }; + + m_flowScene.iterateOverNodes([&](QtNodes::Node* node) + { + if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) + DetectVariables(node); + }); + + QHash variableExpressions; std::function HandleNode; HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderAst::ExpressionPtr { ShaderNode* shaderNode = static_cast(node->nodeDataModel()); - qDebug() << shaderNode->name(); + qDebug() << shaderNode->name() << node->id(); + if (auto it = variableExpressions.find(node->id()); it != variableExpressions.end()) + return *it; + + auto it = usageCount.find(node->id()); + assert(it != usageCount.end()); + std::size_t inputCount = shaderNode->nPorts(QtNodes::PortType::In); Nz::StackArray expressions = NazaraStackArray(Nz::ShaderAst::ExpressionPtr, inputCount); std::size_t i = 0; @@ -104,7 +157,25 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() } } - return shaderNode->GetExpression(expressions.data(), expressions.size()); + auto expression = shaderNode->GetExpression(expressions.data(), expressions.size()); + + if (*it > 1) + { + Nz::ShaderAst::ExpressionPtr varExpression; + if (expression->GetExpressionCategory() == Nz::ShaderAst::ExpressionCategory::RValue) + { + varExpression = Nz::ShaderBuilder::Variable("var" + std::to_string(varCount++), expression->GetExpressionType()); + statements.emplace_back(Nz::ShaderBuilder::ExprStatement(Nz::ShaderBuilder::Assign(varExpression, expression))); + } + else + varExpression = expression; + + variableExpressions.insert(node->id(), varExpression); + + return varExpression; + } + else + return expression; }; m_flowScene.iterateOverNodes([&](QtNodes::Node* node) diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index 3ed906edd..ca29ff174 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -26,10 +26,12 @@ class ShaderGraph std::size_t AddTexture(std::string name, TextureType type); inline const InputEntry& GetInput(std::size_t inputIndex) const; + inline std::size_t GetInputCount() const; inline const std::vector& GetInputs() const; inline const PreviewModel& GetPreviewModel() const; inline QtNodes::FlowScene& GetScene(); inline const TextureEntry& GetTexture(std::size_t textureIndex) const; + inline std::size_t GetTextureCount() const; inline const std::vector& GetTextures() const; Nz::ShaderAst::StatementPtr ToAst(); diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index 100cd822e..97184906e 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -6,6 +6,11 @@ inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEn return m_inputs[inputIndex]; } +inline std::size_t ShaderGraph::GetInputCount() const +{ + return m_inputs.size(); +} + inline auto ShaderGraph::GetInputs() const -> const std::vector& { return m_inputs; @@ -27,6 +32,11 @@ inline auto ShaderGraph::GetTexture(std::size_t textureIndex) const -> const Tex return m_textures[textureIndex]; } +inline std::size_t ShaderGraph::GetTextureCount() const +{ + return m_textures.size(); +} + inline auto ShaderGraph::GetTextures() const -> const std::vector& { return m_textures; diff --git a/src/ShaderNode/main.cpp b/src/ShaderNode/main.cpp index a939e708a..8cea2a20f 100644 --- a/src/ShaderNode/main.cpp +++ b/src/ShaderNode/main.cpp @@ -8,8 +8,6 @@ int main(int argc, char* argv[]) QApplication app(argc, argv); ShaderGraph shaderGraph; - shaderGraph.AddInput("UV", InputType::Float2, InputRole::TexCoord, 0); - shaderGraph.AddTexture("Potato", TextureType::Sampler2D); MainWindow mainWindow(shaderGraph); mainWindow.resize(1280, 720);