* @brief Rebuilds the ribbon node from the source series: project to pixels once, one * counting pass sizes the vertex/index buffers (stable sizes reuse the allocation), * one streaming pass fills them. Fully-offscreen runs are culled by run visibility, * so zoomed curves cost the visible slice, not the full series. */
| 616 | * so zoomed curves cost the visible slice, not the full series. |
| 617 | */ |
| 618 | QSGNode* Widgets::PlotCurve::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* data) |
| 619 | { |
| 620 | Q_UNUSED(data) |
| 621 | |
| 622 | const double w = width(); |
| 623 | const double h = height(); |
| 624 | const double xRange = m_xMax - m_xMin; |
| 625 | const double yRange = m_yMax - m_yMin; |
| 626 | |
| 627 | const QList<QPointF> points = m_source ? m_source->points() : QList<QPointF>(); |
| 628 | |
| 629 | const bool valid = |
| 630 | points.size() >= 2 && xRange > 0 && yRange > 0 && w > 0 && h > 0 && m_lineWidth > 0; |
| 631 | if (!valid) { |
| 632 | delete oldNode; |
| 633 | return nullptr; |
| 634 | } |
| 635 | |
| 636 | const QPointF* pts = points.constData(); |
| 637 | const qsizetype n = points.size(); |
| 638 | projectToPixels(pts, n, w, h); |
| 639 | const QPointF* px = m_px.constData(); |
| 640 | |
| 641 | qsizetype vertexCount = 0; |
| 642 | qsizetype indexCount = 0; |
| 643 | countRibbon(pts, px, n, vertexCount, indexCount); |
| 644 | if (vertexCount < 8 || indexCount < 18) { |
| 645 | delete oldNode; |
| 646 | return nullptr; |
| 647 | } |
| 648 | |
| 649 | if (vertexCount > kMaxGeometry || indexCount > kMaxGeometry) { |
| 650 | delete oldNode; |
| 651 | return nullptr; |
| 652 | } |
| 653 | |
| 654 | const int vertices = static_cast<int>(vertexCount); |
| 655 | const int idxs = static_cast<int>(indexCount); |
| 656 | const double hw = std::max(0.5, m_lineWidth * 0.5); |
| 657 | |
| 658 | auto* node = static_cast<QSGGeometryNode*>(oldNode); |
| 659 | if (!node) { |
| 660 | node = new QSGGeometryNode; |
| 661 | auto* geometry = new QSGGeometry( |
| 662 | QSGGeometry::defaultAttributes_ColoredPoint2D(), 0, 0, QSGGeometry::UnsignedIntType); |
| 663 | geometry->setDrawingMode(QSGGeometry::DrawTriangles); |
| 664 | node->setGeometry(geometry); |
| 665 | node->setFlag(QSGNode::OwnsGeometry); |
| 666 | node->setMaterial(new QSGVertexColorMaterial); |
| 667 | node->setFlag(QSGNode::OwnsMaterial); |
| 668 | } |
| 669 | |
| 670 | auto* geometry = node->geometry(); |
| 671 | Q_ASSERT(geometry != nullptr); |
| 672 | if (geometry->vertexCount() != vertices || geometry->indexCount() != idxs) |
| 673 | geometry->allocate(vertices, idxs); |
| 674 | |
| 675 | emitRibbon(geometry->vertexDataAsColoredPoint2D(), |