ShaderNode: Add automatic variables

This commit is contained in:
Lynix 2020-05-26 20:30:24 +02:00
parent 09e08255fb
commit d96bc9db6e
12 changed files with 143 additions and 19 deletions

View File

@ -40,6 +40,12 @@ namespace Nz
VertexPosition, // gl_Position VertexPosition, // gl_Position
}; };
enum class ExpressionCategory
{
LValue,
RValue
};
enum class ExpressionType enum class ExpressionType
{ {
Boolean, // bool Boolean, // bool
@ -104,6 +110,7 @@ namespace Nz
class NAZARA_RENDERER_API Expression : public Node class NAZARA_RENDERER_API Expression : public Node
{ {
public: public:
virtual ExpressionCategory GetExpressionCategory() const;
virtual ExpressionType GetExpressionType() const = 0; virtual ExpressionType GetExpressionType() const = 0;
}; };
@ -152,6 +159,7 @@ namespace Nz
public: public:
inline Variable(VariableType varKind, ExpressionType varType); inline Variable(VariableType varKind, ExpressionType varType);
ExpressionCategory GetExpressionCategory() const override;
ExpressionType GetExpressionType() const override; ExpressionType GetExpressionType() const override;
ExpressionType type; ExpressionType type;
@ -191,14 +199,14 @@ namespace Nz
class NAZARA_RENDERER_API AssignOp : public Expression class NAZARA_RENDERER_API AssignOp : public Expression
{ {
public: public:
inline AssignOp(AssignType Op, VariablePtr Var, ExpressionPtr Right); inline AssignOp(AssignType Op, ExpressionPtr Left, ExpressionPtr Right);
ExpressionType GetExpressionType() const override; ExpressionType GetExpressionType() const override;
void Register(ShaderWriter& visitor) override; void Register(ShaderWriter& visitor) override;
void Visit(ShaderWriter& visitor) override; void Visit(ShaderWriter& visitor) override;
AssignType op; AssignType op;
VariablePtr variable; ExpressionPtr left;
ExpressionPtr right; ExpressionPtr right;
}; };
@ -277,6 +285,7 @@ namespace Nz
public: public:
inline SwizzleOp(ExpressionPtr expressionPtr, std::initializer_list<SwizzleComponent> swizzleComponents); inline SwizzleOp(ExpressionPtr expressionPtr, std::initializer_list<SwizzleComponent> swizzleComponents);
ExpressionCategory GetExpressionCategory() const override;
ExpressionType GetExpressionType() const override; ExpressionType GetExpressionType() const override;
void Register(ShaderWriter& visitor) override; void Register(ShaderWriter& visitor) override;
void Visit(ShaderWriter& visitor) override; void Visit(ShaderWriter& visitor) override;

View File

@ -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), op(Op),
variable(std::move(Var)), left(std::move(Left)),
right(std::move(Right)) 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) : inline BinaryOp::BinaryOp(BinaryType Op, ExpressionPtr Left, ExpressionPtr Right) :

View File

@ -18,7 +18,7 @@ namespace Nz { namespace ShaderBuilder
{ {
constexpr AssignOpBuilder() {} constexpr AssignOpBuilder() {}
std::shared_ptr<ShaderAst::AssignOp> operator()(const ShaderAst::VariablePtr& left, const ShaderAst::ExpressionPtr& right) const; std::shared_ptr<ShaderAst::AssignOp> operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const;
}; };
template<ShaderAst::BinaryType op> template<ShaderAst::BinaryType op>

View File

@ -15,7 +15,7 @@ namespace Nz { namespace ShaderBuilder
} }
template<ShaderAst::AssignType op> template<ShaderAst::AssignType op>
std::shared_ptr<ShaderAst::AssignOp> AssignOpBuilder<op>::operator()(const ShaderAst::VariablePtr& left, const ShaderAst::ExpressionPtr& right) const std::shared_ptr<ShaderAst::AssignOp> AssignOpBuilder<op>::operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const
{ {
return std::make_shared<ShaderAst::AssignOp>(op, left, right); return std::make_shared<ShaderAst::AssignOp>(op, left, right);
} }

