ShaderNode: Add preview / cast / texture sampling

This commit is contained in:
Lynix 2020-05-23 22:04:10 +02:00
parent 206724c911
commit 93e76a17c7
23 changed files with 686 additions and 144 deletions

View File

View File

@ -0,0 +1,59 @@
#pragma once
#ifndef NAZARA_SHADERNODES_CAST_HPP
#define NAZARA_SHADERNODES_CAST_HPP
#include <QtWidgets/QComboBox>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QLabel>
#include <ShaderGraph.hpp>
#include <DataModels/ShaderNode.hpp>
#include <DataModels/VecValue.hpp>
#include <array>
template<typename From, typename To>
class CastVec : public ShaderNode
{
public:
CastVec(ShaderGraph& graph);
~CastVec() = default;
Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override;
QString caption() const override;
QString name() const override;
QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
QWidget* embeddedWidget() override;
unsigned int nPorts(QtNodes::PortType portType) const override;
std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex port) override;
void setInData(std::shared_ptr<QtNodes::NodeData> value, int index) override;
private:
static constexpr std::size_t FromComponents = From::ComponentCount;
static constexpr std::size_t ToComponents = To::ComponentCount;
static constexpr std::size_t ComponentDiff = (ToComponents >= FromComponents) ? ToComponents - FromComponents : 0;
void ComputePreview(QPixmap& pixmap) const;
void UpdatePreview();
QLabel* m_pixmapLabel;
QPixmap m_pixmap;
QWidget* m_widget;
std::array<QDoubleSpinBox*, ComponentDiff> m_spinboxes;
std::shared_ptr<From> m_input;
std::shared_ptr<To> m_output;
};
using CastVec2ToVec3 = CastVec<Vec2Data, Vec3Data>;
using CastVec2ToVec4 = CastVec<Vec2Data, Vec4Data>;
using CastVec3ToVec2 = CastVec<Vec3Data, Vec2Data>;
using CastVec3ToVec4 = CastVec<Vec3Data, Vec4Data>;
using CastVec4ToVec2 = CastVec<Vec4Data, Vec2Data>;
using CastVec4ToVec3 = CastVec<Vec4Data, Vec3Data>;
#include <DataModels/Cast.inl>
#endif

View File

