Add shadernode (big WIP)
This commit is contained in:
parent
8c0d34313e
commit
c26f3b9b71
|
|
@ -1,7 +1,8 @@
|
||||||
# Nazara build
|
# Nazara build
|
||||||
build/config.lua
|
build/config.lua
|
||||||
|
|
||||||
# Nazara libraries
|
# Nazara binaries
|
||||||
|
bin/*
|
||||||
lib/*
|
lib/*
|
||||||
|
|
||||||
# Self-hosted thirdparty libraries binaries
|
# 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