View File

@ -139,7 +139,7 @@ namespace Nz
void GlslWriter::Write(const ShaderAst::AssignOp& node) void GlslWriter::Write(const ShaderAst::AssignOp& node)
{ {
Write(node.variable); Write(node.left);
switch (node.op) switch (node.op)
{ {

View File

@ -8,6 +8,11 @@
namespace Nz::ShaderAst namespace Nz::ShaderAst
{ {
ExpressionCategory Expression::GetExpressionCategory() const
{
return ExpressionCategory::RValue;
}
void ExpressionStatement::Register(ShaderWriter& visitor) void ExpressionStatement::Register(ShaderWriter& visitor)
{ {
expression->Register(visitor); expression->Register(visitor);
@ -43,6 +48,10 @@ namespace Nz::ShaderAst
visitor.Write(*this); visitor.Write(*this);
} }
ExpressionCategory Variable::GetExpressionCategory() const
{
return ExpressionCategory::LValue;
}
ExpressionType Variable::GetExpressionType() const 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 ExpressionType AssignOp::GetExpressionType() const
{ {
return variable->GetExpressionType(); return left->GetExpressionType();
} }
void AssignOp::Register(ShaderWriter& visitor) void AssignOp::Register(ShaderWriter& visitor)
{ {
variable->Register(visitor); left->Register(visitor);
right->Register(visitor); right->Register(visitor);
} }
@ -102,6 +111,7 @@ namespace Nz::ShaderAst
case ShaderAst::BinaryType::Equality: case ShaderAst::BinaryType::Equality:
exprType = ExpressionType::Boolean; exprType = ExpressionType::Boolean;
break;
} }
NazaraAssert(exprType != ShaderAst::ExpressionType::Void, "Unhandled builtin"); 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<ExpressionType>(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1); return static_cast<ExpressionType>(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1);
} }

View File

@ -13,6 +13,13 @@ ShaderNode(graph)
UpdatePreview(); UpdatePreview();
}); });
if (graph.GetInputCount() > 0)
{
auto& firstInput = graph.GetInput(0);
m_currentInputIndex = 0;
m_currentInputText = firstInput.name;
}
UpdatePreview(); UpdatePreview();
} }

View File

@ -14,6 +14,15 @@ ShaderNode(graph)
if (m_currentTextureIndex == textureIndex) if (m_currentTextureIndex == textureIndex)
UpdatePreview(); 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 unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const

View File