@ -0,0 +1,201 @@
#include <DataModels/Cast.hpp>
#include <Nazara/Renderer/ShaderBuilder.hpp>
#include <stdexcept>
template<typename From, typename To>
CastVec<From, To>::CastVec(ShaderGraph& graph) :
ShaderNode(graph)
{
constexpr std::array<char, 4> componentName = { 'X', 'Y', 'Z', 'W' };
static_assert(ComponentDiff <= componentName.size());
QFormLayout* layout = new QFormLayout;
if constexpr (ComponentDiff > 0)
{
for (std::size_t i = 0; i < ComponentDiff; ++i)
{
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();
});
layout->addRow(QString::fromUtf8(&componentName[FromComponents + i], 1), m_spinboxes[i]);
}
}
m_pixmap = QPixmap(64, 64);
m_pixmap.fill();
m_pixmapLabel = new QLabel;
m_pixmapLabel->setPixmap(m_pixmap);
layout->addWidget(m_pixmapLabel);
m_widget = new QWidget;
m_widget->setStyleSheet("background-color: rgba(0,0,0,0)");
m_widget->setLayout(layout);
m_output = std::make_shared<To>();
}
template<typename From, typename To>
Nz::ShaderAst::ExpressionPtr CastVec<From, To>::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const
{
assert(count == 1);
if constexpr (ComponentDiff > 0)
{
std::array<Nz::ShaderAst::ExpressionPtr, ComponentDiff> constants;
for (std::size_t i = 0; i < ComponentDiff; ++i)
constants[i] = Nz::ShaderBuilder::Constant(float(m_spinboxes[i]->value()));
return std::apply([&](auto&&... values)
{
return Nz::ShaderBuilder::Cast<To::ExpressionType>(expressions[0], values...); //< TODO: Forward
}, constants);
}
else
{
std::array<Nz::ShaderAst::SwizzleComponent, ToComponents> swizzleComponents;
for (std::size_t i = 0; i < ToComponents; ++i)
swizzleComponents[i] = static_cast<Nz::ShaderAst::SwizzleComponent>(static_cast<std::size_t>(Nz::ShaderAst::SwizzleComponent::First) + i);
return std::apply([&](auto... components)
{
std::initializer_list<Nz::ShaderAst::SwizzleComponent> componentList{ components... };
return Nz::ShaderBuilder::Swizzle(expressions[0], componentList);
}, swizzleComponents);
}
}
template<typename From, typename To>
QString CastVec<From, To>::caption() const
{
static QString caption = From::Type().name + " to " + To::Type().name;
return caption;
}
template<typename From, typename To>
QString CastVec<From, To>::name() const
{
static QString name = From::Type().id + "to" + To::Type().id;
return name;
}
template<typename From, typename To>
QtNodes::NodeDataType CastVec<From, To>::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
{
assert(portIndex == 0);
switch (portType)
{
case QtNodes::PortType::In: return From::Type();
case QtNodes::PortType::Out: return To::Type();
}
assert(false);
throw std::runtime_error("Invalid port type");
}
template<typename From, typename To>
QWidget* CastVec<From, To>::embeddedWidget()
{
return m_widget;
}
template<typename From, typename To>
unsigned int CastVec<From, To>::nPorts(QtNodes::PortType portType) const
{
switch (portType)
{
case QtNodes::PortType::In: return 1;
case QtNodes::PortType::Out: return 1;
}
return 0;
}
template<typename From, typename To>
std::shared_ptr<QtNodes::NodeData> CastVec<From, To>::outData(QtNodes::PortIndex port)
{
assert(port == 0);
return m_output;
}
template<typename From, typename To>
void CastVec<From, To>::setInData(std::shared_ptr<QtNodes::NodeData> value, int index)
{
assert(index == 0);
if (value)
{
assert(dynamic_cast<From*>(value.get()) != nullptr);
m_input = std::static_pointer_cast<From>(value);
}
else
m_input.reset();
UpdatePreview();
}
template<typename From, typename To>
void CastVec<From, To>::ComputePreview(QPixmap& pixmap) const
{
assert(m_input);
const QImage& input = m_input->preview;
int inputWidth = input.width();
int inputHeight = input.height();
QImage& output = m_output->preview;
output = QImage(inputWidth, inputHeight, QImage::Format_RGBA8888);
std::array<std::uint8_t, ComponentDiff> constants;
for (std::size_t i = 0; i < ComponentDiff; ++i)
constants[i] = static_cast<std::uint8_t>(std::clamp(int(m_spinboxes[i]->value() * 255), 0, 255));
std::uint8_t* outputPtr = output.bits();
const std::uint8_t* inputPtr = input.constBits();
for (int y = 0; y < inputHeight; ++y)
{
for (int x = 0; x < inputWidth; ++x)
{
constexpr std::size_t CommonComponents = std::min(FromComponents, ToComponents);
constexpr std::size_t VoidComponents = 4 - ComponentDiff - CommonComponents;
for (std::size_t i = 0; i < CommonComponents; ++i)
*outputPtr++ = inputPtr[i];
for (std::size_t i = 0; i < ComponentDiff; ++i)
*outputPtr++ = constants[i];
for (std::size_t i = 0; i < VoidComponents; ++i)
*outputPtr++ = (i == VoidComponents - 1) ? 255 : 0;
inputPtr += 4;
}
}
pixmap = QPixmap::fromImage(output).scaled(64, 64);
}
template<typename From, typename To>
void CastVec<From, To>::UpdatePreview()
{
if (!m_input)
{
m_pixmap = QPixmap(64, 64);
m_pixmap.fill(QColor::fromRgb(255, 255, 255, 0));
}
else
ComputePreview(m_pixmap);
m_pixmapLabel->setPixmap(m_pixmap);
Q_EMIT dataUpdated(0);
}

View File

