From 93e76a17c7ba2888e303db2fa8401e9abb105a4d Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 23 May 2020 22:04:10 +0200 Subject: [PATCH] ShaderNode: Add preview / cast / texture sampling --- src/ShaderNode/DataModels/Cast.cpp | 0 src/ShaderNode/DataModels/Cast.hpp | 59 ++++++ src/ShaderNode/DataModels/Cast.inl | 201 ++++++++++++++++++++ src/ShaderNode/DataModels/InputValue.cpp | 18 +- src/ShaderNode/DataModels/SampleTexture.cpp | 65 ++++++- src/ShaderNode/DataModels/SampleTexture.hpp | 5 + src/ShaderNode/DataModels/VecBinOp.cpp | 22 --- src/ShaderNode/DataModels/VecBinOp.hpp | 48 +++-- src/ShaderNode/DataModels/VecBinOp.inl | 86 ++++++++- src/ShaderNode/DataModels/VecData.cpp | 1 + src/ShaderNode/DataModels/VecData.hpp | 67 +++++++ src/ShaderNode/DataModels/VecData.inl | 7 + src/ShaderNode/DataModels/VecValue.hpp | 65 ++----- src/ShaderNode/DataModels/VecValue.inl | 83 ++++---- src/ShaderNode/Previews/PreviewModel.cpp | 3 + src/ShaderNode/Previews/PreviewModel.hpp | 21 ++ src/ShaderNode/Previews/PreviewModel.inl | 1 + src/ShaderNode/Previews/QuadPreview.cpp | 24 +++ src/ShaderNode/Previews/QuadPreview.hpp | 20 ++ src/ShaderNode/Previews/QuadPreview.inl | 1 + src/ShaderNode/ShaderGraph.cpp | 23 +++ src/ShaderNode/ShaderGraph.hpp | 5 +- src/ShaderNode/ShaderGraph.inl | 5 + 23 files changed, 686 insertions(+), 144 deletions(-) create mode 100644 src/ShaderNode/DataModels/Cast.cpp create mode 100644 src/ShaderNode/DataModels/Cast.hpp create mode 100644 src/ShaderNode/DataModels/Cast.inl create mode 100644 src/ShaderNode/DataModels/VecData.cpp create mode 100644 src/ShaderNode/DataModels/VecData.hpp create mode 100644 src/ShaderNode/DataModels/VecData.inl create mode 100644 src/ShaderNode/Previews/PreviewModel.cpp create mode 100644 src/ShaderNode/Previews/PreviewModel.hpp create mode 100644 src/ShaderNode/Previews/PreviewModel.inl create mode 100644 src/ShaderNode/Previews/QuadPreview.cpp create mode 100644 src/ShaderNode/Previews/QuadPreview.hpp create mode 100644 src/ShaderNode/Previews/QuadPreview.inl diff --git a/src/ShaderNode/DataModels/Cast.cpp b/src/ShaderNode/DataModels/Cast.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/ShaderNode/DataModels/Cast.hpp b/src/ShaderNode/DataModels/Cast.hpp new file mode 100644 index 000000000..f17cff625 --- /dev/null +++ b/src/ShaderNode/DataModels/Cast.hpp @@ -0,0 +1,59 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_CAST_HPP +#define NAZARA_SHADERNODES_CAST_HPP + +#include +#include +#include +#include +#include +#include +#include + +template +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 outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr 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 m_spinboxes; + std::shared_ptr m_input; + std::shared_ptr m_output; +}; + +using CastVec2ToVec3 = CastVec; +using CastVec2ToVec4 = CastVec; +using CastVec3ToVec2 = CastVec; +using CastVec3ToVec4 = CastVec; +using CastVec4ToVec2 = CastVec; +using CastVec4ToVec3 = CastVec; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl new file mode 100644 index 000000000..9e70e9f8b --- /dev/null +++ b/src/ShaderNode/DataModels/Cast.inl @@ -0,0 +1,201 @@ +#include +#include +#include + +template +CastVec::CastVec(ShaderGraph& graph) : +ShaderNode(graph) +{ + constexpr std::array 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(&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(); +} + +template +Nz::ShaderAst::ExpressionPtr CastVec::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +{ + assert(count == 1); + + if constexpr (ComponentDiff > 0) + { + std::array 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(expressions[0], values...); //< TODO: Forward + }, constants); + } + else + { + std::array swizzleComponents; + for (std::size_t i = 0; i < ToComponents; ++i) + swizzleComponents[i] = static_cast(static_cast(Nz::ShaderAst::SwizzleComponent::First) + i); + + return std::apply([&](auto... components) + { + std::initializer_list componentList{ components... }; + return Nz::ShaderBuilder::Swizzle(expressions[0], componentList); + }, swizzleComponents); + } +} + +template +QString CastVec::caption() const +{ + static QString caption = From::Type().name + " to " + To::Type().name; + return caption; +} + +template +QString CastVec::name() const +{ + static QString name = From::Type().id + "to" + To::Type().id; + return name; +} + +template +QtNodes::NodeDataType CastVec::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 +QWidget* CastVec::embeddedWidget() +{ + return m_widget; +} + +template +unsigned int CastVec::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 1; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +template +std::shared_ptr CastVec::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + return m_output; +} + +template +void CastVec::setInData(std::shared_ptr value, int index) +{ + assert(index == 0); + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + m_input = std::static_pointer_cast(value); + } + else + m_input.reset(); + + UpdatePreview(); +} + +template +void CastVec::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 constants; + for (std::size_t i = 0; i < ComponentDiff; ++i) + constants[i] = static_cast(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 +void CastVec::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); +} diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index f1cc97d0d..1a1bdfb5a 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -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 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(); - vecData->preview = QImage(); + auto vecData = std::make_shared(); + vecData->preview = preview.GetImage(inputEntry.role, inputEntry.roleIndex); return vecData; } diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 925094b6b..d7ae63713 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -7,6 +7,8 @@ SampleTexture::SampleTexture(ShaderGraph& graph) : ShaderNode(graph), m_currentTextureIndex(0) { + m_output = std::make_shared(); + 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 SampleTexture::outData(QtNodes::PortIndex por { assert(port == 0); - const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex); - - auto vecData = std::make_shared(); - vecData->preview = textureEntry.preview; - - return vecData; + return m_output; +} + +void SampleTexture::setInData(std::shared_ptr value, int index) +{ + assert(index == 0); + + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + + m_uv = std::static_pointer_cast(value); + } + else + m_uv.reset(); + + UpdatePreview(); } diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index af11d14ec..3621d0c14 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include class SampleTexture : public ShaderNode @@ -32,6 +33,8 @@ class SampleTexture : public ShaderNode std::shared_ptr outData(QtNodes::PortIndex port) override; + void setInData(std::shared_ptr 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 m_uv; + std::shared_ptr m_output; QComboBox* m_textureSelection; QLabel* m_pixmapLabel; QPixmap m_pixmap; diff --git a/src/ShaderNode/DataModels/VecBinOp.cpp b/src/ShaderNode/DataModels/VecBinOp.cpp index 7349b708f..dd13b5b56 100644 --- a/src/ShaderNode/DataModels/VecBinOp.cpp +++ b/src/ShaderNode/DataModels/VecBinOp.cpp @@ -1,23 +1 @@ #include - -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::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(lValue * rValue / 255); - } -} diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp index 97f433048..31ae4732e 100644 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -30,33 +30,59 @@ class VecBinOp : public ShaderNode QLabel* m_pixmapLabel; QPixmap m_preview; - std::shared_ptr m_lhs; - std::shared_ptr m_rhs; - std::shared_ptr m_output; + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; + std::shared_ptr m_output; }; -class Vec4Add : public VecBinOp +template +class VecAdd : public VecBinOp { public: - using VecBinOp::VecBinOp; + using VecBinOp::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 +template +class VecMul : public VecBinOp { public: - using VecBinOp::VecBinOp; + using VecBinOp::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 +class VecSub : public VecBinOp +{ + public: + using VecBinOp::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; +using Vec3Add = VecAdd; +using Vec4Add = VecAdd; + +using Vec2Mul = VecMul; +using Vec3Mul = VecMul; +using Vec4Mul = VecMul; + +using Vec2Sub = VecSub; +using Vec3Sub = VecSub; +using Vec4Sub = VecSub; + #include #endif diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl index fea7837a7..5d5cfc251 100644 --- a/src/ShaderNode/DataModels/VecBinOp.inl +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -96,14 +96,10 @@ void VecBinOp::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::UpdatePreview() m_pixmapLabel->setPixmap(m_preview); } + +template +QString VecAdd::caption() const +{ + static QString caption = Data::Type().name + " addition"; + return caption; +} + +template +QString VecAdd::name() const +{ + static QString name = Data::Type().name + "add"; + return name; +} + +template +void VecAdd::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::min(lValue + rValue, 255U)); + } +} + +template +QString VecMul::caption() const +{ + static QString caption = Data::Type().name + " multiplication"; + return caption; +} + +template +QString VecMul::name() const +{ + static QString name = Data::Type().name + "mul"; + return name; +} + +template +void VecMul::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(lValue * rValue / 255); + } +} + +template +QString VecSub::caption() const +{ + static QString caption = Data::Type().name + " subtraction"; + return caption; +} + +template +QString VecSub::name() const +{ + static QString name = Data::Type().name + "sub"; + return name; +} + +template +void VecSub::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(sub); + } +} diff --git a/src/ShaderNode/DataModels/VecData.cpp b/src/ShaderNode/DataModels/VecData.cpp new file mode 100644 index 000000000..2cf74c1e6 --- /dev/null +++ b/src/ShaderNode/DataModels/VecData.cpp @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/VecData.hpp b/src/ShaderNode/DataModels/VecData.hpp new file mode 100644 index 000000000..ad44d68b1 --- /dev/null +++ b/src/ShaderNode/DataModels/VecData.hpp @@ -0,0 +1,67 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_VECDATA_HPP +#define NAZARA_SHADERNODES_VECDATA_HPP + +#include +#include +#include + +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 + +#endif diff --git a/src/ShaderNode/DataModels/VecData.inl b/src/ShaderNode/DataModels/VecData.inl new file mode 100644 index 000000000..92765c835 --- /dev/null +++ b/src/ShaderNode/DataModels/VecData.inl @@ -0,0 +1,7 @@ +#include + +inline VecData::VecData() : +preview(64, 64, QImage::Format_RGBA8888) +{ + preview.fill(QColor::fromRgb(255, 255, 255, 0)); +} diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index ba7a61f08..77656f373 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include template @@ -33,13 +34,16 @@ struct VecTypeHelper<4> template using VecType = typename VecTypeHelper::template Type; -template +template 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 ToVector() const; + VecType ToVector() const; void UpdatePreview(); QLabel* m_pixmapLabel; QPixmap m_pixmap; QWidget* m_widget; QFormLayout* m_layout; - std::array m_spinboxes; + std::array 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; +using Vec3Value = VecValue; +using Vec4Value = VecValue; #include diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index 8f8a53fc7..3ab11cd37 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -2,16 +2,17 @@ #include #include #include +#include -template -VecValue::VecValue(ShaderGraph& graph) : +template +VecValue::VecValue(ShaderGraph& graph) : ShaderNode(graph) { constexpr std::array 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 -QtNodes::NodeDataType VecValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +template +QString VecValue::caption() const +{ + static QString caption = Data::Type().name + " constant"; + return caption; +} + +template +QString VecValue::name() const +{ + static QString name = Data::Type().id + "Value"; + return name; +} + +template +QtNodes::NodeDataType VecValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { assert(portType == QtNodes::PortType::Out); assert(portIndex == 0); @@ -51,14 +66,14 @@ QtNodes::NodeDataType VecValue::dataType(QtNodes::PortType portType, Qt return Data::Type(); } -template -QWidget* VecValue::embeddedWidget() +template +QWidget* VecValue::embeddedWidget() { return m_widget; } -template -unsigned int VecValue::nPorts(QtNodes::PortType portType) const +template +unsigned int VecValue::nPorts(QtNodes::PortType portType) const { switch (portType) { @@ -69,8 +84,8 @@ unsigned int VecValue::nPorts(QtNodes::PortType portType) const return 0; } -template -std::shared_ptr VecValue::outData(QtNodes::PortIndex port) +template +std::shared_ptr VecValue::outData(QtNodes::PortIndex port) { assert(port == 0); @@ -81,52 +96,42 @@ std::shared_ptr VecValue::outData(QtNodes::PortIndex return out; } -template -Nz::ShaderAst::ExpressionPtr VecValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +template +Nz::ShaderAst::ExpressionPtr VecValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const { assert(count == 0); return Nz::ShaderBuilder::Constant(ToVector()); } -template -QColor VecValue::ToColor() const +template +QColor VecValue::ToColor() const { std::array values = { 0.f, 0.f, 0.f, 1.f }; - for (std::size_t i = 0; i < N; ++i) - values[i] = std::clamp(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 -VecType VecValue::ToVector() const +template +auto VecValue::ToVector() const -> VecType { - std::array values = { 0.f, 0.f, 0.f, 1.f }; + std::array values; - for (std::size_t i = 0; i < N; ++i) - values[i] = std::clamp(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>(), "Unhandled vector size"); + return std::apply([](auto... values) + { + return VecType(values...); + }, values); } -template -void VecValue::UpdatePreview() +template +void VecValue::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)); -} diff --git a/src/ShaderNode/Previews/PreviewModel.cpp b/src/ShaderNode/Previews/PreviewModel.cpp new file mode 100644 index 000000000..845c19fe2 --- /dev/null +++ b/src/ShaderNode/Previews/PreviewModel.cpp @@ -0,0 +1,3 @@ +#include + +PreviewModel::~PreviewModel() = default; diff --git a/src/ShaderNode/Previews/PreviewModel.hpp b/src/ShaderNode/Previews/PreviewModel.hpp new file mode 100644 index 000000000..138374ea4 --- /dev/null +++ b/src/ShaderNode/Previews/PreviewModel.hpp @@ -0,0 +1,21 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_PREVIEWMODEL_HPP +#define NAZARA_SHADERNODES_PREVIEWMODEL_HPP + +#include + +class QImage; + +class PreviewModel +{ + public: + PreviewModel() = default; + virtual ~PreviewModel(); + + virtual QImage GetImage(InputRole role, std::size_t roleIndex) const = 0; +}; + +#include + +#endif diff --git a/src/ShaderNode/Previews/PreviewModel.inl b/src/ShaderNode/Previews/PreviewModel.inl new file mode 100644 index 000000000..d5f2e699b --- /dev/null +++ b/src/ShaderNode/Previews/PreviewModel.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Previews/QuadPreview.cpp b/src/ShaderNode/Previews/QuadPreview.cpp new file mode 100644 index 000000000..a518287fd --- /dev/null +++ b/src/ShaderNode/Previews/QuadPreview.cpp @@ -0,0 +1,24 @@ +#include +#include + +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; +} diff --git a/src/ShaderNode/Previews/QuadPreview.hpp b/src/ShaderNode/Previews/QuadPreview.hpp new file mode 100644 index 000000000..f193e99d0 --- /dev/null +++ b/src/ShaderNode/Previews/QuadPreview.hpp @@ -0,0 +1,20 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_QUADPREVIEW_HPP +#define NAZARA_SHADERNODES_QUADPREVIEW_HPP + +#include +#include + +class QuadPreview : public PreviewModel +{ + public: + QuadPreview() = default; + ~QuadPreview() = default; + + QImage GetImage(InputRole role, std::size_t roleIndex) const override; +}; + +#include + +#endif diff --git a/src/ShaderNode/Previews/QuadPreview.inl b/src/ShaderNode/Previews/QuadPreview.inl new file mode 100644 index 000000000..01178d2d2 --- /dev/null +++ b/src/ShaderNode/Previews/QuadPreview.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 0b95e137f..be77909de 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -1,11 +1,13 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -34,6 +36,13 @@ m_flowScene(BuildRegistry()) node2.nodeGraphicsObject().setPos(500, 300); m_flowScene.createConnection(node2, 0, node1, 0); + + m_previewModel = std::make_unique(); +} + +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 ShaderGraph::BuildRegistry() { auto registry = std::make_shared(); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Inputs"); RegisterShaderNode(*this, registry, "Texture"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Constants"); + RegisterShaderNode(*this, registry, "Constants"); RegisterShaderNode(*this, registry, "Constants"); return registry; diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index 132c9c25b..dda8dba20 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -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& GetInputs() const; + inline const PreviewModel& GetPreviewModel() const; inline QtNodes::FlowScene& GetScene(); inline const TextureEntry& GetTexture(std::size_t textureIndex) const; inline const std::vector& GetTextures() const; @@ -59,6 +61,7 @@ class ShaderGraph QtNodes::FlowScene m_flowScene; std::vector m_inputs; std::vector m_textures; + std::unique_ptr m_previewModel; }; #include diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index bb39d44f3..fb0a9e556 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -11,6 +11,11 @@ inline auto ShaderGraph::GetInputs() const -> const std::vector& return m_inputs; } +inline const PreviewModel& ShaderGraph::GetPreviewModel() const +{ + return *m_previewModel; +} + inline QtNodes::FlowScene& ShaderGraph::GetScene() { return m_flowScene;