257 lines
6.9 KiB
C++
257 lines
6.9 KiB
C++
#include <ShaderNode/DataModels/Cast.hpp>
|
|
#include <NZSL/ShaderBuilder.hpp>
|
|
#include <QtWidgets/QDoubleSpinBox>
|
|
#include <QtWidgets/QFormLayout>
|
|
#include <QtCore/QJsonArray>
|
|
#include <stdexcept>
|
|
|
|
template<std::size_t ToComponentCount>
|
|
CastVec<ToComponentCount>::CastVec(ShaderGraph& graph) :
|
|
ShaderNode(graph)
|
|
{
|
|
static_assert(ToComponentCount <= s_vectorComponents.size());
|
|
|
|
for (std::size_t i = 0; i < ToComponentCount; ++i)
|
|
m_overflowComponents[i] = 0.f;
|
|
|
|
m_output = std::make_shared<VecData>(ToComponentCount);
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
nzsl::Ast::NodePtr CastVec<ToComponentCount>::BuildNode(nzsl::Ast::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const
|
|
{
|
|
assert(m_input);
|
|
assert(count == 1);
|
|
assert(outputIndex == 0);
|
|
|
|
std::size_t fromComponentCount = m_input->componentCount;
|
|
|
|
if (ToComponentCount > fromComponentCount)
|
|
{
|
|
std::size_t overflowComponentCount = ToComponentCount - fromComponentCount;
|
|
|
|
std::vector<nzsl::Ast::ExpressionPtr> params;
|
|
params.emplace_back(std::move(expressions[0]));
|
|
for (std::size_t i = 0; i < overflowComponentCount; ++i)
|
|
params.emplace_back(nzsl::ShaderBuilder::ConstantValue(m_overflowComponents[i]));
|
|
|
|
return nzsl::ShaderBuilder::Cast(nzsl::Ast::ExpressionType{ nzsl::Ast::VectorType{ ToComponentCount, nzsl::Ast::PrimitiveType::Float32 } }, std::move(params));
|
|
}
|
|
else if (ToComponentCount < fromComponentCount)
|
|
{
|
|
std::array<Nz::UInt32, ToComponentCount> swizzleComponents;
|
|
for (std::size_t i = 0; i < ToComponentCount; ++i)
|
|
swizzleComponents[i] = Nz::SafeCast<Nz::UInt32>(i);
|
|
|
|
return std::apply([&](auto... components)
|
|
{
|
|
std::initializer_list<Nz::UInt32> componentList{ components... };
|
|
return nzsl::ShaderBuilder::Swizzle(std::move(expressions[0]), componentList);
|
|
}, swizzleComponents);
|
|
}
|
|
else
|
|
return std::move(expressions[0]); //< no-op
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
void CastVec<ToComponentCount>::BuildNodeEdition(QFormLayout* layout)
|
|
{
|
|
ShaderNode::BuildNodeEdition(layout);
|
|
|
|
if (!m_input)
|
|
return;
|
|
|
|
std::size_t fromComponentCount = m_input->componentCount;
|
|
|
|
if (ToComponentCount > fromComponentCount)
|
|
{
|
|
std::size_t overflowComponentCount = ToComponentCount - fromComponentCount;
|
|
|
|
for (std::size_t i = 0; i < overflowComponentCount; ++i)
|
|
{
|
|
QDoubleSpinBox* spinbox = new QDoubleSpinBox;
|
|
spinbox->setDecimals(6);
|
|
spinbox->setRange(std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
|
|
spinbox->setValue(m_overflowComponents[i]);
|
|
|
|
connect(spinbox, qOverload<double>(&QDoubleSpinBox::valueChanged), [=](double)
|
|
{
|
|
m_overflowComponents[i] = spinbox->value();
|
|
UpdateOutput();
|
|
});
|
|
|
|
layout->addRow(QString::fromUtf8(&s_vectorComponents[fromComponentCount + i], 1), spinbox);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
QString CastVec<ToComponentCount>::caption() const
|
|
{
|
|
static QString caption = "To Vector" + QString::number(ToComponentCount);
|
|
return caption;
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
QString CastVec<ToComponentCount>::name() const
|
|
{
|
|
static QString name = "cast_vec" + QString::number(ToComponentCount);
|
|
return name;
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
QtNodes::NodeDataType CastVec<ToComponentCount>::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
|
|
{
|
|
assert(portIndex == 0);
|
|
|
|
switch (portType)
|
|
{
|
|
case QtNodes::PortType::In: return VecData::Type();
|
|
case QtNodes::PortType::Out: return VecData::Type();
|
|
default: break;
|
|
}
|
|
|
|
assert(false);
|
|
throw std::runtime_error("Invalid port type");
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
unsigned int CastVec<ToComponentCount>::nPorts(QtNodes::PortType portType) const
|
|
{
|
|
switch (portType)
|
|
{
|
|
case QtNodes::PortType::None:
|
|
break;
|
|
|
|
case QtNodes::PortType::In: return 1;
|
|
case QtNodes::PortType::Out: return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
std::shared_ptr<QtNodes::NodeData> CastVec<ToComponentCount>::outData(QtNodes::PortIndex port)
|
|
{
|
|
assert(port == 0);
|
|
|
|
if (!m_input)
|
|
return nullptr;
|
|
|
|
return m_output;
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
void CastVec<ToComponentCount>::setInData(std::shared_ptr<QtNodes::NodeData> value, int index)
|
|
{
|
|
assert(index == 0);
|
|
if (value && value->type().id == VecData::Type().id)
|
|
{
|
|
assert(dynamic_cast<VecData*>(value.get()) != nullptr);
|
|
m_input = std::static_pointer_cast<VecData>(value);
|
|
}
|
|
else
|
|
m_input.reset();
|
|
|
|
UpdateOutput();
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
QtNodes::NodeValidationState CastVec<ToComponentCount>::validationState() const
|
|
{
|
|
if (!m_input)
|
|
return QtNodes::NodeValidationState::Error;
|
|
|
|
return QtNodes::NodeValidationState::Valid;
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
QString CastVec<ToComponentCount>::validationMessage() const
|
|
{
|
|
if (!m_input)
|
|
return "Missing input";
|
|
|
|
return QString();
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
bool CastVec<ToComponentCount>::ComputePreview(QPixmap& pixmap)
|
|
{
|
|
if (!m_input)
|
|
return false;
|
|
|
|
pixmap = QPixmap::fromImage(m_output->preview.GenerateImage());
|
|
return true;
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
void CastVec<ToComponentCount>::UpdateOutput()
|
|
{
|
|
if (!m_input)
|
|
{
|
|
m_output->preview = PreviewValues(1, 1);
|
|
m_output->preview(0, 0) = nzsl::Vector4f32(0.f, 0.f, 0.f, 0.f);
|
|
return;
|
|
}
|
|
|
|
const PreviewValues& input = m_input->preview;
|
|
|
|
std::size_t inputWidth = input.GetWidth();
|
|
std::size_t inputHeight = input.GetHeight();
|
|
|
|
PreviewValues& output = m_output->preview;
|
|
output = PreviewValues(inputWidth, inputHeight);
|
|
|
|
std::size_t fromComponentCount = m_input->componentCount;
|
|
std::size_t commonComponents = std::min(fromComponentCount, ToComponentCount);
|
|
std::size_t overflowComponentCount = (ToComponentCount > fromComponentCount) ? ToComponentCount - fromComponentCount : 0;
|
|
std::size_t voidComponents = 4 - overflowComponentCount - commonComponents;
|
|
|
|
for (std::size_t y = 0; y < inputHeight; ++y)
|
|
{
|
|
for (std::size_t x = 0; x < inputWidth; ++x)
|
|
{
|
|
nzsl::Vector4f32 color = input(x, y);
|
|
|
|
float* colorPtr = &color[0];
|
|
for (std::size_t i = 0; i < overflowComponentCount; ++i)
|
|
*colorPtr++ = m_overflowComponents[i];
|
|
|
|
for (std::size_t i = 0; i < voidComponents; ++i)
|
|
*colorPtr++ = (i == voidComponents - 1) ? 1.f : 0.f;
|
|
|
|
output(x, y) = color;
|
|
}
|
|
}
|
|
|
|
Q_EMIT dataUpdated(0);
|
|
|
|
UpdatePreview();
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
void CastVec<ToComponentCount>::restore(const QJsonObject& data)
|
|
{
|
|
QJsonArray vecValues = data["value"].toArray();
|
|
std::size_t commonValues = std::min(static_cast<std::size_t>(vecValues.size()), ToComponentCount);
|
|
|
|
for (std::size_t i = 0; i < commonValues; ++i)
|
|
m_overflowComponents[i] = float(vecValues[int(i)].toDouble(m_overflowComponents[i]));
|
|
|
|
ShaderNode::restore(data);
|
|
}
|
|
|
|
template<std::size_t ToComponentCount>
|
|
QJsonObject CastVec<ToComponentCount>::save() const
|
|
{
|
|
QJsonObject data = ShaderNode::save();
|
|
|
|
QJsonArray vecValues;
|
|
for (std::size_t i = 0; i < ToComponentCount; ++i)
|
|
vecValues.push_back(m_overflowComponents[i]);
|
|
|
|
data["value"] = vecValues;
|
|
|
|
return data;
|
|
}
|