#include #include #include #include #include template VecComposition::VecComposition(ShaderGraph& graph) : ShaderNode(graph) { static_assert(ComponentCount <= s_vectorComponents.size()); m_output = std::make_shared(ComponentCount); } template Nz::ShaderNodes::NodePtr VecComposition::BuildNode(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { assert(count == ComponentCount); assert(outputIndex == 0); std::array expr; for (std::size_t i = 0; i < count; ++i) expr[i] = expressions[i]; constexpr auto ExpressionType = VecExpressionType; return Nz::ShaderBuilder::Cast(expr.data(), expr.size()); } template QString VecComposition::caption() const { static QString caption = "Compose Vector" + QString::number(ComponentCount); return caption; } template QString VecComposition::name() const { static QString name = "vec_compose" + QString::number(ComponentCount); return name; } template QtNodes::NodeDataType VecComposition::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 unsigned int VecComposition::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::shared_ptr VecComposition::outData(QtNodes::PortIndex port) { assert(port == 0); if (validationState() != QtNodes::NodeValidationState::Valid) return nullptr; return m_output; } template void VecComposition::setInData(std::shared_ptr value, int index) { assert(index >= 0 && index < ComponentCount); if (value && value->type().id == FloatData::Type().id) { assert(dynamic_cast(value.get()) != nullptr); m_inputs[index] = std::static_pointer_cast(value); } else m_inputs[index].reset(); UpdateOutput(); } template QtNodes::NodeValidationState VecComposition::validationState() const { for (std::size_t i = 0; i < ComponentCount; ++i) { if (!m_inputs[i]) return QtNodes::NodeValidationState::Error; } return QtNodes::NodeValidationState::Valid; } template QString VecComposition::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 bool VecComposition::ComputePreview(QPixmap& pixmap) { if (validationState() != QtNodes::NodeValidationState::Valid) return false; pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); return true; } template void VecComposition::UpdateOutput() { if (validationState() != QtNodes::NodeValidationState::Valid) { m_output->preview = PreviewValues(1, 1); m_output->preview(0, 0) = Nz::Vector4f::Zero(); return; } std::array 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(); }