Exemple #1
0
void QSGNode::insertChildNodeBefore(QSGNode *node, QSGNode *before)
{
    //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeBefore", "QSGNode is already a child!");
    Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeBefore", "QSGNode already has a parent");
    Q_ASSERT_X(before && before->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong");

#ifndef QT_NO_DEBUG
    if (node->type() == QSGNode::GeometryNodeType) {
        QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
        Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing material");
        Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing geometry");
    }
#endif

    QSGNode *previous = before->m_previousSibling;
    if (previous)
        previous->m_nextSibling = node;
    else
        m_firstChild = node;
    node->m_previousSibling = previous;
    node->m_nextSibling = before;
    before->m_previousSibling = node;
    node->m_parent = this;

    node->markDirty(DirtyNodeAdded);
}
Exemple #2
0
void QSGNode::insertChildNodeAfter(QSGNode *node, QSGNode *after)
{
    //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeAfter", "QSGNode is already a child!");
    Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeAfter", "QSGNode already has a parent");
    Q_ASSERT_X(after && after->m_parent == this, "QSGNode::insertChildNodeAfter", "The parent of \'after\' is wrong");

#ifndef QT_NO_DEBUG
    if (node->type() == QSGNode::GeometryNodeType) {
        QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
        Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing material");
        Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing geometry");
    }
#endif

    QSGNode *next = after->m_nextSibling;
    if (next)
        next->m_previousSibling = node;
    else
        m_lastChild = node;
    node->m_nextSibling = next;
    node->m_previousSibling = after;
    after->m_nextSibling = node;
    node->m_parent = this;

    node->markDirty(DirtyNodeAdded);
}
void compareSelectionNode(QSGNode *node, const QRectF &rect, int selectionId)
{
    QSGGeometryNode *geometryNode = static_cast<QSGGeometryNode *>(node);
    QSGGeometry *geometry = geometryNode->geometry();
    QCOMPARE(geometry->vertexCount(), 4);
    QCOMPARE(geometry->drawingMode(), (GLenum)GL_TRIANGLE_STRIP);
    OpaqueColoredPoint2DWithSize *data =
            static_cast<OpaqueColoredPoint2DWithSize *>(geometry->vertexData());
    float *lowerLeft = reinterpret_cast<float *>(data);
    float *lowerRight = reinterpret_cast<float *>(++data);
    float *upperLeft = reinterpret_cast<float *>(++data);
    float *upperRight = reinterpret_cast<float *>(++data);

    QCOMPARE(QRectF(QPointF(upperLeft[0], upperLeft[1]), QPointF(lowerRight[0], lowerRight[1])),
            rect);
    QCOMPARE(lowerRight[0], upperRight[0]);
    QCOMPARE(lowerRight[1], lowerLeft[1]);
    QCOMPARE(upperLeft[0], lowerLeft[0]);
    QCOMPARE(upperLeft[1], upperRight[1]);

    QCOMPARE(int(lowerLeft[4]), selectionId);
    QCOMPARE(int(lowerRight[4]), selectionId);
    QCOMPARE(int(upperLeft[4]), selectionId);
    QCOMPARE(int(upperRight[4]), selectionId);

    TimelineItemsMaterial *material = static_cast<TimelineItemsMaterial *>(
                geometryNode->material());
    QVERIFY(!(material->flags() & QSGMaterial::Blending));
}
QSGNode *PhosphorRender::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    if (!m_ybuffer) {
        return 0;
    }

    QSGGeometryNode *node = 0;
    QSGGeometry *geometry = 0;
    Material *material = 0;

    unsigned n_points;

    if (m_xbuffer) {
        n_points = std::min(m_xbuffer->size(), m_ybuffer->size());
    } else {
        n_points = m_ybuffer->countPointsBetween(m_xmin, m_xmax);
    }

    n_points = std::min(n_points,(unsigned) 65767);

    if (!oldNode) {
        node = new QSGGeometryNode;
        geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), n_points);
        geometry->setDrawingMode(GL_POINTS);
        node->setGeometry(geometry);
        node->setFlag(QSGNode::OwnsGeometry);
        material = new Material;
        material->setFlag(QSGMaterial::Blending);
        node->setMaterial(material);
        node->setFlag(QSGNode::OwnsMaterial);
    } else {
        node = static_cast<QSGGeometryNode *>(oldNode);
        geometry = node->geometry();
        geometry->allocate(n_points);
        geometry->setLineWidth(m_pointSize);
        material = static_cast<Material*>(node->material());
    }

    QRectF bounds = boundingRect();

    material->transformation.setToIdentity();
    material->transformation.scale(bounds.width()/(m_xmax - m_xmin), bounds.height()/(m_ymin - m_ymax));
    material->transformation.translate(-m_xmin, -m_ymax);

    material->pointSize = m_pointSize;
    material->color = m_color;

    auto verticies = geometry->vertexDataAsPoint2D();
    if (m_xbuffer) {
        for (unsigned i=0; i<n_points; i++) {
            verticies[i].set(m_xbuffer->get(i), m_ybuffer->get(i));
        }
    } else {
        m_ybuffer->toVertexData(m_xmin, m_xmax, verticies, n_points);
    }
    node->markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial);

    return node;
}
/*------------------------------------------------------------------------------
|    OMX_CameraSurfaceElement::updatePaintNode
+-----------------------------------------------------------------------------*/
QSGNode* OMX_CameraSurfaceElement::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*)
{
    QSGGeometryNode* node = 0;
    QSGGeometry* geometry = 0;

    if (!oldNode) {
        // Create the node.
        node = new QSGGeometryNode;
        geometry = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
        geometry->setDrawingMode(GL_TRIANGLE_STRIP);
        node->setGeometry(geometry);
        node->setFlag(QSGNode::OwnsGeometry);

        // TODO: Who is freeing this?
        // TODO: I cannot know the texture size here.
        QSGOpaqueTextureMaterial* material = new QSGOpaqueTextureMaterial;
        m_sgtexture = new OMX_SGTexture(0, QSize(640, 480));
        material->setTexture(m_sgtexture);
        node->setMaterial(material);
        node->setFlag(QSGNode::OwnsMaterial);

        QtConcurrent::run(this, &OMX_CameraSurfaceElement::videoAcquire);
    }
    else {
        node = static_cast<QSGGeometryNode*>(oldNode);
        geometry = node->geometry();
        geometry->allocate(4);

        // Update texture in the node if needed.
        QSGOpaqueTextureMaterial* material = (QSGOpaqueTextureMaterial*)node->material();
        QElapsedTimer timer;
        timer.start();
        QSGTexture* texture = window()->createTextureFromImage(m_frame);
        LOG_VERBOSE(LOG_TAG, "Timer tex: %lld.", timer.elapsed());
        material->setTexture(texture);
        m_semAcquire.release();
#if 0
        if (m_texture != (GLuint)material->texture()->textureId()) {
            // TODO: Does setTextureId frees the prev texture?
            // TODO: I should the given the texture size.
            LOG_ERROR(LOG_TAG, "Updating texture to %u!", m_texture);
            material = new QSGOpaqueTextureMaterial;
            m_sgtexture->setTexture(m_texture, QSize(1920, 1080));
        }
#endif
    }

    // Create the vertices and map to texture.
    QRectF bounds = boundingRect();
    QSGGeometry::TexturedPoint2D* vertices = geometry->vertexDataAsTexturedPoint2D();
    vertices[0].set(bounds.x(), bounds.y() + bounds.height(), 0.0f, 0.0f);
    vertices[1].set(bounds.x() + bounds.width(), bounds.y() + bounds.height(), 1.0f, 0.0f);
    vertices[2].set(bounds.x(), bounds.y(), 0.0f, 1.0f);
    vertices[3].set(bounds.x() + bounds.width(), bounds.y(), 1.0f, 1.0f);
    return node;
}
Exemple #6
0
QSGNode * QQuickLineItem::updatePaintNode(QSGNode *prev_node,
                                          UpdatePaintNodeData *upd_data)
{
    Q_UNUSED(upd_data);

    QSGGeometryNode * node = static_cast<QSGGeometryNode*>(prev_node);
    QSGGeometry * geometry = NULL;
    QSGFlatColorMaterial * material = NULL;

    if(!node) {
        // http://qt-project.org/doc/qt-5/qsggeometrynode.html
        node = new QSGGeometryNode;
        geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(),4);
        geometry->setDrawingMode(GL_TRIANGLE_STRIP);
        node->setGeometry(geometry);
        node->setFlag(QSGNode::OwnsGeometry);

        material = new QSGFlatColorMaterial;
        material->setColor(m_color);
        node->setMaterial(material);
        node->setFlag(QSGNode::OwnsMaterial);
    }
    else {
        geometry = node->geometry();
        geometry->allocate(4); // we have to call allocate to invalidate
                               // the older vertex buffer
        material = static_cast<QSGFlatColorMaterial*>(node->material());
    }

    // geometry
    std::vector<QPointF> list_vx;
    if(!calcTriStrip(list_vx)) {
        list_vx.clear();
        list_vx.push_back(QPointF(0,0));
        list_vx.push_back(QPointF(0,0));
        list_vx.push_back(QPointF(0,0));
        list_vx.push_back(QPointF(0,0));
    }

    QSGGeometry::Point2D * vertices =
            geometry->vertexDataAsPoint2D();

    for(size_t i=0; i < list_vx.size(); i++) {
        vertices[i].set(list_vx[i].x(),
                        list_vx[i].y());
    }

    node->markDirty(QSGNode::DirtyGeometry);

    // material
    material->setColor(m_color);
    node->markDirty(QSGNode::DirtyMaterial);

    return node;
}
QSGNode *QPScrollingCurve::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
{
    QSGGeometryNode *node = 0;
    QSGGeometry *geometry = 0;
    QSGFlatColorMaterial *material = 0;

    if (!oldNode) {
        node = new QSGGeometryNode;
        geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), m_data.size());
        geometry->setLineWidth(2);
        geometry->setDrawingMode(GL_LINE_STRIP);
        node->setGeometry(geometry);
        node->setFlag(QSGNode::OwnsGeometry);
        material = new QSGFlatColorMaterial;
        material->setColor(m_color);
        node->setMaterial(material);
        node->setFlag(QSGNode::OwnsMaterial);
        node->markDirty(QSGNode::DirtyMaterial);
    } else {
        node = static_cast<QSGGeometryNode *>(oldNode);
        geometry = node->geometry();
        geometry->allocate(m_data.size());
        material = static_cast<QSGFlatColorMaterial*>(node->material());
        if (material->color() != m_color) {
            material->setColor(m_color);
            node->markDirty(QSGNode::DirtyMaterial);
        }
    }

    QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D();

    for (uint i = 0; i < m_data.size(); ++i) {
        QPointF p(i, m_data[i]);
        vertices[i].set(p.x(), p.y());
    }

    node->markDirty(QSGNode::DirtyGeometry);

    return node;
}
Exemple #8
0
void QSGNode::appendChildNode(QSGNode *node)
{
    //Q_ASSERT_X(!m_children.contains(node), "QSGNode::appendChildNode", "QSGNode is already a child!");
    Q_ASSERT_X(!node->m_parent, "QSGNode::appendChildNode", "QSGNode already has a parent");

#ifndef QT_NO_DEBUG
    if (node->type() == QSGNode::GeometryNodeType) {
        QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
        Q_ASSERT_X(g->material(), "QSGNode::appendChildNode", "QSGGeometryNode is missing material");
        Q_ASSERT_X(g->geometry(), "QSGNode::appendChildNode", "QSGGeometryNode is missing geometry");
    }
#endif

    if (m_lastChild)
        m_lastChild->m_nextSibling = node;
    else
        m_firstChild = node;
    node->m_previousSibling = m_lastChild;
    m_lastChild = node;
    node->m_parent = this;

    node->markDirty(DirtyNodeAdded);
}
QSGNode* OMX_MediaProcessorElement::updatePaintNode(QSGNode*, UpdatePaintNodeData*)
{
    if (!m_texProvider) {
        m_texProvider = new OMX_TextureProviderQQuickItem(this);
        m_mediaProc   = new OMX_MediaProcessor(m_texProvider);
        connect(m_mediaProc, SIGNAL(playbackCompleted()), this, SIGNAL(playbackCompleted()));
        connect(m_mediaProc, SIGNAL(playbackStarted()), this, SIGNAL(playbackStarted()));

        // Open if filepath is set.
        // TODO: Handle errors.
        if (!m_source.isNull()) {
            //if (QFile(m_source).exists()) {
                if (openMedia(m_source))
                    m_mediaProc->play();
            //}
            //else {
                LOG_WARNING(LOG_TAG, "File does not exist.");
            //}
        }
    }

    return NULL;

#if 0
    QSGGeometryNode* node = 0;
    QSGGeometry* geometry = 0;

    if (!oldNode) {
        // Create the node.
        node = new QSGGeometryNode;
        geometry = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
        geometry->setDrawingMode(GL_TRIANGLE_STRIP);
        node->setGeometry(geometry);
        node->setFlag(QSGNode::OwnsGeometry);

        // TODO: Who is freeing this?
        // TODO: I cannot know the texture size here.
        QSGOpaqueTextureMaterial* material = new QSGOpaqueTextureMaterial;
        m_sgtexture = new OMX_SGTexture(m_texture, QSize(1920, 1080));
        material->setTexture(m_sgtexture);
        node->setMaterial(material);
        node->setFlag(QSGNode::OwnsMaterial);

#ifdef ENABLE_VIDEO_PROCESSOR
        QPlatformNativeInterface* nativeInterface =
                QGuiApplicationPrivate::platformIntegration()->nativeInterface();
        Q_ASSERT(nativeInterface);
        EGLDisplay eglDisplay = nativeInterface->nativeResourceForIntegration("egldisplay");
        EGLContext eglContext = nativeInterface->nativeResourceForContext(
                    "eglcontext",
                    QOpenGLContext::currentContext()
                    );
#endif

        // Provider MUST be built in this thread.
        m_provider  = new OMX_TextureProviderQQuickItem(this);
#ifdef ENABLE_VIDEO_PROCESSOR
        m_videoProc = new OMX_VideoProcessor(eglDisplay, eglContext, m_provider);
        connect(m_videoProc, SIGNAL(textureReady(uint)), this, SLOT(onTextureChanged(uint)));
        if (!m_source.isNull())
            m_videoProc->setVideoPath(m_source);
        if (m_playScheduled) {
            m_timer->start(30);
            m_videoProc->play();
        }
#elif ENABLE_MEDIA_PROCESSOR
        LOG_VERBOSE(LOG_TAG, "Starting video using media processor...");
        m_mediaProc = new OMX_MediaProcessor(m_provider);
        m_mediaProc->setFilename("/home/pi/usb/Cars2.mkv", m_texture);
        //if (m_playScheduled) {
            m_timer->start(40);
            m_mediaProc->play();
        //}
#else
        LOG_VERBOSE(LOG_TAG, "Starting video...");
        QtConcurrent::run(&startVideo, m_provider, this);
        m_timer->start(30);
#endif
    }
    else {
        node = static_cast<QSGGeometryNode*>(oldNode);
        geometry = node->geometry();
        geometry->allocate(4);

        // Update texture in the node if needed.
        QSGOpaqueTextureMaterial* material = (QSGOpaqueTextureMaterial*)node->material();
        if (m_texture != (GLuint)material->texture()->textureId()) {
            // TODO: Does setTextureId frees the prev texture?
            // TODO: I should the given the texture size.
            LOG_ERROR(LOG_TAG, "Updating texture to %u!", m_texture);
            material = new QSGOpaqueTextureMaterial;
            m_sgtexture->setTexture(m_texture, QSize(1920, 1080));
        }
    }

    // Create the vertices and map to texture.
    QRectF bounds = boundingRect();
    QSGGeometry::TexturedPoint2D* vertices = geometry->vertexDataAsTexturedPoint2D();
    vertices[0].set(bounds.x(), bounds.y() + bounds.height(), 0.0f, 0.0f);
    vertices[1].set(bounds.x() + bounds.width(), bounds.y() + bounds.height(), 1.0f, 0.0f);
    vertices[2].set(bounds.x(), bounds.y(), 0.0f, 1.0f);
    vertices[3].set(bounds.x() + bounds.width(), bounds.y(), 1.0f, 1.0f);
    return node;
#endif
}
void tst_TimelineNotesRenderPass::update()
{
    const TimelineNotesRenderPass *inst = TimelineNotesRenderPass::instance();
    TimelineAbstractRenderer renderer;
    TimelineRenderState parentState(0, 8, 1, 1);
    TimelineRenderPass::State *nullState = 0;
    QSGNode *nullNode = 0;
    TimelineRenderPass::State *result = inst->update(&renderer, &parentState, 0, 0, 0, true, 1);
    QCOMPARE(result, nullState);

    DummyModel model;
    DummyModel otherModel(13);

    TimelineNotesModel notes;
    notes.addTimelineModel(&model);
    notes.addTimelineModel(&otherModel);
    result = inst->update(&renderer, &parentState, 0, 0, 0, true, 1);
    QCOMPARE(result, nullState);

    renderer.setModel(&model);
    result = inst->update(&renderer, &parentState, 0, 0, 0, true, 1);
    QCOMPARE(result, nullState);

    renderer.setNotes(&notes);
    model.loadData();
    result = inst->update(&renderer, &parentState, 0, 0, 0, true, 1);
    QVERIFY(result != nullState);

    // The notes renderer creates a collapsed overlay and expanded nodes per row.
    QVERIFY(result->collapsedOverlay() != nullNode);
    QCOMPARE(result->expandedOverlay(), nullNode);
    QCOMPARE(result->expandedRows().count(), 1);
    QCOMPARE(result->collapsedRows().count(), 0);

    TimelineRenderPass::State *result2 = inst->update(&renderer, &parentState, result, 0, 0, false,
                                                      1);
    QCOMPARE(result2, result);

    notes.add(12, 0, QLatin1String("x"));
    notes.add(12, 9, QLatin1String("xx"));
    notes.add(13, 0, QLatin1String("y"));
    QVERIFY(renderer.notesDirty());
    result = inst->update(&renderer, &parentState, result, 0, 0, true, 1);
    QVERIFY(result != nullState);
    QSGGeometryNode *node = static_cast<QSGGeometryNode *>(result->expandedRows()[0]);
    QSGMaterial *material1 = node->material();
    QVERIFY(material1 != 0);
    QCOMPARE(node->geometry()->vertexCount(), 2);
    node = static_cast<QSGGeometryNode *>(result->collapsedOverlay());
    QSGMaterial *material2 = node->material();
    QCOMPARE(node->geometry()->vertexCount(), 2);
    QVERIFY(material2 != 0);
    QCOMPARE(material1->type(), material2->type());
    QSGMaterialShader *shader1 = material1->createShader();
    QVERIFY(shader1 != 0);
    QSGMaterialShader *shader2 = material2->createShader();
    QVERIFY(shader2 != 0);
    QCOMPARE(shader1->attributeNames(), shader2->attributeNames());

    delete shader1;
    delete shader2;

    parentState.setPassState(0, result);
    parentState.assembleNodeTree(&model, 1, 1);

    runSceneGraphTest(parentState.collapsedOverlayRoot());
    runSceneGraphTest(parentState.expandedRowRoot());
}
QSGNode* MDeclarativeStatusBar::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*)
{
    QSGGeometryNode* node = static_cast<QSGGeometryNode*>(oldNode);
    if (!node) {
        node = new QSGGeometryNode;
        node->setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial | QSGNode::OwnsOpaqueMaterial);
        node->setGeometry(new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4));
    }

    if (!sharedPixmapHandle) {
        node->setMaterial(new QSGFlatColorMaterial);
        node->setOpaqueMaterial(new QSGFlatColorMaterial);
        node->markDirty(QSGNode::DirtyMaterial);
        return node;
    }

    if (!sharedTexture || updateSharedTexture) {
        node->setMaterial(new QSGTextureMaterial);
        node->setOpaqueMaterial(new QSGTextureMaterial);

#if defined(HAVE_XLIB)
        MDeclarativeScreen* screen = MDeclarativeScreen::instance();

#if defined(QT_OPENGL_ES_2)
        static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
        static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
        static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
        static PFNEGLQUERYIMAGENOKPROC eglQueryImageNOK = (PFNEGLQUERYIMAGENOKPROC) eglGetProcAddress("eglQueryImageNOK");

        const EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };

        EGLDisplay eglDpy = eglGetDisplay((EGLNativeDisplayType)screen->display());
        EGLImageKHR img = eglCreateImageKHR(eglDpy, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)sharedPixmapHandle, attribs);

        GLuint textureId;
        glGenTextures(1, &textureId);
        glBindTexture(GL_TEXTURE_2D, textureId);
        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)img);

        GLint width = 0;
        GLint height = 0;
        eglQueryImageNOK(eglDpy, img, EGL_WIDTH, &width);
        eglQueryImageNOK(eglDpy, img, EGL_HEIGHT, &height);

        sharedTexture.reset(canvas()->createTextureFromId(textureId, QSize(width, height), QQuickCanvas::TextureOwnsGLTexture));

        eglDestroyImageKHR(eglDpy, img);