@ -62,6 +62,12 @@ void InputValue::UpdatePreview()
if (m_inputSelection->count() == 0)
return;
const ShaderGraph& graph = GetGraph();
const auto& inputEntry = graph.GetInput(m_currentInputIndex);
const auto& preview = graph.GetPreviewModel();
m_previewLabel->setPixmap(QPixmap::fromImage(preview.GetImage(inputEntry.role, inputEntry.roleIndex)));
Q_EMIT dataUpdated(0);
}
@ -76,7 +82,7 @@ void InputValue::UpdateInputList()
m_inputSelection->setCurrentText(currentInput);
}
Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const
Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const
{
assert(count == 0);
@ -111,7 +117,7 @@ auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portInd
//case InputType::Bool: return Nz::ShaderAst::ExpressionType::Boolean;
//case InputType::Float1: return Nz::ShaderAst::ExpressionType::Float1;
case InputType::Float2: return Vec2Data::Type();
//case InputType::Float3: return Nz::ShaderAst::ExpressionType::Float3;
case InputType::Float3: return Vec3Data::Type();
case InputType::Float4: return Vec4Data::Type();
}
@ -123,10 +129,12 @@ std::shared_ptr<QtNodes::NodeData> InputValue::outData(QtNodes::PortIndex port)
{
assert(port == 0);
const auto& inputEntry = GetGraph().GetInput(m_currentInputIndex);
const ShaderGraph& graph = GetGraph();
const auto& inputEntry = graph.GetInput(m_currentInputIndex);
const auto& preview = graph.GetPreviewModel();
auto vecData = std::make_shared<Vec4Data>();
vecData->preview = QImage();
auto vecData = std::make_shared<Vec2Data>();
vecData->preview = preview.GetImage(inputEntry.role, inputEntry.roleIndex);
return vecData;
}

View File

@ -7,6 +7,8 @@ SampleTexture::SampleTexture(ShaderGraph& graph) :
ShaderNode(graph),
m_currentTextureIndex(0)
{
m_output = std::make_shared<Vec4Data>();
m_layout = new QVBoxLayout;
m_textureSelection = new QComboBox;
@ -85,9 +87,45 @@ void SampleTexture::UpdateTextureList()
void SampleTexture::ComputePreview(QPixmap& pixmap) const
{
if (!m_uv)
return;
const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex);
pixmap = QPixmap::fromImage(textureEntry.preview).scaled(128, 128, Qt::KeepAspectRatio);
int textureWidth = textureEntry.preview.width();
int textureHeight = textureEntry.preview.height();
QImage& output = m_output->preview;
const QImage& uv = m_uv->preview;
int uvWidth = uv.width();
int uvHeight = uv.height();
output = QImage(uvWidth, uvHeight, QImage::Format_RGBA8888);
std::uint8_t* outputPtr = output.bits();
const std::uint8_t* uvPtr = uv.constBits();
const std::uint8_t* texturePtr = textureEntry.preview.constBits();
for (int y = 0; y < uvHeight; ++y)
{
for (int x = 0; x < uvWidth; ++x)
{
float u = float(uvPtr[0]) / 255;
float v = float(uvPtr[1]) / 255;
int texX = std::clamp(int(u * textureWidth), 0, textureWidth - 1);
int texY = std::clamp(int(v * textureHeight), 0, textureHeight - 1);
int texPixel = (texY * textureWidth + texX) * 4;
*outputPtr++ = texturePtr[texPixel + 0];
*outputPtr++ = texturePtr[texPixel + 1];
*outputPtr++ = texturePtr[texPixel + 2];
*outputPtr++ = texturePtr[texPixel + 3];
uvPtr += 4;
}
}
pixmap = QPixmap::fromImage(output).scaled(128, 128, Qt::KeepAspectRatio);
}
Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const
@ -156,7 +194,7 @@ QString SampleTexture::portCaption(QtNodes::PortType portType, QtNodes::PortInde
}
}
bool SampleTexture::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
bool SampleTexture::portCaptionVisible(QtNodes::PortType /*portType*/, QtNodes::PortIndex /*portIndex*/) const
{
return true;
}
@ -165,10 +203,21 @@ std::shared_ptr<QtNodes::NodeData> SampleTexture::outData(QtNodes::PortIndex por
{
assert(port == 0);
const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex);
auto vecData = std::make_shared<Vec4Data>();
vecData->preview = textureEntry.preview;
return vecData;
return m_output;
}
void SampleTexture::setInData(std::shared_ptr<QtNodes::NodeData> value, int index)
{
assert(index == 0);
if (value)
{
assert(dynamic_cast<Vec2Data*>(value.get()) != nullptr);
m_uv = std::static_pointer_cast<Vec2Data>(value);
}
else
m_uv.reset();
UpdatePreview();
}

