#include #include #include #include #include #include OutputValue::OutputValue(ShaderGraph& graph) : ShaderNode(graph) { m_onOutputListUpdateSlot.Connect(GetGraph().OnOutputListUpdate, [&](ShaderGraph*) { OnOutputListUpdate(); }); m_onOutputUpdateSlot.Connect(GetGraph().OnOutputUpdate, [&](ShaderGraph*, std::size_t inputIndex) { if (m_currentOutputIndex == inputIndex) UpdatePreview(); }); if (graph.GetOutputCount() > 0) { m_currentOutputIndex = 0; UpdateOutputText(); } EnablePreview(); SetPreviewSize({ 128, 128 }); DisableCustomVariableName(); } void OutputValue::BuildNodeEdition(QFormLayout* layout) { ShaderNode::BuildNodeEdition(layout); QComboBox* outputSelection = new QComboBox; for (const auto& outputEntry : GetGraph().GetOutputs()) outputSelection->addItem(QString::fromStdString(outputEntry.name)); if (m_currentOutputIndex) outputSelection->setCurrentIndex(int(*m_currentOutputIndex)); connect(outputSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) { if (index >= 0) m_currentOutputIndex = static_cast(index); else m_currentOutputIndex.reset(); UpdateOutputText(); UpdatePreview(); }); layout->addRow(tr("Output"), outputSelection); } Nz::ShaderNodes::ExpressionPtr OutputValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const { using namespace Nz::ShaderBuilder; using namespace Nz::ShaderNodes; assert(count == 1); if (!m_currentOutputIndex) throw std::runtime_error("no output"); const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); Nz::ShaderNodes::ExpressionType expression = [&] { switch (outputEntry.type) { case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; } assert(false); throw std::runtime_error("Unhandled output type"); }(); auto output = Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Output(outputEntry.name, expression)); return Nz::ShaderBuilder::Assign(std::move(output), *expressions); } QtNodes::NodeDataType OutputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { assert(portType == QtNodes::PortType::In); assert(portIndex == 0); if (!m_currentOutputIndex) return VecData::Type(); const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); switch (outputEntry.type) { //case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; //case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; case InOutType::Float2: case InOutType::Float3: case InOutType::Float4: return VecData::Type(); } assert(false); throw std::runtime_error("Unhandled output type"); } unsigned int OutputValue::nPorts(QtNodes::PortType portType) const { switch (portType) { case QtNodes::PortType::In: return 1; case QtNodes::PortType::Out: return 0; } return 0; } std::shared_ptr OutputValue::outData(QtNodes::PortIndex /*port*/) { return {}; } void OutputValue::setInData(std::shared_ptr value, int index) { assert(index == 0); if (value) { assert(dynamic_cast(value.get()) != nullptr); m_input = std::static_pointer_cast(value); } else m_input.reset(); UpdatePreview(); } QtNodes::NodeValidationState OutputValue::validationState() const { if (!m_currentOutputIndex || !m_input) return QtNodes::NodeValidationState::Error; const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); if (GetComponentCount(outputEntry.type) != m_input->componentCount) return QtNodes::NodeValidationState::Error; return QtNodes::NodeValidationState::Valid; } QString OutputValue::validationMessage() const { if (!m_currentOutputIndex) return "No output selected"; if (!m_input) return "Missing input"; const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); std::size_t outputComponentCount = GetComponentCount(outputEntry.type); if (m_input->componentCount != outputComponentCount) return "Incompatible component count (expected " + QString::number(outputComponentCount) + ", got " + QString::number(m_input->componentCount) + ")"; return QString(); } bool OutputValue::ComputePreview(QPixmap& pixmap) { if (!m_input) return false; pixmap = QPixmap::fromImage(m_input->preview.GenerateImage()); return true; } void OutputValue::OnOutputListUpdate() { m_currentOutputIndex.reset(); std::size_t inputIndex = 0; for (const auto& inputEntry : GetGraph().GetOutputs()) { if (inputEntry.name == m_currentOutputText) { m_currentOutputIndex = inputIndex; break; } inputIndex++; } } void OutputValue::UpdateOutputText() { if (m_currentOutputIndex) { auto& output = GetGraph().GetOutput(*m_currentOutputIndex); m_currentOutputText = output.name; } else m_currentOutputText.clear(); } void OutputValue::restore(const QJsonObject& data) { m_currentOutputText = data["output"].toString().toStdString(); OnOutputListUpdate(); ShaderNode::restore(data); } QJsonObject OutputValue::save() const { QJsonObject data = ShaderNode::save(); data["output"] = QString::fromStdString(m_currentOutputText); return data; }