#include #include #include SampleTexture::SampleTexture(ShaderGraph& graph) : ShaderNode(graph) { m_output = std::make_shared(4); UpdateOutput(); } unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const { switch (portType) { case QtNodes::PortType::In: return 2; case QtNodes::PortType::Out: return 1; } return 0; } void SampleTexture::UpdateOutput() { PreviewValues& output = m_output->preview; if (!m_texture || !m_uv) { output = PreviewValues(1, 1); output.Fill(nzsl::Vector4f32(0.f, 0.f, 0.f, 0.f)); return; } const PreviewValues& texturePreview = m_texture->preview; std::size_t textureWidth = texturePreview.GetWidth(); std::size_t textureHeight = texturePreview.GetHeight(); const PreviewValues& uv = m_uv->preview; std::size_t uvWidth = uv.GetWidth(); std::size_t uvHeight = uv.GetHeight(); output = PreviewValues(uvWidth, uvHeight); for (std::size_t y = 0; y < uvHeight; ++y) { for (std::size_t x = 0; x < uvWidth; ++x) { nzsl::Vector4f32 uvValue = uv(x, y); if (textureWidth > 0 && textureHeight > 0) output(x, y) = texturePreview.Sample(uvValue.x(), uvValue.y()); else output(x, y) = nzsl::Vector4f32(0.f, 0.f, 0.f, 1.f); } } Q_EMIT dataUpdated(0); UpdatePreview(); } bool SampleTexture::ComputePreview(QPixmap& pixmap) { if (!m_texture || !m_uv) return false; pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); return true; } nzsl::Ast::NodePtr SampleTexture::BuildNode(nzsl::Ast::ExpressionPtr* expressions, std::size_t count, std::size_t outputIndex) const { assert(m_texture); assert(m_uv); assert(count == 2); assert(outputIndex == 0); std::vector params; params.push_back(std::move(expressions[0])); params.push_back(std::move(expressions[1])); return nzsl::ShaderBuilder::Intrinsic(nzsl::Ast::IntrinsicType::SampleTexture, std::move(params)); } auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType { switch (portType) { case QtNodes::PortType::In: { switch (portIndex) { case 0: return Texture2Data::Type(); case 1: return VecData::Type(); } assert(false); throw std::runtime_error("invalid port index"); } case QtNodes::PortType::Out: { assert(portIndex == 0); return VecData::Type(); } default: assert(false); throw std::runtime_error("invalid PortType"); } } QString SampleTexture::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { switch (portType) { case QtNodes::PortType::In: { switch (portIndex) { case 0: return tr("Texture"); case 1: return tr("UV"); } assert(false); throw std::runtime_error("invalid port index"); } case QtNodes::PortType::Out: { assert(portIndex == 0); return tr("Sample"); } default: assert(false); throw std::runtime_error("Invalid PortType"); } } bool SampleTexture::portCaptionVisible(QtNodes::PortType /*portType*/, QtNodes::PortIndex /*portIndex*/) const { return true; } std::shared_ptr SampleTexture::outData(QtNodes::PortIndex port) { assert(port == 0); return m_output; } void SampleTexture::setInData(std::shared_ptr value, int index) { switch (index) { case 0: { if (value && value->type().id == Texture2Data::Type().id) { assert(dynamic_cast(value.get()) != nullptr); m_texture = std::static_pointer_cast(value); } else m_texture.reset(); break; } case 1: { if (value && value->type().id == VecData::Type().id) { assert(dynamic_cast(value.get()) != nullptr); m_uv = std::static_pointer_cast(value); } else m_uv.reset(); break; } default: assert(false); throw std::runtime_error("Invalid PortType"); } UpdateOutput(); } QtNodes::NodeValidationState SampleTexture::validationState() const { if (!m_texture || !m_uv) return QtNodes::NodeValidationState::Error; if (m_uv->componentCount != 2) return QtNodes::NodeValidationState::Error; return QtNodes::NodeValidationState::Valid; } QString SampleTexture::validationMessage() const { if (!m_texture) return "Missing texture"; if (!m_uv) return "Missing uv"; if (m_uv->componentCount != 2) return "Incompatible UV (expected 2, got " + QString::number(m_uv->componentCount) + ")"; return QString(); }