#include #include #include #include #include #include template CastVec::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(ToComponentCount); } template nzsl::Ast::NodePtr CastVec::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 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 swizzleComponents; for (std::size_t i = 0; i < ToComponentCount; ++i) swizzleComponents[i] = Nz::SafeCast(i); return std::apply([&](auto... components) { std::initializer_list componentList{ components... }; return nzsl::ShaderBuilder::Swizzle(std::move(expressions[0]), componentList); }, swizzleComponents); } else return std::move(expressions[0]); //< no-op } template void CastVec::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::lowest(), std::numeric_limits::max()); spinbox->setValue(m_overflowComponents[i]); connect(spinbox, qOverload(&QDoubleSpinBox::valueChanged), [=](double) { m_overflowComponents[i] = spinbox->value(); UpdateOutput(); }); layout->addRow(QString::fromUtf8(&s_vectorComponents[fromComponentCount + i], 1), spinbox); } } } template QString CastVec::caption() const { static QString caption = "To Vector" + QString::number(ToComponentCount); return caption; } template QString CastVec::name() const { static QString name = "cast_vec" + QString::number(ToComponentCount); return name; } template QtNodes::NodeDataType CastVec::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 unsigned int CastVec::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::shared_ptr CastVec::outData(QtNodes::PortIndex port) { assert(port == 0); if (!m_input) return nullptr; return m_output; } template void CastVec::setInData(std::shared_ptr value, int index) { assert(index == 0); if (value && value->type().id == VecData::Type().id) { assert(dynamic_cast(value.get()) != nullptr); m_input = std::static_pointer_cast(value); } else m_input.reset(); UpdateOutput(); } template QtNodes::NodeValidationState CastVec::validationState() const { if (!m_input) return QtNodes::NodeValidationState::Error; return QtNodes::NodeValidationState::Valid; } template QString CastVec::validationMessage() const { if (!m_input) return "Missing input"; return QString(); } template bool CastVec::ComputePreview(QPixmap& pixmap) { if (!m_input) return false; pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); return true; } template void CastVec::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 void CastVec::restore(const QJsonObject& data) { QJsonArray vecValues = data["value"].toArray(); std::size_t commonValues = std::min(static_cast(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 QJsonObject CastVec::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; }