View File

@ -8,6 +8,7 @@
#include <QtWidgets/QLabel>
#include <ShaderGraph.hpp>
#include <DataModels/ShaderNode.hpp>
#include <DataModels/VecValue.hpp>
#include <array>
class SampleTexture : public ShaderNode
@ -32,6 +33,8 @@ class SampleTexture : public ShaderNode
std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex port) override;
void setInData(std::shared_ptr<QtNodes::NodeData> value, int index) override;
protected:
void ComputePreview(QPixmap& pixmap) const;
void UpdatePreview();
@ -41,6 +44,8 @@ class SampleTexture : public ShaderNode
NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot);
std::size_t m_currentTextureIndex;
std::shared_ptr<Vec2Data> m_uv;
std::shared_ptr<Vec4Data> m_output;
QComboBox* m_textureSelection;
QLabel* m_pixmapLabel;
QPixmap m_pixmap;

View File

@ -1,23 +1 @@
#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);
}
}

View File

@ -30,33 +30,59 @@ class VecBinOp : public ShaderNode
QLabel* m_pixmapLabel;
QPixmap m_preview;
std::shared_ptr<Vec4Data> m_lhs;
std::shared_ptr<Vec4Data> m_rhs;
std::shared_ptr<Vec4Data> m_output;
std::shared_ptr<Data> m_lhs;
std::shared_ptr<Data> m_rhs;
std::shared_ptr<Data> m_output;
};
class Vec4Add : public VecBinOp<Vec4Data, Nz::ShaderAst::BinaryType::Add>
template<typename Data>
class VecAdd : public VecBinOp<Data, Nz::ShaderAst::BinaryType::Add>
{
public:
using VecBinOp::VecBinOp;
using VecBinOp<Data, Nz::ShaderAst::BinaryType::Add>::VecBinOp;
QString caption() const override { return "Vec4 addition"; }
QString name() const override { return "Vec4Add"; }
QString caption() const override;
QString name() const override;
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>
template<typename Data>
class VecMul : public VecBinOp<Data, Nz::ShaderAst::BinaryType::Multiply>
{
public:
using VecBinOp::VecBinOp;
using VecBinOp<Data, Nz::ShaderAst::BinaryType::Multiply>::VecBinOp;
QString caption() const override { return "Vec4 multiplication"; }
QString name() const override { return "Vec4Mul"; }
QString caption() const override;
QString name() const override;
void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override;
};
template<typename Data>
class VecSub : public VecBinOp<Data, Nz::ShaderAst::BinaryType::Substract>
{
public:
using VecBinOp<Data, Nz::ShaderAst::BinaryType::Substract>::VecBinOp;
QString caption() const override;
QString name() const override;
void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override;
};
using Vec2Add = VecAdd<Vec2Data>;
using Vec3Add = VecAdd<Vec3Data>;
using Vec4Add = VecAdd<Vec4Data>;
using Vec2Mul = VecMul<Vec2Data>;
using Vec3Mul = VecMul<Vec3Data>;
using Vec4Mul = VecMul<Vec4Data>;
using Vec2Sub = VecSub<Vec2Data>;
using Vec3Sub = VecSub<Vec3Data>;
using Vec4Sub = VecSub<Vec4Data>;
#include <DataModels/VecBinOp.inl>
#endif

View File

@ -96,14 +96,10 @@ void VecBinOp<Data, BinOp>::UpdatePreview()
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);
m_preview = QPixmap::fromImage(m_output->preview).scaled(64, 64);
}
else
{
@ -113,3 +109,83 @@ void VecBinOp<Data, BinOp>::UpdatePreview()
m_pixmapLabel->setPixmap(m_preview);
}
template<typename Data>
QString VecAdd<Data>::caption() const
{
static QString caption = Data::Type().name + " addition";
return caption;
}
template<typename Data>
QString VecAdd<Data>::name() const
{
static QString name = Data::Type().name + "add";
return name;
}
template<typename Data>
void VecAdd<Data>::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));
}
}
template<typename Data>
QString VecMul<Data>::caption() const
{
static QString caption = Data::Type().name + " multiplication";
return caption;
}
template<typename Data>
QString VecMul<Data>::name() const
{
static QString name = Data::Type().name + "mul";
return name;
}
template<typename Data>
void VecMul<Data>::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);
}
}
template<typename Data>
QString VecSub<Data>::caption() const
{
static QString caption = Data::Type().name + " subtraction";
return caption;
}
template<typename Data>
QString VecSub<Data>::name() const
{
static QString name = Data::Type().name + "sub";
return name;
}
template<typename Data>
void VecSub<Data>::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];
unsigned int sub = (lValue >= rValue) ? lValue - rValue : 0u;
output[i] = static_cast<std::uint8_t>(sub);
}
}

