diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index 035aa5cce..51117c1d7 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -8,6 +8,7 @@ #define NAZARA_SHADER_AST_HPP #include +#include #include #include #include @@ -27,7 +28,9 @@ namespace Nz struct Uniform; struct VariableBase; - ShaderAst() = default; + inline ShaderAst(ShaderStageType shaderStage); + ShaderAst(const ShaderAst&) = default; + ShaderAst(ShaderAst&&) = default; ~ShaderAst() = default; void AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters = {}, ShaderNodes::BasicType returnType = ShaderNodes::BasicType::Void); @@ -45,6 +48,7 @@ namespace Nz inline const InputOutput& GetOutput(std::size_t i) const; inline std::size_t GetOutputCount() const; inline const std::vector& GetOutputs() const; + inline ShaderStageType GetStage() const; inline const Struct& GetStruct(std::size_t i) const; inline std::size_t GetStructCount() const; inline const std::vector& GetStructs() const; @@ -52,6 +56,9 @@ namespace Nz inline std::size_t GetUniformCount() const; inline const std::vector& GetUniforms() const; + ShaderAst& operator=(const ShaderAst&) = default; + ShaderAst& operator=(ShaderAst&&) = default; + struct VariableBase { std::string name; @@ -99,6 +106,7 @@ namespace Nz std::vector m_outputs; std::vector m_structs; std::vector m_uniforms; + ShaderStageType m_stage; }; } diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index c42c1e9c1..f0bc1aebb 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -7,6 +7,11 @@ namespace Nz { + inline ShaderAst::ShaderAst(ShaderStageType shaderStage) : + m_stage(shaderStage) + { + } + inline auto ShaderAst::GetFunction(std::size_t i) const -> const Function& { assert(i < m_functions.size()); @@ -55,6 +60,11 @@ namespace Nz return m_outputs; } + inline ShaderStageType ShaderAst::GetStage() const + { + return m_stage; + } + inline auto ShaderAst::GetStruct(std::size_t i) const -> const Struct& { assert(i < m_structs.size()); diff --git a/include/Nazara/Renderer/ShaderWriter.hpp b/include/Nazara/Renderer/ShaderWriter.hpp index 6c2655226..e4fe2d835 100644 --- a/include/Nazara/Renderer/ShaderWriter.hpp +++ b/include/Nazara/Renderer/ShaderWriter.hpp @@ -19,8 +19,8 @@ namespace Nz { public: ShaderWriter() = default; - ShaderWriter(const ShaderWriter&) = delete; - ShaderWriter(ShaderWriter&&) = delete; + ShaderWriter(const ShaderWriter&) = default; + ShaderWriter(ShaderWriter&&) = default; virtual ~ShaderWriter(); virtual std::string Generate(const ShaderAst& shader) = 0; diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp index b7cc63c9f..a2a3fbf7a 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp @@ -31,6 +31,9 @@ namespace Nz ByteStream byteStream(source, sourceSize); auto shader = Nz::UnserializeShader(byteStream); + if (shader.GetStage() != type) + throw std::runtime_error("incompatible shader stage"); + const auto& context = device.GetReferenceContext(); const auto& contextParams = context.GetParams(); diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderSerializer.cpp index 350ec2096..7441162a0 100644 --- a/src/Nazara/Renderer/ShaderSerializer.cpp +++ b/src/Nazara/Renderer/ShaderSerializer.cpp @@ -261,6 +261,8 @@ namespace Nz { m_stream << s_magicNumber << s_currentVersion; + m_stream << UInt32(shader.GetStage()); + auto SerializeType = [&](const ShaderExpressionType& type) { std::visit([&](auto&& arg) @@ -454,7 +456,10 @@ namespace Nz if (version > s_currentVersion) throw std::runtime_error("unsupported version"); - ShaderAst shader; + UInt32 shaderStage; + m_stream >> shaderStage; + + ShaderAst shader(static_cast(shaderStage)); UInt32 structCount; m_stream >> structCount; diff --git a/src/ShaderNode/Enums.cpp b/src/ShaderNode/Enums.cpp index 2c924c3ed..73af36b06 100644 --- a/src/ShaderNode/Enums.cpp +++ b/src/ShaderNode/Enums.cpp @@ -58,6 +58,19 @@ const char* EnumToString(PrimitiveType input) return ""; } +const char* EnumToString(ShaderType type) +{ + switch (type) + { + case ShaderType::NotSet: return "NotSet"; + case ShaderType::Fragment: return "Fragment"; + case ShaderType::Vertex: return "Vertex"; + } + + assert(false); + return ""; +} + const char* EnumToString(TextureType textureType) { switch (textureType) diff --git a/src/ShaderNode/Enums.hpp b/src/ShaderNode/Enums.hpp index e59d66424..c57969fb2 100644 --- a/src/ShaderNode/Enums.hpp +++ b/src/ShaderNode/Enums.hpp @@ -42,6 +42,18 @@ enum class PrimitiveType constexpr std::size_t PrimitiveTypeCount = static_cast(PrimitiveType::Max) + 1; +enum class ShaderType +{ + NotSet = -1, + + Fragment, + Vertex, + + Max = Vertex +}; + +constexpr std::size_t ShaderTypeCount = static_cast(ShaderType::Max) + 1; + enum class TextureType { Sampler2D, @@ -56,6 +68,7 @@ template std::optional DecodeEnum(const std::string_view& str); const char* EnumToString(BufferType bufferType); const char* EnumToString(InputRole role); const char* EnumToString(PrimitiveType input); +const char* EnumToString(ShaderType type); const char* EnumToString(TextureType textureType); std::size_t GetComponentCount(PrimitiveType type); diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index b7f9b99a6..a1799df3b 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -41,7 +41,8 @@ namespace } ShaderGraph::ShaderGraph() : -m_flowScene(BuildRegistry()) +m_flowScene(BuildRegistry()), +m_type(ShaderType::NotSet) { m_previewModel = std::make_unique(); @@ -178,6 +179,8 @@ std::size_t ShaderGraph::AddTexture(std::string name, TextureType type, std::siz void ShaderGraph::Clear() { + m_type = ShaderType::NotSet; + m_flowScene.clearScene(); m_flowScene.clear(); @@ -198,6 +201,9 @@ void ShaderGraph::Load(const QJsonObject& data) { Clear(); + if (auto typeOpt = DecodeEnum(data["type"].toString().toStdString())) + m_type = typeOpt.value(); + QJsonArray bufferArray = data["buffers"].toArray(); for (const auto& bufferDocRef : bufferArray) { @@ -289,6 +295,7 @@ void ShaderGraph::Load(const QJsonObject& data) QJsonObject ShaderGraph::Save() { QJsonObject sceneJson; + sceneJson["type"] = QString(EnumToString(m_type)); QJsonArray bufferArray; { @@ -599,6 +606,15 @@ void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) OnTexturePreviewUpdate(this, textureIndex); } +void ShaderGraph::UpdateType(ShaderType type) +{ + if (m_type != type) + { + m_type = type; + OnTypeUpdated(this); + } +} + QtNodes::NodeDataType ShaderGraph::ToNodeDataType(PrimitiveType type) { switch (type) @@ -649,6 +665,21 @@ Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(TextureType type) throw std::runtime_error("Unhandled texture type"); } +Nz::ShaderStageType ShaderGraph::ToShaderStageType(ShaderType type) +{ + switch (type) + { + case ShaderType::NotSet: + throw std::runtime_error("Invalid shader type"); + + case ShaderType::Fragment: return Nz::ShaderStageType::Fragment; + case ShaderType::Vertex: return Nz::ShaderStageType::Vertex; + } + + assert(false); + throw std::runtime_error("Unhandled shader type"); +} + std::shared_ptr ShaderGraph::BuildRegistry() { auto registry = std::make_shared(); diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index e91127cb5..be7aeba4c 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -4,6 +4,7 @@ #define NAZARA_SHADERNODES_SHADERGRAPH_HPP #include +#include #include #include #include @@ -51,6 +52,7 @@ class ShaderGraph inline const TextureEntry& GetTexture(std::size_t textureIndex) const; inline std::size_t GetTextureCount() const; inline const std::vector& GetTextures() const; + inline ShaderType GetType() const; void Load(const QJsonObject& data); QJsonObject Save(); @@ -64,6 +66,7 @@ class ShaderGraph void UpdateStruct(std::size_t structIndex, std::string name, std::vector members); void UpdateTexture(std::size_t textureIndex, std::string name, TextureType type, std::size_t bindingIndex); void UpdateTexturePreview(std::size_t texture, QImage preview); + void UpdateType(ShaderType type); struct BufferEntry { @@ -121,10 +124,12 @@ class ShaderGraph NazaraSignal(OnTextureListUpdate, ShaderGraph*); NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/); NazaraSignal(OnTextureUpdate, ShaderGraph*, std::size_t /*textureIndex*/); + NazaraSignal(OnTypeUpdated, ShaderGraph*); static QtNodes::NodeDataType ToNodeDataType(PrimitiveType type); static Nz::ShaderExpressionType ToShaderExpressionType(PrimitiveType type); static Nz::ShaderExpressionType ToShaderExpressionType(TextureType type); + static Nz::ShaderStageType ToShaderStageType(ShaderType type); private: std::shared_ptr BuildRegistry(); @@ -136,6 +141,7 @@ class ShaderGraph std::vector m_structs; std::vector m_textures; std::unique_ptr m_previewModel; + ShaderType m_type; }; #include diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index 04f86834c..afa867dcd 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -90,3 +90,8 @@ inline auto ShaderGraph::GetTextures() const -> const std::vector& return m_textures; } +inline ShaderType ShaderGraph::GetType() const +{ + return m_type; +} + diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index 7c7101047..f25f95a18 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -104,19 +105,27 @@ void MainWindow::BuildMenu() { QMenuBar* menu = menuBar(); + QMenu* file = menu->addMenu(tr("&File")); + { + QAction* loadShader = file->addAction(tr("Load...")); + QObject::connect(loadShader, &QAction::triggered, this, &MainWindow::OnLoad); + QAction* saveShader = file->addAction(tr("Save...")); + QObject::connect(saveShader, &QAction::triggered, this, &MainWindow::OnSave); + } + QMenu* shader = menu->addMenu(tr("&Shader")); { - QAction* loadShader = shader->addAction(tr("Load...")); - QObject::connect(loadShader, &QAction::triggered, this, &MainWindow::OnLoad); - QAction* saveShader = shader->addAction(tr("Save...")); - QObject::connect(saveShader, &QAction::triggered, this, &MainWindow::OnSave); + QAction* settings = shader->addAction(tr("Settings...")); + QObject::connect(settings, &QAction::triggered, this, &MainWindow::OnUpdateInfo); QAction* compileShader = shader->addAction(tr("Compile...")); 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(); }); + { + QAction* generateGlsl = generateMenu->addAction(tr("GLSL")); + connect(generateGlsl, &QAction::triggered, [&](bool) { OnGenerateGLSL(); }); + } } void MainWindow::OnCompile() @@ -208,11 +217,27 @@ void MainWindow::OnSave() file.write(QJsonDocument(m_shaderGraph.Save()).toJson()); } +void MainWindow::OnUpdateInfo() +{ + ShaderInfo info; + info.type = m_shaderGraph.GetType(); + + ShaderInfoDialog* dialog = new ShaderInfoDialog(std::move(info), this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog] + { + ShaderInfo shaderInfo = dialog->GetShaderInfo(); + m_shaderGraph.UpdateType(shaderInfo.type); + }); + + dialog->open(); +} + Nz::ShaderAst MainWindow::ToShader() { Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst(); - Nz::ShaderAst shader; + Nz::ShaderAst shader(ShaderGraph::ToShaderStageType(m_shaderGraph.GetType())); //< FIXME for (const auto& input : m_shaderGraph.GetInputs()) shader.AddInput(input.name, m_shaderGraph.ToShaderExpressionType(input.type), input.locationIndex); diff --git a/src/ShaderNode/Widgets/MainWindow.hpp b/src/ShaderNode/Widgets/MainWindow.hpp index 25c742625..76615bb98 100644 --- a/src/ShaderNode/Widgets/MainWindow.hpp +++ b/src/ShaderNode/Widgets/MainWindow.hpp @@ -26,6 +26,7 @@ class MainWindow : public QMainWindow void OnGenerateGLSL(); void OnLoad(); void OnSave(); + void OnUpdateInfo(); Nz::ShaderAst ToShader(); NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate); diff --git a/src/ShaderNode/Widgets/ShaderInfoDialog.cpp b/src/ShaderNode/Widgets/ShaderInfoDialog.cpp new file mode 100644 index 000000000..54687a99e --- /dev/null +++ b/src/ShaderNode/Widgets/ShaderInfoDialog.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ShaderInfoDialog::ShaderInfoDialog(QWidget* parent) : +QDialog(parent) +{ + setWindowTitle(tr("Shader edit dialog")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + m_typeList = new QComboBox; + for (std::size_t i = 0; i < ShaderTypeCount; ++i) + m_typeList->addItem(EnumToString(static_cast(i))); + + QFormLayout* formLayout = new QFormLayout; + formLayout->addRow(tr("Type"), m_typeList); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &ShaderInfoDialog::OnAccept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QVBoxLayout* verticalLayout = new QVBoxLayout; + verticalLayout->addLayout(formLayout); + verticalLayout->addWidget(buttonBox); + + setLayout(verticalLayout); +} + +ShaderInfoDialog::ShaderInfoDialog(const ShaderInfo& shader, QWidget* parent) : +ShaderInfoDialog(parent) +{ + m_typeList->setCurrentText(QString(EnumToString(shader.type))); +} + +ShaderInfo ShaderInfoDialog::GetShaderInfo() const +{ + ShaderInfo bufferInfo; + bufferInfo.type = static_cast(m_typeList->currentIndex()); + + return bufferInfo; +} + +void ShaderInfoDialog::OnAccept() +{ + if (m_typeList->currentIndex() < 0) + { + QMessageBox::critical(this, tr("Invalid shader type"), tr("You must select a shader type"), QMessageBox::Ok); + return; + } + + accept(); +} diff --git a/src/ShaderNode/Widgets/ShaderInfoDialog.hpp b/src/ShaderNode/Widgets/ShaderInfoDialog.hpp new file mode 100644 index 000000000..210323a8e --- /dev/null +++ b/src/ShaderNode/Widgets/ShaderInfoDialog.hpp @@ -0,0 +1,33 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_BUFFEREDITDIALOG_HPP +#define NAZARA_SHADERNODES_BUFFEREDITDIALOG_HPP + +#include +#include + +class QComboBox; + +struct ShaderInfo +{ + ShaderType type; +}; + +class ShaderInfoDialog : public QDialog +{ + public: + ShaderInfoDialog(QWidget* parent = nullptr); + ShaderInfoDialog(const ShaderInfo& shader, QWidget* parent = nullptr); + ~ShaderInfoDialog() = default; + + ShaderInfo GetShaderInfo() const; + + private: + void OnAccept(); + + QComboBox* m_typeList; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/ShaderInfoDialog.inl b/src/ShaderNode/Widgets/ShaderInfoDialog.inl new file mode 100644 index 000000000..e81e9cd71 --- /dev/null +++ b/src/ShaderNode/Widgets/ShaderInfoDialog.inl @@ -0,0 +1 @@ +#include