ShaderNode: Add code output window
This commit is contained in:
parent
a037eef4c9
commit
c8f4e53244
|
|
@ -1,5 +1,6 @@
|
||||||
#include <ShaderNode/ShaderGraph.hpp>
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
#include <Nazara/Core/StackArray.hpp>
|
#include <Nazara/Core/StackArray.hpp>
|
||||||
|
#include <Nazara/Shader/ShaderAstUtils.hpp>
|
||||||
#include <ShaderNode/DataModels/BinOp.hpp>
|
#include <ShaderNode/DataModels/BinOp.hpp>
|
||||||
#include <ShaderNode/DataModels/BoolValue.hpp>
|
#include <ShaderNode/DataModels/BoolValue.hpp>
|
||||||
#include <ShaderNode/DataModels/BufferField.hpp>
|
#include <ShaderNode/DataModels/BufferField.hpp>
|
||||||
|
|
@ -62,6 +63,7 @@ m_type(ShaderType::NotSet)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
|
m_type = ShaderType::Fragment;
|
||||||
AddInput("UV", PrimitiveType::Float2, InputRole::TexCoord, 0, 0);
|
AddInput("UV", PrimitiveType::Float2, InputRole::TexCoord, 0, 0);
|
||||||
AddOutput("RenderTarget0", PrimitiveType::Float4, 0);
|
AddOutput("RenderTarget0", PrimitiveType::Float4, 0);
|
||||||
AddTexture("Potato", TextureType::Sampler2D, 1);
|
AddTexture("Potato", TextureType::Sampler2D, 1);
|
||||||
|
|
@ -440,7 +442,7 @@ QJsonObject ShaderGraph::Save()
|
||||||
return sceneJson;
|
return sceneJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst()
|
Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst() const
|
||||||
{
|
{
|
||||||
std::vector<Nz::ShaderNodes::StatementPtr> statements;
|
std::vector<Nz::ShaderNodes::StatementPtr> statements;
|
||||||
|
|
||||||
|
|
@ -580,6 +582,61 @@ Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst()
|
||||||
return Nz::ShaderNodes::StatementBlock::Build(std::move(statements));
|
return Nz::ShaderNodes::StatementBlock::Build(std::move(statements));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Nz::ShaderAst ShaderGraph::ToShader() const
|
||||||
|
{
|
||||||
|
Nz::ShaderAst shader(ShaderGraph::ToShaderStageType(m_type)); //< FIXME
|
||||||
|
for (const auto& condition : m_conditions)
|
||||||
|
shader.AddCondition(condition.name);
|
||||||
|
|
||||||
|
for (const auto& input : m_inputs)
|
||||||
|
shader.AddInput(input.name, ToShaderExpressionType(input.type), input.locationIndex);
|
||||||
|
|
||||||
|
for (const auto& output : m_outputs)
|
||||||
|
shader.AddOutput(output.name, ToShaderExpressionType(output.type), output.locationIndex);
|
||||||
|
|
||||||
|
for (const auto& buffer : m_buffers)
|
||||||
|
{
|
||||||
|
if (buffer.structIndex >= m_structs.size())
|
||||||
|
throw std::runtime_error("buffer " + buffer.name + " references out-of-bounds struct #" + std::to_string(buffer.structIndex));
|
||||||
|
|
||||||
|
const auto& structInfo = m_structs[buffer.structIndex];
|
||||||
|
shader.AddUniform(buffer.name, structInfo.name, buffer.bindingIndex, Nz::ShaderNodes::MemoryLayout::Std140);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& uniform : m_textures)
|
||||||
|
shader.AddUniform(uniform.name, ToShaderExpressionType(uniform.type), uniform.bindingIndex, {});
|
||||||
|
|
||||||
|
for (const auto& s : m_structs)
|
||||||
|
{
|
||||||
|
std::vector<Nz::ShaderAst::StructMember> members;
|
||||||
|
for (const auto& sMember : s.members)
|
||||||
|
{
|
||||||
|
auto& member = members.emplace_back();
|
||||||
|
member.name = sMember.name;
|
||||||
|
|
||||||
|
std::visit([&](auto&& arg)
|
||||||
|
{
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, PrimitiveType>)
|
||||||
|
member.type = ToShaderExpressionType(arg);
|
||||||
|
else if constexpr (std::is_same_v<T, std::size_t>)
|
||||||
|
{
|
||||||
|
if (arg >= m_structs.size())
|
||||||
|
throw std::runtime_error("struct " + s.name + " references out-of-bounds struct #" + std::to_string(arg));
|
||||||
|
|
||||||
|
member.type = m_structs[arg].name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
||||||
|
}, sMember.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
shader.AddStruct(s.name, std::move(members));
|
||||||
|
}
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(const std::variant<PrimitiveType, std::size_t>& type) const
|
Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(const std::variant<PrimitiveType, std::size_t>& type) const
|
||||||
{
|
{
|
||||||
return std::visit([&](auto&& arg) -> Nz::ShaderExpressionType
|
return std::visit([&](auto&& arg) -> Nz::ShaderExpressionType
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <Nazara/Core/Signal.hpp>
|
#include <Nazara/Core/Signal.hpp>
|
||||||
#include <Nazara/Utility/Enums.hpp>
|
#include <Nazara/Utility/Enums.hpp>
|
||||||
|
#include <Nazara/Shader/ShaderAst.hpp>
|
||||||
#include <Nazara/Shader/ShaderNodes.hpp>
|
#include <Nazara/Shader/ShaderNodes.hpp>
|
||||||
#include <nodes/FlowScene>
|
#include <nodes/FlowScene>
|
||||||
#include <ShaderNode/Enums.hpp>
|
#include <ShaderNode/Enums.hpp>
|
||||||
|
|
@ -66,7 +67,8 @@ class ShaderGraph
|
||||||
void Load(const QJsonObject& data);
|
void Load(const QJsonObject& data);
|
||||||
QJsonObject Save();
|
QJsonObject Save();
|
||||||
|
|
||||||
Nz::ShaderNodes::StatementPtr ToAst();
|
Nz::ShaderNodes::StatementPtr ToAst() const;
|
||||||
|
Nz::ShaderAst ToShader() const;
|
||||||
Nz::ShaderExpressionType ToShaderExpressionType(const std::variant<PrimitiveType, std::size_t>& type) const;
|
Nz::ShaderExpressionType ToShaderExpressionType(const std::variant<PrimitiveType, std::size_t>& type) const;
|
||||||
|
|
||||||
void UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex);
|
void UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex);
|
||||||
|
|
@ -152,7 +154,7 @@ class ShaderGraph
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<QtNodes::DataModelRegistry> BuildRegistry();
|
std::shared_ptr<QtNodes::DataModelRegistry> BuildRegistry();
|
||||||
|
|
||||||
QtNodes::FlowScene m_flowScene;
|
mutable QtNodes::FlowScene m_flowScene;
|
||||||
std::vector<BufferEntry> m_buffers;
|
std::vector<BufferEntry> m_buffers;
|
||||||
std::vector<ConditionEntry> m_conditions;
|
std::vector<ConditionEntry> m_conditions;
|
||||||
std::vector<InputEntry> m_inputs;
|
std::vector<InputEntry> m_inputs;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
#include <ShaderNode/Widgets/CodeOutputWidget.hpp>
|
||||||
|
#include <Nazara/Shader/GlslWriter.hpp>
|
||||||
|
#include <Nazara/Shader/ShaderAstOptimizer.hpp>
|
||||||
|
#include <Nazara/Shader/SpirvPrinter.hpp>
|
||||||
|
#include <Nazara/Shader/SpirvWriter.hpp>
|
||||||
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
|
#include <QtWidgets/QCheckBox>
|
||||||
|
#include <QtWidgets/QComboBox>
|
||||||
|
#include <QtWidgets/QMessageBox>
|
||||||
|
#include <QtWidgets/QScrollBar>
|
||||||
|
#include <QtWidgets/QTextEdit>
|
||||||
|
#include <QtWidgets/QVBoxLayout>
|
||||||
|
|
||||||
|
enum class OutputLanguage
|
||||||
|
{
|
||||||
|
GLSL,
|
||||||
|
SpirV
|
||||||
|
};
|
||||||
|
|
||||||
|
CodeOutputWidget::CodeOutputWidget(const ShaderGraph& shaderGraph) :
|
||||||
|
m_shaderGraph(shaderGraph)
|
||||||
|
{
|
||||||
|
m_textOutput = new QTextEdit;
|
||||||
|
|
||||||
|
m_outputLang = new QComboBox;
|
||||||
|
m_outputLang->addItem("GLSL", int(OutputLanguage::GLSL));
|
||||||
|
m_outputLang->addItem("SPIR-V", int(OutputLanguage::SpirV));
|
||||||
|
connect(m_outputLang, qOverload<int>(&QComboBox::currentIndexChanged), [this](int)
|
||||||
|
{
|
||||||
|
Refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_optimisationCheckbox = new QCheckBox;
|
||||||
|
m_optimisationCheckbox->setText("Enable optimisation");
|
||||||
|
connect(m_optimisationCheckbox, &QCheckBox::stateChanged, [this](int)
|
||||||
|
{
|
||||||
|
Refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
QVBoxLayout* verticalLayout = new QVBoxLayout;
|
||||||
|
verticalLayout->addWidget(m_textOutput);
|
||||||
|
verticalLayout->addWidget(m_outputLang);
|
||||||
|
verticalLayout->addWidget(m_optimisationCheckbox);
|
||||||
|
|
||||||
|
setLayout(verticalLayout);
|
||||||
|
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeOutputWidget::Refresh()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Nz::UInt64 enabledConditions = 0;
|
||||||
|
for (std::size_t i = 0; i < m_shaderGraph.GetConditionCount(); ++i)
|
||||||
|
{
|
||||||
|
if (m_shaderGraph.IsConditionEnabled(i))
|
||||||
|
enabledConditions = Nz::SetBit<Nz::UInt64>(enabledConditions, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Nz::ShaderAst shaderAst = m_shaderGraph.ToShader();
|
||||||
|
|
||||||
|
Nz::ShaderNodes::StatementPtr mainAst = m_shaderGraph.ToAst();
|
||||||
|
if (m_optimisationCheckbox->isChecked())
|
||||||
|
{
|
||||||
|
Nz::ShaderAstOptimizer optimiser;
|
||||||
|
mainAst = optimiser.Optimise(mainAst, shaderAst, enabledConditions);
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderAst.AddFunction("main", mainAst);
|
||||||
|
|
||||||
|
Nz::ShaderWriter::States states;
|
||||||
|
states.enabledConditions = enabledConditions;
|
||||||
|
|
||||||
|
std::string output;
|
||||||
|
OutputLanguage outputLang = static_cast<OutputLanguage>(m_outputLang->currentIndex());
|
||||||
|
switch (outputLang)
|
||||||
|
{
|
||||||
|
case OutputLanguage::GLSL:
|
||||||
|
{
|
||||||
|
Nz::GlslWriter writer;
|
||||||
|
output = writer.Generate(shaderAst, states);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OutputLanguage::SpirV:
|
||||||
|
{
|
||||||
|
Nz::SpirvWriter writer;
|
||||||
|
std::vector<std::uint32_t> spirv = writer.Generate(shaderAst, states);
|
||||||
|
|
||||||
|
Nz::SpirvPrinter printer;
|
||||||
|
output = printer.Print(spirv.data(), spirv.size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int scrollValue = m_textOutput->verticalScrollBar()->value();
|
||||||
|
m_textOutput->setText(QString::fromStdString(output));
|
||||||
|
m_textOutput->verticalScrollBar()->setValue(scrollValue);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
m_textOutput->setText("Generation failed: " + QString::fromStdString(e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SHADERNODES_CODEOUTPUTWIDGET_HPP
|
||||||
|
#define NAZARA_SHADERNODES_CODEOUTPUTWIDGET_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Shader/ShaderAst.hpp>
|
||||||
|
#include <ShaderNode/Enums.hpp>
|
||||||
|
#include <QtWidgets/QWidget>
|
||||||
|
|
||||||
|
class QCheckBox;
|
||||||
|
class QComboBox;
|
||||||
|
class QTextEdit;
|
||||||
|
class ShaderGraph;
|
||||||
|
|
||||||
|
class CodeOutputWidget : public QWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CodeOutputWidget(const ShaderGraph& shaderGraph);
|
||||||
|
~CodeOutputWidget() = default;
|
||||||
|
|
||||||
|
void Refresh();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ShaderGraph& m_shaderGraph;
|
||||||
|
QCheckBox* m_optimisationCheckbox;
|
||||||
|
QComboBox* m_outputLang;
|
||||||
|
QTextEdit* m_textOutput;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <ShaderNode/Widgets/CodeOutputWidget.inl>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
#include <ShaderNode/Widgets/CodeOutputWidget.hpp>
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <Nazara/Shader/ShaderAstSerializer.hpp>
|
#include <Nazara/Shader/ShaderAstSerializer.hpp>
|
||||||
#include <ShaderNode/ShaderGraph.hpp>
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
#include <ShaderNode/Widgets/BufferEditor.hpp>
|
#include <ShaderNode/Widgets/BufferEditor.hpp>
|
||||||
|
#include <ShaderNode/Widgets/CodeOutputWidget.hpp>
|
||||||
#include <ShaderNode/Widgets/ConditionEditor.hpp>
|
#include <ShaderNode/Widgets/ConditionEditor.hpp>
|
||||||
#include <ShaderNode/Widgets/InputEditor.hpp>
|
#include <ShaderNode/Widgets/InputEditor.hpp>
|
||||||
#include <ShaderNode/Widgets/OutputEditor.hpp>
|
#include <ShaderNode/Widgets/OutputEditor.hpp>
|
||||||
|
|
@ -14,6 +15,7 @@
|
||||||
#include <nodes/FlowView>
|
#include <nodes/FlowView>
|
||||||
#include <QtCore/QFile>
|
#include <QtCore/QFile>
|
||||||
#include <QtCore/QJsonDocument>
|
#include <QtCore/QJsonDocument>
|
||||||
|
#include <QtCore/QTimer>
|
||||||
#include <QtWidgets/QDockWidget>
|
#include <QtWidgets/QDockWidget>
|
||||||
#include <QtWidgets/QFileDialog>
|
#include <QtWidgets/QFileDialog>
|
||||||
#include <QtWidgets/QMenuBar>
|
#include <QtWidgets/QMenuBar>
|
||||||
|
|
@ -35,7 +37,6 @@ m_shaderGraph(graph)
|
||||||
InputEditor* inputEditor = new InputEditor(m_shaderGraph);
|
InputEditor* inputEditor = new InputEditor(m_shaderGraph);
|
||||||
|
|
||||||
QDockWidget* inputDock = new QDockWidget(tr("Inputs"));
|
QDockWidget* inputDock = new QDockWidget(tr("Inputs"));
|
||||||
inputDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
|
|
||||||
inputDock->setWidget(inputEditor);
|
inputDock->setWidget(inputEditor);
|
||||||
|
|
||||||
addDockWidget(Qt::LeftDockWidgetArea, inputDock);
|
addDockWidget(Qt::LeftDockWidgetArea, inputDock);
|
||||||
|
|
@ -44,7 +45,6 @@ m_shaderGraph(graph)
|
||||||
OutputEditor* outputEditor = new OutputEditor(m_shaderGraph);
|
OutputEditor* outputEditor = new OutputEditor(m_shaderGraph);
|
||||||
|
|
||||||
QDockWidget* outputDock = new QDockWidget(tr("Outputs"));
|
QDockWidget* outputDock = new QDockWidget(tr("Outputs"));
|
||||||
outputDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
|
|
||||||
outputDock->setWidget(outputEditor);
|
outputDock->setWidget(outputEditor);
|
||||||
|
|
||||||
addDockWidget(Qt::LeftDockWidgetArea, outputDock);
|
addDockWidget(Qt::LeftDockWidgetArea, outputDock);
|
||||||
|
|
@ -53,7 +53,6 @@ m_shaderGraph(graph)
|
||||||
TextureEditor* textureEditor = new TextureEditor(m_shaderGraph);
|
TextureEditor* textureEditor = new TextureEditor(m_shaderGraph);
|
||||||
|
|
||||||
QDockWidget* textureDock = new QDockWidget(tr("Textures"));
|
QDockWidget* textureDock = new QDockWidget(tr("Textures"));
|
||||||
textureDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
|
|
||||||
textureDock->setWidget(textureEditor);
|
textureDock->setWidget(textureEditor);
|
||||||
|
|
||||||
addDockWidget(Qt::LeftDockWidgetArea, textureDock);
|
addDockWidget(Qt::LeftDockWidgetArea, textureDock);
|
||||||
|
|
@ -62,7 +61,6 @@ m_shaderGraph(graph)
|
||||||
m_nodeEditor = new NodeEditor;
|
m_nodeEditor = new NodeEditor;
|
||||||
|
|
||||||
QDockWidget* nodeEditorDock = new QDockWidget(tr("Node editor"));
|
QDockWidget* nodeEditorDock = new QDockWidget(tr("Node editor"));
|
||||||
nodeEditorDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
|
|
||||||
nodeEditorDock->setWidget(m_nodeEditor);
|
nodeEditorDock->setWidget(m_nodeEditor);
|
||||||
|
|
||||||
addDockWidget(Qt::RightDockWidgetArea, nodeEditorDock);
|
addDockWidget(Qt::RightDockWidgetArea, nodeEditorDock);
|
||||||
|
|
@ -71,7 +69,6 @@ m_shaderGraph(graph)
|
||||||
BufferEditor* bufferEditor = new BufferEditor(m_shaderGraph);
|
BufferEditor* bufferEditor = new BufferEditor(m_shaderGraph);
|
||||||
|
|
||||||
QDockWidget* bufferDock = new QDockWidget(tr("Buffers"));
|
QDockWidget* bufferDock = new QDockWidget(tr("Buffers"));
|
||||||
bufferDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
|
|
||||||
bufferDock->setWidget(bufferEditor);
|
bufferDock->setWidget(bufferEditor);
|
||||||
|
|
||||||
addDockWidget(Qt::RightDockWidgetArea, bufferDock);
|
addDockWidget(Qt::RightDockWidgetArea, bufferDock);
|
||||||
|
|
@ -80,7 +77,6 @@ m_shaderGraph(graph)
|
||||||
StructEditor* structEditor = new StructEditor(m_shaderGraph);
|
StructEditor* structEditor = new StructEditor(m_shaderGraph);
|
||||||
|
|
||||||
QDockWidget* structDock = new QDockWidget(tr("Structs"));
|
QDockWidget* structDock = new QDockWidget(tr("Structs"));
|
||||||
structDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
|
|
||||||
structDock->setWidget(structEditor);
|
structDock->setWidget(structEditor);
|
||||||
|
|
||||||
addDockWidget(Qt::RightDockWidgetArea, structDock);
|
addDockWidget(Qt::RightDockWidgetArea, structDock);
|
||||||
|
|
@ -89,11 +85,18 @@ m_shaderGraph(graph)
|
||||||
ConditionEditor* conditionEditor = new ConditionEditor(m_shaderGraph);
|
ConditionEditor* conditionEditor = new ConditionEditor(m_shaderGraph);
|
||||||
|
|
||||||
QDockWidget* conditionDock = new QDockWidget(tr("Conditions"));
|
QDockWidget* conditionDock = new QDockWidget(tr("Conditions"));
|
||||||
conditionDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
|
|
||||||
conditionDock->setWidget(conditionEditor);
|
conditionDock->setWidget(conditionEditor);
|
||||||
|
|
||||||
addDockWidget(Qt::RightDockWidgetArea, conditionDock);
|
addDockWidget(Qt::RightDockWidgetArea, conditionDock);
|
||||||
|
|
||||||
|
// Code output
|
||||||
|
CodeOutputWidget* codeOutput = new CodeOutputWidget(m_shaderGraph);
|
||||||
|
|
||||||
|
QDockWidget* codeOutputDock = new QDockWidget(tr("Code output"));
|
||||||
|
codeOutputDock->setWidget(codeOutput);
|
||||||
|
|
||||||
|
addDockWidget(Qt::BottomDockWidgetArea, codeOutputDock);
|
||||||
|
|
||||||
m_onSelectedNodeUpdate.Connect(m_shaderGraph.OnSelectedNodeUpdate, [&](ShaderGraph*, ShaderNode* node)
|
m_onSelectedNodeUpdate.Connect(m_shaderGraph.OnSelectedNodeUpdate, [&](ShaderGraph*, ShaderNode* node)
|
||||||
{
|
{
|
||||||
if (node)
|
if (node)
|
||||||
|
|
@ -109,21 +112,46 @@ m_shaderGraph(graph)
|
||||||
|
|
||||||
|
|
||||||
BuildMenu();
|
BuildMenu();
|
||||||
|
|
||||||
m_codeOutput = new QTextEdit;
|
|
||||||
m_codeOutput->setReadOnly(true);
|
|
||||||
m_codeOutput->setWindowTitle("GLSL Output");
|
|
||||||
|
|
||||||
m_onConditionUpdate.Connect(m_shaderGraph.OnConditionUpdate, [&](ShaderGraph*, std::size_t conditionIndex)
|
|
||||||
{
|
{
|
||||||
if (m_codeOutput->isVisible())
|
QMenu* view = menuBar()->addMenu("View");
|
||||||
OnGenerateGLSL();
|
view->addAction(inputDock->toggleViewAction());
|
||||||
|
view->addAction(outputDock->toggleViewAction());
|
||||||
|
view->addAction(textureDock->toggleViewAction());
|
||||||
|
view->addAction(nodeEditorDock->toggleViewAction());
|
||||||
|
view->addAction(bufferDock->toggleViewAction());
|
||||||
|
view->addAction(structDock->toggleViewAction());
|
||||||
|
view->addAction(conditionDock->toggleViewAction());
|
||||||
|
view->addAction(codeOutputDock->toggleViewAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(scene, &QtNodes::FlowScene::connectionCreated, [=](const QtNodes::Connection& /*connection*/)
|
||||||
|
{
|
||||||
|
QTimer::singleShot(0, [=]
|
||||||
|
{
|
||||||
|
if (codeOutput->isVisible())
|
||||||
|
codeOutput->Refresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(scene, &QtNodes::FlowScene::connectionDeleted, [=](const QtNodes::Connection& /*connection*/)
|
||||||
|
{
|
||||||
|
QTimer::singleShot(0, [=]
|
||||||
|
{
|
||||||
|
if (codeOutput->isVisible())
|
||||||
|
codeOutput->Refresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
m_onConditionUpdate.Connect(m_shaderGraph.OnConditionUpdate, [=](ShaderGraph*, std::size_t /*conditionIndex*/)
|
||||||
|
{
|
||||||
|
if (codeOutput->isVisible())
|
||||||
|
codeOutput->Refresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
{
|
{
|
||||||
delete m_codeOutput;
|
m_shaderGraph.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::BuildMenu()
|
void MainWindow::BuildMenu()
|
||||||
|
|
@ -147,19 +175,13 @@ void MainWindow::BuildMenu()
|
||||||
QAction* compileShader = shader->addAction(tr("Compile..."));
|
QAction* compileShader = shader->addAction(tr("Compile..."));
|
||||||
QObject::connect(compileShader, &QAction::triggered, this, &MainWindow::OnCompile);
|
QObject::connect(compileShader, &QAction::triggered, this, &MainWindow::OnCompile);
|
||||||
}
|
}
|
||||||
|
|
||||||
QMenu* generateMenu = menu->addMenu(tr("&Generate"));
|
|
||||||
{
|
|
||||||
QAction* generateGlsl = generateMenu->addAction(tr("GLSL"));
|
|
||||||
connect(generateGlsl, &QAction::triggered, [&](bool) { OnGenerateGLSL(); });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::OnCompile()
|
void MainWindow::OnCompile()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto shader = ToShader();
|
auto shader = m_shaderGraph.ToShader();
|
||||||
|
|
||||||
QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save shader"), QString(), tr("Shader Files (*.shader)"));
|
QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save shader"), QString(), tr("Shader Files (*.shader)"));
|
||||||
if (fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
|
|
@ -177,32 +199,6 @@ void MainWindow::OnCompile()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::OnGenerateGLSL()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Nz::GlslWriter writer;
|
|
||||||
|
|
||||||
Nz::GlslWriter::States states;
|
|
||||||
for (std::size_t i = 0; i < m_shaderGraph.GetConditionCount(); ++i)
|
|
||||||
{
|
|
||||||
if (m_shaderGraph.IsConditionEnabled(i))
|
|
||||||
states.enabledConditions = Nz::SetBit<Nz::UInt64>(states.enabledConditions, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string glsl = writer.Generate(ToShader(), states);
|
|
||||||
|
|
||||||
std::cout << glsl << std::endl;
|
|
||||||
|
|
||||||
m_codeOutput->setText(QString::fromStdString(glsl));
|
|
||||||
m_codeOutput->show();
|
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
QMessageBox::critical(this, tr("Generation failed"), QString("Generation failed: ") + e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::OnLoad()
|
void MainWindow::OnLoad()
|
||||||
{
|
{
|
||||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open shader flow"), QString(), tr("Shader Flow Files (*.shaderflow)"));
|
QString fileName = QFileDialog::getOpenFileName(this, tr("Open shader flow"), QString(), tr("Shader Flow Files (*.shaderflow)"));
|
||||||
|
|
@ -263,54 +259,3 @@ void MainWindow::OnUpdateInfo()
|
||||||
|
|
||||||
dialog->open();
|
dialog->open();
|
||||||
}
|
}
|
||||||
|
|
||||||
Nz::ShaderAst MainWindow::ToShader()
|
|
||||||
{
|
|
||||||
Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst();
|
|
||||||
|
|
||||||
Nz::ShaderAst shader(ShaderGraph::ToShaderStageType(m_shaderGraph.GetType())); //< FIXME
|
|
||||||
for (const auto& condition : m_shaderGraph.GetConditions())
|
|
||||||
shader.AddCondition(condition.name);
|
|
||||||
|
|
||||||
for (const auto& input : m_shaderGraph.GetInputs())
|
|
||||||
shader.AddInput(input.name, m_shaderGraph.ToShaderExpressionType(input.type), input.locationIndex);
|
|
||||||
|
|
||||||
for (const auto& output : m_shaderGraph.GetOutputs())
|
|
||||||
shader.AddOutput(output.name, m_shaderGraph.ToShaderExpressionType(output.type), output.locationIndex);
|
|
||||||
|
|
||||||
for (const auto& buffer : m_shaderGraph.GetBuffers())
|
|
||||||
{
|
|
||||||
const auto& structInfo = m_shaderGraph.GetStruct(buffer.structIndex);
|
|
||||||
shader.AddUniform(buffer.name, structInfo.name, buffer.bindingIndex, Nz::ShaderNodes::MemoryLayout::Std140);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& uniform : m_shaderGraph.GetTextures())
|
|
||||||
shader.AddUniform(uniform.name, m_shaderGraph.ToShaderExpressionType(uniform.type), uniform.bindingIndex, {});
|
|
||||||
|
|
||||||
for (const auto& s : m_shaderGraph.GetStructs())
|
|
||||||
{
|
|
||||||
std::vector<Nz::ShaderAst::StructMember> members;
|
|
||||||
for (const auto& sMember : s.members)
|
|
||||||
{
|
|
||||||
auto& member = members.emplace_back();
|
|
||||||
member.name = sMember.name;
|
|
||||||
|
|
||||||
std::visit([&](auto&& arg)
|
|
||||||
{
|
|
||||||
using T = std::decay_t<decltype(arg)>;
|
|
||||||
if constexpr (std::is_same_v<T, PrimitiveType>)
|
|
||||||
member.type = m_shaderGraph.ToShaderExpressionType(arg);
|
|
||||||
else if constexpr (std::is_same_v<T, std::size_t>)
|
|
||||||
member.type = m_shaderGraph.GetStruct(arg).name;
|
|
||||||
else
|
|
||||||
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
|
||||||
}, sMember.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
shader.AddStruct(s.name, std::move(members));
|
|
||||||
}
|
|
||||||
|
|
||||||
shader.AddFunction("main", shaderAst);
|
|
||||||
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
#include <ShaderNode/DataModels/ShaderNode.hpp>
|
#include <ShaderNode/DataModels/ShaderNode.hpp>
|
||||||
|
|
||||||
class NodeEditor;
|
class NodeEditor;
|
||||||
class QTextEdit;
|
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
|
@ -24,18 +23,15 @@ class MainWindow : public QMainWindow
|
||||||
private:
|
private:
|
||||||
void BuildMenu();
|
void BuildMenu();
|
||||||
void OnCompile();
|
void OnCompile();
|
||||||
void OnGenerateGLSL();
|
|
||||||
void OnLoad();
|
void OnLoad();
|
||||||
void OnSave();
|
void OnSave();
|
||||||
void OnUpdateInfo();
|
void OnUpdateInfo();
|
||||||
Nz::ShaderAst ToShader();
|
|
||||||
|
|
||||||
NazaraSlot(ShaderGraph, OnConditionUpdate, m_onConditionUpdate);
|
NazaraSlot(ShaderGraph, OnConditionUpdate, m_onConditionUpdate);
|
||||||
NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate);
|
NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate);
|
||||||
|
|
||||||
NodeEditor* m_nodeEditor;
|
NodeEditor* m_nodeEditor;
|
||||||
ShaderGraph& m_shaderGraph;
|
ShaderGraph& m_shaderGraph;
|
||||||
QTextEdit* m_codeOutput;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <ShaderNode/Widgets/MainWindow.inl>
|
#include <ShaderNode/Widgets/MainWindow.inl>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue