ShaderNode: Add texture support
This commit is contained in:
parent
effaa9b88f
commit
33c8fe2562
|
|
@ -4,12 +4,21 @@
|
|||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||
|
||||
SampleTexture::SampleTexture(ShaderGraph& graph) :
|
||||
ShaderNode(graph)
|
||||
ShaderNode(graph),
|
||||
m_currentTextureIndex(0)
|
||||
{
|
||||
m_layout = new QVBoxLayout;
|
||||
|
||||
m_textureSelection = new QComboBox;
|
||||
m_textureSelection->setStyleSheet("background-color: rgba(255,255,255,255)");
|
||||
connect(m_textureSelection, qOverload<int>(&QComboBox::currentIndexChanged), [&](int index)
|
||||
{
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
m_currentTextureIndex = static_cast<std::size_t>(index);
|
||||
UpdatePreview();
|
||||
});
|
||||
|
||||
m_layout->addWidget(m_textureSelection);
|
||||
|
||||
|
|
@ -25,8 +34,15 @@ ShaderNode(graph)
|
|||
m_widget->setStyleSheet("background-color: rgba(0,0,0,0)");
|
||||
m_widget->setLayout(m_layout);
|
||||
|
||||
m_onTextureListUpdate.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { UpdateTextureList(); });
|
||||
m_onTextureListUpdateSlot.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { UpdateTextureList(); });
|
||||
m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, [&](ShaderGraph*, std::size_t textureIndex)
|
||||
{
|
||||
if (m_currentTextureIndex == textureIndex)
|
||||
UpdatePreview();
|
||||
});
|
||||
|
||||
UpdateTextureList();
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
QWidget* SampleTexture::embeddedWidget()
|
||||
|
|
@ -47,8 +63,13 @@ unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const
|
|||
|
||||
void SampleTexture::UpdatePreview()
|
||||
{
|
||||
if (m_textureSelection->count() == 0)
|
||||
return;
|
||||
|
||||
ComputePreview(m_pixmap);
|
||||
m_pixmapLabel->setPixmap(m_pixmap);
|
||||
|
||||
Q_EMIT dataUpdated(0);
|
||||
}
|
||||
|
||||
void SampleTexture::UpdateTextureList()
|
||||
|
|
@ -64,7 +85,9 @@ void SampleTexture::UpdateTextureList()
|
|||
|
||||
void SampleTexture::ComputePreview(QPixmap& pixmap) const
|
||||
{
|
||||
pixmap.fill();
|
||||
const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex);
|
||||
|
||||
pixmap = QPixmap::fromImage(textureEntry.preview).scaled(128, 128, Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const
|
||||
|
|
@ -102,5 +125,10 @@ std::shared_ptr<QtNodes::NodeData> SampleTexture::outData(QtNodes::PortIndex por
|
|||
{
|
||||
assert(port == 0);
|
||||
|
||||
return std::make_shared<Vec4Data>(Nz::Vector4f::Zero());
|
||||
const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex);
|
||||
|
||||
auto vecData = std::make_shared<Vec4Data>();
|
||||
vecData->preview = textureEntry.preview;
|
||||
|
||||
return vecData;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,13 +28,14 @@ class SampleTexture : public ShaderNode
|
|||
std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex port) override;
|
||||
|
||||
protected:
|
||||
void ComputePreview(QPixmap& pixmap) const;
|
||||
void UpdatePreview();
|
||||
void UpdateTextureList();
|
||||
|
||||
void ComputePreview(QPixmap& pixmap) const;
|
||||
|
||||
NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdate);
|
||||
NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot);
|
||||
NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot);
|
||||
|
||||
std::size_t m_currentTextureIndex;
|
||||
QComboBox* m_textureSelection;
|
||||
QLabel* m_pixmapLabel;
|
||||
QPixmap m_pixmap;
|
||||
|
|
|
|||
|
|
@ -1 +1,5 @@
|
|||
#include <DataModels/ShaderNode.hpp>
|
||||
|
||||
void ShaderNode::setInData(std::shared_ptr<QtNodes::NodeData>, int)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class ShaderNode : public QtNodes::NodeDataModel
|
|||
inline ShaderGraph& GetGraph();
|
||||
inline const ShaderGraph& GetGraph() const;
|
||||
|
||||
void setInData(std::shared_ptr<QtNodes::NodeData>, int) override {};
|
||||
void setInData(std::shared_ptr<QtNodes::NodeData>, int) override;
|
||||
|
||||
private:
|
||||
ShaderGraph& m_graph;
|
||||
|
|
|
|||
|
|
@ -1 +1,23 @@
|
|||
#include <DataModels/VecBinOp.hpp>
|
||||
|
||||
void Vec4Add::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount)
|
||||
{
|
||||
for (std::size_t i = 0; i < pixelCount; ++i)
|
||||
{
|
||||
unsigned int lValue = left[i];
|
||||
unsigned int rValue = right[i];
|
||||
|
||||
output[i] = static_cast<std::uint8_t>(std::min(lValue + rValue, 255U));
|
||||
}
|
||||
}
|
||||
|
||||
void Vec4Mul::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount)
|
||||
{
|
||||
for (std::size_t i = 0; i < pixelCount; ++i)
|
||||
{
|
||||
unsigned int lValue = left[i];
|
||||
unsigned int rValue = right[i];
|
||||
|
||||
output[i] = static_cast<std::uint8_t>(lValue * rValue / 255);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,16 +25,14 @@ class VecBinOp : public ShaderNode
|
|||
void setInData(std::shared_ptr<QtNodes::NodeData> value, int index) override;
|
||||
|
||||
private:
|
||||
virtual void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) = 0;
|
||||
void UpdatePreview();
|
||||
|
||||
using InternalType = typename Data::InternalType;
|
||||
|
||||
InternalType GetValue() const;
|
||||
|
||||
QLabel* m_pixmapLabel;
|
||||
QPixmap m_preview;
|
||||
std::shared_ptr<Vec4Data> m_lhs;
|
||||
std::shared_ptr<Vec4Data> m_rhs;
|
||||
std::shared_ptr<Vec4Data> m_output;
|
||||
};
|
||||
|
||||
class Vec4Add : public VecBinOp<Vec4Data, Nz::ShaderAst::BinaryType::Add>
|
||||
|
|
@ -44,6 +42,8 @@ class Vec4Add : public VecBinOp<Vec4Data, Nz::ShaderAst::BinaryType::Add>
|
|||
|
||||
QString caption() const override { return "Vec4 addition"; }
|
||||
QString name() const override { return "Vec4Add"; }
|
||||
|
||||
void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override;
|
||||
};
|
||||
|
||||
class Vec4Mul : public VecBinOp<Vec4Data, Nz::ShaderAst::BinaryType::Multiply>
|
||||
|
|
@ -53,6 +53,8 @@ class Vec4Mul : public VecBinOp<Vec4Data, Nz::ShaderAst::BinaryType::Multiply>
|
|||
|
||||
QString caption() const override { return "Vec4 multiplication"; }
|
||||
QString name() const override { return "Vec4Mul"; }
|
||||
|
||||
void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override;
|
||||
};
|
||||
|
||||
#include <DataModels/VecBinOp.inl>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@ template<typename Data, Nz::ShaderAst::BinaryType BinOp>
|
|||
VecBinOp<Data, BinOp>::VecBinOp(ShaderGraph& graph) :
|
||||
ShaderNode(graph)
|
||||
{
|
||||
m_preview = QPixmap(64, 64);
|
||||
m_output = std::make_shared<Data>();
|
||||
|
||||
m_pixmapLabel = new QLabel;
|
||||
m_pixmapLabel->setPixmap(m_preview);
|
||||
m_pixmapLabel->setStyleSheet("background-color: rgba(0,0,0,0)");
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
template<typename Data, Nz::ShaderAst::BinaryType BinOp>
|
||||
|
|
@ -50,17 +51,18 @@ template<typename Data, Nz::ShaderAst::BinaryType BinOp>
|
|||
std::shared_ptr<QtNodes::NodeData> VecBinOp<Data, BinOp>::outData(QtNodes::PortIndex port)
|
||||
{
|
||||
assert(port == 0);
|
||||
return std::make_shared<Data>(GetValue());
|
||||
return m_output;
|
||||
}
|
||||
|
||||
template<typename Data, Nz::ShaderAst::BinaryType BinOp>
|
||||
void VecBinOp<Data, BinOp>::setInData(std::shared_ptr<QtNodes::NodeData> value, int index)
|
||||
{
|
||||
assert(index == 0 || index == 1);
|
||||
|
||||
std::shared_ptr<Data> castedValue;
|
||||
if (value)
|
||||
{
|
||||
assert(dynamic_cast<Data*>(value.get()) != nullptr);
|
||||
assert(index == 0 || index == 1);
|
||||
|
||||
castedValue = std::static_pointer_cast<Data>(value);
|
||||
}
|
||||
|
|
@ -78,16 +80,36 @@ void VecBinOp<Data, BinOp>::setInData(std::shared_ptr<QtNodes::NodeData> value,
|
|||
template<typename Data, Nz::ShaderAst::BinaryType BinOp>
|
||||
void VecBinOp<Data, BinOp>::UpdatePreview()
|
||||
{
|
||||
InternalType value = GetValue();
|
||||
m_preview.fill(QColor::fromRgbF(value.x, value.y, value.z, value.w));
|
||||
if (m_lhs && m_rhs)
|
||||
{
|
||||
const QImage& leftPreview = m_lhs->preview;
|
||||
const QImage& rightPreview = m_rhs->preview;
|
||||
int maxWidth = std::max(leftPreview.width(), rightPreview.width());
|
||||
int maxHeight = std::max(leftPreview.height(), rightPreview.height());
|
||||
|
||||
// Exploit COW
|
||||
QImage leftResized = leftPreview;
|
||||
if (leftResized.width() != maxWidth || leftResized.height() != maxHeight)
|
||||
leftResized = leftResized.scaled(maxWidth, maxHeight);
|
||||
|
||||
QImage rightResized = rightPreview;
|
||||
if (rightResized.width() != maxWidth || rightResized.height() != maxHeight)
|
||||
rightResized = rightResized.scaled(maxWidth, maxHeight);
|
||||
|
||||
int w = m_output->preview.width();
|
||||
int h = m_output->preview.height();
|
||||
|
||||
m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888);
|
||||
ApplyOp(leftResized.constBits(), rightResized.constBits(), m_output->preview.bits(), maxWidth * maxHeight * 4);
|
||||
m_output->preview = m_output->preview.scaled(w, h);
|
||||
|
||||
m_preview = QPixmap::fromImage(m_output->preview, Qt::AutoColor | Qt::NoOpaqueDetection);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_preview = QPixmap(64, 64);
|
||||
m_preview.fill(QColor::fromRgb(255, 255, 0, 0));
|
||||
}
|
||||
|
||||
m_pixmapLabel->setPixmap(m_preview);
|
||||
}
|
||||
|
||||
template<typename Data, Nz::ShaderAst::BinaryType BinOp>
|
||||
auto VecBinOp<Data, BinOp>::GetValue() const -> InternalType
|
||||
{
|
||||
if (!m_lhs || !m_rhs)
|
||||
return InternalType::Zero();
|
||||
|
||||
return m_lhs->value * m_rhs->value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,89 +1 @@
|
|||
#include <DataModels/VecValue.hpp>
|
||||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||
|
||||
Vec2Value::Vec2Value(ShaderGraph& graph) :
|
||||
VecValue(graph)
|
||||
{
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
Nz::ShaderAst::ExpressionPtr Vec2Value::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const
|
||||
{
|
||||
assert(count == 0);
|
||||
|
||||
return Nz::ShaderBuilder::Constant(GetValue());
|
||||
}
|
||||
|
||||
auto Vec2Value::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType
|
||||
{
|
||||
assert(portType == QtNodes::PortType::Out);
|
||||
assert(portIndex == 0);
|
||||
|
||||
return Vec2Data::Type();
|
||||
}
|
||||
|
||||
std::shared_ptr<QtNodes::NodeData> Vec2Value::outData(QtNodes::PortIndex port)
|
||||
{
|
||||
assert(port == 0);
|
||||
|
||||
return std::make_shared<Vec2Data>(GetValue());
|
||||
}
|
||||
|
||||
void Vec2Value::ComputePreview(QPixmap& pixmap) const
|
||||
{
|
||||
Nz::Vector4f value = GetValue();
|
||||
pixmap.fill(QColor::fromRgbF(value.x, value.y, value.z, value.w));
|
||||
}
|
||||
|
||||
Nz::Vector2f Vec2Value::GetValue() const
|
||||
{
|
||||
float x = float(m_values[0]->value());
|
||||
float y = float(m_values[1]->value());
|
||||
|
||||
return Nz::Vector2f(x, y);
|
||||
}
|
||||
|
||||
|
||||
Vec4Value::Vec4Value(ShaderGraph& graph) :
|
||||
VecValue(graph)
|
||||
{
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
Nz::ShaderAst::ExpressionPtr Vec4Value::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const
|
||||
{
|
||||
assert(count == 0);
|
||||
|
||||
return Nz::ShaderBuilder::Constant(GetValue());
|
||||
}
|
||||
|
||||
auto Vec4Value::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType
|
||||
{
|
||||
assert(portType == QtNodes::PortType::Out);
|
||||
assert(portIndex == 0);
|
||||
|
||||
return Vec4Data::Type();
|
||||
}
|
||||
|
||||
std::shared_ptr<QtNodes::NodeData> Vec4Value::outData(QtNodes::PortIndex port)
|
||||
{
|
||||
assert(port == 0);
|
||||
|
||||
return std::make_shared<Vec4Data>(GetValue());
|
||||
}
|
||||
|
||||
void Vec4Value::ComputePreview(QPixmap& pixmap) const
|
||||
{
|
||||
Nz::Vector4f value = GetValue();
|
||||
pixmap.fill(QColor::fromRgbF(value.x, value.y, value.z, value.w));
|
||||
}
|
||||
|
||||
Nz::Vector4f Vec4Value::GetValue() const
|
||||
{
|
||||
float x = float(m_values[0]->value());
|
||||
float y = float(m_values[1]->value());
|
||||
float z = float(m_values[2]->value());
|
||||
float w = float(m_values[3]->value());
|
||||
|
||||
return Nz::Vector4f(x, y, z, w);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#ifndef NAZARA_SHADERNODES_VECVALUE_HPP
|
||||
#define NAZARA_SHADERNODES_VECVALUE_HPP
|
||||
|
||||
#include <QtGui/QImage>
|
||||
#include <QtWidgets/QDoubleSpinBox>
|
||||
#include <QtWidgets/QFormLayout>
|
||||
#include <QtWidgets/QLabel>
|
||||
|
|
@ -10,34 +11,65 @@
|
|||
#include <array>
|
||||
|
||||
template<std::size_t N>
|
||||
struct VecTypeHelper;
|
||||
|
||||
template<>
|
||||
struct VecTypeHelper<2>
|
||||
{
|
||||
using Type = Nz::Vector2f;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct VecTypeHelper<3>
|
||||
{
|
||||
using Type = Nz::Vector3f;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct VecTypeHelper<4>
|
||||
{
|
||||
using Type = Nz::Vector4f;
|
||||
};
|
||||
|
||||
template<std::size_t N> using VecType = typename VecTypeHelper<N>::template Type;
|
||||
|
||||
template<std::size_t N, typename Data>
|
||||
class VecValue : public ShaderNode
|
||||
{
|
||||
public:
|
||||
VecValue(ShaderGraph& graph);
|
||||
~VecValue() = default;
|
||||
|
||||
QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
|
||||
|
||||
QWidget* embeddedWidget() override;
|
||||
unsigned int nPorts(QtNodes::PortType portType) const override;
|
||||
|
||||
protected:
|
||||
void UpdatePreview();
|
||||
std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex port) override;
|
||||
|
||||
virtual void ComputePreview(QPixmap& pixmap) const = 0;
|
||||
Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override;
|
||||
|
||||
protected:
|
||||
QColor ToColor() const;
|
||||
VecType<N> ToVector() const;
|
||||
void UpdatePreview();
|
||||
|
||||
QLabel* m_pixmapLabel;
|
||||
QPixmap m_pixmap;
|
||||
QWidget* m_widget;
|
||||
QFormLayout* m_layout;
|
||||
std::array<QDoubleSpinBox*, N> m_values;
|
||||
std::array<QDoubleSpinBox*, N> m_spinboxes;
|
||||
};
|
||||
|
||||
class Vec2Data : public QtNodes::NodeData
|
||||
struct VecData : public QtNodes::NodeData
|
||||
{
|
||||
public:
|
||||
using InternalType = Nz::Vector2f;
|
||||
inline VecData();
|
||||
|
||||
inline Vec2Data(const InternalType& vec);
|
||||
QImage preview;
|
||||
};
|
||||
|
||||
struct Vec2Data : public VecData
|
||||
{
|
||||
QtNodes::NodeDataType type() const override
|
||||
{
|
||||
return Type();
|
||||
|
|
@ -47,17 +79,10 @@ class Vec2Data : public QtNodes::NodeData
|
|||
{
|
||||
return { "vec2", "Vec2" };
|
||||
}
|
||||
|
||||
InternalType value;
|
||||
};
|
||||
|
||||
class Vec4Data : public QtNodes::NodeData
|
||||
struct Vec4Data : public VecData
|
||||
{
|
||||
public:
|
||||
using InternalType = Nz::Vector4f;
|
||||
|
||||
inline Vec4Data(const InternalType& vec);
|
||||
|
||||
QtNodes::NodeDataType type() const override
|
||||
{
|
||||
return Type();
|
||||
|
|
@ -67,48 +92,24 @@ class Vec4Data : public QtNodes::NodeData
|
|||
{
|
||||
return { "vec4", "Vec4" };
|
||||
}
|
||||
|
||||
InternalType value;
|
||||
};
|
||||
|
||||
class Vec2Value : public VecValue<2>
|
||||
class Vec2Value : public VecValue<2, Vec2Data>
|
||||
{
|
||||
public:
|
||||
Vec2Value(ShaderGraph& graph);
|
||||
|
||||
Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override;
|
||||
using VecValue::VecValue;
|
||||
|
||||
QString caption() const override { return "Vec2 value"; }
|
||||
QString name() const override { return "Vec2Value"; }
|
||||
|
||||
QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
|
||||
|
||||
std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex port) override;
|
||||
|
||||
private:
|
||||
void ComputePreview(QPixmap& pixmap) const override;
|
||||
|
||||
Nz::Vector2f GetValue() const;
|
||||
};
|
||||
|
||||
class Vec4Value : public VecValue<4>
|
||||
class Vec4Value : public VecValue<4, Vec4Data>
|
||||
{
|
||||
public:
|
||||
Vec4Value(ShaderGraph& graph);
|
||||
|
||||
Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override;
|
||||
using VecValue::VecValue;
|
||||
|
||||
QString caption() const override { return "Vec4 value"; }
|
||||
QString name() const override { return "Vec4Value"; }
|
||||
|
||||
QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
|
||||
|
||||
std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex port) override;
|
||||
|
||||
private:
|
||||
void ComputePreview(QPixmap& pixmap) const override;
|
||||
|
||||
Nz::Vector4f GetValue() const;
|
||||
};
|
||||
|
||||
#include <DataModels/VecValue.inl>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||
#include <DataModels/VecValue.hpp>
|
||||
#include <array>
|
||||
|
||||
template<std::size_t N>
|
||||
VecValue<N>::VecValue(ShaderGraph& graph) :
|
||||
template<std::size_t N, typename Data>
|
||||
VecValue<N, Data>::VecValue(ShaderGraph& graph) :
|
||||
ShaderNode(graph)
|
||||
{
|
||||
constexpr std::array<char, 4> componentName = { 'X', 'Y', 'Z', 'W' };
|
||||
|
|
@ -11,21 +13,21 @@ ShaderNode(graph)
|
|||
m_layout = new QFormLayout;
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
m_values[i] = new QDoubleSpinBox;
|
||||
m_values[i]->setDecimals(6);
|
||||
m_values[i]->setValue(1.0);
|
||||
m_values[i]->setStyleSheet("background-color: rgba(255,255,255,255)");
|
||||
connect(m_values[i], qOverload<double>(&QDoubleSpinBox::valueChanged), [this](double)
|
||||
m_spinboxes[i] = new QDoubleSpinBox;
|
||||
m_spinboxes[i]->setDecimals(6);
|
||||
m_spinboxes[i]->setValue(1.0);
|
||||
m_spinboxes[i]->setStyleSheet("background-color: rgba(255,255,255,255)");
|
||||
connect(m_spinboxes[i], qOverload<double>(&QDoubleSpinBox::valueChanged), [this](double)
|
||||
{
|
||||
UpdatePreview();
|
||||
|
||||
Q_EMIT dataUpdated(0);
|
||||
});
|
||||
|
||||
m_layout->addRow(QString::fromUtf8(&componentName[i], 1), m_values[i]);
|
||||
m_layout->addRow(QString::fromUtf8(&componentName[i], 1), m_spinboxes[i]);
|
||||
}
|
||||
|
||||
m_pixmap = QPixmap(64, 64);
|
||||
m_pixmap = QPixmap(32, 32);
|
||||
m_pixmap.fill();
|
||||
|
||||
m_pixmapLabel = new QLabel;
|
||||
|
|
@ -36,16 +38,27 @@ ShaderNode(graph)
|
|||
m_widget = new QWidget;
|
||||
m_widget->setStyleSheet("background-color: rgba(0,0,0,0)");
|
||||
m_widget->setLayout(m_layout);
|
||||
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
QWidget* VecValue<N>::embeddedWidget()
|
||||
template<std::size_t N, typename Data>
|
||||
QtNodes::NodeDataType VecValue<N, Data>::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
|
||||
{
|
||||
assert(portType == QtNodes::PortType::Out);
|
||||
assert(portIndex == 0);
|
||||
|
||||
return Data::Type();
|
||||
}
|
||||
|
||||
template<std::size_t N, typename Data>
|
||||
QWidget* VecValue<N, Data>::embeddedWidget()
|
||||
{
|
||||
return m_widget;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
unsigned int VecValue<N>::nPorts(QtNodes::PortType portType) const
|
||||
template<std::size_t N, typename Data>
|
||||
unsigned int VecValue<N, Data>::nPorts(QtNodes::PortType portType) const
|
||||
{
|
||||
switch (portType)
|
||||
{
|
||||
|
|
@ -56,19 +69,64 @@ unsigned int VecValue<N>::nPorts(QtNodes::PortType portType) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
void VecValue<N>::UpdatePreview()
|
||||
template<std::size_t N, typename Data>
|
||||
std::shared_ptr<QtNodes::NodeData> VecValue<N, Data>::outData(QtNodes::PortIndex port)
|
||||
{
|
||||
ComputePreview(m_pixmap);
|
||||
assert(port == 0);
|
||||
|
||||
auto out = std::make_shared<Data>();
|
||||
out->preview = QImage(1, 1, QImage::Format_RGBA8888);
|
||||
out->preview.fill(ToColor());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
template<std::size_t N, typename Data>
|
||||
Nz::ShaderAst::ExpressionPtr VecValue<N, Data>::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const
|
||||
{
|
||||
assert(count == 0);
|
||||
|
||||
return Nz::ShaderBuilder::Constant(ToVector());
|
||||
}
|
||||
|
||||
template<std::size_t N, typename Data>
|
||||
QColor VecValue<N, Data>::ToColor() const
|
||||
{
|
||||
std::array<float, 4> values = { 0.f, 0.f, 0.f, 1.f };
|
||||
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
values[i] = std::clamp<float>(m_spinboxes[i]->value(), 0.0, 1.0);
|
||||
|
||||
return QColor::fromRgbF(values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
template<std::size_t N, typename Data>
|
||||
VecType<N> VecValue<N, Data>::ToVector() const
|
||||
{
|
||||
std::array<float, 4> values = { 0.f, 0.f, 0.f, 1.f };
|
||||
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
values[i] = std::clamp<float>(m_spinboxes[i]->value(), 0.0, 1.0);
|
||||
|
||||
if constexpr (N == 2)
|
||||
return Nz::Vector2f(values[0], values[1]);
|
||||
else if constexpr (N == 3)
|
||||
return Nz::Vector3f(values[0], values[1], values[2]);
|
||||
else if constexpr (N == 4)
|
||||
return Nz::Vector4f(values[0], values[1], values[2], values[3]);
|
||||
else
|
||||
static_assert(Nz::AlwaysFalse<std::make_integer_sequence<int, N>>(), "Unhandled vector size");
|
||||
}
|
||||
|
||||
template<std::size_t N, typename Data>
|
||||
void VecValue<N, Data>::UpdatePreview()
|
||||
{
|
||||
m_pixmap.fill(ToColor());
|
||||
m_pixmapLabel->setPixmap(m_pixmap);
|
||||
}
|
||||
|
||||
Vec2Data::Vec2Data(const InternalType& vec) :
|
||||
value(vec)
|
||||
{
|
||||
}
|
||||
|
||||
Vec4Data::Vec4Data(const InternalType& vec) :
|
||||
value(vec)
|
||||
inline VecData::VecData() :
|
||||
preview(64, 64, QImage::Format_RGBA8888)
|
||||
{
|
||||
preview.fill(QColor::fromRgb(255, 255, 255, 0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@
|
|||
namespace
|
||||
{
|
||||
template<typename T>
|
||||
void RegisterShaderNode(ShaderGraph& graph, std::shared_ptr<QtNodes::DataModelRegistry> registry)
|
||||
void RegisterShaderNode(ShaderGraph& graph, std::shared_ptr<QtNodes::DataModelRegistry> registry, QString category = QString())
|
||||
{
|
||||
auto creator = [&] { return std::make_unique<T>(graph); };
|
||||
registry->registerModel<T>(std::move(creator));
|
||||
registry->registerModel<T>(category, std::move(creator));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -35,16 +35,19 @@ m_flowScene(BuildRegistry())
|
|||
m_flowScene.createConnection(node2, 0, node1, 0);
|
||||
}
|
||||
|
||||
void ShaderGraph::AddTexture(std::string name, Nz::ShaderAst::ExpressionType type)
|
||||
std::size_t ShaderGraph::AddTexture(std::string name, Nz::ShaderAst::ExpressionType type)
|
||||
{
|
||||
std::size_t index = m_textures.size();
|
||||
auto& textureEntry = m_textures.emplace_back();
|
||||
textureEntry.name = std::move(name);
|
||||
textureEntry.type = type;
|
||||
|
||||
OnTextureListUpdate(this);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
Nz::ShaderAst::StatementPtr ShaderGraph::Generate()
|
||||
Nz::ShaderAst::StatementPtr ShaderGraph::ToAst()
|
||||
{
|
||||
std::vector<Nz::ShaderAst::StatementPtr> statements;
|
||||
|
||||
|
|
@ -82,14 +85,25 @@ Nz::ShaderAst::StatementPtr ShaderGraph::Generate()
|
|||
return std::make_shared<Nz::ShaderAst::StatementBlock>(std::move(statements));
|
||||
}
|
||||
|
||||
void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview)
|
||||
{
|
||||
assert(textureIndex < m_textures.size());
|
||||
auto& textureEntry = m_textures[textureIndex];
|
||||
textureEntry.preview = std::move(preview);
|
||||
textureEntry.preview.convertTo(QImage::Format_RGBA8888);
|
||||
|
||||
OnTexturePreviewUpdate(this, textureIndex);
|
||||
}
|
||||
|
||||
std::shared_ptr<QtNodes::DataModelRegistry> ShaderGraph::BuildRegistry()
|
||||
{
|
||||
auto registry = std::make_shared<QtNodes::DataModelRegistry>();
|
||||
RegisterShaderNode<FragmentOutput>(*this, registry);
|
||||
RegisterShaderNode<SampleTexture>(*this, registry);
|
||||
RegisterShaderNode<Vec4Mul>(*this, registry);
|
||||
RegisterShaderNode<Vec2Value>(*this, registry);
|
||||
RegisterShaderNode<Vec4Value>(*this, registry);
|
||||
RegisterShaderNode<FragmentOutput>(*this, registry, "Output");
|
||||
RegisterShaderNode<SampleTexture>(*this, registry, "Texture");
|
||||
RegisterShaderNode<Vec4Add>(*this, registry, "Vector operations");
|
||||
RegisterShaderNode<Vec4Mul>(*this, registry, "Vector operations");
|
||||
RegisterShaderNode<Vec2Value>(*this, registry, "Constants");
|
||||
RegisterShaderNode<Vec4Value>(*this, registry, "Constants");
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,21 +18,26 @@ class ShaderGraph
|
|||
ShaderGraph();
|
||||
~ShaderGraph() = default;
|
||||
|
||||
void AddTexture(std::string name, Nz::ShaderAst::ExpressionType type);
|
||||
|
||||
Nz::ShaderAst::StatementPtr Generate();
|
||||
std::size_t AddTexture(std::string name, Nz::ShaderAst::ExpressionType type);
|
||||
|
||||
inline QtNodes::FlowScene& GetScene();
|
||||
inline const TextureEntry& GetTexture(std::size_t textureIndex) const;
|
||||
inline const std::vector<TextureEntry>& GetTextures();
|
||||
|
||||
NazaraSignal(OnTextureListUpdate, ShaderGraph*);
|
||||
Nz::ShaderAst::StatementPtr ToAst();
|
||||
|
||||
void UpdateTexturePreview(std::size_t texture, QImage preview);
|
||||
|
||||
struct TextureEntry
|
||||
{
|
||||
std::string name;
|
||||
Nz::ShaderAst::ExpressionType type;
|
||||
QImage preview;
|
||||
};
|
||||
|
||||
NazaraSignal(OnTextureListUpdate, ShaderGraph*);
|
||||
NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/);
|
||||
|
||||
private:
|
||||
std::shared_ptr<QtNodes::DataModelRegistry> BuildRegistry();
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,14 @@ inline QtNodes::FlowScene& ShaderGraph::GetScene()
|
|||
return m_flowScene;
|
||||
}
|
||||
|
||||
inline auto ShaderGraph::GetTexture(std::size_t textureIndex) const -> const TextureEntry&
|
||||
{
|
||||
assert(textureIndex < m_textures.size());
|
||||
return m_textures[textureIndex];
|
||||
}
|
||||
|
||||
inline auto ShaderGraph::GetTextures() -> const std::vector<TextureEntry>&
|
||||
{
|
||||
return m_textures;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
#include <Widgets/MainWindow.hpp>
|
||||
#include <Nazara/Renderer/GlslWriter.hpp>
|
||||
#include <ShaderGraph.hpp>
|
||||
#include <Widgets/TextureEditor.hpp>
|
||||
#include <nodes/FlowView>
|
||||
#include <QtWidgets/QMenuBar>
|
||||
#include <QtWidgets/QTextEdit>
|
||||
#include <iostream>
|
||||
|
||||
MainWindow::MainWindow(ShaderGraph& graph) :
|
||||
m_shaderGraph(graph)
|
||||
{
|
||||
setWindowTitle("Nazara Shader nodes");
|
||||
|
||||
QtNodes::FlowScene* scene = &m_shaderGraph.GetScene();
|
||||
|
||||
QtNodes::FlowView* flowView = new QtNodes::FlowView(scene);
|
||||
setCentralWidget(flowView);
|
||||
|
||||
QDockWidget* textureDock = new QDockWidget(tr("&Textures"));
|
||||
|
||||
TextureEditor* textureEditor = new TextureEditor(m_shaderGraph);
|
||||
textureDock->setWidget(textureEditor);
|
||||
|
||||
addDockWidget(Qt::LeftDockWidgetArea, textureDock);
|
||||
|
||||
BuildMenu();
|
||||
}
|
||||
|
||||
void MainWindow::BuildMenu()
|
||||
{
|
||||
QMenu* compileMenu = menuBar()->addMenu(tr("&Compilation"));
|
||||
QAction* compileToGlsl = compileMenu->addAction(tr("GLSL"));
|
||||
connect(compileToGlsl, &QAction::triggered, [&](bool) { OnCompileToGLSL(); });
|
||||
}
|
||||
|
||||
void MainWindow::OnCompileToGLSL()
|
||||
{
|
||||
Nz::GlslWriter writer;
|
||||
Nz::String glsl = writer.Generate(m_shaderGraph.ToAst());
|
||||
|
||||
std::cout << glsl << std::endl;
|
||||
|
||||
QTextEdit* output = new QTextEdit;
|
||||
output->setReadOnly(true);
|
||||
output->setText(QString::fromUtf8(glsl.GetConstBuffer(), int(glsl.GetSize())));
|
||||
output->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
output->setWindowTitle("GLSL Output");
|
||||
output->show();
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SHADERNODES_MAINWINDOW_HPP
|
||||
#define NAZARA_SHADERNODES_MAINWINDOW_HPP
|
||||
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <DataModels/ShaderNode.hpp>
|
||||
|
||||
class ShaderGraph;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
public:
|
||||
MainWindow(ShaderGraph& graph);
|
||||
~MainWindow() = default;
|
||||
|
||||
private:
|
||||
void BuildMenu();
|
||||
void OnCompileToGLSL();
|
||||
|
||||
ShaderGraph& m_shaderGraph;
|
||||
};
|
||||
|
||||
#include <Widgets/MainWindow.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include <Widgets/MainWindow.hpp>
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
#include <Widgets/TextureEditor.hpp>
|
||||
#include <ShaderGraph.hpp>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QListWidget>
|
||||
#include <QtWidgets/QVBoxLayout>
|
||||
|
||||
TextureEditor::TextureEditor(ShaderGraph& graph) :
|
||||
m_shaderGraph(graph)
|
||||
{
|
||||
m_textureList = new QListWidget(this);
|
||||
connect(m_textureList, &QListWidget::currentRowChanged, this, &TextureEditor::OnTextureSelectionUpdate);
|
||||
|
||||
m_pixmapLabel = new QLabel;
|
||||
|
||||
QPushButton* updateTextureButton = new QPushButton(tr("Load texture..."));
|
||||
connect(updateTextureButton, &QPushButton::released, this, &TextureEditor::OnLoadTexture);
|
||||
|
||||
m_layout = new QVBoxLayout;
|
||||
m_layout->addWidget(m_textureList);
|
||||
m_layout->addWidget(updateTextureButton);
|
||||
m_layout->addWidget(m_pixmapLabel);
|
||||
|
||||
setLayout(m_layout);
|
||||
|
||||
m_onTextureListUpdateSlot.Connect(m_shaderGraph.OnTextureListUpdate, this, &TextureEditor::OnTextureListUpdate);
|
||||
m_onTexturePreviewUpdateSlot.Connect(m_shaderGraph.OnTexturePreviewUpdate, this, &TextureEditor::OnTexturePreviewUpdate);
|
||||
|
||||
RefreshTextures();
|
||||
}
|
||||
|
||||
void TextureEditor::OnLoadTexture()
|
||||
{
|
||||
if (!m_currentTextureIndex)
|
||||
return;
|
||||
|
||||
QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open Image"), QDir::homePath(), tr("Image Files (*.png *.jpg *.bmp)"));
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
m_shaderGraph.UpdateTexturePreview(m_currentTextureIndex.value(), QImage(fileName));
|
||||
}
|
||||
|
||||
void TextureEditor::OnTextureSelectionUpdate(int textureIndex)
|
||||
{
|
||||
if (textureIndex >= 0)
|
||||
{
|
||||
m_currentTextureIndex = textureIndex;
|
||||
UpdateTexturePreview();
|
||||
}
|
||||
else
|
||||
m_currentTextureIndex.reset();
|
||||
}
|
||||
|
||||
void TextureEditor::OnTextureListUpdate(ShaderGraph* graph)
|
||||
{
|
||||
RefreshTextures();
|
||||
}
|
||||
|
||||
void TextureEditor::OnTexturePreviewUpdate(ShaderGraph* /*graph*/, std::size_t textureIndex)
|
||||
{
|
||||
if (m_currentTextureIndex && *m_currentTextureIndex == textureIndex)
|
||||
UpdateTexturePreview();
|
||||
}
|
||||
|
||||
void TextureEditor::RefreshTextures()
|
||||
{
|
||||
m_textureList->clear();
|
||||
m_textureList->setCurrentRow(-1);
|
||||
|
||||
for (const auto& textureEntry : m_shaderGraph.GetTextures())
|
||||
m_textureList->addItem(QString::fromStdString(textureEntry.name));
|
||||
}
|
||||
|
||||
void TextureEditor::UpdateTexturePreview()
|
||||
{
|
||||
assert(m_currentTextureIndex);
|
||||
const auto& textureEntry = m_shaderGraph.GetTexture(*m_currentTextureIndex);
|
||||
m_pixmapLabel->setPixmap(QPixmap::fromImage(textureEntry.preview).scaled(128, 128, Qt::KeepAspectRatio));
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SHADERNODES_TEXTUREEDITOR_HPP
|
||||
#define NAZARA_SHADERNODES_TEXTUREEDITOR_HPP
|
||||
|
||||
#include <ShaderGraph.hpp>
|
||||
#include <QtWidgets/QDockWidget>
|
||||
#include <optional>
|
||||
|
||||
class QLabel;
|
||||
class QListWidget;
|
||||
class QVBoxLayout;
|
||||
|
||||
class TextureEditor : public QWidget
|
||||
{
|
||||
public:
|
||||
TextureEditor(ShaderGraph& graph);
|
||||
~TextureEditor() = default;
|
||||
|
||||
private:
|
||||
void OnLoadTexture();
|
||||
void OnTextureSelectionUpdate(int textureIndex);
|
||||
void OnTextureListUpdate(ShaderGraph* graph);
|
||||
void OnTexturePreviewUpdate(ShaderGraph* graph, std::size_t textureIndex);
|
||||
void RefreshTextures();
|
||||
void UpdateTexturePreview();
|
||||
|
||||
NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot);
|
||||
NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot);
|
||||
|
||||
std::optional<std::size_t> m_currentTextureIndex;
|
||||
ShaderGraph& m_shaderGraph;
|
||||
QLabel* m_pixmapLabel;
|
||||
QListWidget* m_textureList;
|
||||
QVBoxLayout* m_layout;
|
||||
};
|
||||
|
||||
#include <Widgets/TextureEditor.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include <Widgets/TextureEditor.hpp>
|
||||
|
|
@ -1,59 +1,17 @@
|
|||
#include <Nazara/Renderer/ShaderAst.hpp>
|
||||
#include <Nazara/Renderer/ShaderBuilder.hpp>
|
||||
#include <Nazara/Renderer/GlslWriter.hpp>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QMenuBar>
|
||||
#include <QtWidgets/QVBoxLayout>
|
||||
#include <QtWidgets/QTextEdit>
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <nodes/Node>
|
||||
#include <nodes/NodeData>
|
||||
#include <nodes/NodeGeometry>
|
||||
#include <nodes/FlowScene>
|
||||
#include <nodes/FlowView>
|
||||
#include <nodes/DataModelRegistry>
|
||||
#include <ShaderGraph.hpp>
|
||||
#include <Widgets/MainWindow.hpp>
|
||||
#include <iostream>
|
||||
|
||||
void GenerateGLSL(ShaderGraph& graph)
|
||||
{
|
||||
Nz::GlslWriter writer;
|
||||
Nz::String glsl = writer.Generate(graph.Generate());
|
||||
|
||||
std::cout << glsl << std::endl;
|
||||
|
||||
QTextEdit* output = new QTextEdit;
|
||||
output->setReadOnly(true);
|
||||
output->setText(QString::fromUtf8(glsl.GetConstBuffer(), glsl.GetSize()));
|
||||
output->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
output->setWindowTitle("GLSL Output");
|
||||
output->show();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
ShaderGraph shaderGraph;
|
||||
shaderGraph.AddTexture("TextureMachin", Nz::ShaderAst::ExpressionType::Sampler2D);
|
||||
shaderGraph.AddTexture("Potato", Nz::ShaderAst::ExpressionType::Sampler2D);
|
||||
shaderGraph.AddTexture("Blackbird", Nz::ShaderAst::ExpressionType::Sampler2D);
|
||||
|
||||
QWidget mainWindow;
|
||||
QVBoxLayout* layout = new QVBoxLayout;
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
QtNodes::FlowScene* scene = &shaderGraph.GetScene();
|
||||
|
||||
QMenuBar* menuBar = new QMenuBar;
|
||||
QAction* glslCode = menuBar->addAction("To GLSL");
|
||||
QObject::connect(glslCode, &QAction::triggered, [&](bool) { GenerateGLSL(shaderGraph); });
|
||||
|
||||
layout->addWidget(new QtNodes::FlowView(scene));
|
||||
layout->addWidget(menuBar);
|
||||
|
||||
mainWindow.setLayout(layout);
|
||||
mainWindow.setWindowTitle("Nazara Shader nodes");
|
||||
MainWindow mainWindow(shaderGraph);
|
||||
mainWindow.resize(1280, 720);
|
||||
mainWindow.show();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue