Finish BufferField

This commit is contained in:
Jérôme Leclercq 2020-07-20 20:41:22 +02:00
parent 042eb067a0
commit 5ce67f434b
4 changed files with 299 additions and 235 deletions

View File

@ -7,6 +7,7 @@
#include <Nazara/Renderer/ShaderBuilder.hpp> #include <Nazara/Renderer/ShaderBuilder.hpp>
#include <QtWidgets/QFormLayout> #include <QtWidgets/QFormLayout>
#include <iostream> #include <iostream>
#include <sstream>
BufferField::BufferField(ShaderGraph& graph) : BufferField::BufferField(ShaderGraph& graph) :
ShaderNode(graph) ShaderNode(graph)
@ -17,20 +18,78 @@ ShaderNode(graph)
if (m_currentBufferIndex == bufferIndex) if (m_currentBufferIndex == bufferIndex)
{ {
UpdatePreview(); UpdatePreview();
Q_EMIT dataUpdated(0); Q_EMIT dataUpdated(0);
} }
}); });
if (graph.GetBufferCount() > 0) m_onStructListUpdateSlot.Connect(GetGraph().OnStructListUpdate, [&](ShaderGraph*)
{ {
m_currentBufferIndex = 0; UpdateFieldIndex();
UpdateBufferText(); UpdatePreview();
}
Q_EMIT dataUpdated(0);
});
m_onStructUpdateSlot.Connect(GetGraph().OnStructUpdate, [&](ShaderGraph*, std::size_t)
{
UpdateFieldIndex();
UpdatePreview();
Q_EMIT dataUpdated(0);
});
DisableCustomVariableName(); DisableCustomVariableName();
UpdatePreview(); UpdatePreview();
} }
Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const
{
assert(count == 0);
if (!m_currentBufferIndex)
throw std::runtime_error("no buffer");
const ShaderGraph& graph = GetGraph();
const auto& bufferEntry = graph.GetBuffer(*m_currentBufferIndex);
const auto& structEntry = graph.GetStruct(bufferEntry.structIndex);
Nz::ShaderNodes::VariablePtr varPtr;
switch (bufferEntry.type)
{
case BufferType::UniformBufferObject:
varPtr = Nz::ShaderBuilder::Uniform(bufferEntry.name, structEntry.name);
break;
}
assert(varPtr);
assert(m_currentFieldIndex);
const CurrentField& currentField = *m_currentFieldIndex;
Nz::ShaderNodes::ExpressionPtr sourceExpr = Nz::ShaderBuilder::Identifier(varPtr);
const ShaderGraph::StructEntry* sourceStruct = &structEntry;
for (std::size_t nestedIndex : currentField.nestedFields)
{
assert(nestedIndex < sourceStruct->members.size());
const auto& memberEntry = sourceStruct->members[nestedIndex];
assert(std::holds_alternative<std::size_t>(memberEntry.type));
std::size_t nestedStructIndex = std::get<std::size_t>(memberEntry.type);
sourceStruct = &graph.GetStruct(nestedStructIndex);
sourceExpr = Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(memberEntry.type));
}
assert(currentField.finalFieldIndex < sourceStruct->members.size());
const auto& memberEntry = sourceStruct->members[currentField.finalFieldIndex];
assert(std::holds_alternative<PrimitiveType>(memberEntry.type));
return Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(std::get<PrimitiveType>(memberEntry.type)));
}
unsigned int BufferField::nPorts(QtNodes::PortType portType) const unsigned int BufferField::nPorts(QtNodes::PortType portType) const
{ {
switch (portType) switch (portType)
@ -42,6 +101,211 @@ unsigned int BufferField::nPorts(QtNodes::PortType portType) const
return 0; return 0;
} }
void BufferField::BuildNodeEdition(QFormLayout* layout)
{
ShaderNode::BuildNodeEdition(layout);
QComboBox* fieldSelection = new QComboBox;
connect(fieldSelection, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index)
{
if (index >= 0)
m_currentFieldText = fieldSelection->itemText(index).toStdString();
else
m_currentFieldText.clear();
UpdateFieldIndex();
UpdatePreview();
Q_EMIT dataUpdated(0);
});
QComboBox* bufferSelection = new QComboBox;
for (const auto& inputEntry : GetGraph().GetBuffers())
bufferSelection->addItem(QString::fromStdString(inputEntry.name));
connect(bufferSelection, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index)
{
fieldSelection->clear();
fieldSelection->setCurrentIndex(-1);
if (index >= 0)
{
m_currentBufferIndex = static_cast<std::size_t>(index);
const ShaderGraph& graph = GetGraph();
const auto& buffer = graph.GetBuffer(*m_currentBufferIndex);
PopulateField(fieldSelection, buffer.structIndex);
}
else
m_currentBufferIndex.reset();
UpdateBufferText();
});
if (m_currentBufferIndex)
{
int index = int(*m_currentBufferIndex);
QString currentFieldText = QString::fromStdString(m_currentFieldText);
bufferSelection->setCurrentIndex(-1);
bufferSelection->setCurrentIndex(index);
fieldSelection->setCurrentText(currentFieldText);
}
else
{
bufferSelection->setCurrentIndex(-1);
fieldSelection->setCurrentIndex(-1);
}
layout->addRow(tr("Buffer"), bufferSelection);
layout->addRow(tr("Field"), fieldSelection);
}
auto BufferField::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType
{
assert(portType == QtNodes::PortType::Out);
assert(portIndex == 0);
if (!m_currentBufferIndex || !m_currentFieldIndex)
return VecData::Type();
const auto& member = RetrieveNestedMember();
assert(std::holds_alternative<PrimitiveType>(member.type));
switch (std::get<PrimitiveType>(member.type))
{
case PrimitiveType::Bool:
return BoolData::Type();
case PrimitiveType::Float1:
return FloatData::Type();
case PrimitiveType::Float2:
case PrimitiveType::Float3:
case PrimitiveType::Float4:
return VecData::Type();
}
assert(false);
throw std::runtime_error("Unhandled primitive type");
}
QString BufferField::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
{
assert(portType == QtNodes::PortType::Out);
assert(portIndex == 0);
if (!m_currentBufferIndex || !m_currentFieldIndex)
return "<No field>";
std::stringstream ss;
const ShaderGraph& graph = GetGraph();
const auto& bufferEntry = graph.GetBuffer(*m_currentBufferIndex);
const auto& structEntry = graph.GetStruct(bufferEntry.structIndex);
ss << bufferEntry.name << ".";
const CurrentField& currentField = *m_currentFieldIndex;
const ShaderGraph::StructEntry* sourceStruct = &structEntry;
for (std::size_t nestedIndex : currentField.nestedFields)
{
assert(nestedIndex < sourceStruct->members.size());
const auto& memberEntry = sourceStruct->members[nestedIndex];
assert(std::holds_alternative<std::size_t>(memberEntry.type));
std::size_t nestedStructIndex = std::get<std::size_t>(memberEntry.type);
sourceStruct = &graph.GetStruct(nestedStructIndex);
ss << memberEntry.name << ".";
}
assert(currentField.finalFieldIndex < sourceStruct->members.size());
const auto& memberEntry = sourceStruct->members[currentField.finalFieldIndex];
assert(std::holds_alternative<PrimitiveType>(memberEntry.type));
ss << memberEntry.name;
return QString::fromStdString(ss.str());
}
bool BufferField::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
{
assert(portType == QtNodes::PortType::Out);
assert(portIndex == 0);
return true;
}
std::shared_ptr<QtNodes::NodeData> BufferField::outData(QtNodes::PortIndex port)
{
if (!m_currentBufferIndex)
return nullptr;
assert(port == 0);
if (!m_currentBufferIndex || !m_currentFieldIndex)
return {};
const auto& member = RetrieveNestedMember();
assert(std::holds_alternative<PrimitiveType>(member.type));
switch (std::get<PrimitiveType>(member.type))
{
case PrimitiveType::Bool: return std::make_shared<BoolData>();
case PrimitiveType::Float1: return std::make_shared<FloatData>();
case PrimitiveType::Float2: return std::make_shared<VecData>(2);
case PrimitiveType::Float3: return std::make_shared<VecData>(3);
case PrimitiveType::Float4: return std::make_shared<VecData>(4);
}
assert(false);
throw std::runtime_error("Unhandled primitive type");
}
void BufferField::restore(const QJsonObject& data)
{
m_currentBufferText = data["buffer"].toString().toStdString();
m_currentFieldText = data["field"].toString().toStdString();
UpdateBufferIndex();
ShaderNode::restore(data);
}
QJsonObject BufferField::save() const
{
QJsonObject data = ShaderNode::save();
data["buffer"] = QString::fromStdString(m_currentBufferText);
data["field"] = QString::fromStdString(m_currentFieldText);
return data;
}
QtNodes::NodeValidationState BufferField::validationState() const
{
if (!m_currentBufferIndex)
return QtNodes::NodeValidationState::Error;
if (!m_currentFieldIndex)
return QtNodes::NodeValidationState::Error;
return QtNodes::NodeValidationState::Valid;
}
QString BufferField::validationMessage() const
{
if (!m_currentBufferIndex)
return "No input selected";
if (!m_currentFieldIndex)
return "No field selected";
return QString();
}
bool BufferField::ComputePreview(QPixmap& pixmap) bool BufferField::ComputePreview(QPixmap& pixmap)
{ {
return false; return false;
@ -136,67 +400,6 @@ void BufferField::UpdateBufferText()
m_currentBufferText.clear(); m_currentBufferText.clear();
} }
void BufferField::BuildNodeEdition(QFormLayout* layout)
{
ShaderNode::BuildNodeEdition(layout);
QComboBox* fieldSelection = new QComboBox;
connect(fieldSelection, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index)
{
if (index >= 0)
m_currentFieldText = fieldSelection->itemText(index).toStdString();
else
m_currentFieldText.clear();
UpdateFieldIndex();
UpdatePreview();
Q_EMIT dataUpdated(0);
});
QComboBox* bufferSelection = new QComboBox;
for (const auto& inputEntry : GetGraph().GetBuffers())
bufferSelection->addItem(QString::fromStdString(inputEntry.name));
connect(bufferSelection, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index)
{
fieldSelection->clear();
fieldSelection->setCurrentIndex(-1);
if (index >= 0)
{
m_currentBufferIndex = static_cast<std::size_t>(index);
const ShaderGraph& graph = GetGraph();
const auto& buffer = graph.GetBuffer(*m_currentBufferIndex);
PopulateField(fieldSelection, buffer.structIndex);
}
else
m_currentBufferIndex.reset();
UpdateBufferText();
});
if (m_currentBufferIndex)
{
int index = int(*m_currentBufferIndex);
QString currentFieldText = QString::fromStdString(m_currentFieldText);
bufferSelection->setCurrentIndex(-1);
bufferSelection->setCurrentIndex(index);
fieldSelection->setCurrentText(currentFieldText);
}
else
{
bufferSelection->setCurrentIndex(-1);
fieldSelection->setCurrentIndex(-1);
}
layout->addRow(tr("Buffer"), bufferSelection);
layout->addRow(tr("Field"), fieldSelection);
}
void BufferField::UpdateFieldIndex() void BufferField::UpdateFieldIndex()
{ {
Nz::CallOnExit resetIfNotFound([&] Nz::CallOnExit resetIfNotFound([&]
@ -265,145 +468,3 @@ void BufferField::UpdateFieldIndex()
if (FetchField(buffer.structIndex, "")) if (FetchField(buffer.structIndex, ""))
resetIfNotFound.Reset(); resetIfNotFound.Reset();
} }
Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const
{
assert(count == 0);
if (!m_currentBufferIndex)
throw std::runtime_error("no buffer");
const ShaderGraph& graph = GetGraph();
const auto& bufferEntry = graph.GetBuffer(*m_currentBufferIndex);
const auto& structEntry = graph.GetStruct(bufferEntry.structIndex);
Nz::ShaderNodes::VariablePtr varPtr;
switch (bufferEntry.type)
{
case BufferType::UniformBufferObject:
varPtr = Nz::ShaderBuilder::Uniform(bufferEntry.name, structEntry.name);
break;
}
assert(varPtr);
assert(m_currentFieldIndex);
const CurrentField& currentField = *m_currentFieldIndex;
Nz::ShaderNodes::ExpressionPtr sourceExpr = Nz::ShaderBuilder::Identifier(varPtr);
const ShaderGraph::StructEntry* sourceStruct = &structEntry;
for (std::size_t nestedIndex : currentField.nestedFields)
{
assert(nestedIndex < sourceStruct->members.size());
const auto& memberEntry = sourceStruct->members[nestedIndex];
assert(std::holds_alternative<std::size_t>(memberEntry.type));
std::size_t nestedStructIndex = std::get<std::size_t>(memberEntry.type);
sourceStruct = &graph.GetStruct(nestedStructIndex);
sourceExpr = Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(memberEntry.type));
}
assert(currentField.finalFieldIndex < sourceStruct->members.size());
const auto& memberEntry = sourceStruct->members[currentField.finalFieldIndex];
assert(std::holds_alternative<PrimitiveType>(memberEntry.type));
return Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(std::get<PrimitiveType>(memberEntry.type)));
}
auto BufferField::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType
{
assert(portType == QtNodes::PortType::Out);
assert(portIndex == 0);
if (!m_currentBufferIndex || !m_currentFieldIndex)
return VecData::Type();
const auto& member = RetrieveNestedMember();
assert(std::holds_alternative<PrimitiveType>(member.type));
switch (std::get<PrimitiveType>(member.type))
{
case PrimitiveType::Bool:
return BoolData::Type();
case PrimitiveType::Float1:
return FloatData::Type();
case PrimitiveType::Float2:
case PrimitiveType::Float3:
case PrimitiveType::Float4:
return VecData::Type();
}
assert(false);
throw std::runtime_error("Unhandled primitive type");
}
std::shared_ptr<QtNodes::NodeData> BufferField::outData(QtNodes::PortIndex port)
{
if (!m_currentBufferIndex)
return nullptr;
assert(port == 0);
if (!m_currentBufferIndex || !m_currentFieldIndex)
return {};
const auto& member = RetrieveNestedMember();
assert(std::holds_alternative<PrimitiveType>(member.type));
switch (std::get<PrimitiveType>(member.type))
{
case PrimitiveType::Bool: return std::make_shared<BoolData>();
case PrimitiveType::Float1: return std::make_shared<FloatData>();
case PrimitiveType::Float2: return std::make_shared<VecData>(2);
case PrimitiveType::Float3: return std::make_shared<VecData>(3);
case PrimitiveType::Float4: return std::make_shared<VecData>(4);
}
assert(false);
throw std::runtime_error("Unhandled primitive type");
}
QtNodes::NodeValidationState BufferField::validationState() const
{
if (!m_currentBufferIndex)
return QtNodes::NodeValidationState::Error;
if (!m_currentFieldIndex)
return QtNodes::NodeValidationState::Error;
return QtNodes::NodeValidationState::Valid;
}
QString BufferField::validationMessage() const
{
if (!m_currentBufferIndex)
return "No input selected";
if (!m_currentFieldIndex)
return "No field selected";
return QString();
}
void BufferField::restore(const QJsonObject& data)
{
m_currentBufferText = data["buffer"].toString().toStdString();
m_currentFieldText = data["field"].toString().toStdString();
UpdateBufferIndex();
ShaderNode::restore(data);
}
QJsonObject BufferField::save() const
{
QJsonObject data = ShaderNode::save();
data["buffer"] = QString::fromStdString(m_currentBufferText);
data["field"] = QString::fromStdString(m_currentFieldText);
return data;
}

