ShaderEditor: Add VecDot

This commit is contained in:
Lynix 2020-06-16 17:45:36 +02:00
parent d3db22ce22
commit 80527dec3e
4 changed files with 213 additions and 0 deletions

View File

@ -0,0 +1,167 @@
#include <ShaderNode/DataModels/VecDot.hpp>
#include <Nazara/Renderer/ShaderAst.hpp>
VecDot::VecDot(ShaderGraph& graph) :
ShaderNode(graph)
{
m_output = std::make_shared<FloatData>();
UpdateOutput();
}
Nz::ShaderAst::ExpressionPtr VecDot::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const
{
assert(count == 2);
using namespace Nz::ShaderAst;
return BinaryFunc::Build(BinaryIntrinsic::DotProduct, expressions[0], expressions[1]);
}
QString VecDot::caption() const
{
static QString caption = "Vector dot";
return caption;
}
QString VecDot::name() const
{
static QString name = "vec_dot";
return name;
}
QtNodes::NodeDataType VecDot::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
{
switch (portType)
{
case QtNodes::PortType::In:
{
assert(portIndex == 0 || portIndex == 1);
return VecData::Type();
}
case QtNodes::PortType::Out:
{
assert(portIndex == 0);
return FloatData::Type();
}
}
assert(false);
throw std::runtime_error("Invalid port type");
}
unsigned int VecDot::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<QtNodes::NodeData> VecDot::outData(QtNodes::PortIndex port)
{
assert(port == 0);
return m_output;
}
void VecDot::setInData(std::shared_ptr<QtNodes::NodeData> value, int index)
{
assert(index == 0 || index == 1);
std::shared_ptr<VecData> castedValue;
if (value)
{
assert(dynamic_cast<VecData*>(value.get()) != nullptr);
castedValue = std::static_pointer_cast<VecData>(value);
}
if (index == 0)
m_lhs = std::move(castedValue);
else
m_rhs = std::move(castedValue);
UpdateOutput();
}
QtNodes::NodeValidationState VecDot::validationState() const
{
if (!m_lhs || !m_rhs)
return QtNodes::NodeValidationState::Error;
if (m_lhs->componentCount != m_rhs->componentCount)
return QtNodes::NodeValidationState::Error;
return QtNodes::NodeValidationState::Valid;
}
QString VecDot::validationMessage() const
{
if (!m_lhs || !m_rhs)
return "Missing operands";
if (m_lhs->componentCount != m_rhs->componentCount)
return "Incompatible components count (left has " + QString::number(m_lhs->componentCount) + ", right has " + QString::number(m_rhs->componentCount) + ")";
return QString();
}
bool VecDot::ComputePreview(QPixmap& pixmap)
{
if (validationState() != QtNodes::NodeValidationState::Valid)
return false;
pixmap = QPixmap::fromImage(m_output->preview);
return true;
}
void VecDot::UpdateOutput()
{
if (validationState() != QtNodes::NodeValidationState::Valid)
{
m_output->preview = QImage(1, 1, QImage::Format_RGBA8888);
m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0));
return;
}
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;
for (std::size_t i = 0; i < pixelCount; ++i)
{
unsigned int acc = 0;
for (std::size_t j = 0; j < m_lhs->componentCount; ++j)
acc += left[j] * right[j] / 255;
unsigned int result = static_cast<std::uint8_t>(std::min(acc, 255U));
for (std::size_t j = 0; j < 3; ++j)
*output++ = result;
*output++ = 255; //< leave alpha at maximum
left += 4;
right += 4;
}
Q_EMIT dataUpdated(0);
UpdatePreview();
}

View File

@ -0,0 +1,43 @@
#pragma once
#ifndef NAZARA_SHADERNODES_VECDOT_HPP
#define NAZARA_SHADERNODES_VECDOT_HPP
#include <ShaderNode/DataModels/ShaderNode.hpp>
#include <ShaderNode/DataTypes/FloatData.hpp>
#include <ShaderNode/DataTypes/VecData.hpp>
class VecDot : public ShaderNode
{
public:
VecDot(ShaderGraph& graph);
~VecDot() = 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<QtNodes::NodeData> outData(QtNodes::PortIndex port) override;
void setInData(std::shared_ptr<QtNodes::NodeData> value, int index) override;
QtNodes::NodeValidationState validationState() const override;
QString validationMessage() const override;
private:
bool ComputePreview(QPixmap& pixmap) override;
void UpdateOutput();
std::shared_ptr<VecData> m_lhs;
std::shared_ptr<VecData> m_rhs;
std::shared_ptr<FloatData> m_output;
};
#include <ShaderNode/DataModels/VecDot.inl>
#endif

View File

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

View File

@ -8,6 +8,7 @@
#include <ShaderNode/DataModels/ShaderNode.hpp> #include <ShaderNode/DataModels/ShaderNode.hpp>
#include <ShaderNode/DataModels/TextureValue.hpp> #include <ShaderNode/DataModels/TextureValue.hpp>
#include <ShaderNode/DataModels/VecBinOp.hpp> #include <ShaderNode/DataModels/VecBinOp.hpp>
#include <ShaderNode/DataModels/VecDot.hpp>
#include <ShaderNode/DataModels/VecValue.hpp> #include <ShaderNode/DataModels/VecValue.hpp>
#include <ShaderNode/Previews/QuadPreview.hpp> #include <ShaderNode/Previews/QuadPreview.hpp>
#include <QtCore/QDebug> #include <QtCore/QDebug>
@ -400,6 +401,7 @@ std::shared_ptr<QtNodes::DataModelRegistry> ShaderGraph::BuildRegistry()
RegisterShaderNode<TextureValue>(*this, registry, "Texture"); RegisterShaderNode<TextureValue>(*this, registry, "Texture");
RegisterShaderNode<VecAdd>(*this, registry, "Vector operations"); RegisterShaderNode<VecAdd>(*this, registry, "Vector operations");
RegisterShaderNode<VecDiv>(*this, registry, "Vector operations"); RegisterShaderNode<VecDiv>(*this, registry, "Vector operations");
RegisterShaderNode<VecDot>(*this, registry, "Vector operations");
RegisterShaderNode<VecMul>(*this, registry, "Vector operations"); RegisterShaderNode<VecMul>(*this, registry, "Vector operations");
RegisterShaderNode<VecSub>(*this, registry, "Vector operations"); RegisterShaderNode<VecSub>(*this, registry, "Vector operations");
RegisterShaderNode<Vec2Value>(*this, registry, "Constants"); RegisterShaderNode<Vec2Value>(*this, registry, "Constants");