View File

@ -0,0 +1 @@
#include <DataModels/VecData.hpp>

View File

@ -0,0 +1,67 @@
#pragma once
#ifndef NAZARA_SHADERNODES_VECDATA_HPP
#define NAZARA_SHADERNODES_VECDATA_HPP
#include <Nazara/Renderer/ShaderAst.hpp>
#include <nodes/NodeData>
#include <QtGui/QImage>
struct VecData : public QtNodes::NodeData
{
inline VecData();
QImage preview;
};
struct Vec2Data : public VecData
{
static constexpr std::size_t ComponentCount = 2;
static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float2;
QtNodes::NodeDataType type() const override
{
return Type();
}
static QtNodes::NodeDataType Type()
{
return { "vec2", "Vec2" };
}
};
struct Vec3Data : public VecData
{
static constexpr std::size_t ComponentCount = 3;
static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float3;
QtNodes::NodeDataType type() const override
{
return Type();
}
static QtNodes::NodeDataType Type()
{
return { "vec3", "Vec3" };
}
};
struct Vec4Data : public VecData
{
static constexpr std::size_t ComponentCount = 4;
static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float4;
QtNodes::NodeDataType type() const override
{
return Type();
}
static QtNodes::NodeDataType Type()
{
return { "vec4", "Vec4" };
}
};
#include <DataModels/VecData.inl>
#endif

View File

@ -0,0 +1,7 @@
#include <DataModels/VecData.hpp>
inline VecData::VecData() :
preview(64, 64, QImage::Format_RGBA8888)
{
preview.fill(QColor::fromRgb(255, 255, 255, 0));
}

View File