@ -40,13 +40,28 @@ m_flowScene(BuildRegistry())
OnSelectedNodeUpdate(this, nullptr); OnSelectedNodeUpdate(this, nullptr);
}); });
auto& node1 = m_flowScene.createNode(std::make_unique<Vec4Value>(*this)); // Test
node1.nodeGraphicsObject().setPos(200, 200); AddInput("UV", InputType::Float2, InputRole::TexCoord, 0);
AddTexture("Potato", TextureType::Sampler2D);
auto& node2 = m_flowScene.createNode(std::make_unique<FragmentOutput>(*this)); UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)"));
node2.nodeGraphicsObject().setPos(500, 300);
auto& node1 = m_flowScene.createNode(std::make_unique<InputValue>(*this));
node1.nodeGraphicsObject().setPos(0, 200);
auto& node2 = m_flowScene.createNode(std::make_unique<SampleTexture>(*this));
node2.nodeGraphicsObject().setPos(200, 200);
auto& node3 = m_flowScene.createNode(std::make_unique<Vec4Mul>(*this));
node3.nodeGraphicsObject().setPos(400, 200);
auto& node4 = m_flowScene.createNode(std::make_unique<FragmentOutput>(*this));
node4.nodeGraphicsObject().setPos(600, 300);
m_flowScene.createConnection(node2, 0, node1, 0); 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() ShaderGraph::~ShaderGraph()
@ -83,13 +98,51 @@ std::size_t ShaderGraph::AddTexture(std::string name, TextureType type)
Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() Nz::ShaderAst::StatementPtr ShaderGraph::ToAst()
{ {
std::vector<Nz::ShaderAst::StatementPtr> statements; std::vector<Nz::ShaderAst::StatementPtr> statements;
QHash<QUuid, unsigned int> usageCount;
unsigned int varCount = 0;
std::function<void(QtNodes::Node*)> DetectVariables;
DetectVariables = [&](QtNodes::Node* node)
{
ShaderNode* shaderNode = static_cast<ShaderNode*>(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<QUuid, Nz::ShaderAst::ExpressionPtr> variableExpressions;
std::function<Nz::ShaderAst::ExpressionPtr(QtNodes::Node*)> HandleNode; std::function<Nz::ShaderAst::ExpressionPtr(QtNodes::Node*)> HandleNode;
HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderAst::ExpressionPtr HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderAst::ExpressionPtr
{ {
ShaderNode* shaderNode = static_cast<ShaderNode*>(node->nodeDataModel()); ShaderNode* shaderNode = static_cast<ShaderNode*>(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); std::size_t inputCount = shaderNode->nPorts(QtNodes::PortType::In);
Nz::StackArray<Nz::ShaderAst::ExpressionPtr> expressions = NazaraStackArray(Nz::ShaderAst::ExpressionPtr, inputCount); Nz::StackArray<Nz::ShaderAst::ExpressionPtr> expressions = NazaraStackArray(Nz::ShaderAst::ExpressionPtr, inputCount);
std::size_t i = 0; 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) m_flowScene.iterateOverNodes([&](QtNodes::Node* node)

View File

@ -26,10 +26,12 @@ class ShaderGraph
std::size_t AddTexture(std::string name, TextureType type); std::size_t AddTexture(std::string name, TextureType type);
inline const InputEntry& GetInput(std::size_t inputIndex) const; inline const InputEntry& GetInput(std::size_t inputIndex) const;
inline std::size_t GetInputCount() const;
inline const std::vector<InputEntry>& GetInputs() const; inline const std::vector<InputEntry>& GetInputs() const;
inline const PreviewModel& GetPreviewModel() const; inline const PreviewModel& GetPreviewModel() const;
inline QtNodes::FlowScene& GetScene(); inline QtNodes::FlowScene& GetScene();
inline const TextureEntry& GetTexture(std::size_t textureIndex) const; inline const TextureEntry& GetTexture(std::size_t textureIndex) const;
inline std::size_t GetTextureCount() const;
inline const std::vector<TextureEntry>& GetTextures() const; inline const std::vector<TextureEntry>& GetTextures() const;
Nz::ShaderAst::StatementPtr ToAst(); Nz::ShaderAst::StatementPtr ToAst();

View File

@ -6,6 +6,11 @@ inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEn
return m_inputs[inputIndex]; return m_inputs[inputIndex];
} }
inline std::size_t ShaderGraph::GetInputCount() const
{
return m_inputs.size();
}
inline auto ShaderGraph::GetInputs() const -> const std::vector<InputEntry>& inline auto ShaderGraph::GetInputs() const -> const std::vector<InputEntry>&
{ {
return m_inputs; return m_inputs;
@ -27,6 +32,11 @@ inline auto ShaderGraph::GetTexture(std::size_t textureIndex) const -> const Tex
return m_textures[textureIndex]; return m_textures[textureIndex];
} }
inline std::size_t ShaderGraph::GetTextureCount() const
{
return m_textures.size();
}
inline auto ShaderGraph::GetTextures() const -> const std::vector<TextureEntry>& inline auto ShaderGraph::GetTextures() const -> const std::vector<TextureEntry>&
{ {
return m_textures; return m_textures;

View File

@ -8,8 +8,6 @@ int main(int argc, char* argv[])
QApplication app(argc, argv); QApplication app(argc, argv);
ShaderGraph shaderGraph; ShaderGraph shaderGraph;
shaderGraph.AddInput("UV", InputType::Float2, InputRole::TexCoord, 0);
shaderGraph.AddTexture("Potato", TextureType::Sampler2D);
MainWindow mainWindow(shaderGraph); MainWindow mainWindow(shaderGraph);
mainWindow.resize(1280, 720); mainWindow.resize(1280, 720);