#else
        Display* dpy = screen->display();
        Window dummy1;
        int x, y;
        unsigned int width, height, borderwidth, depth;
        XGetGeometry(dpy, sharedPixmapHandle, &dummy1, &x, &y, &width, &height, &borderwidth, &depth);
        XImage* xi = XGetImage(dpy, sharedPixmapHandle, 0, 0, width, height, ULONG_MAX, ZPixmap);
        QImage img = MX11Wrapper::qimageFromXImage(xi);
        XDestroyImage(xi);
        sharedTexture.reset(canvas()->createTextureFromImage(img));
#endif
#endif // HAVE_XLIB

        static_cast<QSGTextureMaterial*>(node->material())->setTexture(sharedTexture.data());
        static_cast<QSGOpaqueTextureMaterial*>(node->opaqueMaterial())->setTexture(sharedTexture.data());
        node->markDirty(QSGNode::DirtyMaterial);
        updateSharedTexture = false;
    }

    QRectF sourceRect;
    sourceRect = QRectF(0, 0, width(), height());
    if (mOrientation == MDeclarativeScreen::Portrait || mOrientation == MDeclarativeScreen::PortraitInverted)
        sourceRect.moveTop(height());
    sourceRect = sharedTexture.data()->convertToNormalizedSourceRect(sourceRect);

    QRect targetRect(x(), y(), width(), height());

    QSGGeometry::updateTexturedRectGeometry(node->geometry(), targetRect, sourceRect);
    node->markDirty(QSGNode::DirtyGeometry);

    return node;
}
QSGNode* NodeConnectionLines::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) {
    if (!m_nodeObject) return nullptr;
    const QVector<QPointer<NodeBase>>& connectedNodes = m_nodeObject->getConnectedNodes();
    int connectionCount = connectedNodes.size();

    // -------------------- Prepare QSG Nodes:
    QSGNode* parentNode = oldNode;
    if (!oldNode) {
        parentNode = new QSGNode();
    } else {
        // update color in case it changed:
        // FIXME: is there a more efficient way to do this?
        for (int i=0; i<parentNode->childCount(); ++i) {
            QSGGeometryNode* childNode = static_cast<QSGGeometryNode*>(parentNode->childAtIndex(i));
            if (!childNode) continue;
            QSGFlatColorMaterial* material = static_cast<QSGFlatColorMaterial*>(childNode->material());
            if (!material) continue;
            material->setColor(m_color);
        }
    }
    // adapt child count:
    int childCount = parentNode->childCount();
    if (childCount < connectionCount) {
        for (int i=0; i<(connectionCount - childCount); ++i) {
            QSGGeometryNode* node = new QSGGeometryNode;
            QSGGeometry* geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 3);
            geometry->setDrawingMode(GL_TRIANGLE_STRIP);
            node->setGeometry(geometry);
            node->setFlag(QSGNode::OwnsGeometry);
            QSGFlatColorMaterial* material = new QSGFlatColorMaterial;
            material->setColor(m_color);
            node->setMaterial(material);
            node->setFlag(QSGNode::OwnsMaterial);
            parentNode->appendChildNode(node);
        }
    } else if (childCount > connectionCount) {
        for (int i=0; i<(childCount - connectionCount); ++i) {
            parentNode->removeChildNode(parentNode->childAtIndex(0));
        }
    }
    Q_ASSERT(parentNode->childCount() == connectionCount);

    // calculate common start point:
    const QPointF p0(width(), height() / 2);
    double widthOffset = m_lineWidth / 2;
    //const QPointF posInScene = mapToScene(QPointF(0, 0));


    for (int i=0; i<connectionCount; ++i) {
        NodeBase* otherNode = connectedNodes[i];
        if (!otherNode) continue;
        QQuickItem* otherGuiItem = otherNode->getGuiItem();
        if (!otherGuiItem) continue;
        const QPointF p3 = mapFromItem(otherGuiItem, QPointF(-otherGuiItem->width() / 2, otherGuiItem->height() / 2));
        int handleLength = std::max(50, std::min(int(p3.x() - p0.x()), 80));
        const QPointF p1(p0.x() + handleLength, p0.y());
        const QPointF p2(p3.x() - handleLength, p3.y());

        // calculate reasonable segment count:
        int segmentCount = qMax(16.0, qMin(qAbs(p3.y() - p0.y()) / 25, 50.0));
        int verticesCount = segmentCount * 2;

        QSGGeometryNode* qsgNode = static_cast<QSGGeometryNode*>(parentNode->childAtIndex(i));
        if (!qsgNode) continue;

        QSGGeometry* geometry = qsgNode->geometry();
        if (!geometry) continue;
        geometry->allocate(verticesCount);
        QSGGeometry::Point2D* vertices = geometry->vertexDataAsPoint2D();

        // triangulate cubic bezier curve:
        for (int i = 0; i < segmentCount; ++i) {
            // t is the position on the line:
            const qreal t = i / qreal(segmentCount - 1);

            // pos is the point on the curve at "t":
            const QPointF pos = calculateBezierPoint(t, p0, p1, p2, p3);

            // normal is the normal vector at that point
            const QPointF normal = normalFromTangent(calculateBezierTangent(t, p0, p1, p2, p3));

            // first is a point offsetted in the normal direction by lineWidth / 2 from pos
            const QPointF first = pos - normal * widthOffset;

            // ssecond is a point offsetted in the negative normal direction by lineWidth / 2 from pos
            const QPointF second = pos + normal * widthOffset;

            // add first and second as vertices to this geometry:
            vertices[i*2].set(first.x(), first.y());
            vertices[i*2+1].set(second.x(), second.y());
        }

        // tell Scene Graph that this items needs to be drawn:
        qsgNode->markDirty(QSGNode::DirtyGeometry);
    }

    return parentNode;
}