NazaraEngine/src/ShaderNode/DataModels/Cast.inl

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;
}