#include #include template VecBinOp::VecBinOp(ShaderGraph& graph) : ShaderNode(graph) { m_output = std::make_shared(); m_pixmapLabel = new QLabel; m_pixmapLabel->setStyleSheet("background-color: rgba(0,0,0,0)"); UpdatePreview(); } template Nz::ShaderAst::ExpressionPtr VecBinOp::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const { assert(count == 2); using BuilderType = typename Nz::ShaderBuilder::template BinOpBuilder; constexpr BuilderType builder; return builder(expressions[0], expressions[1]); } template QWidget* VecBinOp::embeddedWidget() { return m_pixmapLabel; } template QtNodes::NodeDataType VecBinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const { assert(portIndex == 0 || portIndex == 1); return Data::Type(); } template unsigned int VecBinOp::nPorts(QtNodes::PortType portType) const { switch (portType) { case QtNodes::PortType::In: return 2; case QtNodes::PortType::Out: return 1; } return 0; } template std::shared_ptr VecBinOp::outData(QtNodes::PortIndex port) { assert(port == 0); return m_output; } template void VecBinOp::setInData(std::shared_ptr value, int index) { assert(index == 0 || index == 1); std::shared_ptr castedValue; if (value) { assert(dynamic_cast(value.get()) != nullptr); castedValue = std::static_pointer_cast(value); } if (index == 0) m_lhs = std::move(castedValue); else m_rhs = std::move(castedValue); UpdatePreview(); Q_EMIT dataUpdated(0); } template void VecBinOp::UpdatePreview() { 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); m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888); ApplyOp(leftResized.constBits(), rightResized.constBits(), m_output->preview.bits(), maxWidth * maxHeight * 4); m_preview = QPixmap::fromImage(m_output->preview).scaled(64, 64); } else { m_preview = QPixmap(64, 64); m_preview.fill(QColor::fromRgb(255, 255, 0, 0)); } 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); } }