@ -8,6 +8,7 @@
#include <QtWidgets/QFormLayout>
#include <QtWidgets/QLabel>
#include <DataModels/ShaderNode.hpp>
#include <DataModels/VecData.hpp>
#include <array>
template<std::size_t N>
@ -33,13 +34,16 @@ struct VecTypeHelper<4>
template<std::size_t N> using VecType = typename VecTypeHelper<N>::template Type;
template<std::size_t N, typename Data>
template<typename Data>
class VecValue : public ShaderNode
{
public:
VecValue(ShaderGraph& graph);
~VecValue() = default;
QString caption() const override;
QString name() const override;
QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override;
QWidget* embeddedWidget() override;
@ -50,67 +54,22 @@ class VecValue : public ShaderNode
Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override;
protected:
static constexpr std::size_t ComponentCount = Data::ComponentCount;
QColor ToColor() const;
VecType<N> ToVector() const;
VecType<ComponentCount> ToVector() const;
void UpdatePreview();
QLabel* m_pixmapLabel;
QPixmap m_pixmap;
QWidget* m_widget;
QFormLayout* m_layout;
std::array<QDoubleSpinBox*, N> m_spinboxes;
std::array<QDoubleSpinBox*, ComponentCount> m_spinboxes;
};
struct VecData : public QtNodes::NodeData
{
inline VecData();
QImage preview;
};
struct Vec2Data : public VecData
{
QtNodes::NodeDataType type() const override
{
return Type();
}
static QtNodes::NodeDataType Type()
{
return { "vec2", "Vec2" };
}
};
struct Vec4Data : public VecData
{
QtNodes::NodeDataType type() const override
{
return Type();
}
static QtNodes::NodeDataType Type()
{
return { "vec4", "Vec4" };
}
};
class Vec2Value : public VecValue<2, Vec2Data>
{
public:
using VecValue::VecValue;
QString caption() const override { return "Vec2 value"; }
QString name() const override { return "Vec2Value"; }
};
class Vec4Value : public VecValue<4, Vec4Data>
{
public:
using VecValue::VecValue;
QString caption() const override { return "Vec4 value"; }
QString name() const override { return "Vec4Value"; }
};
using Vec2Value = VecValue<Vec2Data>;
using Vec3Value = VecValue<Vec3Data>;
using Vec4Value = VecValue<Vec4Data>;
#include <DataModels/VecValue.inl>

View File

