Skip to content

Is it possible to write all-Rust custom scenegraph nodes? #176

@mikolajsnioch

Description

@mikolajsnioch

The purpose of this issue is educational. I am still learning both Qt and QMetaObject-rs.

I studied the Graph example and tried to recreate Qt's BezierCurve example in Rust (https://doc.qt.io/qt-5/qtquick-scenegraph-customgeometry-example.html). The more I look into it, the more I am convinced that at the moment it is not possible to recreate this example without writing C++, I would love to be wrong, however.

In theory, all this example requires is a Rust struct with reimplemented update_paint_node().

The C++ version of this method is as follows:

QSGNode *BezierCurve::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    QSGGeometryNode *node = nullptr;
    QSGGeometry *geometry = nullptr;

    if (!oldNode) {
        node = new QSGGeometryNode;
        geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), m_segmentCount);
        geometry->setLineWidth(2);
        geometry->setDrawingMode(QSGGeometry::DrawLineStrip);
        node->setGeometry(geometry);
        node->setFlag(QSGNode::OwnsGeometry);
        QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
        material->setColor(QColor(255, 0, 0));
        node->setMaterial(material);
        node->setFlag(QSGNode::OwnsMaterial);
    } else {
        node = static_cast<QSGGeometryNode *>(oldNode);
        geometry = node->geometry();
        geometry->allocate(m_segmentCount);
    }

    QSizeF itemSize = size();
    QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D();
    for (int i = 0; i < m_segmentCount; ++i) {
        qreal t = i / qreal(m_segmentCount - 1);
        qreal invt = 1 - t;

        QPointF pos = invt * invt * invt * m_p1
                    + 3 * invt * invt * t * m_p2
                    + 3 * invt * t * t * m_p3
                    + t * t * t * m_p4;

        float x = pos.x() * itemSize.width();
        float y = pos.y() * itemSize.height();

        vertices[i].set(x, y);
    }
    node->markDirty(QSGNode::DirtyGeometry);

    return node;
}

Upon reviewing the source of SGNode::update_static and SGNode::update_dynamic I understood that both functions take care of the condition when the oldNode is empty or not empty.

If I understand correctly, I could go past the if statement from the code above directly to drawing. To be able to draw, I would need to have access to geometry. This is where things are becoming less clear to me. I see that there is some code regarding Geometry in the scenegraph module, however it is commented out. Therefore I understand that currently there's no way to create custom Geometry in Rust. If that's true, then I need to follow the same structure as in the Graph example - write my own Nodes in C++ and interface them from Rust.

Is my understanding correct?

Essentially, what I am trying to do, after understanding how it all works and what's possible right now, is to create my own Canvas (a QQuickItem), where I can draw shapes (also QQuickItems - children of the Canvas). I would like to define all these elements in Rust, because I don't really know C++ and C++'s build system is beyond my comprehension at the moment...

I would be happy to help out with exposing Geometry nodes from Qt to Rust, if some guidance was offered.

Thank you

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-wrappersArea: Wrappers and bindingsC-discussionCategory: Discussion or questions that doesn't represent real issues.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions