From 463b54073957c8ac8a4c59af6e23e0d342324eef Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 Jun 2020 17:46:03 +0200 Subject: [PATCH] ShaderEditor: Add VecFloatMul --- src/ShaderNode/DataModels/VecFloatMul.cpp | 183 ++++++++++++++++++++++ src/ShaderNode/DataModels/VecFloatMul.hpp | 43 +++++ src/ShaderNode/DataModels/VecFloatMul.inl | 1 + src/ShaderNode/ShaderGraph.cpp | 2 + 4 files changed, 229 insertions(+) create mode 100644 src/ShaderNode/DataModels/VecFloatMul.cpp create mode 100644 src/ShaderNode/DataModels/VecFloatMul.hpp create mode 100644 src/ShaderNode/DataModels/VecFloatMul.inl diff --git a/src/ShaderNode/DataModels/VecFloatMul.cpp b/src/ShaderNode/DataModels/VecFloatMul.cpp new file mode 100644 index 000000000..f4ec6f957 --- /dev/null +++ b/src/ShaderNode/DataModels/VecFloatMul.cpp @@ -0,0 +1,183 @@ +#include +#include + +VecFloatMul::VecFloatMul(ShaderGraph& graph) : +ShaderNode(graph) +{ + UpdateOutput(); +} + +Nz::ShaderAst::ExpressionPtr VecFloatMul::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +{ + assert(count == 2); + using namespace Nz::ShaderAst; + return BinaryOp::Build(BinaryType::Multiply, expressions[0], expressions[1]); +} + +QString VecFloatMul::caption() const +{ + static QString caption = "Float/vector multiplication"; + return caption; +} + +QString VecFloatMul::name() const +{ + static QString name = "vecfloat_mul"; + return name; +} + +QtNodes::NodeDataType VecFloatMul::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + assert(portIndex == 0 || portIndex == 1); + switch (portIndex) + { + case 0: return FloatData::Type(); + case 1: return VecData::Type(); + } + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + return VecData::Type(); + } + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +unsigned int VecFloatMul::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 2; + case QtNodes::PortType::Out: return 1; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +std::shared_ptr VecFloatMul::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + return m_output; +} + +void VecFloatMul::setInData(std::shared_ptr value, int index) +{ + assert(index == 0 || index == 1); + + switch (index) + { + case 0: + { + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + + m_lhs = std::static_pointer_cast(value); + } + else + m_lhs.reset(); + + break; + } + + case 1: + { + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + + m_rhs = std::static_pointer_cast(value); + } + else + m_rhs.reset(); + + break; + } + + default: + assert(false); + throw std::runtime_error("Invalid PortType"); + } + + UpdateOutput(); +} + +QtNodes::NodeValidationState VecFloatMul::validationState() const +{ + if (!m_lhs || !m_rhs) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString VecFloatMul::validationMessage() const +{ + if (!m_lhs || !m_rhs) + return "Missing operands"; + + return QString(); +} + +bool VecFloatMul::ComputePreview(QPixmap& pixmap) +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + return false; + + pixmap = QPixmap::fromImage(m_output->preview); + return true; +} + +void VecFloatMul::UpdateOutput() +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + { + m_output = std::make_shared(4); + m_output->preview = QImage(1, 1, QImage::Format_RGBA8888); + m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0)); + return; + } + + m_output = std::make_shared(m_rhs->componentCount); + + 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); + + m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888); + + const uchar* left = leftResized.constBits(); + const uchar* right = rightPreview.constBits(); + uchar* output = m_output->preview.bits(); + + std::size_t pixelCount = maxWidth * maxHeight * 4; + 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); + } + + Q_EMIT dataUpdated(0); + + UpdatePreview(); +} diff --git a/src/ShaderNode/DataModels/VecFloatMul.hpp b/src/ShaderNode/DataModels/VecFloatMul.hpp new file mode 100644 index 000000000..c4a9a97f7 --- /dev/null +++ b/src/ShaderNode/DataModels/VecFloatMul.hpp @@ -0,0 +1,43 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_VECFLOATMUL_HPP +#define NAZARA_SHADERNODES_VECFLOATMUL_HPP + +#include +#include +#include + +class VecFloatMul : public ShaderNode +{ + public: + VecFloatMul(ShaderGraph& graph); + ~VecFloatMul() = default; + + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + + QString caption() const override; + QString name() const override; + + 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; + + void setInData(std::shared_ptr value, int index) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + bool ComputePreview(QPixmap& pixmap) override; + void UpdateOutput(); + + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; + std::shared_ptr m_output; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/VecFloatMul.inl b/src/ShaderNode/DataModels/VecFloatMul.inl new file mode 100644 index 000000000..a798943a8 --- /dev/null +++ b/src/ShaderNode/DataModels/VecFloatMul.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 57b9429e3..06b0ddea0 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -402,6 +403,7 @@ std::shared_ptr ShaderGraph::BuildRegistry() 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");