View File

@ -28,8 +28,14 @@ class BufferField : public ShaderNode
QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex port) override; std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex port) override;
void restore(const QJsonObject& data) override;
QJsonObject save() const override;
QtNodes::NodeValidationState validationState() const override; QtNodes::NodeValidationState validationState() const override;
QString validationMessage() const override; QString validationMessage() const override;
@ -41,9 +47,6 @@ class BufferField : public ShaderNode
void UpdateBufferText(); void UpdateBufferText();
void UpdateFieldIndex(); void UpdateFieldIndex();
void restore(const QJsonObject& data) override;
QJsonObject save() const override;
NazaraSlot(ShaderGraph, OnBufferListUpdate, m_onBufferListUpdateSlot); NazaraSlot(ShaderGraph, OnBufferListUpdate, m_onBufferListUpdateSlot);
NazaraSlot(ShaderGraph, OnBufferUpdate, m_onBufferUpdateSlot); NazaraSlot(ShaderGraph, OnBufferUpdate, m_onBufferUpdateSlot);

View File

@ -89,10 +89,6 @@ QWidget* ShaderNode::embeddedWidget()
return m_pixmapLabel; return m_pixmapLabel;
} }
void ShaderNode::setInData(std::shared_ptr<QtNodes::NodeData>, int)
{
}
void ShaderNode::restore(const QJsonObject& data) void ShaderNode::restore(const QJsonObject& data)
{ {
NodeDataModel::restore(data); NodeDataModel::restore(data);
@ -116,6 +112,10 @@ QJsonObject ShaderNode::save() const
return data; return data;
} }
void ShaderNode::setInData(std::shared_ptr<QtNodes::NodeData>, int)
{
}
bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/) bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/)
{ {
return false; return false;

View File

@ -33,6 +33,9 @@ class ShaderNode : public QtNodes::NodeDataModel
QWidget* embeddedWidget() final; QWidget* embeddedWidget() final;
void restore(const QJsonObject& data) override;
QJsonObject save() const override;
void setInData(std::shared_ptr<QtNodes::NodeData>, int) override; void setInData(std::shared_ptr<QtNodes::NodeData>, int) override;
protected: protected:
@ -40,9 +43,6 @@ 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);