ShaderNode: Add save/load
This commit is contained in:
parent
5790b502f7
commit
0888589716
|
|
@ -1,5 +1,6 @@
|
||||||
#include <ShaderNode/ShaderGraph.hpp>
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
#include <ShaderNode/DataModels/InputValue.hpp>
|
#include <ShaderNode/DataModels/InputValue.hpp>
|
||||||
|
#include <ShaderNode/DataTypes/FloatData.hpp>
|
||||||
#include <ShaderNode/DataTypes/VecData.hpp>
|
#include <ShaderNode/DataTypes/VecData.hpp>
|
||||||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||||
#include <QtWidgets/QFormLayout>
|
#include <QtWidgets/QFormLayout>
|
||||||
|
|
@ -11,7 +12,10 @@ ShaderNode(graph)
|
||||||
m_onInputUpdateSlot.Connect(GetGraph().OnInputUpdate, [&](ShaderGraph*, std::size_t inputIndex)
|
m_onInputUpdateSlot.Connect(GetGraph().OnInputUpdate, [&](ShaderGraph*, std::size_t inputIndex)
|
||||||
{
|
{
|
||||||
if (m_currentInputIndex == inputIndex)
|
if (m_currentInputIndex == inputIndex)
|
||||||
|
{
|
||||||
UpdatePreview();
|
UpdatePreview();
|
||||||
|
Q_EMIT dataUpdated(0);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (graph.GetInputCount() > 0)
|
if (graph.GetInputCount() > 0)
|
||||||
|
|
@ -172,3 +176,19 @@ QString InputValue::validationMessage() const
|
||||||
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputValue::restore(const QJsonObject& data)
|
||||||
|
{
|
||||||
|
m_currentInputText = data["input"].toString().toStdString();
|
||||||
|
OnInputListUpdate();
|
||||||
|
|
||||||
|
ShaderNode::restore(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject InputValue::save() const
|
||||||
|
{
|
||||||
|
QJsonObject data = ShaderNode::save();
|
||||||
|
data["input"] = QString::fromStdString(m_currentInputText);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,9 @@ class InputValue : public ShaderNode
|
||||||
bool ComputePreview(QPixmap& pixmap) override;
|
bool ComputePreview(QPixmap& pixmap) override;
|
||||||
void OnInputListUpdate();
|
void OnInputListUpdate();
|
||||||
|
|
||||||
|
void restore(const QJsonObject& data) override;
|
||||||
|
QJsonObject save() const override;
|
||||||
|
|
||||||
NazaraSlot(ShaderGraph, OnInputListUpdate, m_onInputListUpdateSlot);
|
NazaraSlot(ShaderGraph, OnInputListUpdate, m_onInputListUpdateSlot);
|
||||||
NazaraSlot(ShaderGraph, OnInputUpdate, m_onInputUpdateSlot);
|
NazaraSlot(ShaderGraph, OnInputUpdate, m_onInputUpdateSlot);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -188,3 +188,19 @@ void OutputValue::OnOutputListUpdate()
|
||||||
inputIndex++;
|
inputIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OutputValue::restore(const QJsonObject& data)
|
||||||
|
{
|
||||||
|
m_currentOutputText = data["input"].toString().toStdString();
|
||||||
|
OnOutputListUpdate();
|
||||||
|
|
||||||
|
ShaderNode::restore(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject OutputValue::save() const
|
||||||
|
{
|
||||||
|
QJsonObject data = ShaderNode::save();
|
||||||
|
data["input"] = QString::fromStdString(m_currentOutputText);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ class OutputValue : public ShaderNode
|
||||||
bool ComputePreview(QPixmap& pixmap) override;
|
bool ComputePreview(QPixmap& pixmap) override;
|
||||||
void OnOutputListUpdate();
|
void OnOutputListUpdate();
|
||||||
|
|
||||||
|
void restore(const QJsonObject& data) override;
|
||||||
|
QJsonObject save() const override;
|
||||||
|
|
||||||
NazaraSlot(ShaderGraph, OnOutputListUpdate, m_onOutputListUpdateSlot);
|
NazaraSlot(ShaderGraph, OnOutputListUpdate, m_onOutputListUpdateSlot);
|
||||||
NazaraSlot(ShaderGraph, OnOutputUpdate, m_onOutputUpdateSlot);
|
NazaraSlot(ShaderGraph, OnOutputUpdate, m_onOutputUpdateSlot);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,14 +54,25 @@ void SampleTexture::UpdateOutput()
|
||||||
float u = float(uvPtr[0]) / 255;
|
float u = float(uvPtr[0]) / 255;
|
||||||
float v = float(uvPtr[1]) / 255;
|
float v = float(uvPtr[1]) / 255;
|
||||||
|
|
||||||
int texX = std::clamp(int(u * textureWidth), 0, textureWidth - 1);
|
if (textureWidth > 0 && textureHeight > 0)
|
||||||
int texY = std::clamp(int(v * textureHeight), 0, textureHeight - 1);
|
{
|
||||||
int texPixel = (texY * textureWidth + texX) * 4;
|
int texX = std::clamp(int(u * textureWidth), 0, textureWidth - 1);
|
||||||
|
int texY = std::clamp(int(v * textureHeight), 0, textureHeight - 1);
|
||||||
|
int texPixel = (texY * textureWidth + texX) * 4;
|
||||||
|
|
||||||
|
*outputPtr++ = texturePtr[texPixel + 0];
|
||||||
|
*outputPtr++ = texturePtr[texPixel + 1];
|
||||||
|
*outputPtr++ = texturePtr[texPixel + 2];
|
||||||
|
*outputPtr++ = texturePtr[texPixel + 3];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*outputPtr++ = 0;
|
||||||
|
*outputPtr++ = 0;
|
||||||
|
*outputPtr++ = 0;
|
||||||
|
*outputPtr++ = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
*outputPtr++ = texturePtr[texPixel + 0];
|
|
||||||
*outputPtr++ = texturePtr[texPixel + 1];
|
|
||||||
*outputPtr++ = texturePtr[texPixel + 2];
|
|
||||||
*outputPtr++ = texturePtr[texPixel + 3];
|
|
||||||
uvPtr += 4;
|
uvPtr += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,8 +81,6 @@ void ShaderNode::EnablePreview(bool enable)
|
||||||
m_pixmapLabel->clear();
|
m_pixmapLabel->clear();
|
||||||
m_pixmap.reset();
|
m_pixmap.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
embeddedWidgetSizeUpdated();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,6 +93,29 @@ void ShaderNode::setInData(std::shared_ptr<QtNodes::NodeData>, int)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShaderNode::restore(const QJsonObject& data)
|
||||||
|
{
|
||||||
|
NodeDataModel::restore(data);
|
||||||
|
|
||||||
|
bool isPreviewEnabled = data["preview_enabled"].toBool(m_isPreviewEnabled);
|
||||||
|
m_previewSize.x = data["preview_width"].toInt(m_previewSize.x);
|
||||||
|
m_previewSize.y = data["preview_height"].toInt(m_previewSize.y);
|
||||||
|
m_variableName = data["variable_name"].toString().toStdString();
|
||||||
|
|
||||||
|
EnablePreview(isPreviewEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject ShaderNode::save() const
|
||||||
|
{
|
||||||
|
QJsonObject data = NodeDataModel::save();
|
||||||
|
data["preview_enabled"] = m_isPreviewEnabled;
|
||||||
|
data["preview_width"] = m_previewSize.x;
|
||||||
|
data["preview_height"] = m_previewSize.y;
|
||||||
|
data["variable_name"] = QString::fromStdString(m_variableName);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/)
|
bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -103,7 +124,10 @@ bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/)
|
||||||
void ShaderNode::UpdatePreview()
|
void ShaderNode::UpdatePreview()
|
||||||
{
|
{
|
||||||
if (!m_pixmap)
|
if (!m_pixmap)
|
||||||
|
{
|
||||||
|
embeddedWidgetSizeUpdated();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QPixmap& pixmap = *m_pixmap;
|
QPixmap& pixmap = *m_pixmap;
|
||||||
|
|
||||||
|
|
@ -116,4 +140,6 @@ void ShaderNode::UpdatePreview()
|
||||||
pixmap = pixmap.scaled(m_previewSize.x, m_previewSize.y);
|
pixmap = pixmap.scaled(m_previewSize.x, m_previewSize.y);
|
||||||
|
|
||||||
m_pixmapLabel->setPixmap(pixmap);
|
m_pixmapLabel->setPixmap(pixmap);
|
||||||
|
|
||||||
|
embeddedWidgetSizeUpdated();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,9 @@ class ShaderNode : public QtNodes::NodeDataModel
|
||||||
inline void EnableCustomVariableName(bool enable = true);
|
inline void EnableCustomVariableName(bool enable = true);
|
||||||
void UpdatePreview();
|
void UpdatePreview();
|
||||||
|
|
||||||
|
void restore(const QJsonObject& data) override;
|
||||||
|
QJsonObject save() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool ComputePreview(QPixmap& pixmap);
|
virtual bool ComputePreview(QPixmap& pixmap);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,10 @@ ShaderNode(graph)
|
||||||
m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, [&](ShaderGraph*, std::size_t textureIndex)
|
m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, [&](ShaderGraph*, std::size_t textureIndex)
|
||||||
{
|
{
|
||||||
if (m_currentTextureIndex == textureIndex)
|
if (m_currentTextureIndex == textureIndex)
|
||||||
|
{
|
||||||
UpdatePreview();
|
UpdatePreview();
|
||||||
|
Q_EMIT dataUpdated(0);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (graph.GetTextureCount() > 0)
|
if (graph.GetTextureCount() > 0)
|
||||||
|
|
@ -161,3 +164,19 @@ QString TextureValue::validationMessage() const
|
||||||
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureValue::restore(const QJsonObject& data)
|
||||||
|
{
|
||||||
|
m_currentTextureText = data["texture"].toString().toStdString();
|
||||||
|
OnTextureListUpdate();
|
||||||
|
|
||||||
|
ShaderNode::restore(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject TextureValue::save() const
|
||||||
|
{
|
||||||
|
QJsonObject data = ShaderNode::save();
|
||||||
|
data["texture"] = QString::fromStdString(m_currentTextureText);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ class TextureValue : public ShaderNode
|
||||||
bool ComputePreview(QPixmap& pixmap) override;
|
bool ComputePreview(QPixmap& pixmap) override;
|
||||||
void OnTextureListUpdate();
|
void OnTextureListUpdate();
|
||||||
|
|
||||||
|
void restore(const QJsonObject& data) override;
|
||||||
|
QJsonObject save() const override;
|
||||||
|
|
||||||
NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot);
|
NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot);
|
||||||
NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot);
|
NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,11 @@ class VecValue : public ShaderNode
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ComputePreview(QPixmap& pixmap) override;
|
bool ComputePreview(QPixmap& pixmap) override;
|
||||||
|
|
||||||
QColor ToColor() const;
|
QColor ToColor() const;
|
||||||
|
|
||||||
|
void restore(const QJsonObject& data) override;
|
||||||
|
QJsonObject save() const override;
|
||||||
|
|
||||||
VecType<ComponentCount> m_value;
|
VecType<ComponentCount> m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include <Nazara/Core/Algorithm.hpp>
|
#include <Nazara/Core/Algorithm.hpp>
|
||||||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||||
#include <ShaderNode/DataTypes/VecData.hpp>
|
#include <ShaderNode/DataTypes/VecData.hpp>
|
||||||
|
#include <QtCore/QJsonArray>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
|
@ -116,3 +117,27 @@ QColor VecValue<ComponentCount>::ToColor() const
|
||||||
|
|
||||||
return QColor::fromRgbF(values[0], values[1], values[2], values[3]);
|
return QColor::fromRgbF(values[0], values[1], values[2], values[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<std::size_t ComponentCount>
|
||||||
|
void VecValue<ComponentCount>::restore(const QJsonObject& data)
|
||||||
|
{
|
||||||
|
QJsonArray vecValues = data["value"].toArray();
|
||||||
|
for (std::size_t i = 0; i < ComponentCount; ++i)
|
||||||
|
m_value[i] = vecValues[int(i)].toInt(m_value[i]);
|
||||||
|
|
||||||
|
ShaderNode::restore(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t ComponentCount>
|
||||||
|
QJsonObject VecValue<ComponentCount>::save() const
|
||||||
|
{
|
||||||
|
QJsonObject data = ShaderNode::save();
|
||||||
|
|
||||||
|
QJsonArray vecValues;
|
||||||
|
for (std::size_t i = 0; i < ComponentCount; ++i)
|
||||||
|
vecValues.push_back(m_value[i]);
|
||||||
|
|
||||||
|
data["value"] = vecValues;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
#define NAZARA_SHADERNODES_ENUMS_HPP
|
#define NAZARA_SHADERNODES_ENUMS_HPP
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
enum class InputRole
|
enum class InputRole
|
||||||
{
|
{
|
||||||
|
|
@ -40,10 +42,11 @@ enum class TextureType
|
||||||
constexpr std::size_t TextureTypeCount = static_cast<std::size_t>(TextureType::Max) + 1;
|
constexpr std::size_t TextureTypeCount = static_cast<std::size_t>(TextureType::Max) + 1;
|
||||||
|
|
||||||
|
|
||||||
std::size_t GetComponentCount(InOutType type);
|
template<typename T> std::optional<T> DecodeEnum(const std::string_view& str);
|
||||||
const char* EnumToString(InputRole role);
|
const char* EnumToString(InputRole role);
|
||||||
const char* EnumToString(InOutType input);
|
const char* EnumToString(InOutType input);
|
||||||
const char* EnumToString(TextureType textureType);
|
const char* EnumToString(TextureType textureType);
|
||||||
|
std::size_t GetComponentCount(InOutType type);
|
||||||
|
|
||||||
#include <ShaderNode/Enums.inl>
|
#include <ShaderNode/Enums.inl>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1,15 @@
|
||||||
#include <ShaderNode/Enums.hpp>
|
#include <ShaderNode/Enums.hpp>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::optional<T> DecodeEnum(const std::string_view& str)
|
||||||
|
{
|
||||||
|
constexpr std::size_t ValueCount = static_cast<std::size_t>(T::Max) + 1;
|
||||||
|
for (std::size_t i = 0; i < ValueCount; ++i)
|
||||||
|
{
|
||||||
|
T value = static_cast<T>(i);
|
||||||
|
if (str == EnumToString(value))
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include <ShaderNode/ShaderGraph.hpp>
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
#include <Nazara/Core/StackArray.hpp>
|
#include <Nazara/Core/StackArray.hpp>
|
||||||
#include <ShaderNode/DataModels/Cast.hpp>
|
#include <ShaderNode/DataModels/Cast.hpp>
|
||||||
|
#include <ShaderNode/DataModels/FloatValue.hpp>
|
||||||
#include <ShaderNode/DataModels/InputValue.hpp>
|
#include <ShaderNode/DataModels/InputValue.hpp>
|
||||||
#include <ShaderNode/DataModels/OutputValue.hpp>
|
#include <ShaderNode/DataModels/OutputValue.hpp>
|
||||||
#include <ShaderNode/DataModels/SampleTexture.hpp>
|
#include <ShaderNode/DataModels/SampleTexture.hpp>
|
||||||
|
|
@ -114,6 +115,136 @@ std::size_t ShaderGraph::AddTexture(std::string name, TextureType type)
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShaderGraph::Clear()
|
||||||
|
{
|
||||||
|
m_flowScene.clearScene();
|
||||||
|
m_flowScene.clear();
|
||||||
|
|
||||||
|
m_inputs.clear();
|
||||||
|
m_outputs.clear();
|
||||||
|
m_textures.clear();
|
||||||
|
|
||||||
|
OnInputListUpdate(this);
|
||||||
|
OnOutputListUpdate(this);
|
||||||
|
OnTextureListUpdate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderGraph::Load(const QJsonObject& data)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
QJsonArray inputArray = data["inputs"].toArray();
|
||||||
|
for (const auto& inputDocRef : inputArray)
|
||||||
|
{
|
||||||
|
QJsonObject inputDoc = inputDocRef.toObject();
|
||||||
|
|
||||||
|
InputEntry& input = m_inputs.emplace_back();
|
||||||
|
input.name = inputDoc["name"].toString().toStdString();
|
||||||
|
input.role = DecodeEnum<InputRole>(inputDoc["role"].toString().toStdString()).value();
|
||||||
|
input.roleIndex = static_cast<std::size_t>(inputDoc["roleIndex"].toInt(0));
|
||||||
|
input.type = DecodeEnum<InOutType>(inputDoc["type"].toString().toStdString()).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
OnInputListUpdate(this);
|
||||||
|
|
||||||
|
QJsonArray outputArray = data["outputs"].toArray();
|
||||||
|
for (const auto& outputDocRef : outputArray)
|
||||||
|
{
|
||||||
|
QJsonObject outputDoc = outputDocRef.toObject();
|
||||||
|
|
||||||
|
OutputEntry& output = m_outputs.emplace_back();
|
||||||
|
output.name = outputDoc["name"].toString().toStdString();
|
||||||
|
output.type = DecodeEnum<InOutType>(outputDoc["type"].toString().toStdString()).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
OnOutputListUpdate(this);
|
||||||
|
|
||||||
|
QJsonArray textureArray = data["textures"].toArray();
|
||||||
|
for (const auto& textureDocRef : textureArray)
|
||||||
|
{
|
||||||
|
QJsonObject textureDoc = textureDocRef.toObject();
|
||||||
|
|
||||||
|
TextureEntry& texture = m_textures.emplace_back();
|
||||||
|
texture.name = textureDoc["name"].toString().toStdString();
|
||||||
|
texture.type = DecodeEnum<TextureType>(textureDoc["type"].toString().toStdString()).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
OnTextureListUpdate(this);
|
||||||
|
|
||||||
|
for (QJsonValueRef node : data["nodes"].toArray())
|
||||||
|
m_flowScene.restoreNode(node.toObject());
|
||||||
|
|
||||||
|
for (QJsonValueRef connection : data["connections"].toArray())
|
||||||
|
m_flowScene.restoreConnection(connection.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject ShaderGraph::Save()
|
||||||
|
{
|
||||||
|
QJsonObject sceneJson;
|
||||||
|
|
||||||
|
QJsonArray inputArray;
|
||||||
|
{
|
||||||
|
for (const auto& input : m_inputs)
|
||||||
|
{
|
||||||
|
QJsonObject inputDoc;
|
||||||
|
inputDoc["name"] = QString::fromStdString(input.name);
|
||||||
|
inputDoc["role"] = QString(EnumToString(input.role));
|
||||||
|
inputDoc["roleIndex"] = int(input.roleIndex);
|
||||||
|
inputDoc["type"] = QString(EnumToString(input.type));
|
||||||
|
|
||||||
|
inputArray.append(inputDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sceneJson["inputs"] = inputArray;
|
||||||
|
|
||||||
|
QJsonArray outputArray;
|
||||||
|
{
|
||||||
|
for (const auto& output : m_outputs)
|
||||||
|
{
|
||||||
|
QJsonObject outputDoc;
|
||||||
|
outputDoc["name"] = QString::fromStdString(output.name);
|
||||||
|
outputDoc["type"] = QString(EnumToString(output.type));
|
||||||
|
|
||||||
|
outputArray.append(outputDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sceneJson["outputs"] = outputArray;
|
||||||
|
|
||||||
|
QJsonArray textureArray;
|
||||||
|
{
|
||||||
|
for (const auto& texture : m_textures)
|
||||||
|
{
|
||||||
|
QJsonObject textureDoc;
|
||||||
|
textureDoc["name"] = QString::fromStdString(texture.name);
|
||||||
|
textureDoc["type"] = QString(EnumToString(texture.type));
|
||||||
|
|
||||||
|
textureArray.append(textureDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sceneJson["textures"] = textureArray;
|
||||||
|
|
||||||
|
QJsonArray nodesJsonArray;
|
||||||
|
{
|
||||||
|
for (auto&& [uuid, node] : m_flowScene.nodes())
|
||||||
|
nodesJsonArray.append(node->save());
|
||||||
|
}
|
||||||
|
sceneJson["nodes"] = nodesJsonArray;
|
||||||
|
|
||||||
|
QJsonArray connectionJsonArray;
|
||||||
|
{
|
||||||
|
for (auto&& [uuid, connection] : m_flowScene.connections())
|
||||||
|
{
|
||||||
|
QJsonObject connectionJson = connection->save();
|
||||||
|
|
||||||
|
if (!connectionJson.isEmpty())
|
||||||
|
connectionJsonArray.append(connectionJson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sceneJson["connections"] = connectionJsonArray;
|
||||||
|
|
||||||
|
return sceneJson;
|
||||||
|
}
|
||||||
|
|
||||||
Nz::ShaderAst::StatementPtr ShaderGraph::ToAst()
|
Nz::ShaderAst::StatementPtr ShaderGraph::ToAst()
|
||||||
{
|
{
|
||||||
std::vector<Nz::ShaderAst::StatementPtr> statements;
|
std::vector<Nz::ShaderAst::StatementPtr> statements;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ class ShaderGraph
|
||||||
std::size_t AddOutput(std::string name, InOutType type);
|
std::size_t AddOutput(std::string name, InOutType type);
|
||||||
std::size_t AddTexture(std::string name, TextureType type);
|
std::size_t AddTexture(std::string name, TextureType type);
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
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 std::size_t GetInputCount() const;
|
||||||
inline const std::vector<InputEntry>& GetInputs() const;
|
inline const std::vector<InputEntry>& GetInputs() const;
|
||||||
|
|
@ -39,6 +41,9 @@ class ShaderGraph
|
||||||
inline std::size_t GetTextureCount() const;
|
inline std::size_t GetTextureCount() const;
|
||||||
inline const std::vector<TextureEntry>& GetTextures() const;
|
inline const std::vector<TextureEntry>& GetTextures() const;
|
||||||
|
|
||||||
|
void Load(const QJsonObject& data);
|
||||||
|
QJsonObject Save();
|
||||||
|
|
||||||
Nz::ShaderAst::StatementPtr ToAst();
|
Nz::ShaderAst::StatementPtr ToAst();
|
||||||
|
|
||||||
void UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex);
|
void UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex);
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,10 @@
|
||||||
#include <ShaderNode/Widgets/NodeEditor.hpp>
|
#include <ShaderNode/Widgets/NodeEditor.hpp>
|
||||||
#include <ShaderNode/Widgets/TextureEditor.hpp>
|
#include <ShaderNode/Widgets/TextureEditor.hpp>
|
||||||
#include <nodes/FlowView>
|
#include <nodes/FlowView>
|
||||||
|
#include <QtCore/QFile>
|
||||||
|
#include <QtCore/QJsonDocument>
|
||||||
#include <QtWidgets/QDockWidget>
|
#include <QtWidgets/QDockWidget>
|
||||||
|
#include <QtWidgets/QFileDialog>
|
||||||
#include <QtWidgets/QMenuBar>
|
#include <QtWidgets/QMenuBar>
|
||||||
#include <QtWidgets/QMessageBox>
|
#include <QtWidgets/QMessageBox>
|
||||||
#include <QtWidgets/QTextEdit>
|
#include <QtWidgets/QTextEdit>
|
||||||
|
|
@ -77,7 +80,19 @@ m_shaderGraph(graph)
|
||||||
|
|
||||||
void MainWindow::BuildMenu()
|
void MainWindow::BuildMenu()
|
||||||
{
|
{
|
||||||
QMenu* compileMenu = menuBar()->addMenu(tr("&Compilation"));
|
QMenuBar* menu = menuBar();
|
||||||
|
|
||||||
|
QMenu* shader = menu->addMenu(tr("&Shader"));
|
||||||
|
{
|
||||||
|
QtNodes::FlowScene* scene = &m_shaderGraph.GetScene();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu* compileMenu = menu->addMenu(tr("&Compilation"));
|
||||||
QAction* compileToGlsl = compileMenu->addAction(tr("GLSL"));
|
QAction* compileToGlsl = compileMenu->addAction(tr("GLSL"));
|
||||||
connect(compileToGlsl, &QAction::triggered, [&](bool) { OnCompileToGLSL(); });
|
connect(compileToGlsl, &QAction::triggered, [&](bool) { OnCompileToGLSL(); });
|
||||||
}
|
}
|
||||||
|
|
@ -103,3 +118,48 @@ void MainWindow::OnCompileToGLSL()
|
||||||
QMessageBox::critical(this, tr("Compilation failed"), QString("Compilation failed: ") + e.what());
|
QMessageBox::critical(this, tr("Compilation failed"), QString("Compilation failed: ") + e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::OnLoad()
|
||||||
|
{
|
||||||
|
QString fileName = QFileDialog::getOpenFileName(this, tr("Open shader flow"), QDir::homePath(), tr("Shader Flow Files (*.shaderflow)"));
|
||||||
|
if (fileName.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QFile file(fileName);
|
||||||
|
if (!file.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Failed to open file"), QString("Failed to open shader flow file: ") + file.errorString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject jsonDocument = QJsonDocument::fromJson(file.readAll()).object();
|
||||||
|
if (jsonDocument.isEmpty())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Invalid file"), tr("Invalid shader flow file"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_shaderGraph.Load(jsonDocument);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Invalid file"), tr("Invalid shader flow file: ") + e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::OnSave()
|
||||||
|
{
|
||||||
|
QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Open shader flow"), QDir::homePath(), tr("Shader Flow Files (*.shaderflow)"));
|
||||||
|
if (fileName.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!fileName.endsWith("flow", Qt::CaseInsensitive))
|
||||||
|
fileName += ".shaderflow";
|
||||||
|
|
||||||
|
QFile file(fileName);
|
||||||
|
if (file.open(QIODevice::WriteOnly))
|
||||||
|
file.write(QJsonDocument(m_shaderGraph.Save()).toJson());
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ class MainWindow : public QMainWindow
|
||||||
private:
|
private:
|
||||||
void BuildMenu();
|
void BuildMenu();
|
||||||
void OnCompileToGLSL();
|
void OnCompileToGLSL();
|
||||||
|
void OnLoad();
|
||||||
|
void OnSave();
|
||||||
|
|
||||||
NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate);
|
NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue