Add shadernode (big WIP)
This commit is contained in:
parent
8c0d34313e
commit
c26f3b9b71
|
|
@ -1,7 +1,8 @@
|
|||
# Nazara build
|
||||
build/config.lua
|
||||
|
||||
# Nazara libraries
|
||||
# Nazara binaries
|
||||
bin/*
|
||||
lib/*
|
||||
|
||||
# Self-hosted thirdparty libraries binaries
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
TOOL.Name = "ShaderNodes"
|
||||
|
||||
TOOL.ClientOnly = true
|
||||
TOOL.EnableConsole = true
|
||||
TOOL.Kind = "Application"
|
||||
TOOL.TargetDirectory = "../bin"
|
||||
|
||||
TOOL.Defines = {
|
||||
"NODE_EDITOR_SHARED"
|
||||
}
|
||||
|
||||
TOOL.Includes = {
|
||||
"../include",
|
||||
"../extlibs/include",
|
||||
"../src/ShaderNode",
|
||||
[[E:\Qt\5.14.1\msvc2017_64\include]],
|
||||
[[E:\Qt\5.14.1\msvc2017_64\include\QtCore]],
|
||||
[[E:\Qt\5.14.1\msvc2017_64\include\QtGui]],
|
||||
[[E:\Qt\5.14.1\msvc2017_64\include\QtWidgets]],
|
||||
[[C:\Users\Lynix\Documents\GitHub\nodeeditor\include]],
|
||||
}
|
||||
|
||||
TOOL.Files = {
|
||||
"../src/ShaderNode/**.hpp",
|
||||
"../src/ShaderNode/**.inl",
|
||||
"../src/ShaderNode/**.cpp"
|
||||
}
|
||||
|
||||
TOOL.Libraries = {
|
||||
"NazaraCore",
|
||||
"NazaraRenderer",
|
||||
"NazaraUtility",
|
||||
"Qt5Cored",
|
||||
"Qt5Guid",
|
||||
"Qt5Widgetsd",
|
||||
"nodes"
|
||||
}
|
||||
|
||||
TOOL.LibraryPaths.x64 = {
|
||||
[[E:\Qt\5.14.1\msvc2017_64\lib]],
|
||||
[[C:\Users\Lynix\Documents\GitHub\nodeeditor\build\lib\Debug]]
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
#include <DataModels/FragmentOutput.hpp>
|
||||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||
#include <DataModels/VecValue.hpp>
|
||||
|
||||
Nz::ShaderAst::ExpressionPtr FragmentOutput::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const
|
||||
{
|
||||
using namespace Nz::ShaderAst;
|
||||
using namespace Nz::ShaderBuilder;
|
||||
|
||||
assert(count == 1);
|
||||
|
||||
auto output = Nz::ShaderBuilder::Output("RenderTarget0", ExpressionType::Float4);
|
||||
|
||||
return Nz::ShaderBuilder::Assign(output, *expressions);
|
||||
}
|
||||
|
||||
QtNodes::NodeDataType FragmentOutput::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
|
||||
{
|
||||
assert(portType == QtNodes::PortType::In);
|
||||
assert(portIndex == 0);
|
||||
|
||||
return Vec4Data::Type();
|
||||
}
|
||||
|
||||
QWidget* FragmentOutput::embeddedWidget()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int FragmentOutput::nPorts(QtNodes::PortType portType) const
|
||||
{
|
||||
switch (portType)
|
||||
{
|
||||
case QtNodes::PortType::In: return 1;
|
||||
case QtNodes::PortType::Out: return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<QtNodes::NodeData> FragmentOutput::outData(QtNodes::PortIndex /*port*/)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP
|
||||
#define NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP
|
||||
|
||||
#include <DataModels/ShaderNode.hpp>
|
||||
#include <QtWidgets/QDoubleSpinBox>
|
||||
#include <QtWidgets/QFormLayout>
|
||||
|
||||
class FragmentOutput : public ShaderNode
|
||||
{
|
||||
public:
|
||||
Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override;
|
||||
|
||||
QString caption() const override { return "Fragment shader output"; }
|
||||
QString name() const override { return "FragmentShaderOutput"; }
|
||||
|
||||
QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
|
||||
|
||||
QWidget* embeddedWidget() override;
|
||||
unsigned int nPorts(QtNodes::PortType portType) const override;
|
||||
|
||||
std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex port) override;
|
||||
|
||||
void setInData(std::shared_ptr<QtNodes::NodeData>, int) override {};
|
||||
|
||||
};
|
||||
|
||||
#include <DataModels/FragmentOutput.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include <DataModels/FragmentOutput.hpp>
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include <DataModels/ShaderNode.hpp>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SHADERNODES_SHADERNODE_HPP
|
||||
#define NAZARA_SHADERNODES_SHADERNODE_HPP
|
||||
|
||||
#include <Nazara/Renderer/ShaderAst.hpp>
|
||||
#include <nodes/NodeDataModel>
|
||||
|
||||
class ShaderNode : public QtNodes::NodeDataModel
|
||||
{
|
||||
public:
|
||||
virtual Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const = 0;
|
||||
};
|
||||
|
||||
#include <DataModels/ShaderNode.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include <DataModels/ShaderNode.hpp>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#include <DataModels/VecValue.hpp>
|
||||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||
|
||||
Nz::ShaderAst::ExpressionPtr Vec4Value::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const
|
||||
{
|
||||
assert(count == 0);
|
||||
|
||||
return Nz::ShaderBuilder::Constant(GetValue());
|
||||
}
|
||||
|
||||
auto Vec4Value::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType
|
||||
{
|
||||
assert(portType == QtNodes::PortType::Out);
|
||||
assert(portIndex == 0);
|
||||
|
||||
return Vec4Data::Type();
|
||||
}
|
||||
|
||||
std::shared_ptr<QtNodes::NodeData> Vec4Value::outData(QtNodes::PortIndex port)
|
||||
{
|
||||
assert(port == 0);
|
||||
|
||||
return std::make_shared<Vec4Data>(GetValue());
|
||||
}
|
||||
|
||||
Nz::Vector4f Vec4Value::GetValue() const
|
||||
{
|
||||
float x = float(m_values[0]->value());
|
||||
float y = float(m_values[1]->value());
|
||||
float z = float(m_values[2]->value());
|
||||
float w = float(m_values[3]->value());
|
||||
|
||||
return Nz::Vector4f(x, y, z, w);
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SHADERNODES_VECVALUE_HPP
|
||||
#define NAZARA_SHADERNODES_VECVALUE_HPP
|
||||
|
||||
#include <QtWidgets/QDoubleSpinBox>
|
||||
#include <QtWidgets/QFormLayout>
|
||||
#include <DataModels/ShaderNode.hpp>
|
||||
#include <array>
|
||||
|
||||
template<std::size_t N>
|
||||
class VecValue : public ShaderNode
|
||||
{
|
||||
public:
|
||||
VecValue();
|
||||
~VecValue() = default;
|
||||
|
||||
QWidget* embeddedWidget() override;
|
||||
unsigned int nPorts(QtNodes::PortType portType) const override;
|
||||
|
||||
protected:
|
||||
QWidget* m_widget;
|
||||
QFormLayout* m_layout;
|
||||
std::array<QDoubleSpinBox*, N> m_values;
|
||||
};
|
||||
|
||||
class Vec4Data : public QtNodes::NodeData
|
||||
{
|
||||
public:
|
||||
inline Vec4Data(const Nz::Vector4f& vec);
|
||||
|
||||
QtNodes::NodeDataType type() const override
|
||||
{
|
||||
return Type();
|
||||
}
|
||||
|
||||
static QtNodes::NodeDataType Type()
|
||||
{
|
||||
return { "vec4", "Vec4" };
|
||||
}
|
||||
|
||||
Nz::Vector4f value;
|
||||
};
|
||||
|
||||
class Vec4Value : public VecValue<4>
|
||||
{
|
||||
public:
|
||||
Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override;
|
||||
|
||||
QString caption() const override { return "Vec4 value"; }
|
||||
bool captionVisible() const override { return true; }
|
||||
QString name() const override { return "Vec4Value"; }
|
||||
|
||||
QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
|
||||
|
||||
std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex port) override;
|
||||
|
||||
void setInData(std::shared_ptr<QtNodes::NodeData>, int) override {};
|
||||
|
||||
private:
|
||||
Nz::Vector4f GetValue() const;
|
||||
};
|
||||
|
||||
#include <DataModels/VecValue.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
#include <DataModels/VecValue.hpp>
|
||||
#include <array>
|
||||
|
||||
template<std::size_t N>
|
||||
VecValue<N>::VecValue()
|
||||
{
|
||||
constexpr std::array<char, 4> componentName = { 'X', 'Y', 'Z', 'W' };
|
||||
static_assert(N <= componentName.size());
|
||||
|
||||
m_layout = new QFormLayout;
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
m_values[i] = new QDoubleSpinBox;
|
||||
m_values[i]->setStyleSheet("background-color: rgba(255,255,255,255)");
|
||||
m_layout->addRow(QString::fromUtf8(&componentName[i], 1), m_values[i]);
|
||||
}
|
||||
|
||||
m_widget = new QWidget;
|
||||
m_widget->setStyleSheet("background-color: rgba(0,0,0,0)");
|
||||
m_widget->setLayout(m_layout);
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
QWidget* VecValue<N>::embeddedWidget()
|
||||
{
|
||||
return m_widget;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
unsigned int VecValue<N>::nPorts(QtNodes::PortType portType) const
|
||||
{
|
||||
switch (portType)
|
||||
{
|
||||
case QtNodes::PortType::In: return 0;
|
||||
case QtNodes::PortType::Out: return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Vec4Data::Vec4Data(const Nz::Vector4f& vec) :
|
||||
value(vec)
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
#include <Nazara/Core/StackArray.hpp>
|
||||
#include <Nazara/Renderer/ShaderAst.hpp>
|
||||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||
#include <Nazara/Renderer/GlslWriter.hpp>
|
||||
#include <DataModels/FragmentOutput.hpp>
|
||||
#include <DataModels/ShaderNode.hpp>
|
||||
#include <DataModels/VecValue.hpp>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QMenuBar>
|
||||
#include <QtWidgets/QVBoxLayout>
|
||||
#include <QtWidgets/QTextEdit>
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <nodes/Node>
|
||||
#include <nodes/NodeData>
|
||||
#include <nodes/NodeGeometry>
|
||||
#include <nodes/FlowScene>
|
||||
#include <nodes/FlowView>
|
||||
#include <nodes/DataModelRegistry>
|
||||
#include <iostream>
|
||||
|
||||
std::shared_ptr<QtNodes::DataModelRegistry> registerDataModels()
|
||||
{
|
||||
auto ret = std::make_shared<QtNodes::DataModelRegistry>();
|
||||
ret->registerModel<FragmentOutput>();
|
||||
ret->registerModel<Vec4Value>();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GenerateGLSL(QtNodes::FlowScene* scene)
|
||||
{
|
||||
/*using namespace ShaderBuilder;
|
||||
using ShaderAst::BuiltinEntry;
|
||||
using ShaderAst::ExpressionType;
|
||||
|
||||
// Fragment shader
|
||||
{
|
||||
auto rt0 = Output("RenderTarget0", ExpressionType::Float4);
|
||||
auto color = Uniform("Color", ExpressionType::Float4);
|
||||
|
||||
fragmentShader = writer.Generate(ExprStatement(Assign(rt0, color)));
|
||||
}*/
|
||||
|
||||
Nz::GlslWriter writer;
|
||||
std::vector<Nz::ShaderAst::StatementPtr> statements;
|
||||
|
||||
std::function<Nz::ShaderAst::ExpressionPtr(QtNodes::Node*)> HandleNode;
|
||||
HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderAst::ExpressionPtr
|
||||
{
|
||||
ShaderNode* shaderNode = static_cast<ShaderNode*>(node->nodeDataModel());
|
||||
|
||||
qDebug() << shaderNode->name();
|
||||
std::size_t inputCount = shaderNode->nPorts(QtNodes::PortType::In);
|
||||
Nz::StackArray<Nz::ShaderAst::ExpressionPtr> expressions = NazaraStackArray(Nz::ShaderAst::ExpressionPtr, inputCount);
|
||||
std::size_t i = 0;
|
||||
|
||||
for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In))
|
||||
{
|
||||
for (const auto& [uuid, conn] : connectionSet)
|
||||
{
|
||||
assert(i < expressions.size());
|
||||
expressions[i] = HandleNode(conn->getNode(QtNodes::PortType::Out));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return shaderNode->GetExpression(expressions.data(), expressions.size());
|
||||
};
|
||||
|
||||
scene->iterateOverNodes([&](QtNodes::Node* node)
|
||||
{
|
||||
if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0)
|
||||
{
|
||||
statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node)));
|
||||
//qDebug() << node->nodeDataModel()->name();
|
||||
}
|
||||
});
|
||||
|
||||
Nz::String glsl = writer.Generate(std::make_shared<Nz::ShaderAst::StatementBlock>(std::move(statements)));
|
||||
|
||||
QTextEdit* output = new QTextEdit;
|
||||
output->setText(QString::fromUtf8(glsl.GetConstBuffer(), glsl.GetSize()));
|
||||
output->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
output->setWindowTitle("GLSL Output");
|
||||
output->show();
|
||||
|
||||
std::cout << glsl << std::endl;
|
||||
}
|
||||
|
||||
void SetupTestScene(QtNodes::FlowScene* scene)
|
||||
{
|
||||
auto& node1 = scene->createNode(std::make_unique<Vec4Value>());
|
||||
node1.nodeGraphicsObject().setPos(200, 200);
|
||||
|
||||
auto& node2 = scene->createNode(std::make_unique<FragmentOutput>());
|
||||
node2.nodeGraphicsObject().setPos(500, 300);
|
||||
|
||||
scene->createConnection(node2, 0, node1, 0);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QWidget mainWindow;
|
||||
QVBoxLayout* layout = new QVBoxLayout;
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
QtNodes::FlowScene* scene = new QtNodes::FlowScene(registerDataModels());
|
||||
SetupTestScene(scene);
|
||||
|
||||
QMenuBar* menuBar = new QMenuBar;
|
||||
QAction* glslCode = menuBar->addAction("To GLSL");
|
||||
QObject::connect(glslCode, &QAction::triggered, [&](bool) { GenerateGLSL(scene); });
|
||||
|
||||
layout->addWidget(new QtNodes::FlowView(scene));
|
||||
layout->addWidget(menuBar);
|
||||
|
||||
mainWindow.setLayout(layout);
|
||||
mainWindow.setWindowTitle("Nazara Shader nodes");
|
||||
mainWindow.resize(1280, 720);
|
||||
mainWindow.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
Loading…
Reference in New Issue