@ -2,16 +2,17 @@
#include <Nazara/Renderer/ShaderBuilder.hpp>
#include <DataModels/VecValue.hpp>
#include <array>
#include <tuple>
template<std::size_t N, typename Data>
VecValue<N, Data>::VecValue(ShaderGraph& graph) :
template<typename Data>
VecValue<Data>::VecValue(ShaderGraph& graph) :
ShaderNode(graph)
{
constexpr std::array<char, 4> componentName = { 'X', 'Y', 'Z', 'W' };
static_assert(N <= componentName.size());
static_assert(ComponentCount <= componentName.size());
m_layout = new QFormLayout;
for (std::size_t i = 0; i < N; ++i)
for (std::size_t i = 0; i < ComponentCount; ++i)
{
m_spinboxes[i] = new QDoubleSpinBox;
m_spinboxes[i]->setDecimals(6);
@ -42,8 +43,22 @@ ShaderNode(graph)
UpdatePreview();
}
template<std::size_t N, typename Data>
QtNodes::NodeDataType VecValue<N, Data>::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
template<typename Data>
QString VecValue<Data>::caption() const
{
static QString caption = Data::Type().name + " constant";
return caption;
}
template<typename Data>
QString VecValue<Data>::name() const
{
static QString name = Data::Type().id + "Value";
return name;
}
template<typename Data>
QtNodes::NodeDataType VecValue<Data>::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
{
assert(portType == QtNodes::PortType::Out);
assert(portIndex == 0);
@ -51,14 +66,14 @@ QtNodes::NodeDataType VecValue<N, Data>::dataType(QtNodes::PortType portType, Qt
return Data::Type();
}
template<std::size_t N, typename Data>
QWidget* VecValue<N, Data>::embeddedWidget()
template<typename Data>
QWidget* VecValue<Data>::embeddedWidget()
{
return m_widget;
}
template<std::size_t N, typename Data>
unsigned int VecValue<N, Data>::nPorts(QtNodes::PortType portType) const
template<typename Data>
unsigned int VecValue<Data>::nPorts(QtNodes::PortType portType) const
{
switch (portType)
{
@ -69,8 +84,8 @@ unsigned int VecValue<N, Data>::nPorts(QtNodes::PortType portType) const
return 0;
}
template<std::size_t N, typename Data>
std::shared_ptr<QtNodes::NodeData> VecValue<N, Data>::outData(QtNodes::PortIndex port)
template<typename Data>
std::shared_ptr<QtNodes::NodeData> VecValue<Data>::outData(QtNodes::PortIndex port)
{
assert(port == 0);
@ -81,52 +96,42 @@ std::shared_ptr<QtNodes::NodeData> VecValue<N, Data>::outData(QtNodes::PortIndex
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
template<typename Data>
Nz::ShaderAst::ExpressionPtr VecValue<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
template<typename Data>
QColor VecValue<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);
for (std::size_t i = 0; i < ComponentCount; ++i)
values[i] = std::clamp(float(m_spinboxes[i]->value()), 0.f, 1.f);
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
template<typename Data>
auto VecValue<Data>::ToVector() const -> VecType<ComponentCount>
{
std::array<float, 4> values = { 0.f, 0.f, 0.f, 1.f };
std::array<float, ComponentCount> values;
for (std::size_t i = 0; i < N; ++i)
values[i] = std::clamp<float>(m_spinboxes[i]->value(), 0.0, 1.0);
for (std::size_t i = 0; i < ComponentCount; ++i)
values[i] = std::clamp(float(m_spinboxes[i]->value()), 0.f, 1.f);
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");
return std::apply([](auto... values)
{
return VecType<ComponentCount>(values...);
}, values);
}
template<std::size_t N, typename Data>
void VecValue<N, Data>::UpdatePreview()
template<typename Data>
void VecValue<Data>::UpdatePreview()
{
m_pixmap.fill(ToColor());
m_pixmapLabel->setPixmap(m_pixmap);
}
inline VecData::VecData() :
preview(64, 64, QImage::Format_RGBA8888)
{
preview.fill(QColor::fromRgb(255, 255, 255, 0));
}

View File

@ -0,0 +1,3 @@
#include <Previews/PreviewModel.hpp>
PreviewModel::~PreviewModel() = default;

View File

@ -0,0 +1,21 @@
#pragma once
#ifndef NAZARA_SHADERNODES_PREVIEWMODEL_HPP
#define NAZARA_SHADERNODES_PREVIEWMODEL_HPP
#include <Enums.hpp>
class QImage;
class PreviewModel
{
public:
PreviewModel() = default;
virtual ~PreviewModel();
virtual QImage GetImage(InputRole role, std::size_t roleIndex) const = 0;
};
#include <Previews/PreviewModel.inl>
#endif

View File

@ -0,0 +1 @@
#include <Previews/PreviewModel.hpp>

View File

@ -0,0 +1,24 @@
#include <Previews/QuadPreview.hpp>
#include <cassert>
QImage QuadPreview::GetImage(InputRole role, std::size_t roleIndex) const
{
assert(role == InputRole::TexCoord);
assert(roleIndex == 0);
QImage uv(128, 128, QImage::Format_RGBA8888);
std::uint8_t* content = uv.bits();
for (std::size_t y = 0; y < 128; ++y)
{
for (std::size_t x = 0; x < 128; ++x)
{
*content++ = (x * 255) / 128;
*content++ = (y * 255) / 128;
*content++ = 0;
*content++ = 255;
}
}
return uv;
}

View File

@ -0,0 +1,20 @@
#pragma once
#ifndef NAZARA_SHADERNODES_QUADPREVIEW_HPP
#define NAZARA_SHADERNODES_QUADPREVIEW_HPP
#include <Previews/PreviewModel.hpp>
#include <QtGui/QImage>
class QuadPreview : public PreviewModel
{
public:
QuadPreview() = default;
~QuadPreview() = default;
QImage GetImage(InputRole role, std::size_t roleIndex) const override;
};
#include <Previews/QuadPreview.inl>
#endif

View File

@ -0,0 +1 @@
#include <Previews/QuadPreview.hpp>

View File

@ -1,11 +1,13 @@
#include <ShaderGraph.hpp>
#include <Nazara/Core/StackArray.hpp>
#include <DataModels/Cast.hpp>
#include <DataModels/FragmentOutput.hpp>
#include <DataModels/InputValue.hpp>
#include <DataModels/SampleTexture.hpp>
#include <DataModels/ShaderNode.hpp>
#include <DataModels/VecBinOp.hpp>
#include <DataModels/VecValue.hpp>
#include <Previews/QuadPreview.hpp>
#include <QtCore/QDebug>
#include <nodes/Node>
#include <nodes/NodeData>
@ -34,6 +36,13 @@ m_flowScene(BuildRegistry())
node2.nodeGraphicsObject().setPos(500, 300);
m_flowScene.createConnection(node2, 0, node1, 0);
m_previewModel = std::make_unique<QuadPreview>();
}
ShaderGraph::~ShaderGraph()
{
m_flowScene.clearScene();
}
std::size_t ShaderGraph::AddInput(std::string name, InputType type, InputRole role, std::size_t roleIndex)
@ -125,12 +134,26 @@ void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview)
std::shared_ptr<QtNodes::DataModelRegistry> ShaderGraph::BuildRegistry()
{
auto registry = std::make_shared<QtNodes::DataModelRegistry>();
RegisterShaderNode<CastVec2ToVec3>(*this, registry, "Casts");
RegisterShaderNode<CastVec2ToVec4>(*this, registry, "Casts");
RegisterShaderNode<CastVec3ToVec2>(*this, registry, "Casts");
RegisterShaderNode<CastVec3ToVec4>(*this, registry, "Casts");
RegisterShaderNode<CastVec4ToVec2>(*this, registry, "Casts");
RegisterShaderNode<CastVec4ToVec3>(*this, registry, "Casts");
RegisterShaderNode<FragmentOutput>(*this, registry, "Outputs");
RegisterShaderNode<InputValue>(*this, registry, "Inputs");
RegisterShaderNode<SampleTexture>(*this, registry, "Texture");
RegisterShaderNode<Vec2Add>(*this, registry, "Vector operations");
RegisterShaderNode<Vec2Mul>(*this, registry, "Vector operations");
RegisterShaderNode<Vec2Sub>(*this, registry, "Vector operations");
RegisterShaderNode<Vec3Add>(*this, registry, "Vector operations");
RegisterShaderNode<Vec3Mul>(*this, registry, "Vector operations");
RegisterShaderNode<Vec3Sub>(*this, registry, "Vector operations");
RegisterShaderNode<Vec4Add>(*this, registry, "Vector operations");
RegisterShaderNode<Vec4Mul>(*this, registry, "Vector operations");
RegisterShaderNode<Vec4Sub>(*this, registry, "Vector operations");
RegisterShaderNode<Vec2Value>(*this, registry, "Constants");
RegisterShaderNode<Vec3Value>(*this, registry, "Constants");
RegisterShaderNode<Vec4Value>(*this, registry, "Constants");
return registry;

View File

@ -7,6 +7,7 @@
#include <Nazara/Renderer/ShaderAst.hpp>
#include <nodes/FlowScene>
#include <Enums.hpp>
#include <Previews/PreviewModel.hpp>
#include <string>
#include <vector>
@ -17,13 +18,14 @@ class ShaderGraph
struct TextureEntry;
ShaderGraph();
~ShaderGraph() = default;
~ShaderGraph();
std::size_t AddInput(std::string name, InputType type, InputRole role, std::size_t roleIndex);
std::size_t AddTexture(std::string name, TextureType type);
inline const InputEntry& GetInput(std::size_t inputIndex) const;
inline const std::vector<InputEntry>& GetInputs() const;
inline const PreviewModel& GetPreviewModel() const;
inline QtNodes::FlowScene& GetScene();
inline const TextureEntry& GetTexture(std::size_t textureIndex) const;
inline const std::vector<TextureEntry>& GetTextures() const;
@ -59,6 +61,7 @@ class ShaderGraph
QtNodes::FlowScene m_flowScene;
std::vector<InputEntry> m_inputs;
std::vector<TextureEntry> m_textures;
std::unique_ptr<PreviewModel> m_previewModel;
};
#include <ShaderGraph.inl>

View File

@ -11,6 +11,11 @@ inline auto ShaderGraph::GetInputs() const -> const std::vector<InputEntry>&
return m_inputs;
}
inline const PreviewModel& ShaderGraph::GetPreviewModel() const
{
return *m_previewModel;
}
inline QtNodes::FlowScene& ShaderGraph::GetScene()
{
return m_flowScene;