ShaderNode: Add buffers and structs
This commit is contained in:
parent
fbba281d14
commit
c7a8091e68
|
|
@ -120,11 +120,11 @@ Nz::ShaderNodes::ExpressionPtr InputValue::GetExpression(Nz::ShaderNodes::Expres
|
||||||
{
|
{
|
||||||
switch (inputEntry.type)
|
switch (inputEntry.type)
|
||||||
{
|
{
|
||||||
case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean;
|
case PrimitiveType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean;
|
||||||
case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1;
|
case PrimitiveType::Float1: return Nz::ShaderNodes::ExpressionType::Float1;
|
||||||
case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2;
|
case PrimitiveType::Float2: return Nz::ShaderNodes::ExpressionType::Float2;
|
||||||
case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3;
|
case PrimitiveType::Float3: return Nz::ShaderNodes::ExpressionType::Float3;
|
||||||
case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4;
|
case PrimitiveType::Float4: return Nz::ShaderNodes::ExpressionType::Float4;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
@ -146,12 +146,12 @@ auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portInd
|
||||||
switch (inputEntry.type)
|
switch (inputEntry.type)
|
||||||
{
|
{
|
||||||
//case InputType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean;
|
//case InputType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean;
|
||||||
case InOutType::Float1:
|
case PrimitiveType::Float1:
|
||||||
return FloatData::Type();
|
return FloatData::Type();
|
||||||
|
|
||||||
case InOutType::Float2:
|
case PrimitiveType::Float2:
|
||||||
case InOutType::Float3:
|
case PrimitiveType::Float3:
|
||||||
case InOutType::Float4:
|
case PrimitiveType::Float4:
|
||||||
return VecData::Type();
|
return VecData::Type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,11 +67,11 @@ Nz::ShaderNodes::ExpressionPtr OutputValue::GetExpression(Nz::ShaderNodes::Expre
|
||||||
{
|
{
|
||||||
switch (outputEntry.type)
|
switch (outputEntry.type)
|
||||||
{
|
{
|
||||||
case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean;
|
case PrimitiveType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean;
|
||||||
case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1;
|
case PrimitiveType::Float1: return Nz::ShaderNodes::ExpressionType::Float1;
|
||||||
case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2;
|
case PrimitiveType::Float2: return Nz::ShaderNodes::ExpressionType::Float2;
|
||||||
case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3;
|
case PrimitiveType::Float3: return Nz::ShaderNodes::ExpressionType::Float3;
|
||||||
case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4;
|
case PrimitiveType::Float4: return Nz::ShaderNodes::ExpressionType::Float4;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
@ -96,9 +96,9 @@ QtNodes::NodeDataType OutputValue::dataType(QtNodes::PortType portType, QtNodes:
|
||||||
{
|
{
|
||||||
//case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean;
|
//case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean;
|
||||||
//case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1;
|
//case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1;
|
||||||
case InOutType::Float2:
|
case PrimitiveType::Float2:
|
||||||
case InOutType::Float3:
|
case PrimitiveType::Float3:
|
||||||
case InOutType::Float4:
|
case PrimitiveType::Float4:
|
||||||
return VecData::Type();
|
return VecData::Type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,32 @@
|
||||||
#include <ShaderNode/Enums.hpp>
|
#include <ShaderNode/Enums.hpp>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
std::size_t GetComponentCount(InOutType type)
|
std::size_t GetComponentCount(PrimitiveType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case InOutType::Bool: return 1;
|
case PrimitiveType::Bool: return 1;
|
||||||
case InOutType::Float1: return 1;
|
case PrimitiveType::Float1: return 1;
|
||||||
case InOutType::Float2: return 2;
|
case PrimitiveType::Float2: return 2;
|
||||||
case InOutType::Float3: return 3;
|
case PrimitiveType::Float3: return 3;
|
||||||
case InOutType::Float4: return 4;
|
case PrimitiveType::Float4: return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* EnumToString(BufferType bufferType)
|
||||||
|
{
|
||||||
|
switch (bufferType)
|
||||||
|
{
|
||||||
|
case BufferType::UniformBufferObject: return "UniformBufferObject";
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
return "<Unhandled>";
|
||||||
|
}
|
||||||
|
|
||||||
const char* EnumToString(InputRole role)
|
const char* EnumToString(InputRole role)
|
||||||
{
|
{
|
||||||
switch (role)
|
switch (role)
|
||||||
|
|
@ -30,15 +41,15 @@ const char* EnumToString(InputRole role)
|
||||||
return "<Unhandled>";
|
return "<Unhandled>";
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* EnumToString(InOutType input)
|
const char* EnumToString(PrimitiveType input)
|
||||||
{
|
{
|
||||||
switch (input)
|
switch (input)
|
||||||
{
|
{
|
||||||
case InOutType::Bool: return "Bool";
|
case PrimitiveType::Bool: return "Bool";
|
||||||
case InOutType::Float1: return "Float";
|
case PrimitiveType::Float1: return "Float";
|
||||||
case InOutType::Float2: return "Float2";
|
case PrimitiveType::Float2: return "Float2";
|
||||||
case InOutType::Float3: return "Float3";
|
case PrimitiveType::Float3: return "Float3";
|
||||||
case InOutType::Float4: return "Float4";
|
case PrimitiveType::Float4: return "Float4";
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,15 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
enum class BufferType
|
||||||
|
{
|
||||||
|
UniformBufferObject,
|
||||||
|
|
||||||
|
Max = UniformBufferObject
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::size_t BufferTypeCount = static_cast<std::size_t>(BufferType::Max) + 1;
|
||||||
|
|
||||||
enum class InputRole
|
enum class InputRole
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
|
@ -19,7 +28,7 @@ enum class InputRole
|
||||||
|
|
||||||
constexpr std::size_t InputRoleCount = static_cast<std::size_t>(InputRole::Max) + 1;
|
constexpr std::size_t InputRoleCount = static_cast<std::size_t>(InputRole::Max) + 1;
|
||||||
|
|
||||||
enum class InOutType
|
enum class PrimitiveType
|
||||||
{
|
{
|
||||||
Bool,
|
Bool,
|
||||||
Float1,
|
Float1,
|
||||||
|
|
@ -30,7 +39,7 @@ enum class InOutType
|
||||||
Max = Float4
|
Max = Float4
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::size_t InOutTypeCount = static_cast<std::size_t>(InOutType::Max) + 1;
|
constexpr std::size_t PrimitiveTypeCount = static_cast<std::size_t>(PrimitiveType::Max) + 1;
|
||||||
|
|
||||||
enum class TextureType
|
enum class TextureType
|
||||||
{
|
{
|
||||||
|
|
@ -43,10 +52,11 @@ constexpr std::size_t TextureTypeCount = static_cast<std::size_t>(TextureType::M
|
||||||
|
|
||||||
|
|
||||||
template<typename T> std::optional<T> DecodeEnum(const std::string_view& str);
|
template<typename T> std::optional<T> DecodeEnum(const std::string_view& str);
|
||||||
|
const char* EnumToString(BufferType bufferType);
|
||||||
const char* EnumToString(InputRole role);
|
const char* EnumToString(InputRole role);
|
||||||
const char* EnumToString(InOutType input);
|
const char* EnumToString(PrimitiveType input);
|
||||||
const char* EnumToString(TextureType textureType);
|
const char* EnumToString(TextureType textureType);
|
||||||
std::size_t GetComponentCount(InOutType type);
|
std::size_t GetComponentCount(PrimitiveType type);
|
||||||
|
|
||||||
#include <ShaderNode/Enums.inl>
|
#include <ShaderNode/Enums.inl>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@ inline const Nz::Vector4f* PreviewValues::GetData() const
|
||||||
|
|
||||||
inline std::size_t PreviewValues::GetHeight() const
|
inline std::size_t PreviewValues::GetHeight() const
|
||||||
{
|
{
|
||||||
return m_width;
|
return m_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::size_t PreviewValues::GetWidth() const
|
inline std::size_t PreviewValues::GetWidth() const
|
||||||
{
|
{
|
||||||
return m_height;
|
return m_width;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,23 @@ m_flowScene(BuildRegistry())
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
AddInput("UV", InOutType::Float2, InputRole::TexCoord, 0, 0);
|
AddInput("UV", PrimitiveType::Float2, InputRole::TexCoord, 0, 0);
|
||||||
AddOutput("RenderTarget0", InOutType::Float4, 0);
|
AddOutput("RenderTarget0", PrimitiveType::Float4, 0);
|
||||||
AddTexture("Potato", TextureType::Sampler2D, 1);
|
AddTexture("Potato", TextureType::Sampler2D, 1);
|
||||||
|
AddStruct("TestStruct", {
|
||||||
|
{
|
||||||
|
{ "position", PrimitiveType::Float3 },
|
||||||
|
{ "normal", PrimitiveType::Float3 },
|
||||||
|
{ "uv", PrimitiveType::Float2 },
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AddStruct("TestStruct2", {
|
||||||
|
{
|
||||||
|
{ "position", PrimitiveType::Float3 },
|
||||||
|
{ "normal", PrimitiveType::Float3 },
|
||||||
|
{ "uv", PrimitiveType::Float2 },
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)"));
|
UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)"));
|
||||||
|
|
||||||
|
|
@ -79,7 +93,21 @@ ShaderGraph::~ShaderGraph()
|
||||||
m_flowScene.clearScene();
|
m_flowScene.clearScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t ShaderGraph::AddInput(std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex)
|
std::size_t ShaderGraph::AddBuffer(std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex)
|
||||||
|
{
|
||||||
|
std::size_t index = m_buffers.size();
|
||||||
|
auto& bufferEntry = m_buffers.emplace_back();
|
||||||
|
bufferEntry.bindingIndex = bindingIndex;
|
||||||
|
bufferEntry.name = std::move(name);
|
||||||
|
bufferEntry.structIndex = structIndex;
|
||||||
|
bufferEntry.type = bufferType;
|
||||||
|
|
||||||
|
OnBufferListUpdate(this);
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t ShaderGraph::AddInput(std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex)
|
||||||
{
|
{
|
||||||
std::size_t index = m_inputs.size();
|
std::size_t index = m_inputs.size();
|
||||||
auto& inputEntry = m_inputs.emplace_back();
|
auto& inputEntry = m_inputs.emplace_back();
|
||||||
|
|
@ -94,7 +122,7 @@ std::size_t ShaderGraph::AddInput(std::string name, InOutType type, InputRole ro
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t ShaderGraph::AddOutput(std::string name, InOutType type, std::size_t locationIndex)
|
std::size_t ShaderGraph::AddOutput(std::string name, PrimitiveType type, std::size_t locationIndex)
|
||||||
{
|
{
|
||||||
std::size_t index = m_outputs.size();
|
std::size_t index = m_outputs.size();
|
||||||
auto& outputEntry = m_outputs.emplace_back();
|
auto& outputEntry = m_outputs.emplace_back();
|
||||||
|
|
@ -107,6 +135,18 @@ std::size_t ShaderGraph::AddOutput(std::string name, InOutType type, std::size_t
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t ShaderGraph::AddStruct(std::string name, std::vector<StructMemberEntry> members)
|
||||||
|
{
|
||||||
|
std::size_t index = m_structs.size();
|
||||||
|
auto& structEntry = m_structs.emplace_back();
|
||||||
|
structEntry.name = std::move(name);
|
||||||
|
structEntry.members = std::move(members);
|
||||||
|
|
||||||
|
OnStructListUpdate(this);
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t ShaderGraph::AddTexture(std::string name, TextureType type, std::size_t bindingIndex)
|
std::size_t ShaderGraph::AddTexture(std::string name, TextureType type, std::size_t bindingIndex)
|
||||||
{
|
{
|
||||||
std::size_t index = m_textures.size();
|
std::size_t index = m_textures.size();
|
||||||
|
|
@ -125,11 +165,15 @@ void ShaderGraph::Clear()
|
||||||
m_flowScene.clearScene();
|
m_flowScene.clearScene();
|
||||||
m_flowScene.clear();
|
m_flowScene.clear();
|
||||||
|
|
||||||
|
m_buffers.clear();
|
||||||
m_inputs.clear();
|
m_inputs.clear();
|
||||||
|
m_structs.clear();
|
||||||
m_outputs.clear();
|
m_outputs.clear();
|
||||||
m_textures.clear();
|
m_textures.clear();
|
||||||
|
|
||||||
|
OnBufferListUpdate(this);
|
||||||
OnInputListUpdate(this);
|
OnInputListUpdate(this);
|
||||||
|
OnStructListUpdate(this);
|
||||||
OnOutputListUpdate(this);
|
OnOutputListUpdate(this);
|
||||||
OnTextureListUpdate(this);
|
OnTextureListUpdate(this);
|
||||||
}
|
}
|
||||||
|
|
@ -138,6 +182,20 @@ void ShaderGraph::Load(const QJsonObject& data)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
|
QJsonArray bufferArray = data["buffers"].toArray();
|
||||||
|
for (const auto& bufferDocRef : bufferArray)
|
||||||
|
{
|
||||||
|
QJsonObject bufferDoc = bufferDocRef.toObject();
|
||||||
|
|
||||||
|
BufferEntry& buffer = m_buffers.emplace_back();
|
||||||
|
buffer.bindingIndex = static_cast<std::size_t>(bufferDoc["bindingIndex"].toInt(0));
|
||||||
|
buffer.name = bufferDoc["name"].toString().toStdString();
|
||||||
|
buffer.structIndex = bufferDoc["structIndex"].toInt();
|
||||||
|
buffer.type = DecodeEnum<BufferType>(bufferDoc["type"].toString().toStdString()).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
OnBufferListUpdate(this);
|
||||||
|
|
||||||
QJsonArray inputArray = data["inputs"].toArray();
|
QJsonArray inputArray = data["inputs"].toArray();
|
||||||
for (const auto& inputDocRef : inputArray)
|
for (const auto& inputDocRef : inputArray)
|
||||||
{
|
{
|
||||||
|
|
@ -148,7 +206,7 @@ void ShaderGraph::Load(const QJsonObject& data)
|
||||||
input.name = inputDoc["name"].toString().toStdString();
|
input.name = inputDoc["name"].toString().toStdString();
|
||||||
input.role = DecodeEnum<InputRole>(inputDoc["role"].toString().toStdString()).value();
|
input.role = DecodeEnum<InputRole>(inputDoc["role"].toString().toStdString()).value();
|
||||||
input.roleIndex = static_cast<std::size_t>(inputDoc["roleIndex"].toInt(0));
|
input.roleIndex = static_cast<std::size_t>(inputDoc["roleIndex"].toInt(0));
|
||||||
input.type = DecodeEnum<InOutType>(inputDoc["type"].toString().toStdString()).value();
|
input.type = DecodeEnum<PrimitiveType>(inputDoc["type"].toString().toStdString()).value();
|
||||||
}
|
}
|
||||||
|
|
||||||
OnInputListUpdate(this);
|
OnInputListUpdate(this);
|
||||||
|
|
@ -161,11 +219,37 @@ void ShaderGraph::Load(const QJsonObject& data)
|
||||||
OutputEntry& output = m_outputs.emplace_back();
|
OutputEntry& output = m_outputs.emplace_back();
|
||||||
output.locationIndex = static_cast<std::size_t>(outputDoc["locationIndex"].toInt(0));
|
output.locationIndex = static_cast<std::size_t>(outputDoc["locationIndex"].toInt(0));
|
||||||
output.name = outputDoc["name"].toString().toStdString();
|
output.name = outputDoc["name"].toString().toStdString();
|
||||||
output.type = DecodeEnum<InOutType>(outputDoc["type"].toString().toStdString()).value();
|
output.type = DecodeEnum<PrimitiveType>(outputDoc["type"].toString().toStdString()).value();
|
||||||
}
|
}
|
||||||
|
|
||||||
OnOutputListUpdate(this);
|
OnOutputListUpdate(this);
|
||||||
|
|
||||||
|
QJsonArray structArray = data["structs"].toArray();
|
||||||
|
for (const auto& structDocRef : structArray)
|
||||||
|
{
|
||||||
|
QJsonObject structDoc = structDocRef.toObject();
|
||||||
|
|
||||||
|
StructEntry& structInfo = m_structs.emplace_back();
|
||||||
|
structInfo.name = structDoc["name"].toString().toStdString();
|
||||||
|
|
||||||
|
QJsonArray memberArray = structDoc["members"].toArray();
|
||||||
|
for (const auto& memberDocRef : memberArray)
|
||||||
|
{
|
||||||
|
QJsonObject memberDoc = memberDocRef.toObject();
|
||||||
|
|
||||||
|
auto& memberInfo = structInfo.members.emplace_back();
|
||||||
|
memberInfo.name = memberDoc["name"].toString().toStdString();
|
||||||
|
|
||||||
|
const auto& typeDocRef = memberDoc["type"];
|
||||||
|
if (typeDocRef.isString())
|
||||||
|
memberInfo.type = DecodeEnum<PrimitiveType>(typeDocRef.toString().toStdString()).value();
|
||||||
|
else
|
||||||
|
memberInfo.type = typeDocRef.toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OnStructListUpdate(this);
|
||||||
|
|
||||||
QJsonArray textureArray = data["textures"].toArray();
|
QJsonArray textureArray = data["textures"].toArray();
|
||||||
for (const auto& textureDocRef : textureArray)
|
for (const auto& textureDocRef : textureArray)
|
||||||
{
|
{
|
||||||
|
|
@ -190,6 +274,21 @@ QJsonObject ShaderGraph::Save()
|
||||||
{
|
{
|
||||||
QJsonObject sceneJson;
|
QJsonObject sceneJson;
|
||||||
|
|
||||||
|
QJsonArray bufferArray;
|
||||||
|
{
|
||||||
|
for (const auto& buffer : m_buffers)
|
||||||
|
{
|
||||||
|
QJsonObject bufferDoc;
|
||||||
|
bufferDoc["bindingIndex"] = int(buffer.bindingIndex);
|
||||||
|
bufferDoc["name"] = QString::fromStdString(buffer.name);
|
||||||
|
bufferDoc["structIndex"] = int(buffer.structIndex);
|
||||||
|
bufferDoc["type"] = QString(EnumToString(buffer.type));
|
||||||
|
|
||||||
|
bufferArray.append(bufferDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sceneJson["buffers"] = bufferArray;
|
||||||
|
|
||||||
QJsonArray inputArray;
|
QJsonArray inputArray;
|
||||||
{
|
{
|
||||||
for (const auto& input : m_inputs)
|
for (const auto& input : m_inputs)
|
||||||
|
|
@ -220,6 +319,39 @@ QJsonObject ShaderGraph::Save()
|
||||||
}
|
}
|
||||||
sceneJson["outputs"] = outputArray;
|
sceneJson["outputs"] = outputArray;
|
||||||
|
|
||||||
|
QJsonArray structArray;
|
||||||
|
{
|
||||||
|
for (const auto& s : m_structs)
|
||||||
|
{
|
||||||
|
QJsonObject structDoc;
|
||||||
|
structDoc["name"] = QString::fromStdString(s.name);
|
||||||
|
|
||||||
|
QJsonArray memberArray;
|
||||||
|
for (const auto& member : s.members)
|
||||||
|
{
|
||||||
|
QJsonObject memberDoc;
|
||||||
|
memberDoc["name"] = QString::fromStdString(member.name);
|
||||||
|
|
||||||
|
std::visit([&](auto&& arg)
|
||||||
|
{
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, PrimitiveType>)
|
||||||
|
memberDoc["type"] = QString(EnumToString(arg));
|
||||||
|
else if constexpr (std::is_same_v<T, std::size_t>)
|
||||||
|
memberDoc["type"] = int(arg);
|
||||||
|
else
|
||||||
|
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
||||||
|
}, member.type);
|
||||||
|
|
||||||
|
memberDoc["type"] = QString::fromStdString(member.name);
|
||||||
|
}
|
||||||
|
structDoc["members"] = memberArray;
|
||||||
|
|
||||||
|
structArray.append(structDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sceneJson["structs"] = structArray;
|
||||||
|
|
||||||
QJsonArray textureArray;
|
QJsonArray textureArray;
|
||||||
{
|
{
|
||||||
for (const auto& texture : m_textures)
|
for (const auto& texture : m_textures)
|
||||||
|
|
@ -366,7 +498,19 @@ Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst()
|
||||||
return Nz::ShaderNodes::StatementBlock::Build(std::move(statements));
|
return Nz::ShaderNodes::StatementBlock::Build(std::move(statements));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex)
|
void ShaderGraph::UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex)
|
||||||
|
{
|
||||||
|
assert(bufferIndex < m_buffers.size());
|
||||||
|
auto& bufferEntry = m_buffers[bufferIndex];
|
||||||
|
bufferEntry.bindingIndex = bindingIndex;
|
||||||
|
bufferEntry.name = std::move(name);
|
||||||
|
bufferEntry.structIndex = structIndex;
|
||||||
|
bufferEntry.type = bufferType;
|
||||||
|
|
||||||
|
OnBufferUpdate(this, bufferIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex)
|
||||||
{
|
{
|
||||||
assert(inputIndex < m_inputs.size());
|
assert(inputIndex < m_inputs.size());
|
||||||
auto& inputEntry = m_inputs[inputIndex];
|
auto& inputEntry = m_inputs[inputIndex];
|
||||||
|
|
@ -379,7 +523,7 @@ void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InOutTyp
|
||||||
OnInputUpdate(this, inputIndex);
|
OnInputUpdate(this, inputIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderGraph::UpdateOutput(std::size_t outputIndex, std::string name, InOutType type, std::size_t locationIndex)
|
void ShaderGraph::UpdateOutput(std::size_t outputIndex, std::string name, PrimitiveType type, std::size_t locationIndex)
|
||||||
{
|
{
|
||||||
assert(outputIndex < m_outputs.size());
|
assert(outputIndex < m_outputs.size());
|
||||||
auto& outputEntry = m_outputs[outputIndex];
|
auto& outputEntry = m_outputs[outputIndex];
|
||||||
|
|
@ -390,6 +534,16 @@ void ShaderGraph::UpdateOutput(std::size_t outputIndex, std::string name, InOutT
|
||||||
OnOutputUpdate(this, outputIndex);
|
OnOutputUpdate(this, outputIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShaderGraph::UpdateStruct(std::size_t structIndex, std::string name, std::vector<StructMemberEntry> members)
|
||||||
|
{
|
||||||
|
assert(structIndex < m_structs.size());
|
||||||
|
auto& structEntry = m_structs[structIndex];
|
||||||
|
structEntry.name = std::move(name);
|
||||||
|
structEntry.members = std::move(members);
|
||||||
|
|
||||||
|
OnStructUpdate(this, structIndex);
|
||||||
|
}
|
||||||
|
|
||||||
void ShaderGraph::UpdateTexture(std::size_t textureIndex, std::string name, TextureType type, std::size_t bindingIndex)
|
void ShaderGraph::UpdateTexture(std::size_t textureIndex, std::string name, TextureType type, std::size_t bindingIndex)
|
||||||
{
|
{
|
||||||
assert(textureIndex < m_textures.size());
|
assert(textureIndex < m_textures.size());
|
||||||
|
|
|
||||||
|
|
@ -16,25 +16,36 @@ class ShaderNode;
|
||||||
class ShaderGraph
|
class ShaderGraph
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
struct BufferEntry;
|
||||||
struct InputEntry;
|
struct InputEntry;
|
||||||
struct OutputEntry;
|
struct OutputEntry;
|
||||||
|
struct StructEntry;
|
||||||
|
struct StructMemberEntry;
|
||||||
struct TextureEntry;
|
struct TextureEntry;
|
||||||
|
|
||||||
ShaderGraph();
|
ShaderGraph();
|
||||||
~ShaderGraph();
|
~ShaderGraph();
|
||||||
|
|
||||||
std::size_t AddInput(std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex);
|
std::size_t AddBuffer(std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex);
|
||||||
std::size_t AddOutput(std::string name, InOutType type, std::size_t locationIndex);
|
std::size_t AddInput(std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex);
|
||||||
|
std::size_t AddOutput(std::string name, PrimitiveType type, std::size_t locationIndex);
|
||||||
|
std::size_t AddStruct(std::string name, std::vector<StructMemberEntry> members);
|
||||||
std::size_t AddTexture(std::string name, TextureType type, std::size_t bindingIndex);
|
std::size_t AddTexture(std::string name, TextureType type, std::size_t bindingIndex);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
inline const InputEntry& GetInput(std::size_t inputIndex) const;
|
inline const BufferEntry& GetBuffer(std::size_t bufferIndex) const;
|
||||||
|
inline std::size_t GetBufferCount() const;
|
||||||
|
inline const std::vector<BufferEntry>& GetBuffers() const;
|
||||||
|
inline const InputEntry& GetInput(std::size_t bufferIndex) 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;
|
||||||
inline const OutputEntry& GetOutput(std::size_t outputIndex) const;
|
inline const OutputEntry& GetOutput(std::size_t outputIndex) const;
|
||||||
inline std::size_t GetOutputCount() const;
|
inline std::size_t GetOutputCount() const;
|
||||||
inline const std::vector<OutputEntry>& GetOutputs() const;
|
inline const std::vector<OutputEntry>& GetOutputs() const;
|
||||||
|
inline const StructEntry& GetStruct(std::size_t structIndex) const;
|
||||||
|
inline std::size_t GetStructCount() const;
|
||||||
|
inline const std::vector<StructEntry>& GetStructs() const;
|
||||||
inline const PreviewModel& GetPreviewModel() const;
|
inline const PreviewModel& GetPreviewModel() const;
|
||||||
inline QtNodes::FlowScene& GetScene();
|
inline QtNodes::FlowScene& GetScene();
|
||||||
inline const TextureEntry& GetTexture(std::size_t textureIndex) const;
|
inline const TextureEntry& GetTexture(std::size_t textureIndex) const;
|
||||||
|
|
@ -46,25 +57,47 @@ class ShaderGraph
|
||||||
|
|
||||||
Nz::ShaderNodes::StatementPtr ToAst();
|
Nz::ShaderNodes::StatementPtr ToAst();
|
||||||
|
|
||||||
void UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex);
|
void UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex);
|
||||||
void UpdateOutput(std::size_t outputIndex, std::string name, InOutType type, std::size_t locationIndex);
|
void UpdateInput(std::size_t inputIndex, std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex);
|
||||||
|
void UpdateOutput(std::size_t outputIndex, std::string name, PrimitiveType type, std::size_t locationIndex);
|
||||||
|
void UpdateStruct(std::size_t structIndex, std::string name, std::vector<StructMemberEntry> members);
|
||||||
void UpdateTexture(std::size_t textureIndex, std::string name, TextureType type, std::size_t bindingIndex);
|
void UpdateTexture(std::size_t textureIndex, std::string name, TextureType type, std::size_t bindingIndex);
|
||||||
void UpdateTexturePreview(std::size_t texture, QImage preview);
|
void UpdateTexturePreview(std::size_t texture, QImage preview);
|
||||||
|
|
||||||
|
struct BufferEntry
|
||||||
|
{
|
||||||
|
std::size_t bindingIndex;
|
||||||
|
std::size_t structIndex;
|
||||||
|
std::string name;
|
||||||
|
BufferType type;
|
||||||
|
};
|
||||||
|
|
||||||
struct InputEntry
|
struct InputEntry
|
||||||
{
|
{
|
||||||
std::size_t locationIndex;
|
std::size_t locationIndex;
|
||||||
std::size_t roleIndex;
|
std::size_t roleIndex;
|
||||||
std::string name;
|
std::string name;
|
||||||
InputRole role;
|
InputRole role;
|
||||||
InOutType type;
|
PrimitiveType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OutputEntry
|
struct OutputEntry
|
||||||
{
|
{
|
||||||
std::size_t locationIndex;
|
std::size_t locationIndex;
|
||||||
std::string name;
|
std::string name;
|
||||||
InOutType type;
|
PrimitiveType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StructEntry
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::vector<StructMemberEntry> members;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StructMemberEntry
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::variant<PrimitiveType, std::size_t /*structIndex*/> type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextureEntry
|
struct TextureEntry
|
||||||
|
|
@ -75,11 +108,15 @@ class ShaderGraph
|
||||||
QImage preview;
|
QImage preview;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NazaraSignal(OnBufferListUpdate, ShaderGraph*);
|
||||||
|
NazaraSignal(OnBufferUpdate, ShaderGraph*, std::size_t /*outputIndex*/);
|
||||||
NazaraSignal(OnInputListUpdate, ShaderGraph*);
|
NazaraSignal(OnInputListUpdate, ShaderGraph*);
|
||||||
NazaraSignal(OnInputUpdate, ShaderGraph*, std::size_t /*inputIndex*/);
|
NazaraSignal(OnInputUpdate, ShaderGraph*, std::size_t /*inputIndex*/);
|
||||||
NazaraSignal(OnOutputListUpdate, ShaderGraph*);
|
NazaraSignal(OnOutputListUpdate, ShaderGraph*);
|
||||||
NazaraSignal(OnOutputUpdate, ShaderGraph*, std::size_t /*outputIndex*/);
|
NazaraSignal(OnOutputUpdate, ShaderGraph*, std::size_t /*outputIndex*/);
|
||||||
NazaraSignal(OnSelectedNodeUpdate, ShaderGraph*, ShaderNode* /*node*/);
|
NazaraSignal(OnSelectedNodeUpdate, ShaderGraph*, ShaderNode* /*node*/);
|
||||||
|
NazaraSignal(OnStructListUpdate, ShaderGraph*);
|
||||||
|
NazaraSignal(OnStructUpdate, ShaderGraph*, std::size_t /*structIndex*/);
|
||||||
NazaraSignal(OnTextureListUpdate, ShaderGraph*);
|
NazaraSignal(OnTextureListUpdate, ShaderGraph*);
|
||||||
NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/);
|
NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/);
|
||||||
NazaraSignal(OnTextureUpdate, ShaderGraph*, std::size_t /*textureIndex*/);
|
NazaraSignal(OnTextureUpdate, ShaderGraph*, std::size_t /*textureIndex*/);
|
||||||
|
|
@ -88,8 +125,10 @@ class ShaderGraph
|
||||||
std::shared_ptr<QtNodes::DataModelRegistry> BuildRegistry();
|
std::shared_ptr<QtNodes::DataModelRegistry> BuildRegistry();
|
||||||
|
|
||||||
QtNodes::FlowScene m_flowScene;
|
QtNodes::FlowScene m_flowScene;
|
||||||
|
std::vector<BufferEntry> m_buffers;
|
||||||
std::vector<InputEntry> m_inputs;
|
std::vector<InputEntry> m_inputs;
|
||||||
std::vector<OutputEntry> m_outputs;
|
std::vector<OutputEntry> m_outputs;
|
||||||
|
std::vector<StructEntry> m_structs;
|
||||||
std::vector<TextureEntry> m_textures;
|
std::vector<TextureEntry> m_textures;
|
||||||
std::unique_ptr<PreviewModel> m_previewModel;
|
std::unique_ptr<PreviewModel> m_previewModel;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,21 @@
|
||||||
#include <ShaderNode/ShaderGraph.hpp>
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
|
|
||||||
|
inline auto ShaderGraph::GetBuffer(std::size_t bufferIndex) const -> const BufferEntry&
|
||||||
|
{
|
||||||
|
assert(bufferIndex < m_buffers.size());
|
||||||
|
return m_buffers[bufferIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t ShaderGraph::GetBufferCount() const
|
||||||
|
{
|
||||||
|
return m_buffers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto ShaderGraph::GetBuffers() const -> const std::vector<BufferEntry>&
|
||||||
|
{
|
||||||
|
return m_buffers;
|
||||||
|
}
|
||||||
|
|
||||||
inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEntry&
|
inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEntry&
|
||||||
{
|
{
|
||||||
assert(inputIndex < m_inputs.size());
|
assert(inputIndex < m_inputs.size());
|
||||||
|
|
@ -32,6 +48,22 @@ inline auto ShaderGraph::GetOutputs() const -> const std::vector<OutputEntry>&
|
||||||
return m_outputs;
|
return m_outputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline auto ShaderGraph::GetStruct(std::size_t structIndex) const -> const StructEntry&
|
||||||
|
{
|
||||||
|
assert(structIndex < m_structs.size());
|
||||||
|
return m_structs[structIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t ShaderGraph::GetStructCount() const
|
||||||
|
{
|
||||||
|
return m_structs.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto ShaderGraph::GetStructs() const -> const std::vector<StructEntry>&
|
||||||
|
{
|
||||||
|
return m_structs;
|
||||||
|
}
|
||||||
|
|
||||||
inline const PreviewModel& ShaderGraph::GetPreviewModel() const
|
inline const PreviewModel& ShaderGraph::GetPreviewModel() const
|
||||||
{
|
{
|
||||||
return *m_previewModel;
|
return *m_previewModel;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
#include <ShaderNode/Widgets/BufferEditDialog.hpp>
|
||||||
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
|
#include <QtWidgets/QComboBox>
|
||||||
|
#include <QtWidgets/QDialogButtonBox>
|
||||||
|
#include <QtWidgets/QFormLayout>
|
||||||
|
#include <QtWidgets/QLineEdit>
|
||||||
|
#include <QtWidgets/QMessageBox>
|
||||||
|
#include <QtWidgets/QSpinBox>
|
||||||
|
#include <QtWidgets/QVBoxLayout>
|
||||||
|
|
||||||
|
BufferEditDialog::BufferEditDialog(const ShaderGraph& shaderGraph, QWidget* parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
m_shaderGraph(shaderGraph)
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Buffer edit dialog"));
|
||||||
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
|
m_outputName = new QLineEdit;
|
||||||
|
|
||||||
|
m_typeList = new QComboBox;
|
||||||
|
for (std::size_t i = 0; i < BufferTypeCount; ++i)
|
||||||
|
m_typeList->addItem(EnumToString(static_cast<BufferType>(i)));
|
||||||
|
|
||||||
|
m_structList = new QComboBox;
|
||||||
|
for (const auto& structEntry : m_shaderGraph.GetStructs())
|
||||||
|
m_structList->addItem(QString::fromStdString(structEntry.name));
|
||||||
|
|
||||||
|
m_bindingIndex = new QSpinBox;
|
||||||
|
|
||||||
|
QFormLayout* formLayout = new QFormLayout;
|
||||||
|
formLayout->addRow(tr("Name"), m_outputName);
|
||||||
|
formLayout->addRow(tr("Type"), m_typeList);
|
||||||
|
formLayout->addRow(tr("Struct"), m_structList);
|
||||||
|
formLayout->addRow(tr("Binding index"), m_bindingIndex);
|
||||||
|
|
||||||
|
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &BufferEditDialog::OnAccept);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
|
||||||
|
QVBoxLayout* verticalLayout = new QVBoxLayout;
|
||||||
|
verticalLayout->addLayout(formLayout);
|
||||||
|
verticalLayout->addWidget(buttonBox);
|
||||||
|
|
||||||
|
setLayout(verticalLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferEditDialog::BufferEditDialog(const ShaderGraph& shaderGraph, const BufferInfo& buffer, QWidget* parent) :
|
||||||
|
BufferEditDialog(shaderGraph, parent)
|
||||||
|
{
|
||||||
|
m_bindingIndex->setValue(int(buffer.bindingIndex));
|
||||||
|
m_outputName->setText(QString::fromStdString(buffer.name));
|
||||||
|
m_structList->setCurrentIndex(buffer.structIndex);
|
||||||
|
m_typeList->setCurrentIndex(int(buffer.type));
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferInfo BufferEditDialog::GetBufferInfo() const
|
||||||
|
{
|
||||||
|
BufferInfo bufferInfo;
|
||||||
|
bufferInfo.bindingIndex = static_cast<std::size_t>(m_bindingIndex->value());
|
||||||
|
bufferInfo.name = m_outputName->text().toStdString();
|
||||||
|
bufferInfo.structIndex = m_structList->currentIndex();
|
||||||
|
bufferInfo.type = static_cast<BufferType>(m_typeList->currentIndex());
|
||||||
|
|
||||||
|
return bufferInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferEditDialog::OnAccept()
|
||||||
|
{
|
||||||
|
if (m_outputName->text().isEmpty())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Empty name"), tr("Buffer name must be set"), QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_structList->currentIndex() < 0)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Invalid struct"), tr("You must select a struct"), QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_typeList->currentIndex() < 0)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Invalid type"), tr("You must select a type"), QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
accept();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SHADERNODES_BUFFEREDITDIALOG_HPP
|
||||||
|
#define NAZARA_SHADERNODES_BUFFEREDITDIALOG_HPP
|
||||||
|
|
||||||
|
#include <ShaderNode/Enums.hpp>
|
||||||
|
#include <QtWidgets/QDialog>
|
||||||
|
|
||||||
|
class QComboBox;
|
||||||
|
class QLineEdit;
|
||||||
|
class QSpinBox;
|
||||||
|
class ShaderGraph;
|
||||||
|
|
||||||
|
struct BufferInfo
|
||||||
|
{
|
||||||
|
std::size_t bindingIndex;
|
||||||
|
std::size_t structIndex;
|
||||||
|
std::string name;
|
||||||
|
BufferType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BufferEditDialog : public QDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BufferEditDialog(const ShaderGraph& shaderGraph, QWidget* parent = nullptr);
|
||||||
|
BufferEditDialog(const ShaderGraph& shaderGraph, const BufferInfo& output, QWidget* parent = nullptr);
|
||||||
|
~BufferEditDialog() = default;
|
||||||
|
|
||||||
|
BufferInfo GetBufferInfo() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnAccept();
|
||||||
|
|
||||||
|
const ShaderGraph& m_shaderGraph;
|
||||||
|
QComboBox* m_typeList;
|
||||||
|
QComboBox* m_structList;
|
||||||
|
QLineEdit* m_outputName;
|
||||||
|
QSpinBox* m_bindingIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <ShaderNode/Widgets/BufferEditDialog.inl>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
#include <ShaderNode/Widgets/BufferEditDialog.hpp>
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
#include <ShaderNode/Widgets/BufferEditor.hpp>
|
||||||
|
#include <ShaderNode/Widgets/BufferEditDialog.hpp>
|
||||||
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
|
#include <QtWidgets/QFileDialog>
|
||||||
|
#include <QtWidgets/QLabel>
|
||||||
|
#include <QtWidgets/QPushButton>
|
||||||
|
#include <QtWidgets/QListWidget>
|
||||||
|
#include <QtWidgets/QVBoxLayout>
|
||||||
|
|
||||||
|
BufferEditor::BufferEditor(ShaderGraph& graph) :
|
||||||
|
m_shaderGraph(graph)
|
||||||
|
{
|
||||||
|
m_bufferList = new QListWidget(this);
|
||||||
|
connect(m_bufferList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item)
|
||||||
|
{
|
||||||
|
OnEditBuffer(m_bufferList->row(item));
|
||||||
|
});
|
||||||
|
|
||||||
|
QPushButton* addBufferButton = new QPushButton(tr("Add buffer..."));
|
||||||
|
connect(addBufferButton, &QPushButton::released, this, &BufferEditor::OnAddBuffer);
|
||||||
|
|
||||||
|
m_layout = new QVBoxLayout;
|
||||||
|
m_layout->addWidget(m_bufferList);
|
||||||
|
m_layout->addWidget(addBufferButton);
|
||||||
|
|
||||||
|
setLayout(m_layout);
|
||||||
|
|
||||||
|
m_onBufferListUpdateSlot.Connect(m_shaderGraph.OnBufferListUpdate, this, &BufferEditor::OnBufferListUpdate);
|
||||||
|
m_onBufferUpdateSlot.Connect(m_shaderGraph.OnBufferUpdate, this, &BufferEditor::OnBufferUpdate);
|
||||||
|
|
||||||
|
RefreshBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferEditor::OnAddBuffer()
|
||||||
|
{
|
||||||
|
BufferEditDialog* dialog = new BufferEditDialog(m_shaderGraph, this);
|
||||||
|
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
|
connect(dialog, &QDialog::accepted, [this, dialog]
|
||||||
|
{
|
||||||
|
BufferInfo bufferInfo = dialog->GetBufferInfo();
|
||||||
|
m_shaderGraph.AddBuffer(std::move(bufferInfo.name), bufferInfo.type, bufferInfo.structIndex, bufferInfo.bindingIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferEditor::OnEditBuffer(int inputIndex)
|
||||||
|
{
|
||||||
|
const auto& buffer = m_shaderGraph.GetBuffer(inputIndex);
|
||||||
|
|
||||||
|
BufferInfo info;
|
||||||
|
info.name = buffer.name;
|
||||||
|
info.structIndex = buffer.structIndex;
|
||||||
|
info.type = buffer.type;
|
||||||
|
|
||||||
|
BufferEditDialog* dialog = new BufferEditDialog(m_shaderGraph, std::move(info), this);
|
||||||
|
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
|
connect(dialog, &QDialog::accepted, [this, dialog, inputIndex]
|
||||||
|
{
|
||||||
|
BufferInfo bufferInfo = dialog->GetBufferInfo();
|
||||||
|
m_shaderGraph.UpdateBuffer(inputIndex, std::move(bufferInfo.name), bufferInfo.type, bufferInfo.structIndex, bufferInfo.bindingIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferEditor::OnBufferListUpdate(ShaderGraph* /*graph*/)
|
||||||
|
{
|
||||||
|
RefreshBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferEditor::OnBufferUpdate(ShaderGraph* /*graph*/, std::size_t bufferIndex)
|
||||||
|
{
|
||||||
|
const auto& bufferEntry = m_shaderGraph.GetBuffer(bufferIndex);
|
||||||
|
m_bufferList->item(int(bufferIndex))->setText(QString::fromStdString(bufferEntry.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferEditor::RefreshBuffers()
|
||||||
|
{
|
||||||
|
m_bufferList->clear();
|
||||||
|
m_bufferList->setCurrentRow(-1);
|
||||||
|
|
||||||
|
for (const auto& bufferEntry : m_shaderGraph.GetBuffers())
|
||||||
|
m_bufferList->addItem(QString::fromStdString(bufferEntry.name));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SHADERNODES_BUFFEREDITOR_HPP
|
||||||
|
#define NAZARA_SHADERNODES_BUFFEREDITOR_HPP
|
||||||
|
|
||||||
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
|
#include <QtWidgets/QWidget>
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
class QListWidget;
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
|
class BufferEditor : public QWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BufferEditor(ShaderGraph& graph);
|
||||||
|
~BufferEditor() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnAddBuffer();
|
||||||
|
void OnEditBuffer(int inputIndex);
|
||||||
|
void OnBufferListUpdate(ShaderGraph* graph);
|
||||||
|
void OnBufferUpdate(ShaderGraph* graph, std::size_t inputIndex);
|
||||||
|
void RefreshBuffers();
|
||||||
|
|
||||||
|
NazaraSlot(ShaderGraph, OnBufferListUpdate, m_onBufferListUpdateSlot);
|
||||||
|
NazaraSlot(ShaderGraph, OnBufferUpdate, m_onBufferUpdateSlot);
|
||||||
|
|
||||||
|
ShaderGraph& m_shaderGraph;
|
||||||
|
QListWidget* m_bufferList;
|
||||||
|
QVBoxLayout* m_layout;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <ShaderNode/Widgets/BufferEditor.inl>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
#include <ShaderNode/Widgets/BufferEditor.hpp>
|
||||||
|
|
@ -16,8 +16,8 @@ QDialog(parent)
|
||||||
m_inputName = new QLineEdit;
|
m_inputName = new QLineEdit;
|
||||||
|
|
||||||
m_typeList = new QComboBox;
|
m_typeList = new QComboBox;
|
||||||
for (std::size_t i = 0; i < InOutTypeCount; ++i)
|
for (std::size_t i = 0; i < PrimitiveTypeCount; ++i)
|
||||||
m_typeList->addItem(EnumToString(static_cast<InOutType>(i)));
|
m_typeList->addItem(EnumToString(static_cast<PrimitiveType>(i)));
|
||||||
|
|
||||||
m_roleList = new QComboBox;
|
m_roleList = new QComboBox;
|
||||||
for (std::size_t i = 0; i < InputRoleCount; ++i)
|
for (std::size_t i = 0; i < InputRoleCount; ++i)
|
||||||
|
|
@ -62,7 +62,7 @@ InputInfo InputEditDialog::GetInputInfo() const
|
||||||
inputInfo.name = m_inputName->text().toStdString();
|
inputInfo.name = m_inputName->text().toStdString();
|
||||||
inputInfo.role = static_cast<InputRole>(m_roleList->currentIndex());
|
inputInfo.role = static_cast<InputRole>(m_roleList->currentIndex());
|
||||||
inputInfo.roleIndex = static_cast<std::size_t>(m_roleIndex->value());
|
inputInfo.roleIndex = static_cast<std::size_t>(m_roleIndex->value());
|
||||||
inputInfo.type = static_cast<InOutType>(m_typeList->currentIndex());
|
inputInfo.type = static_cast<PrimitiveType>(m_typeList->currentIndex());
|
||||||
|
|
||||||
return inputInfo;
|
return inputInfo;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ struct InputInfo
|
||||||
std::size_t roleIndex;
|
std::size_t roleIndex;
|
||||||
std::string name;
|
std::string name;
|
||||||
InputRole role;
|
InputRole role;
|
||||||
InOutType type;
|
PrimitiveType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
class InputEditDialog : public QDialog
|
class InputEditDialog : public QDialog
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,11 @@
|
||||||
#include <Nazara/Renderer/GlslWriter.hpp>
|
#include <Nazara/Renderer/GlslWriter.hpp>
|
||||||
#include <Nazara/Renderer/ShaderSerializer.hpp>
|
#include <Nazara/Renderer/ShaderSerializer.hpp>
|
||||||
#include <ShaderNode/ShaderGraph.hpp>
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
|
#include <ShaderNode/Widgets/BufferEditor.hpp>
|
||||||
#include <ShaderNode/Widgets/InputEditor.hpp>
|
#include <ShaderNode/Widgets/InputEditor.hpp>
|
||||||
#include <ShaderNode/Widgets/OutputEditor.hpp>
|
#include <ShaderNode/Widgets/OutputEditor.hpp>
|
||||||
#include <ShaderNode/Widgets/NodeEditor.hpp>
|
#include <ShaderNode/Widgets/NodeEditor.hpp>
|
||||||
|
#include <ShaderNode/Widgets/StructEditor.hpp>
|
||||||
#include <ShaderNode/Widgets/TextureEditor.hpp>
|
#include <ShaderNode/Widgets/TextureEditor.hpp>
|
||||||
#include <nodes/FlowView>
|
#include <nodes/FlowView>
|
||||||
#include <QtCore/QFile>
|
#include <QtCore/QFile>
|
||||||
|
|
@ -63,6 +65,24 @@ m_shaderGraph(graph)
|
||||||
|
|
||||||
addDockWidget(Qt::RightDockWidgetArea, nodeEditorDock);
|
addDockWidget(Qt::RightDockWidgetArea, nodeEditorDock);
|
||||||
|
|
||||||
|
// Buffer editor
|
||||||
|
BufferEditor* bufferEditor = new BufferEditor(m_shaderGraph);
|
||||||
|
|
||||||
|
QDockWidget* bufferDock = new QDockWidget(tr("Buffers"));
|
||||||
|
bufferDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
|
||||||
|
bufferDock->setWidget(bufferEditor);
|
||||||
|
|
||||||
|
addDockWidget(Qt::RightDockWidgetArea, bufferDock);
|
||||||
|
|
||||||
|
// Struct editor
|
||||||
|
StructEditor* structEditor = new StructEditor(m_shaderGraph);
|
||||||
|
|
||||||
|
QDockWidget* structDock = new QDockWidget(tr("Structs"));
|
||||||
|
structDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
|
||||||
|
structDock->setWidget(structEditor);
|
||||||
|
|
||||||
|
addDockWidget(Qt::RightDockWidgetArea, structDock);
|
||||||
|
|
||||||
m_onSelectedNodeUpdate.Connect(m_shaderGraph.OnSelectedNodeUpdate, [&](ShaderGraph*, ShaderNode* node)
|
m_onSelectedNodeUpdate.Connect(m_shaderGraph.OnSelectedNodeUpdate, [&](ShaderGraph*, ShaderNode* node)
|
||||||
{
|
{
|
||||||
if (node)
|
if (node)
|
||||||
|
|
@ -193,15 +213,15 @@ Nz::ShaderAst MainWindow::ToShader()
|
||||||
Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst();
|
Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst();
|
||||||
|
|
||||||
//TODO: Put in another function
|
//TODO: Put in another function
|
||||||
auto GetExpressionFromInOut = [&](InOutType type)
|
auto GetExpressionFromInOut = [&](PrimitiveType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean;
|
case PrimitiveType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean;
|
||||||
case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1;
|
case PrimitiveType::Float1: return Nz::ShaderNodes::ExpressionType::Float1;
|
||||||
case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2;
|
case PrimitiveType::Float2: return Nz::ShaderNodes::ExpressionType::Float2;
|
||||||
case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3;
|
case PrimitiveType::Float3: return Nz::ShaderNodes::ExpressionType::Float3;
|
||||||
case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4;
|
case PrimitiveType::Float4: return Nz::ShaderNodes::ExpressionType::Float4;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
@ -226,8 +246,37 @@ Nz::ShaderAst MainWindow::ToShader()
|
||||||
for (const auto& output : m_shaderGraph.GetOutputs())
|
for (const auto& output : m_shaderGraph.GetOutputs())
|
||||||
shader.AddOutput(output.name, GetExpressionFromInOut(output.type), output.locationIndex);
|
shader.AddOutput(output.name, GetExpressionFromInOut(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())
|
for (const auto& uniform : m_shaderGraph.GetTextures())
|
||||||
shader.AddUniform(uniform.name, GetExpressionFromTexture(uniform.type), uniform.bindingIndex);
|
shader.AddUniform(uniform.name, GetExpressionFromTexture(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 = GetExpressionFromInOut(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);
|
shader.AddFunction("main", shaderAst);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ QDialog(parent)
|
||||||
m_outputName = new QLineEdit;
|
m_outputName = new QLineEdit;
|
||||||
|
|
||||||
m_typeList = new QComboBox;
|
m_typeList = new QComboBox;
|
||||||
for (std::size_t i = 0; i < InOutTypeCount; ++i)
|
for (std::size_t i = 0; i < PrimitiveTypeCount; ++i)
|
||||||
m_typeList->addItem(EnumToString(static_cast<InOutType>(i)));
|
m_typeList->addItem(EnumToString(static_cast<PrimitiveType>(i)));
|
||||||
|
|
||||||
m_locationIndex = new QSpinBox;
|
m_locationIndex = new QSpinBox;
|
||||||
|
|
||||||
|
|
@ -50,7 +50,7 @@ OutputInfo OutputEditDialog::GetOutputInfo() const
|
||||||
OutputInfo inputInfo;
|
OutputInfo inputInfo;
|
||||||
inputInfo.locationIndex = static_cast<std::size_t>(m_locationIndex->value());
|
inputInfo.locationIndex = static_cast<std::size_t>(m_locationIndex->value());
|
||||||
inputInfo.name = m_outputName->text().toStdString();
|
inputInfo.name = m_outputName->text().toStdString();
|
||||||
inputInfo.type = static_cast<InOutType>(m_typeList->currentIndex());
|
inputInfo.type = static_cast<PrimitiveType>(m_typeList->currentIndex());
|
||||||
|
|
||||||
return inputInfo;
|
return inputInfo;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ struct OutputInfo
|
||||||
{
|
{
|
||||||
std::size_t locationIndex;
|
std::size_t locationIndex;
|
||||||
std::string name;
|
std::string name;
|
||||||
InOutType type;
|
PrimitiveType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OutputEditDialog : public QDialog
|
class OutputEditDialog : public QDialog
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,224 @@
|
||||||
|
#include <ShaderNode/Widgets/StructEditDialog.hpp>
|
||||||
|
#include <ShaderNode/Widgets/StructMemberEditDialog.hpp>
|
||||||
|
#include <Nazara/Core/Algorithm.hpp>
|
||||||
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
|
#include <QtWidgets/QComboBox>
|
||||||
|
#include <QtWidgets/QDialogButtonBox>
|
||||||
|
#include <QtWidgets/QFormLayout>
|
||||||
|
#include <QtWidgets/QLineEdit>
|
||||||
|
#include <QtWidgets/QListWidget>
|
||||||
|
#include <QtWidgets/QMessageBox>
|
||||||
|
#include <QtWidgets/QPushButton>
|
||||||
|
#include <QtWidgets/QVBoxLayout>
|
||||||
|
|
||||||
|
StructEditDialog::StructEditDialog(ShaderGraph& graph, QWidget* parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
m_shaderGraph(graph)
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Struct edit dialog"));
|
||||||
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
|
m_structName = new QLineEdit;
|
||||||
|
connect(m_structName, &QLineEdit::textEdited, [this](QString newText)
|
||||||
|
{
|
||||||
|
m_info.name = newText.toStdString();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_memberList = new QListWidget;
|
||||||
|
connect(m_memberList, &QListWidget::currentRowChanged, this, &StructEditDialog::OnMemberSelected);
|
||||||
|
connect(m_memberList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item)
|
||||||
|
{
|
||||||
|
OnEditMember(m_memberList->row(item));
|
||||||
|
});
|
||||||
|
|
||||||
|
m_memberMoveUpButton = new QPushButton(tr("Move up"));
|
||||||
|
m_memberMoveUpButton->setEnabled(false);
|
||||||
|
connect(m_memberMoveUpButton, &QPushButton::released, this, &StructEditDialog::OnMemberMoveUp);
|
||||||
|
|
||||||
|
m_memberMoveDownButton = new QPushButton(tr("Move down"));
|
||||||
|
m_memberMoveDownButton->setEnabled(false);
|
||||||
|
connect(m_memberMoveDownButton, &QPushButton::released, this, &StructEditDialog::OnMemberMoveDown);
|
||||||
|
|
||||||
|
m_deleteMemberButton = new QPushButton(tr("Delete member"));
|
||||||
|
m_deleteMemberButton->setEnabled(false);
|
||||||
|
connect(m_deleteMemberButton, &QPushButton::released, this, &StructEditDialog::OnDeleteMember);
|
||||||
|
|
||||||
|
QPushButton* addMemberButton = new QPushButton(tr("Add member..."));
|
||||||
|
connect(addMemberButton, &QPushButton::released, this, &StructEditDialog::OnAddMember);
|
||||||
|
|
||||||
|
QVBoxLayout* arrowLayout = new QVBoxLayout;
|
||||||
|
arrowLayout->addWidget(m_memberMoveUpButton);
|
||||||
|
arrowLayout->addWidget(m_memberMoveDownButton);
|
||||||
|
arrowLayout->addWidget(m_deleteMemberButton);
|
||||||
|
arrowLayout->addWidget(addMemberButton);
|
||||||
|
|
||||||
|
QHBoxLayout* entityListLayout = new QHBoxLayout;
|
||||||
|
entityListLayout->addWidget(m_memberList);
|
||||||
|
entityListLayout->addLayout(arrowLayout);
|
||||||
|
|
||||||
|
QFormLayout* formLayout = new QFormLayout;
|
||||||
|
formLayout->addRow(tr("Name"), m_structName);
|
||||||
|
formLayout->addRow(tr("Members"), entityListLayout);
|
||||||
|
|
||||||
|
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &StructEditDialog::OnAccept);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
|
||||||
|
QVBoxLayout* verticalLayout = new QVBoxLayout;
|
||||||
|
verticalLayout->addLayout(formLayout);
|
||||||
|
verticalLayout->addWidget(buttonBox);
|
||||||
|
|
||||||
|
setLayout(verticalLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
StructEditDialog::StructEditDialog(ShaderGraph& graph, const StructInfo& structInfo, QWidget* parent) :
|
||||||
|
StructEditDialog(graph, parent)
|
||||||
|
{
|
||||||
|
m_info = structInfo;
|
||||||
|
|
||||||
|
m_structName->setText(QString::fromStdString(m_info.name));
|
||||||
|
UpdateMemberList();
|
||||||
|
}
|
||||||
|
|
||||||
|
const StructInfo& StructEditDialog::GetStructInfo() const
|
||||||
|
{
|
||||||
|
return m_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString StructEditDialog::GetMemberName(const StructInfo::Member& member)
|
||||||
|
{
|
||||||
|
QString name = QString::fromStdString(member.name) + " (";
|
||||||
|
|
||||||
|
std::visit([&](auto&& arg)
|
||||||
|
{
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, PrimitiveType>)
|
||||||
|
name += QString(EnumToString(arg));
|
||||||
|
else if constexpr (std::is_same_v<T, std::size_t>)
|
||||||
|
name += QString::fromStdString(m_shaderGraph.GetStruct(arg).name);
|
||||||
|
else
|
||||||
|
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
||||||
|
},
|
||||||
|
member.type);
|
||||||
|
|
||||||
|
name += ")";
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditDialog::OnAccept()
|
||||||
|
{
|
||||||
|
if (m_info.name.empty())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Empty name"), tr("Struct name must be set"), QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditDialog::OnAddMember()
|
||||||
|
{
|
||||||
|
StructMemberEditDialog* dialog = new StructMemberEditDialog(m_shaderGraph, this);
|
||||||
|
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
|
connect(dialog, &QDialog::accepted, [this, dialog]
|
||||||
|
{
|
||||||
|
const StructMemberInfo& structInfo = dialog->GetMemberInfo();
|
||||||
|
|
||||||
|
auto& memberInfo = m_info.members.emplace_back();
|
||||||
|
memberInfo.name = structInfo.name;
|
||||||
|
memberInfo.type = structInfo.type;
|
||||||
|
|
||||||
|
UpdateMemberList(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditDialog::OnDeleteMember()
|
||||||
|
{
|
||||||
|
int memberIndex = m_memberList->currentRow();
|
||||||
|
if (memberIndex < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_info.members.erase(m_info.members.begin() + memberIndex);
|
||||||
|
UpdateMemberList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditDialog::OnEditMember(int memberIndex)
|
||||||
|
{
|
||||||
|
assert(memberIndex >= 0);
|
||||||
|
|
||||||
|
auto& memberInfo = m_info.members[memberIndex];
|
||||||
|
|
||||||
|
StructMemberInfo info;
|
||||||
|
info.name = memberInfo.name;
|
||||||
|
info.type = memberInfo.type;
|
||||||
|
|
||||||
|
StructMemberEditDialog* dialog = new StructMemberEditDialog(m_shaderGraph, std::move(info), this);
|
||||||
|
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
|
connect(dialog, &QDialog::accepted, [this, dialog, &memberInfo]
|
||||||
|
{
|
||||||
|
const StructMemberInfo& structInfo = dialog->GetMemberInfo();
|
||||||
|
memberInfo.name = structInfo.name;
|
||||||
|
memberInfo.type = structInfo.type;
|
||||||
|
|
||||||
|
UpdateMemberList(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditDialog::OnMemberMoveUp()
|
||||||
|
{
|
||||||
|
int memberIndex = m_memberList->currentRow();
|
||||||
|
if (memberIndex <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::size_t newMemberIndex = static_cast<std::size_t>(memberIndex - 1);
|
||||||
|
std::swap(m_info.members[memberIndex], m_info.members[newMemberIndex]);
|
||||||
|
UpdateMemberList();
|
||||||
|
|
||||||
|
m_memberList->setCurrentRow(int(newMemberIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditDialog::OnMemberMoveDown()
|
||||||
|
{
|
||||||
|
int memberIndex = m_memberList->currentRow();
|
||||||
|
if (memberIndex < 0 || memberIndex + 1 >= m_memberList->count())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::size_t newMemberIndex = static_cast<std::size_t>(memberIndex + 1);
|
||||||
|
std::swap(m_info.members[memberIndex], m_info.members[newMemberIndex]);
|
||||||
|
UpdateMemberList();
|
||||||
|
|
||||||
|
m_memberList->setCurrentRow(int(newMemberIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditDialog::OnMemberSelected(int memberIndex)
|
||||||
|
{
|
||||||
|
if (memberIndex >= 0)
|
||||||
|
{
|
||||||
|
m_deleteMemberButton->setEnabled(true);
|
||||||
|
m_memberMoveDownButton->setEnabled(memberIndex + 1 < m_memberList->count());
|
||||||
|
m_memberMoveUpButton->setEnabled(memberIndex != 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_deleteMemberButton->setEnabled(false);
|
||||||
|
m_memberMoveDownButton->setEnabled(false);
|
||||||
|
m_memberMoveUpButton->setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditDialog::UpdateMemberList(bool keepSelection)
|
||||||
|
{
|
||||||
|
int selectionIndex = m_memberList->currentRow();
|
||||||
|
|
||||||
|
m_memberList->clear();
|
||||||
|
for (const auto& memberInfo : m_info.members)
|
||||||
|
m_memberList->addItem(GetMemberName(memberInfo));
|
||||||
|
|
||||||
|
if (keepSelection && selectionIndex >= 0 && selectionIndex < m_memberList->count())
|
||||||
|
m_memberList->setCurrentRow(selectionIndex);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SHADERNODES_STRUCTEDITDIALOG_HPP
|
||||||
|
#define NAZARA_SHADERNODES_STRUCTEDITDIALOG_HPP
|
||||||
|
|
||||||
|
#include <ShaderNode/Enums.hpp>
|
||||||
|
#include <QtWidgets/QDialog>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class QLineEdit;
|
||||||
|
class QListWidget;
|
||||||
|
class QPushButton;
|
||||||
|
class ShaderGraph;
|
||||||
|
|
||||||
|
struct StructInfo
|
||||||
|
{
|
||||||
|
struct Member
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::variant<PrimitiveType, std::size_t> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::vector<Member> members;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StructEditDialog : public QDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StructEditDialog(ShaderGraph& graph, QWidget* parent = nullptr);
|
||||||
|
StructEditDialog(ShaderGraph& graph, const StructInfo& output, QWidget* parent = nullptr);
|
||||||
|
~StructEditDialog() = default;
|
||||||
|
|
||||||
|
const StructInfo& GetStructInfo() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString GetMemberName(const StructInfo::Member& member);
|
||||||
|
void OnAccept();
|
||||||
|
void OnAddMember();
|
||||||
|
void OnDeleteMember();
|
||||||
|
void OnEditMember(int memberIndex);
|
||||||
|
void OnMemberMoveUp();
|
||||||
|
void OnMemberMoveDown();
|
||||||
|
void OnMemberSelected(int memberIndex);
|
||||||
|
void UpdateMemberList(bool keepSelection = false);
|
||||||
|
|
||||||
|
QLineEdit* m_structName;
|
||||||
|
QListWidget* m_memberList;
|
||||||
|
QPushButton* m_deleteMemberButton;
|
||||||
|
QPushButton* m_memberMoveUpButton;
|
||||||
|
QPushButton* m_memberMoveDownButton;
|
||||||
|
ShaderGraph& m_shaderGraph;
|
||||||
|
StructInfo m_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <ShaderNode/Widgets/StructEditDialog.inl>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
#include <ShaderNode/Widgets/StructEditDialog.hpp>
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
#include <ShaderNode/Widgets/StructEditor.hpp>
|
||||||
|
#include <ShaderNode/Widgets/StructEditDialog.hpp>
|
||||||
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
|
#include <QtWidgets/QFileDialog>
|
||||||
|
#include <QtWidgets/QLabel>
|
||||||
|
#include <QtWidgets/QPushButton>
|
||||||
|
#include <QtWidgets/QListWidget>
|
||||||
|
#include <QtWidgets/QVBoxLayout>
|
||||||
|
|
||||||
|
StructEditor::StructEditor(ShaderGraph& graph) :
|
||||||
|
m_shaderGraph(graph)
|
||||||
|
{
|
||||||
|
m_structList = new QListWidget(this);
|
||||||
|
connect(m_structList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item)
|
||||||
|
{
|
||||||
|
OnEditStruct(m_structList->row(item));
|
||||||
|
});
|
||||||
|
|
||||||
|
QPushButton* addStructButton = new QPushButton(tr("Add struct..."));
|
||||||
|
connect(addStructButton, &QPushButton::released, this, &StructEditor::OnAddStruct);
|
||||||
|
|
||||||
|
m_layout = new QVBoxLayout;
|
||||||
|
m_layout->addWidget(m_structList);
|
||||||
|
m_layout->addWidget(addStructButton);
|
||||||
|
|
||||||
|
setLayout(m_layout);
|
||||||
|
|
||||||
|
m_onStructListUpdateSlot.Connect(m_shaderGraph.OnStructListUpdate, this, &StructEditor::OnStructListUpdate);
|
||||||
|
m_onStructUpdateSlot.Connect(m_shaderGraph.OnStructUpdate, this, &StructEditor::OnStructUpdate);
|
||||||
|
|
||||||
|
RefreshStructs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditor::OnAddStruct()
|
||||||
|
{
|
||||||
|
StructEditDialog* dialog = new StructEditDialog(m_shaderGraph, this);
|
||||||
|
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
|
connect(dialog, &QDialog::accepted, [this, dialog]
|
||||||
|
{
|
||||||
|
const StructInfo& structInfo = dialog->GetStructInfo();
|
||||||
|
|
||||||
|
std::vector<ShaderGraph::StructMemberEntry> members;
|
||||||
|
for (const auto& memberInfo : structInfo.members)
|
||||||
|
{
|
||||||
|
auto& member = members.emplace_back();
|
||||||
|
member.name = memberInfo.name;
|
||||||
|
member.type = memberInfo.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_shaderGraph.AddStruct(std::move(structInfo.name), std::move(members));
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditor::OnEditStruct(int inputIndex)
|
||||||
|
{
|
||||||
|
const auto& structInfo = m_shaderGraph.GetStruct(inputIndex);
|
||||||
|
|
||||||
|
StructInfo info;
|
||||||
|
info.name = structInfo.name;
|
||||||
|
for (const auto& memberInfo : structInfo.members)
|
||||||
|
{
|
||||||
|
auto& member = info.members.emplace_back();
|
||||||
|
member.name = memberInfo.name;
|
||||||
|
member.type = memberInfo.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
StructEditDialog* dialog = new StructEditDialog(m_shaderGraph, std::move(info), this);
|
||||||
|
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
|
connect(dialog, &QDialog::accepted, [this, dialog, inputIndex]
|
||||||
|
{
|
||||||
|
const StructInfo& structInfo = dialog->GetStructInfo();
|
||||||
|
|
||||||
|
std::vector<ShaderGraph::StructMemberEntry> members;
|
||||||
|
for (const auto& memberInfo : structInfo.members)
|
||||||
|
{
|
||||||
|
auto& member = members.emplace_back();
|
||||||
|
member.name = memberInfo.name;
|
||||||
|
member.type = memberInfo.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_shaderGraph.UpdateStruct(inputIndex, std::move(structInfo.name), std::move(members));
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditor::OnStructListUpdate(ShaderGraph* /*graph*/)
|
||||||
|
{
|
||||||
|
RefreshStructs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditor::OnStructUpdate(ShaderGraph* /*graph*/, std::size_t structIndex)
|
||||||
|
{
|
||||||
|
const auto& structEntry = m_shaderGraph.GetStruct(structIndex);
|
||||||
|
m_structList->item(int(structIndex))->setText(QString::fromStdString(structEntry.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructEditor::RefreshStructs()
|
||||||
|
{
|
||||||
|
m_structList->clear();
|
||||||
|
m_structList->setCurrentRow(-1);
|
||||||
|
|
||||||
|
for (const auto& structEntry : m_shaderGraph.GetStructs())
|
||||||
|
m_structList->addItem(QString::fromStdString(structEntry.name));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SHADERNODES_STRUCTEDITOR_HPP
|
||||||
|
#define NAZARA_SHADERNODES_STRUCTEDITOR_HPP
|
||||||
|
|
||||||
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
|
#include <QtWidgets/QWidget>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
class QListWidget;
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
|
class StructEditor : public QWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StructEditor(ShaderGraph& graph);
|
||||||
|
~StructEditor() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnAddStruct();
|
||||||
|
void OnEditStruct(int inputIndex);
|
||||||
|
void OnStructListUpdate(ShaderGraph* graph);
|
||||||
|
void OnStructUpdate(ShaderGraph* graph, std::size_t inputIndex);
|
||||||
|
void RefreshStructs();
|
||||||
|
|
||||||
|
NazaraSlot(ShaderGraph, OnStructListUpdate, m_onStructListUpdateSlot);
|
||||||
|
NazaraSlot(ShaderGraph, OnStructUpdate, m_onStructUpdateSlot);
|
||||||
|
|
||||||
|
ShaderGraph& m_shaderGraph;
|
||||||
|
QListWidget* m_structList;
|
||||||
|
QVBoxLayout* m_layout;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <ShaderNode/Widgets/StructEditor.inl>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
#include <ShaderNode/Widgets/StructEditor.hpp>
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
#include <ShaderNode/Widgets/StructMemberEditDialog.hpp>
|
||||||
|
#include <ShaderNode/ShaderGraph.hpp>
|
||||||
|
#include <QtWidgets/QComboBox>
|
||||||
|
#include <QtWidgets/QDialogButtonBox>
|
||||||
|
#include <QtWidgets/QFormLayout>
|
||||||
|
#include <QtWidgets/QLineEdit>
|
||||||
|
#include <QtWidgets/QMessageBox>
|
||||||
|
#include <QtWidgets/QVBoxLayout>
|
||||||
|
|
||||||
|
StructMemberEditDialog::StructMemberEditDialog(const ShaderGraph& shaderGraph, QWidget* parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
m_shaderGraph(shaderGraph)
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Struct member edit dialog"));
|
||||||
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
|
m_memberName = new QLineEdit;
|
||||||
|
|
||||||
|
m_typeList = new QComboBox;
|
||||||
|
for (std::size_t i = 0; i < PrimitiveTypeCount; ++i)
|
||||||
|
m_typeList->addItem(EnumToString(static_cast<PrimitiveType>(i)));
|
||||||
|
|
||||||
|
for (const auto& structInfo : m_shaderGraph.GetStructs())
|
||||||
|
m_typeList->addItem(QString::fromStdString(structInfo.name));
|
||||||
|
|
||||||
|
QFormLayout* formLayout = new QFormLayout;
|
||||||
|
formLayout->addRow(tr("Name"), m_memberName);
|
||||||
|
formLayout->addRow(tr("Type"), m_typeList);
|
||||||
|
|
||||||
|
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &StructMemberEditDialog::OnAccept);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
|
||||||
|
QVBoxLayout* verticalLayout = new QVBoxLayout;
|
||||||
|
verticalLayout->addLayout(formLayout);
|
||||||
|
verticalLayout->addWidget(buttonBox);
|
||||||
|
|
||||||
|
setLayout(verticalLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
StructMemberEditDialog::StructMemberEditDialog(const ShaderGraph& shaderGraph, const StructMemberInfo& member, QWidget* parent) :
|
||||||
|
StructMemberEditDialog(shaderGraph, parent)
|
||||||
|
{
|
||||||
|
m_memberName->setText(QString::fromStdString(member.name));
|
||||||
|
std::visit([&](auto&& arg)
|
||||||
|
{
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, PrimitiveType>)
|
||||||
|
m_typeList->setCurrentIndex(static_cast<int>(arg));
|
||||||
|
else if constexpr (std::is_same_v<T, std::size_t>)
|
||||||
|
m_typeList->setCurrentIndex(static_cast<int>(PrimitiveTypeCount + arg));
|
||||||
|
else
|
||||||
|
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
||||||
|
},
|
||||||
|
member.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
StructMemberInfo StructMemberEditDialog::GetMemberInfo() const
|
||||||
|
{
|
||||||
|
StructMemberInfo inputInfo;
|
||||||
|
inputInfo.name = m_memberName->text().toStdString();
|
||||||
|
|
||||||
|
if (m_typeList->currentIndex() < PrimitiveTypeCount)
|
||||||
|
inputInfo.type = static_cast<PrimitiveType>(m_typeList->currentIndex());
|
||||||
|
else
|
||||||
|
inputInfo.type = static_cast<std::size_t>(m_typeList->currentIndex() - PrimitiveTypeCount);
|
||||||
|
|
||||||
|
return inputInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructMemberEditDialog::OnAccept()
|
||||||
|
{
|
||||||
|
if (m_memberName->text().isEmpty())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Empty name"), tr("Struct member name must be set"), QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_typeList->currentIndex() < 0)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Invalid type"), tr("You must select a type"), QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
accept();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SHADERNODES_OUTPUTEDITDIALOG_HPP
|
||||||
|
#define NAZARA_SHADERNODES_OUTPUTEDITDIALOG_HPP
|
||||||
|
|
||||||
|
#include <ShaderNode/Enums.hpp>
|
||||||
|
#include <QtWidgets/QDialog>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
class QComboBox;
|
||||||
|
class QLineEdit;
|
||||||
|
class ShaderGraph;
|
||||||
|
|
||||||
|
struct StructMemberInfo
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::variant<PrimitiveType, std::size_t> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StructMemberEditDialog : public QDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StructMemberEditDialog(const ShaderGraph& shaderGraph, QWidget* parent = nullptr);
|
||||||
|
StructMemberEditDialog(const ShaderGraph& shaderGraph, const StructMemberInfo& output, QWidget* parent = nullptr);
|
||||||
|
~StructMemberEditDialog() = default;
|
||||||
|
|
||||||
|
StructMemberInfo GetMemberInfo() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnAccept();
|
||||||
|
|
||||||
|
const ShaderGraph& m_shaderGraph;
|
||||||
|
QComboBox* m_typeList;
|
||||||
|
QLineEdit* m_memberName;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <ShaderNode/Widgets/StructMemberEditDialog.inl>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
#include <ShaderNode/Widgets/StructMemberEditDialog.hpp>
|
||||||
Loading…
Reference in New Issue