193 lines
4.9 KiB
C++
193 lines
4.9 KiB
C++
#include <ShaderNode/DataModels/VecComposition.hpp>
|
|
#include <Nazara/Shader/ShaderBuilder.hpp>
|
|
#include <QtWidgets/QDoubleSpinBox>
|
|
#include <QtWidgets/QFormLayout>
|
|
#include <stdexcept>
|
|
|
|
template<std::size_t ComponentCount>
|
|
VecComposition<ComponentCount>::VecComposition(ShaderGraph& graph) :
|
|
ShaderNode(graph)
|
|
{
|
|
static_assert(ComponentCount <= s_vectorComponents.size());
|
|
|
|
m_output = std::make_shared<VecData>(ComponentCount);
|
|
}
|
|
|
|
template<std::size_t ComponentCount>
|
|
Nz::ShaderNodes::NodePtr VecComposition<ComponentCount>::BuildNode(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const
|
|
{
|
|
assert(count == ComponentCount);
|
|
assert(outputIndex == 0);
|
|
|
|
std::array<Nz::ShaderNodes::ExpressionPtr, ComponentCount> expr;
|
|
for (std::size_t i = 0; i < count; ++i)
|
|
expr[i] = expressions[i];
|
|
|
|
constexpr auto ExpressionType = VecExpressionType<ComponentCount>;
|
|
return Nz::ShaderBuilder::Cast<ExpressionType>(expr.data(), expr.size());
|
|
}
|
|
|
|
template<std::size_t ComponentCount>
|
|
QString VecComposition<ComponentCount>::caption() const
|
|
{
|
|
static QString caption = "Compose Vector" + QString::number(ComponentCount);
|
|
return caption;
|
|
}
|
|
|
|
template<std::size_t ComponentCount>
|
|
QString VecComposition<ComponentCount>::name() const
|
|
{
|
|
static QString name = "vec_compose" + QString::number(ComponentCount);
|
|
return name;
|
|
}
|
|
|
|
template<std::size_t ComponentCount>
|
|
QtNodes::NodeDataType VecComposition<ComponentCount>::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const
|
|
{
|
|
switch (portType)
|
|
{
|
|
case QtNodes::PortType::In:
|
|
{
|
|
assert(portIndex >= 0);
|
|
assert(portIndex < ComponentCount);
|
|
return FloatData::Type();
|
|
}
|
|
|
|
case QtNodes::PortType::Out:
|
|
{
|
|
assert(portIndex == 0);
|
|
return VecData::Type();
|
|
}
|
|
|
|
default: break;
|
|
}
|
|
|
|
assert(false);
|
|
throw std::runtime_error("Invalid port type");
|
|
}
|
|
|
|
template<std::size_t ComponentCount>
|
|
unsigned int VecComposition<ComponentCount>::nPorts(QtNodes::PortType portType) const
|
|
{
|
|
switch (portType)
|
|
{
|
|
case QtNodes::PortType::In: return ComponentCount;
|
|
case QtNodes::PortType::Out: return 1;
|
|
|
|
default: break;
|
|
}
|
|
|
|
assert(false);
|
|
throw std::runtime_error("Invalid port type");
|
|
}
|
|
|
|
template<std::size_t ComponentCount>
|
|
std::shared_ptr<QtNodes::NodeData> VecComposition<ComponentCount>::outData(QtNodes::PortIndex port)
|
|
{
|
|
assert(port == 0);
|
|
|
|
if (validationState() != QtNodes::NodeValidationState::Valid)
|
|
return nullptr;
|
|
|
|
return m_output;
|
|
}
|
|
|
|
template<std::size_t ComponentCount>
|
|
void VecComposition<ComponentCount>::setInData(std::shared_ptr<QtNodes::NodeData> value, int index)
|
|
{
|
|
assert(index >= 0 && index < ComponentCount);
|
|
|
|
if (value && value->type().id == FloatData::Type().id)
|
|
{
|
|
assert(dynamic_cast<FloatData*>(value.get()) != nullptr);
|
|
m_inputs[index] = std::static_pointer_cast<FloatData>(value);
|
|
}
|
|
else
|
|
m_inputs[index].reset();
|
|
|
|
UpdateOutput();
|
|
}
|
|
|
|
template<std::size_t ComponentCount>
|
|
QtNodes::NodeValidationState VecComposition<ComponentCount>::validationState() const
|
|
{
|
|
for (std::size_t i = 0; i < ComponentCount; ++i)
|
|
{
|
|
if (!m_inputs[i])
|
|
return QtNodes::NodeValidationState::Error;
|
|
}
|
|
|
|
return QtNodes::NodeValidationState::Valid;
|
|
}
|
|
|
|
template<std::size_t ComponentCount>
|
|
QString VecComposition<ComponentCount>::validationMessage() const
|
|
{
|
|
for (std::size_t i = 0; i < ComponentCount; ++i)
|
|
{
|
|
if (!m_inputs[i])
|
|
return "Missing input #" + QString::number(i + 1);
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
template<std::size_t ComponentCount>
|
|
bool VecComposition<ComponentCount>::ComputePreview(QPixmap& pixmap)
|
|
{
|
|
if (validationState() != QtNodes::NodeValidationState::Valid)
|
|
return false;
|
|
|
|
pixmap = QPixmap::fromImage(m_output->preview.GenerateImage());
|
|
return true;
|
|
}
|
|
|
|
template<std::size_t ComponentCount>
|
|
void VecComposition<ComponentCount>::UpdateOutput()
|
|
{
|
|
if (validationState() != QtNodes::NodeValidationState::Valid)
|
|
{
|
|
m_output->preview = PreviewValues(1, 1);
|
|
m_output->preview(0, 0) = Nz::Vector4f::Zero();
|
|
return;
|
|
}
|
|
|
|
std::array<PreviewValues, ComponentCount> previewResized;
|
|
std::size_t maxInputWidth = 0;
|
|
std::size_t maxInputHeight = 0;
|
|
|
|
for (std::size_t i = 0; i < ComponentCount; ++i)
|
|
{
|
|
// FIXME: Prevent useless copy
|
|
previewResized[i] = m_inputs[i]->preview;
|
|
|
|
maxInputWidth = std::max(maxInputWidth, previewResized[i].GetWidth());
|
|
maxInputHeight = std::max(maxInputHeight, previewResized[i].GetHeight());
|
|
}
|
|
|
|
PreviewValues& output = m_output->preview;
|
|
output = PreviewValues(maxInputWidth, maxInputHeight);
|
|
|
|
for (std::size_t i = 0; i < ComponentCount; ++i)
|
|
{
|
|
if (previewResized[i].GetWidth() != maxInputWidth || previewResized[i].GetHeight() != maxInputHeight)
|
|
previewResized[i] = previewResized[i].Resized(maxInputWidth, maxInputHeight);
|
|
}
|
|
|
|
for (std::size_t y = 0; y < maxInputHeight; ++y)
|
|
{
|
|
for (std::size_t x = 0; x < maxInputWidth; ++x)
|
|
{
|
|
Nz::Vector4f color(0.f, 0.f, 0.f, 1.f);
|
|
for (std::size_t i = 0; i < ComponentCount; ++i)
|
|
color[i] = previewResized[i](x, y)[0];
|
|
|
|
output(x, y) = color;
|
|
}
|
|
}
|
|
|
|
Q_EMIT dataUpdated(0);
|
|
|
|
UpdatePreview();
|
|
}
|