diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index aa2b9d858..e0fa852c3 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -7,20 +7,6 @@ ShaderNode(graph) { m_output = std::make_shared(); - m_onTextureListUpdateSlot.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { OnTextureListUpdate(); }); - m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, [&](ShaderGraph*, std::size_t textureIndex) - { - if (m_currentTextureIndex == textureIndex) - UpdatePreview(); - }); - - if (graph.GetTextureCount() > 0) - { - auto& firstInput = graph.GetTexture(0); - m_currentTextureIndex = 0; - m_currentTextureText = firstInput.name; - } - UpdateOutput(); } @@ -28,45 +14,28 @@ unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const { switch (portType) { - case QtNodes::PortType::In: return 1; + case QtNodes::PortType::In: return 2; case QtNodes::PortType::Out: return 1; } return 0; } -void SampleTexture::OnTextureListUpdate() -{ - m_currentTextureIndex.reset(); - - std::size_t inputIndex = 0; - for (const auto& textureEntry : GetGraph().GetTextures()) - { - if (textureEntry.name == m_currentTextureText) - { - m_currentTextureIndex = inputIndex; - break; - } - - inputIndex++; - } -} - void SampleTexture::UpdateOutput() { QImage& output = m_output->preview; - if (!m_currentTextureIndex || !m_uv) + if (!m_texture || !m_uv) { output = QImage(1, 1, QImage::Format_RGBA8888); output.fill(QColor::fromRgb(0, 0, 0, 0)); return; } - const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); + const QImage& texturePreview = m_texture->preview; - int textureWidth = textureEntry.preview.width(); - int textureHeight = textureEntry.preview.height(); + int textureWidth = texturePreview.width(); + int textureHeight = texturePreview.height(); const QImage& uv = m_uv->preview; @@ -77,7 +46,7 @@ void SampleTexture::UpdateOutput() std::uint8_t* outputPtr = output.bits(); const std::uint8_t* uvPtr = uv.constBits(); - const std::uint8_t* texturePtr = textureEntry.preview.constBits(); + const std::uint8_t* texturePtr = texturePreview.constBits(); for (int y = 0; y < uvHeight; ++y) { for (int x = 0; x < uvWidth; ++x) @@ -104,57 +73,21 @@ void SampleTexture::UpdateOutput() bool SampleTexture::ComputePreview(QPixmap& pixmap) { - if (!m_currentTextureIndex || !m_uv) + if (!m_texture || !m_uv) return false; pixmap = QPixmap::fromImage(m_output->preview); return true; } -void SampleTexture::BuildNodeEdition(QFormLayout* layout) -{ - ShaderNode::BuildNodeEdition(layout); - - QComboBox* textureSelection = new QComboBox; - connect(textureSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) - { - if (index >= 0) - m_currentTextureIndex = static_cast(index); - else - m_currentTextureIndex.reset(); - - UpdateOutput(); - }); - - for (const auto& textureEntry : GetGraph().GetTextures()) - textureSelection->addItem(QString::fromStdString(textureEntry.name)); - - layout->addRow(tr("Texture"), textureSelection); -} - Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const { - if (!m_currentTextureIndex || !m_uv) + if (!m_texture || !m_uv) throw std::runtime_error("invalid inputs"); - assert(count == 1); + assert(count == 2); - const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); - - Nz::ShaderAst::ExpressionType expression = [&] - { - switch (textureEntry.type) - { - case TextureType::Sampler2D: return Nz::ShaderAst::ExpressionType::Sampler2D; - } - - assert(false); - throw std::runtime_error("Unhandled texture type"); - }(); - - auto sampler = Nz::ShaderBuilder::Uniform(textureEntry.name, expression); - - return Nz::ShaderBuilder::Sample2D(sampler, expressions[0]); + return Nz::ShaderBuilder::Sample2D(expressions[0], expressions[1]); } auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType @@ -163,8 +96,14 @@ auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex port { case QtNodes::PortType::In: { - assert(portIndex == 0); - return Vec2Data::Type(); + switch (portIndex) + { + case 0: return Texture2Data::Type(); + case 1: return Vec2Data::Type(); + } + + assert(false); + throw std::runtime_error("invalid port index"); } case QtNodes::PortType::Out: @@ -175,7 +114,7 @@ auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex port default: assert(false); - throw std::runtime_error("Invalid PortType"); + throw std::runtime_error("invalid PortType"); } } @@ -185,8 +124,14 @@ QString SampleTexture::portCaption(QtNodes::PortType portType, QtNodes::PortInde { case QtNodes::PortType::In: { - assert(portIndex == 0); - return tr("UV"); + switch (portIndex) + { + case 0: return tr("Texture"); + case 1: return tr("UV"); + } + + assert(false); + throw std::runtime_error("invalid port index"); } case QtNodes::PortType::Out: @@ -210,24 +155,45 @@ std::shared_ptr SampleTexture::outData(QtNodes::PortIndex por { assert(port == 0); - if (!m_currentTextureIndex) - return nullptr; - return m_output; } void SampleTexture::setInData(std::shared_ptr value, int index) { - assert(index == 0); - - if (value) + switch (index) { - assert(dynamic_cast(value.get()) != nullptr); + case 0: + { + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); - m_uv = std::static_pointer_cast(value); + m_texture = std::static_pointer_cast(value); + } + else + m_texture.reset(); + + break; + } + + case 1: + { + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + + m_uv = std::static_pointer_cast(value); + } + else + m_uv.reset(); + + break; + } + + default: + assert(false); + throw std::runtime_error("Invalid PortType"); } - else - m_uv.reset(); UpdateOutput(); } diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index 3b463bb3b..7a24409d0 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 @@ -16,8 +17,6 @@ class SampleTexture : public ShaderNode SampleTexture(ShaderGraph& graph); ~SampleTexture() = default; - void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; QString caption() const override { return "Sample texture"; } @@ -37,16 +36,11 @@ class SampleTexture : public ShaderNode protected: bool ComputePreview(QPixmap& pixmap) override; - void OnTextureListUpdate(); void UpdateOutput(); - NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot); - NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot); - - std::optional m_currentTextureIndex; + std::shared_ptr m_texture; std::shared_ptr m_uv; std::shared_ptr m_output; - std::string m_currentTextureText; }; #include diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp new file mode 100644 index 000000000..57127005b --- /dev/null +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include + +TextureValue::TextureValue(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_onTextureListUpdateSlot.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { OnTextureListUpdate(); }); + m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, [&](ShaderGraph*, std::size_t textureIndex) + { + if (m_currentTextureIndex == textureIndex) + UpdatePreview(); + }); + + if (graph.GetTextureCount() > 0) + { + auto& firstInput = graph.GetTexture(0); + m_currentTextureIndex = 0; + m_currentTextureText = firstInput.name; + } + + EnablePreview(true); +} + +unsigned int TextureValue::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 0; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +void TextureValue::OnTextureListUpdate() +{ + m_currentTextureIndex.reset(); + + std::size_t inputIndex = 0; + for (const auto& textureEntry : GetGraph().GetTextures()) + { + if (textureEntry.name == m_currentTextureText) + { + m_currentTextureIndex = inputIndex; + break; + } + + inputIndex++; + } +} + +bool TextureValue::ComputePreview(QPixmap& pixmap) +{ + if (!m_currentTextureIndex) + return false; + + const ShaderGraph& graph = GetGraph(); + const auto& textureEntry = graph.GetTexture(*m_currentTextureIndex); + + pixmap = QPixmap::fromImage(textureEntry.preview); + return true; +} + +void TextureValue::BuildNodeEdition(QFormLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + QComboBox* textureSelection = new QComboBox; + connect(textureSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) + { + if (index >= 0) + m_currentTextureIndex = static_cast(index); + else + m_currentTextureIndex.reset(); + + UpdatePreview(); + + Q_EMIT dataUpdated(0); + }); + + for (const auto& textureEntry : GetGraph().GetTextures()) + textureSelection->addItem(QString::fromStdString(textureEntry.name)); + + layout->addRow(tr("Texture"), textureSelection); +} + +Nz::ShaderAst::ExpressionPtr TextureValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +{ + if (!m_currentTextureIndex) + throw std::runtime_error("invalid inputs"); + + assert(count == 0); + + const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); + + Nz::ShaderAst::ExpressionType expression = [&] + { + switch (textureEntry.type) + { + case TextureType::Sampler2D: return Nz::ShaderAst::ExpressionType::Sampler2D; + } + + assert(false); + throw std::runtime_error("Unhandled texture type"); + }(); + + return Nz::ShaderBuilder::Uniform(textureEntry.name, expression); +} + +auto TextureValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + return Vec4Data::Type(); +} + +std::shared_ptr TextureValue::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + + if (!m_currentTextureIndex) + return nullptr; + + const ShaderGraph& graph = GetGraph(); + const auto& textureEntry = graph.GetTexture(*m_currentTextureIndex); + + std::shared_ptr textureData; + + switch (textureEntry.type) + { + case TextureType::Sampler2D: + textureData = std::make_shared(); + break; + } + + assert(textureData); + + textureData->preview = textureEntry.preview; + + return textureData; +} diff --git a/src/ShaderNode/DataModels/TextureValue.hpp b/src/ShaderNode/DataModels/TextureValue.hpp new file mode 100644 index 000000000..27ae9474a --- /dev/null +++ b/src/ShaderNode/DataModels/TextureValue.hpp @@ -0,0 +1,45 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_TEXTUREVALUE_HPP +#define NAZARA_SHADERNODES_TEXTUREVALUE_HPP + +#include +#include +#include +#include +#include +#include + +class TextureValue : public ShaderNode +{ + public: + TextureValue(ShaderGraph& graph); + ~TextureValue() = default; + + void BuildNodeEdition(QFormLayout* layout) override; + + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; + + QString caption() const override { return "Texture"; } + QString name() const override { return "Texture"; } + + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + protected: + bool ComputePreview(QPixmap& pixmap) override; + void OnTextureListUpdate(); + + NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot); + NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot); + + std::optional m_currentTextureIndex; + std::string m_currentTextureText; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/TextureValue.inl b/src/ShaderNode/DataModels/TextureValue.inl new file mode 100644 index 000000000..f28a64549 --- /dev/null +++ b/src/ShaderNode/DataModels/TextureValue.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataTypes/TextureData.cpp b/src/ShaderNode/DataTypes/TextureData.cpp new file mode 100644 index 000000000..ad29d24f1 --- /dev/null +++ b/src/ShaderNode/DataTypes/TextureData.cpp @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataTypes/TextureData.hpp b/src/ShaderNode/DataTypes/TextureData.hpp new file mode 100644 index 000000000..778e66e05 --- /dev/null +++ b/src/ShaderNode/DataTypes/TextureData.hpp @@ -0,0 +1,32 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_TEXTUREDATA_HPP +#define NAZARA_SHADERNODES_TEXTUREDATA_HPP + +#include +#include +#include + +struct TextureData : public QtNodes::NodeData +{ + inline TextureData(); + + QImage preview; +}; + +struct Texture2Data : public TextureData +{ + QtNodes::NodeDataType type() const override + { + return Type(); + } + + static QtNodes::NodeDataType Type() + { + return { "tex2d", "Texture2D" }; + } +}; + +#include + +#endif diff --git a/src/ShaderNode/DataTypes/TextureData.inl b/src/ShaderNode/DataTypes/TextureData.inl new file mode 100644 index 000000000..e3ae7014f --- /dev/null +++ b/src/ShaderNode/DataTypes/TextureData.inl @@ -0,0 +1,7 @@ +#include + +inline TextureData::TextureData() : +preview(64, 64, QImage::Format_RGBA8888) +{ + preview.fill(QColor::fromRgb(255, 255, 255, 0)); +} diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 3ddffe365..6db88c2f0 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -46,22 +47,26 @@ m_flowScene(BuildRegistry()) UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)")); - auto& node1 = m_flowScene.createNode(std::make_unique(*this)); + auto& node1 = m_flowScene.createNode(std::make_unique(*this)); node1.nodeGraphicsObject().setPos(0, 200); - auto& node2 = m_flowScene.createNode(std::make_unique(*this)); - node2.nodeGraphicsObject().setPos(200, 200); + auto& node2 = m_flowScene.createNode(std::make_unique(*this)); + node2.nodeGraphicsObject().setPos(50, 350); - auto& node3 = m_flowScene.createNode(std::make_unique(*this)); - node3.nodeGraphicsObject().setPos(400, 200); + auto& node3 = m_flowScene.createNode(std::make_unique(*this)); + node3.nodeGraphicsObject().setPos(200, 200); - auto& node4 = m_flowScene.createNode(std::make_unique(*this)); - node4.nodeGraphicsObject().setPos(600, 300); + auto& node4 = m_flowScene.createNode(std::make_unique(*this)); + node4.nodeGraphicsObject().setPos(400, 200); - m_flowScene.createConnection(node2, 0, node1, 0); - m_flowScene.createConnection(node3, 0, node2, 0); + auto& node5 = m_flowScene.createNode(std::make_unique(*this)); + node5.nodeGraphicsObject().setPos(600, 300); + + m_flowScene.createConnection(node3, 0, node1, 0); m_flowScene.createConnection(node3, 1, node2, 0); m_flowScene.createConnection(node4, 0, node3, 0); + m_flowScene.createConnection(node4, 1, node3, 0); + m_flowScene.createConnection(node5, 0, node4, 0); } ShaderGraph::~ShaderGraph() @@ -105,8 +110,6 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() std::function DetectVariables; DetectVariables = [&](QtNodes::Node* node) { - ShaderNode* shaderNode = static_cast(node->nodeDataModel()); - auto it = usageCount.find(node->id()); if (it == usageCount.end()) { @@ -226,6 +229,7 @@ std::shared_ptr ShaderGraph::BuildRegistry() RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Inputs"); RegisterShaderNode(*this, registry, "Texture"); + RegisterShaderNode(*this, registry, "Texture"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations");