void ShaderEffectItem::updateGeometry()
{
    QRectF srcRect(0, 1, 1, -1);

    if (m_mirrored)
        srcRect = QRectF(0, 0, 1, 1);

    QRectF dstRect = QRectF(0,0, width(), height());

    int vmesh = m_meshResolution.height();
    int hmesh = m_meshResolution.width();

    QSGGeometry *g = &m_geometry;
    if (vmesh == 1 && hmesh == 1) {
        if (g->vertexCount() != 4)
            g->allocate(4);
        QSGGeometry::updateTexturedRectGeometry(g, dstRect, srcRect);
        return;
    }

    g->allocate((vmesh + 1) * (hmesh + 1), vmesh * 2 * (hmesh + 2));

    QSGGeometry::TexturedPoint2D *vdata = g->vertexDataAsTexturedPoint2D();

    for (int iy = 0; iy <= vmesh; ++iy) {
        float fy = iy / float(vmesh);
        float y = float(dstRect.top()) + fy * float(dstRect.height());
        float ty = float(srcRect.top()) + fy * float(srcRect.height());
        for (int ix = 0; ix <= hmesh; ++ix) {
            float fx = ix / float(hmesh);
            vdata->x = float(dstRect.left()) + fx * float(dstRect.width());
            vdata->y = y;
            vdata->tx = float(srcRect.left()) + fx * float(srcRect.width());
            vdata->ty = ty;
            ++vdata;
        }
    }

    quint16 *indices = (quint16 *)g->indexDataAsUShort();
    int i = 0;
    for (int iy = 0; iy < vmesh; ++iy) {
        *(indices++) = i + hmesh + 1;
        for (int ix = 0; ix <= hmesh; ++ix, ++i) {
            *(indices++) = i + hmesh + 1;
            *(indices++) = i;
        }
        *(indices++) = i - 1;
    }
}
Exemple #2
0
/*
 * The function hardcodes a fixed set of grid lines and scales
 * those to the bounding rect.
 */
void GridNode::setRect(const QRectF &rect)
{
    int vCount = int((rect.width() - 1) / GRID_SIZE);
    int hCount = int((rect.height() - 1) / GRID_SIZE);

    int lineCount = vCount + hCount;

    QSGGeometry *g = geometry();

    g->allocate(lineCount * 2);

    float x = rect.x();
    float y = rect.y();
    float w = rect.width();
    float h = rect.height();

    QSGGeometry::Point2D *v = g->vertexDataAsPoint2D();

    // Then write the vertical lines
    for (int i=0; i<vCount; ++i)  {
        float dx = (i + 1) * GRID_SIZE;
        v[i*2].set(dx, y);
        v[i*2+1].set(dx, y + h);
    }
    v += vCount * 2;
    // Then write the horizontal lines
    for (int i=0; i<hCount; ++i)  {
        float dy = (i + 1) * GRID_SIZE;
        v[i*2].set(x, dy);
        v[i*2+1].set(x + w, dy);
    }

    // Tell the scenegraph we updated the geometry..
    markDirty(QSGNode::DirtyGeometry);
}
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 #5
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;
}
void QQuickDefaultClipNode::updateGeometry()
{
    QSGGeometry *g = geometry();

    if (qFuzzyIsNull(m_radius)) {
        g->allocate(4);
        QSGGeometry::updateRectGeometry(g, m_rect);

    } else {
        int vertexCount = 0;

        // Radius should never exceeds half of the width or half of the height
        qreal radius = qMin(qMin(m_rect.width() / 2, m_rect.height() / 2), m_radius);
        QRectF rect = m_rect;
        rect.adjust(radius, radius, -radius, -radius);

        int segments = qMin(30, qCeil(radius)); // Number of segments per corner.

        g->allocate((segments + 1) * 2);

        QVector2D *vertices = (QVector2D *)g->vertexData();

        for (int part = 0; part < 2; ++part) {
            for (int i = 0; i <= segments; ++i) {
                //### Should change to calculate sin/cos only once.
                qreal angle = qreal(0.5 * M_PI) * (part + i / qreal(segments));
                qreal s = qFastSin(angle);
                qreal c = qFastCos(angle);
                qreal y = (part ? rect.bottom() : rect.top()) - radius * c; // current inner y-coordinate.
                qreal lx = rect.left() - radius * s; // current inner left x-coordinate.
                qreal rx = rect.right() + radius * s; // current inner right x-coordinate.

                vertices[vertexCount++] = QVector2D(rx, y);
                vertices[vertexCount++] = QVector2D(lx, y);
            }
        }

    }
    markDirty(DirtyGeometry);
    setClipRect(m_rect);
}
Exemple #7
0
//! [4]
QSGNode *BezierCurve::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    QSGGeometryNode *node = 0;
    QSGGeometry *geometry = 0;

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

//! [8]
    QRectF bounds = boundingRect();
    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 = bounds.x() + pos.x() * bounds.width();
        float y = bounds.y() + pos.y() * bounds.height();

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


//! [9]
    return node;
}
void QQuickShapeGenericRenderer::updateStrokeNode(ShapePathData *d, QQuickShapeGenericNode *node)
{
    if (!node->m_strokeNode)
        return;
    if (!(d->effectiveDirty & (DirtyStrokeGeom | DirtyColor)))
        return;

    QQuickShapeGenericStrokeFillNode *n = node->m_strokeNode;
    QSGGeometry *g = n->geometry();
    if (d->strokeVertices.isEmpty()) {
        if (g->vertexCount() || g->indexCount()) {
            g->allocate(0, 0);
            n->markDirty(QSGNode::DirtyGeometry);
        }
        return;
    }

    n->markDirty(QSGNode::DirtyGeometry);

    // Async loading runs update once, bails out above, then updates again once
    // ready. Set the material dirty then. This is in-line with fill where the
    // first activateMaterial() achieves the same.
    if (!g->vertexCount())
        n->markDirty(QSGNode::DirtyMaterial);

    if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyStrokeGeom)) {
        ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData());
        for (int i = 0; i < g->vertexCount(); ++i)
            vdst[i].set(vdst[i].x, vdst[i].y, d->strokeColor);
        return;
    }

    g->allocate(d->strokeVertices.count(), 0);
    g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
    memcpy(g->vertexData(), d->strokeVertices.constData(), g->vertexCount() * g->sizeOfVertex());
}
void QQuickAndroid9PatchNode::initialize(QSGTexture *texture, const QRectF &bounds, const QSize &sourceSize,
        const QQuickAndroid9PatchDivs &xDivs, const QQuickAndroid9PatchDivs &yDivs)
{
    delete m_material.texture();
    m_material.setTexture(texture);

    const int xlen = xDivs.data.size();
    const int ylen = yDivs.data.size();

    if (xlen > 0 && ylen > 0) {
        const int quads = (xlen - 1) * (ylen - 1);
        static const int verticesPerQuad = 6;
        m_geometry.allocate(xlen * ylen, verticesPerQuad * quads);

        QSGGeometry::TexturedPoint2D *vertices = m_geometry.vertexDataAsTexturedPoint2D();
        QVector<qreal> xCoords = xDivs.coordsForSize(bounds.width());
        QVector<qreal> yCoords = yDivs.coordsForSize(bounds.height());
        for (int y = 0; y < ylen; ++y) {
            for (int x = 0; x < xlen; ++x, ++vertices)
                vertices->set(xCoords[x], yCoords[y], xDivs.data[x] / sourceSize.width(),
                              yDivs.data[y] / sourceSize.height());
        }

        quint16 *indices = m_geometry.indexDataAsUShort();
        int n = quads;
        for (int q = 0; n--; ++q) {
            if ((q + 1) % xlen == 0) // next row
                ++q;
            // Bottom-left half quad triangle
            indices[0] = q;
            indices[1] = q + xlen;
            indices[2] = q + xlen + 1;

            // Top-right half quad triangle
            indices[3] = q;
            indices[4] = q + xlen + 1;
            indices[5] = q + 1;

            indices += verticesPerQuad;
        }
    }

    markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial);
}
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;
}
void QSGDefaultImageNode::updateGeometry()
{
    Q_ASSERT(!m_targetRect.isEmpty());
    const QSGTexture *t = m_material.texture();
    if (!t) {
        QSGGeometry *g = geometry();
        g->allocate(4);
        g->setDrawingMode(GL_TRIANGLE_STRIP);
        memset(g->vertexData(), 0, g->sizeOfVertex() * 4);
    } else {
        QRectF sourceRect = t->normalizedTextureSubRect();

        QRectF innerSourceRect(sourceRect.x() + m_innerSourceRect.x() * sourceRect.width(),
                               sourceRect.y() + m_innerSourceRect.y() * sourceRect.height(),
                               m_innerSourceRect.width() * sourceRect.width(),
                               m_innerSourceRect.height() * sourceRect.height());

        bool hasMargins = m_targetRect != m_innerTargetRect;

        int floorLeft = qFloor(m_subSourceRect.left());
        int ceilRight = qCeil(m_subSourceRect.right());
        int floorTop = qFloor(m_subSourceRect.top());
        int ceilBottom = qCeil(m_subSourceRect.bottom());
        int hTiles = ceilRight - floorLeft;
        int vTiles = ceilBottom - floorTop;

        bool hasTiles = hTiles != 1 || vTiles != 1;
        bool fullTexture = innerSourceRect == QRectF(0, 0, 1, 1);

#ifdef QT_OPENGL_ES_2
        QOpenGLContext *ctx = QOpenGLContext::currentContext();
        bool npotSupported = ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
        QSize size = t->textureSize();
        bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
        bool wrapSupported = npotSupported || !isNpot;
#else
        bool wrapSupported = true;
#endif

        // An image can be rendered as a single quad if:
        // - There are no margins, and either:
        //   - the image isn't repeated
        //   - the source rectangle fills the entire texture so that texture wrapping can be used,
        //     and NPOT is supported
        if (!hasMargins && (!hasTiles || (fullTexture && wrapSupported))) {
            QRectF sr;
            if (!fullTexture) {
                sr = QRectF(innerSourceRect.x() + (m_subSourceRect.left() - floorLeft) * innerSourceRect.width(),
                            innerSourceRect.y() + (m_subSourceRect.top() - floorTop) * innerSourceRect.height(),
                            m_subSourceRect.width() * innerSourceRect.width(),
                            m_subSourceRect.height() * innerSourceRect.height());
            } else {
                sr = QRectF(m_subSourceRect.left() - floorLeft, m_subSourceRect.top() - floorTop,
                            m_subSourceRect.width(), m_subSourceRect.height());
            }
            if (m_mirror) {
                qreal oldLeft = sr.left();
                sr.setLeft(sr.right());
                sr.setRight(oldLeft);
            }

            if (m_antialiasing) {
                QSGGeometry *g = geometry();
                Q_ASSERT(g != &m_geometry);
                g->allocate(8, 14);
                g->setDrawingMode(GL_TRIANGLE_STRIP);
                SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData());
                float delta = float(qAbs(m_targetRect.width()) < qAbs(m_targetRect.height())
                        ? m_targetRect.width() : m_targetRect.height()) * 0.5f;
                float sx = float(sr.width() / m_targetRect.width());
                float sy = float(sr.height() / m_targetRect.height());
                for (int d = -1; d <= 1; d += 2) {
                    for (int j = 0; j < 2; ++j) {
                        for (int i = 0; i < 2; ++i, ++vertices) {
                            vertices->x = m_targetRect.x() + i * m_targetRect.width();
                            vertices->y = m_targetRect.y() + j * m_targetRect.height();
                            vertices->u = sr.x() + i * sr.width();
                            vertices->v = sr.y() + j * sr.height();
                            vertices->dx = (i == 0 ? delta : -delta) * d;
                            vertices->dy = (j == 0 ? delta : -delta) * d;
                            vertices->du = (d < 0 ? 0 : vertices->dx * sx);
                            vertices->dv = (d < 0 ? 0 : vertices->dy * sy);
                        }
                    }
                }
                Q_ASSERT(vertices - g->vertexCount() == g->vertexData());
                static const quint16 indices[] = {
                    0, 4, 1, 5, 3, 7, 2, 6, 0, 4,
                    4, 6, 5, 7
                };
                Q_ASSERT(g->sizeOfIndex() * g->indexCount() == sizeof(indices));
                memcpy(g->indexDataAsUShort(), indices, sizeof(indices));
            } else {
                m_geometry.allocate(4);
                m_geometry.setDrawingMode(GL_TRIANGLE_STRIP);
                QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_targetRect, sr);
            }
        } else {
            int hCells = hTiles;
            int vCells = vTiles;
            if (m_innerTargetRect.width() == 0)
                hCells = 0;
            if (m_innerTargetRect.left() != m_targetRect.left())
                ++hCells;
            if (m_innerTargetRect.right() != m_targetRect.right())
                ++hCells;
            if (m_innerTargetRect.height() == 0)
                vCells = 0;
            if (m_innerTargetRect.top() != m_targetRect.top())
                ++vCells;
            if (m_innerTargetRect.bottom() != m_targetRect.bottom())
                ++vCells;
            QVarLengthArray<X, 32> xData(2 * hCells);
            QVarLengthArray<Y, 32> yData(2 * vCells);
            X *xs = xData.data();
            Y *ys = yData.data();

            if (m_innerTargetRect.left() != m_targetRect.left()) {
                xs[0].x = m_targetRect.left();
                xs[0].tx = sourceRect.left();
                xs[1].x = m_innerTargetRect.left();
                xs[1].tx = innerSourceRect.left();
                xs += 2;
            }
            if (m_innerTargetRect.width() != 0) {
                xs[0].x = m_innerTargetRect.left();
                xs[0].tx = innerSourceRect.x() + (m_subSourceRect.left() - floorLeft) * innerSourceRect.width();
                ++xs;
                float b = m_innerTargetRect.width() / m_subSourceRect.width();
                float a = m_innerTargetRect.x() - m_subSourceRect.x() * b;
                for (int i = floorLeft + 1; i <= ceilRight - 1; ++i) {
                    xs[0].x = xs[1].x = a + b * i;
                    xs[0].tx = innerSourceRect.right();
                    xs[1].tx = innerSourceRect.left();
                    xs += 2;
                }
                xs[0].x = m_innerTargetRect.right();
                xs[0].tx = innerSourceRect.x() + (m_subSourceRect.right() - ceilRight + 1) * innerSourceRect.width();
                ++xs;
            }
            if (m_innerTargetRect.right() != m_targetRect.right()) {
                xs[0].x = m_innerTargetRect.right();
                xs[0].tx = innerSourceRect.right();
                xs[1].x = m_targetRect.right();
                xs[1].tx = sourceRect.right();
                xs += 2;
            }
            Q_ASSERT(xs == xData.data() + xData.size());
            if (m_mirror) {
                float leftPlusRight = m_targetRect.left() + m_targetRect.right();
                int count = xData.size();
                xs = xData.data();
                for (int i = 0; i < count >> 1; ++i)
                    qSwap(xs[i], xs[count - 1 - i]);
                for (int i = 0; i < count; ++i)
                    xs[i].x = leftPlusRight - xs[i].x;
            }

            if (m_innerTargetRect.top() != m_targetRect.top()) {
                ys[0].y = m_targetRect.top();
                ys[0].ty = sourceRect.top();
                ys[1].y = m_innerTargetRect.top();
                ys[1].ty = innerSourceRect.top();
                ys += 2;
            }
            if (m_innerTargetRect.height() != 0) {
                ys[0].y = m_innerTargetRect.top();
                ys[0].ty = innerSourceRect.y() + (m_subSourceRect.top() - floorTop) * innerSourceRect.height();
                ++ys;
                float b = m_innerTargetRect.height() / m_subSourceRect.height();
                float a = m_innerTargetRect.y() - m_subSourceRect.y() * b;
                for (int i = floorTop + 1; i <= ceilBottom - 1; ++i) {
                    ys[0].y = ys[1].y = a + b * i;
                    ys[0].ty = innerSourceRect.bottom();
                    ys[1].ty = innerSourceRect.top();
                    ys += 2;
                }
                ys[0].y = m_innerTargetRect.bottom();
                ys[0].ty = innerSourceRect.y() + (m_subSourceRect.bottom() - ceilBottom + 1) * innerSourceRect.height();
                ++ys;
            }
            if (m_innerTargetRect.bottom() != m_targetRect.bottom()) {
                ys[0].y = m_innerTargetRect.bottom();
                ys[0].ty = innerSourceRect.bottom();
                ys[1].y = m_targetRect.bottom();
                ys[1].ty = sourceRect.bottom();
                ys += 2;
            }
            Q_ASSERT(ys == yData.data() + yData.size());

            if (m_antialiasing) {
                QSGGeometry *g = geometry();
                Q_ASSERT(g != &m_geometry);

                g->allocate(hCells * vCells * 4 + (hCells + vCells - 1) * 4,
                            hCells * vCells * 6 + (hCells + vCells) * 12);
                g->setDrawingMode(GL_TRIANGLES);
                SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData());
                memset(vertices, 0, g->vertexCount() * g->sizeOfVertex());
                quint16 *indices = g->indexDataAsUShort();

                // The deltas are how much the fuzziness can reach into the image.
                // Only the border vertices are moved by the vertex shader, so the fuzziness
                // can't reach further into the image than the closest interior vertices.
                float leftDx = xData.at(1).x - xData.at(0).x;
                float rightDx = xData.at(xData.size() - 1).x - xData.at(xData.size() - 2).x;
                float topDy = yData.at(1).y - yData.at(0).y;
                float bottomDy = yData.at(yData.size() - 1).y - yData.at(yData.size() - 2).y;

                float leftDu = xData.at(1).tx - xData.at(0).tx;
                float rightDu = xData.at(xData.size() - 1).tx - xData.at(xData.size() - 2).tx;
                float topDv = yData.at(1).ty - yData.at(0).ty;
                float bottomDv = yData.at(yData.size() - 1).ty - yData.at(yData.size() - 2).ty;

                if (hCells == 1) {
                    leftDx = rightDx *= 0.5f;
                    leftDu = rightDu *= 0.5f;
                }
                if (vCells == 1) {
                    topDy = bottomDy *= 0.5f;
                    topDv = bottomDv *= 0.5f;
                }

                // This delta is how much the fuzziness can reach out from the image.
                float delta = float(qAbs(m_targetRect.width()) < qAbs(m_targetRect.height())
                                    ? m_targetRect.width() : m_targetRect.height()) * 0.5f;

                quint16 index = 0;
                ys = yData.data();
                for (int j = 0; j < vCells; ++j, ys += 2) {
                    xs = xData.data();
                    bool isTop = j == 0;
                    bool isBottom = j == vCells - 1;
                    for (int i = 0; i < hCells; ++i, xs += 2) {
                        bool isLeft = i == 0;
                        bool isRight = i == hCells - 1;

                        SmoothVertex *v = vertices + index;

                        quint16 topLeft = index;
                        for (int k = (isTop || isLeft ? 2 : 1); k--; ++v, ++index) {
                            v->x = xs[0].x;
                            v->u = xs[0].tx;
                            v->y = ys[0].y;
                            v->v = ys[0].ty;
                        }

                        quint16 topRight = index;
                        for (int k = (isTop || isRight ? 2 : 1); k--; ++v, ++index) {
                            v->x = xs[1].x;
                            v->u = xs[1].tx;
                            v->y = ys[0].y;
                            v->v = ys[0].ty;
                        }

                        quint16 bottomLeft = index;
                        for (int k = (isBottom || isLeft ? 2 : 1); k--; ++v, ++index) {
                            v->x = xs[0].x;
                            v->u = xs[0].tx;
                            v->y = ys[1].y;
                            v->v = ys[1].ty;
                        }

                        quint16 bottomRight = index;
                        for (int k = (isBottom || isRight ? 2 : 1); k--; ++v, ++index) {
                            v->x = xs[1].x;
                            v->u = xs[1].tx;
                            v->y = ys[1].y;
                            v->v = ys[1].ty;
                        }

                        appendQuad(&indices, topLeft, topRight, bottomLeft, bottomRight);

                        if (isTop) {
                            vertices[topLeft].dy = vertices[topRight].dy = topDy;
                            vertices[topLeft].dv = vertices[topRight].dv = topDv;
                            vertices[topLeft + 1].dy = vertices[topRight + 1].dy = -delta;
                            appendQuad(&indices, topLeft + 1, topRight + 1, topLeft, topRight);
                        }

                        if (isBottom) {
                            vertices[bottomLeft].dy = vertices[bottomRight].dy = -bottomDy;
                            vertices[bottomLeft].dv = vertices[bottomRight].dv = -bottomDv;
                            vertices[bottomLeft + 1].dy = vertices[bottomRight + 1].dy = delta;
                            appendQuad(&indices, bottomLeft, bottomRight, bottomLeft + 1, bottomRight + 1);
                        }

                        if (isLeft) {
                            vertices[topLeft].dx = vertices[bottomLeft].dx = leftDx;
                            vertices[topLeft].du = vertices[bottomLeft].du = leftDu;
                            vertices[topLeft + 1].dx = vertices[bottomLeft + 1].dx = -delta;
                            appendQuad(&indices, topLeft + 1, topLeft, bottomLeft + 1, bottomLeft);
                        }

                        if (isRight) {
                            vertices[topRight].dx = vertices[bottomRight].dx = -rightDx;
                            vertices[topRight].du = vertices[bottomRight].du = -rightDu;
                            vertices[topRight + 1].dx = vertices[bottomRight + 1].dx = delta;
                            appendQuad(&indices, topRight, topRight + 1, bottomRight, bottomRight + 1);
                        }
                    }
                }

                Q_ASSERT(index == g->vertexCount());
                Q_ASSERT(indices - g->indexCount() == g->indexData());
            } else {
                m_geometry.allocate(hCells * vCells * 4, hCells * vCells * 6);
                m_geometry.setDrawingMode(GL_TRIANGLES);
                QSGGeometry::TexturedPoint2D *vertices = m_geometry.vertexDataAsTexturedPoint2D();
                ys = yData.data();
                for (int j = 0; j < vCells; ++j, ys += 2) {
                    xs = xData.data();
                    for (int i = 0; i < hCells; ++i, xs += 2) {
                        vertices[0].x = vertices[2].x = xs[0].x;
                        vertices[0].tx = vertices[2].tx = xs[0].tx;
                        vertices[1].x = vertices[3].x = xs[1].x;
                        vertices[1].tx = vertices[3].tx = xs[1].tx;

                        vertices[0].y = vertices[1].y = ys[0].y;
                        vertices[0].ty = vertices[1].ty = ys[0].ty;
                        vertices[2].y = vertices[3].y = ys[1].y;
                        vertices[2].ty = vertices[3].ty = ys[1].ty;

                        vertices += 4;
                    }
                }

                quint16 *indices = m_geometry.indexDataAsUShort();
                for (int i = 0; i < 4 * vCells * hCells; i += 4)
                    appendQuad(&indices, i, i + 1, i + 2, i + 3);
            }
        }
    }
    markDirty(DirtyGeometry);
    m_dirtyGeometry = false;
}
Exemple #12
0
QSGNode *GraphConnection::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    if (m_source == m_sink)
        return oldNode;

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

    QPointF p1, p2, p3, p4;

    p1.setX(m_source.x());
    p1.setY(m_source.y());
    p4.setX(m_sink.x());
    p4.setY(m_sink.y());

    p2.setX(p1.x());
    p3.setX(p4.x());
    if (p1.y() < p4.y()) {
        p2.setY(p1.y() * 0.75 + p4.y() * 0.25);
        p3.setY(p4.y() * 0.75 + p1.y() * 0.25);
    } else {
        p2.setY(p1.y() - (p4.y()-p1.y())*0.25);
        p3.setY(p4.y() + (p4.y()-p1.y())*0.25);
    }

    // quick 'n' dirty estimation of bezier length
    // http://steve.hollasch.net/cgindex/curves/cbezarclen.html
    qreal l1 = (QVector2D(p2)-QVector2D(p1)).length() +
               (QVector2D(p3)-QVector2D(p2)).length() +
               (QVector2D(p4)-QVector2D(p3)).length();
    qreal l0 = (QVector2D(p4)-QVector2D(p1)).length();
    qreal length = 0.5*l0 + 0.5*l1;

    int segmentCount = length;

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

    QRectF bounds = boundingRect();
    QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D();
    for (int i = 0; i < segmentCount; ++i) {
        qreal t = i / qreal(segmentCount - 1);
        qreal invt = 1 - t;

        // Bezier
        QPointF pos = invt * invt * invt * p1
                    + 3 * invt * invt * t * p2
                    + 3 * invt * t * t * p3
                    + t * t * t * p4;

        float x = pos.x();
        float y = pos.y();

        vertices[i].set(x, y);
    }

    return node;
}
Exemple #13
0
QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect,
                                               const QRectF &innerTargetRect,
                                               const QRectF &sourceRect,
                                               const QRectF &innerSourceRect,
                                               const QRectF &subSourceRect,
                                               QSGGeometry *geometry,
                                               bool mirror,
                                               bool antialiasing)
{
    int floorLeft = qFloor(subSourceRect.left());
    int ceilRight = qCeil(subSourceRect.right());
    int floorTop = qFloor(subSourceRect.top());
    int ceilBottom = qCeil(subSourceRect.bottom());
    int hTiles = ceilRight - floorLeft;
    int vTiles = ceilBottom - floorTop;

    int hCells = hTiles;
    int vCells = vTiles;
    if (innerTargetRect.width() == 0)
        hCells = 0;
    if (innerTargetRect.left() != targetRect.left())
        ++hCells;
    if (innerTargetRect.right() != targetRect.right())
        ++hCells;
    if (innerTargetRect.height() == 0)
        vCells = 0;
    if (innerTargetRect.top() != targetRect.top())
        ++vCells;
    if (innerTargetRect.bottom() != targetRect.bottom())
        ++vCells;
    QVarLengthArray<X, 32> xData(2 * hCells);
    QVarLengthArray<Y, 32> yData(2 * vCells);
    X *xs = xData.data();
    Y *ys = yData.data();

    if (innerTargetRect.left() != targetRect.left()) {
        xs[0].x = targetRect.left();
        xs[0].tx = sourceRect.left();
        xs[1].x = innerTargetRect.left();
        xs[1].tx = innerSourceRect.left();
        xs += 2;
    }
    if (innerTargetRect.width() != 0) {
        xs[0].x = innerTargetRect.left();
        xs[0].tx = innerSourceRect.x() + (subSourceRect.left() - floorLeft) * innerSourceRect.width();
        ++xs;
        float b = innerTargetRect.width() / subSourceRect.width();
        float a = innerTargetRect.x() - subSourceRect.x() * b;
        for (int i = floorLeft + 1; i <= ceilRight - 1; ++i) {
            xs[0].x = xs[1].x = a + b * i;
            xs[0].tx = innerSourceRect.right();
            xs[1].tx = innerSourceRect.left();
            xs += 2;
        }
        xs[0].x = innerTargetRect.right();
        xs[0].tx = innerSourceRect.x() + (subSourceRect.right() - ceilRight + 1) * innerSourceRect.width();
        ++xs;
    }
    if (innerTargetRect.right() != targetRect.right()) {
        xs[0].x = innerTargetRect.right();
        xs[0].tx = innerSourceRect.right();
        xs[1].x = targetRect.right();
        xs[1].tx = sourceRect.right();
        xs += 2;
    }
    Q_ASSERT(xs == xData.data() + xData.size());
    if (mirror) {
        float leftPlusRight = targetRect.left() + targetRect.right();
        int count = xData.size();
        xs = xData.data();
        for (int i = 0; i < count >> 1; ++i)
            qSwap(xs[i], xs[count - 1 - i]);
        for (int i = 0; i < count; ++i)
            xs[i].x = leftPlusRight - xs[i].x;
    }

    if (innerTargetRect.top() != targetRect.top()) {
        ys[0].y = targetRect.top();
        ys[0].ty = sourceRect.top();
        ys[1].y = innerTargetRect.top();
        ys[1].ty = innerSourceRect.top();
        ys += 2;
    }
    if (innerTargetRect.height() != 0) {
        ys[0].y = innerTargetRect.top();
        ys[0].ty = innerSourceRect.y() + (subSourceRect.top() - floorTop) * innerSourceRect.height();
        ++ys;
        float b = innerTargetRect.height() / subSourceRect.height();
        float a = innerTargetRect.y() - subSourceRect.y() * b;
        for (int i = floorTop + 1; i <= ceilBottom - 1; ++i) {
            ys[0].y = ys[1].y = a + b * i;
            ys[0].ty = innerSourceRect.bottom();
            ys[1].ty = innerSourceRect.top();
            ys += 2;
        }
        ys[0].y = innerTargetRect.bottom();
        ys[0].ty = innerSourceRect.y() + (subSourceRect.bottom() - ceilBottom + 1) * innerSourceRect.height();
        ++ys;
    }
    if (innerTargetRect.bottom() != targetRect.bottom()) {
        ys[0].y = innerTargetRect.bottom();
        ys[0].ty = innerSourceRect.bottom();
        ys[1].y = targetRect.bottom();
        ys[1].ty = sourceRect.bottom();
        ys += 2;
    }
    Q_ASSERT(ys == yData.data() + yData.size());

    if (antialiasing) {
        QSGGeometry *g = geometry;
        Q_ASSERT(g);

        g->allocate(hCells * vCells * 4 + (hCells + vCells - 1) * 4,
                    hCells * vCells * 6 + (hCells + vCells) * 12);
        g->setDrawingMode(QSGGeometry::DrawTriangles);
        SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData());
        memset(vertices, 0, g->vertexCount() * g->sizeOfVertex());
        quint16 *indices = g->indexDataAsUShort();

        // The deltas are how much the fuzziness can reach into the image.
        // Only the border vertices are moved by the vertex shader, so the fuzziness
        // can't reach further into the image than the closest interior vertices.
        float leftDx = xData.at(1).x - xData.at(0).x;
        float rightDx = xData.at(xData.size() - 1).x - xData.at(xData.size() - 2).x;
        float topDy = yData.at(1).y - yData.at(0).y;
        float bottomDy = yData.at(yData.size() - 1).y - yData.at(yData.size() - 2).y;

        float leftDu = xData.at(1).tx - xData.at(0).tx;
        float rightDu = xData.at(xData.size() - 1).tx - xData.at(xData.size() - 2).tx;
        float topDv = yData.at(1).ty - yData.at(0).ty;
        float bottomDv = yData.at(yData.size() - 1).ty - yData.at(yData.size() - 2).ty;

        if (hCells == 1) {
            leftDx = rightDx *= 0.5f;
            leftDu = rightDu *= 0.5f;
        }
        if (vCells == 1) {
            topDy = bottomDy *= 0.5f;
            topDv = bottomDv *= 0.5f;
        }

        // This delta is how much the fuzziness can reach out from the image.
        float delta = float(qAbs(targetRect.width()) < qAbs(targetRect.height())
                            ? targetRect.width() : targetRect.height()) * 0.5f;

        quint16 index = 0;
        ys = yData.data();
        for (int j = 0; j < vCells; ++j, ys += 2) {
            xs = xData.data();
            bool isTop = j == 0;
            bool isBottom = j == vCells - 1;
            for (int i = 0; i < hCells; ++i, xs += 2) {
                bool isLeft = i == 0;
                bool isRight = i == hCells - 1;

                SmoothVertex *v = vertices + index;

                quint16 topLeft = index;
                for (int k = (isTop || isLeft ? 2 : 1); k--; ++v, ++index) {
                    v->x = xs[0].x;
                    v->u = xs[0].tx;
                    v->y = ys[0].y;
                    v->v = ys[0].ty;
                }

                quint16 topRight = index;
                for (int k = (isTop || isRight ? 2 : 1); k--; ++v, ++index) {
                    v->x = xs[1].x;
                    v->u = xs[1].tx;
                    v->y = ys[0].y;
                    v->v = ys[0].ty;
                }

                quint16 bottomLeft = index;
                for (int k = (isBottom || isLeft ? 2 : 1); k--; ++v, ++index) {
                    v->x = xs[0].x;
                    v->u = xs[0].tx;
                    v->y = ys[1].y;
                    v->v = ys[1].ty;
                }

                quint16 bottomRight = index;
                for (int k = (isBottom || isRight ? 2 : 1); k--; ++v, ++index) {
                    v->x = xs[1].x;
                    v->u = xs[1].tx;
                    v->y = ys[1].y;
                    v->v = ys[1].ty;
                }

                appendQuad(&indices, topLeft, topRight, bottomLeft, bottomRight);

                if (isTop) {
                    vertices[topLeft].dy = vertices[topRight].dy = topDy;
                    vertices[topLeft].dv = vertices[topRight].dv = topDv;
                    vertices[topLeft + 1].dy = vertices[topRight + 1].dy = -delta;
                    appendQuad(&indices, topLeft + 1, topRight + 1, topLeft, topRight);
                }

                if (isBottom) {
                    vertices[bottomLeft].dy = vertices[bottomRight].dy = -bottomDy;
                    vertices[bottomLeft].dv = vertices[bottomRight].dv = -bottomDv;
                    vertices[bottomLeft + 1].dy = vertices[bottomRight + 1].dy = delta;
                    appendQuad(&indices, bottomLeft, bottomRight, bottomLeft + 1, bottomRight + 1);
                }

                if (isLeft) {
                    vertices[topLeft].dx = vertices[bottomLeft].dx = leftDx;
                    vertices[topLeft].du = vertices[bottomLeft].du = leftDu;
                    vertices[topLeft + 1].dx = vertices[bottomLeft + 1].dx = -delta;
                    appendQuad(&indices, topLeft + 1, topLeft, bottomLeft + 1, bottomLeft);
                }

                if (isRight) {
                    vertices[topRight].dx = vertices[bottomRight].dx = -rightDx;
                    vertices[topRight].du = vertices[bottomRight].du = -rightDu;
                    vertices[topRight + 1].dx = vertices[bottomRight + 1].dx = delta;
                    appendQuad(&indices, topRight, topRight + 1, bottomRight, bottomRight + 1);
                }
            }
        }

        Q_ASSERT(index == g->vertexCount());
        Q_ASSERT(indices - g->indexCount() == g->indexData());
    } else {
        if (!geometry) {
            geometry = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(),
                                       hCells * vCells * 4, hCells * vCells * 6,
                                       QSGGeometry::UnsignedShortType);
        } else {
            geometry->allocate(hCells * vCells * 4, hCells * vCells * 6);
        }
        geometry->setDrawingMode(QSGGeometry::DrawTriangles);
        QSGGeometry::TexturedPoint2D *vertices = geometry->vertexDataAsTexturedPoint2D();
        ys = yData.data();
        for (int j = 0; j < vCells; ++j, ys += 2) {
            xs = xData.data();
            for (int i = 0; i < hCells; ++i, xs += 2) {
                vertices[0].x = vertices[2].x = xs[0].x;
                vertices[0].tx = vertices[2].tx = xs[0].tx;
                vertices[1].x = vertices[3].x = xs[1].x;
                vertices[1].tx = vertices[3].tx = xs[1].tx;

                vertices[0].y = vertices[1].y = ys[0].y;
                vertices[0].ty = vertices[1].ty = ys[0].ty;
                vertices[2].y = vertices[3].y = ys[1].y;
                vertices[2].ty = vertices[3].ty = ys[1].ty;

                vertices += 4;
            }
        }

        quint16 *indices = geometry->indexDataAsUShort();
        for (int i = 0; i < 4 * vCells * hCells; i += 4)
            appendQuad(&indices, i, i + 1, i + 2, i + 3);
    }
    return geometry;
}
void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node)
{
    if (!node->m_fillNode)
        return;
    if (!(d->effectiveDirty & (DirtyFillGeom | DirtyColor | DirtyFillGradient)))
        return;

    // Make a copy of the data that will be accessed by the material on
    // the render thread. This must be done even when we bail out below.
    QQuickShapeGenericStrokeFillNode *n = node->m_fillNode;
    updateShadowDataInNode(d, n);

    QSGGeometry *g = n->geometry();
    if (d->fillVertices.isEmpty()) {
        if (g->vertexCount() || g->indexCount()) {
            g->allocate(0, 0);
            n->markDirty(QSGNode::DirtyGeometry);
        }
        return;
    }

    if (d->fillGradientActive) {
        QQuickShapeGenericStrokeFillNode::Material gradMat;
        switch (d->fillGradientActive) {
        case LinearGradient:
            gradMat = QQuickShapeGenericStrokeFillNode::MatLinearGradient;
            break;
        case RadialGradient:
            gradMat = QQuickShapeGenericStrokeFillNode::MatRadialGradient;
            break;
        case ConicalGradient:
            gradMat = QQuickShapeGenericStrokeFillNode::MatConicalGradient;
            break;
        default:
            Q_UNREACHABLE();
        }
        n->activateMaterial(m_item->window(), gradMat);
        if (d->effectiveDirty & DirtyFillGradient) {
            // Gradients are implemented via a texture-based material.
            n->markDirty(QSGNode::DirtyMaterial);
            // stop here if only the gradient changed; no need to touch the geometry
            if (!(d->effectiveDirty & DirtyFillGeom))
                return;
        }
    } else {
        n->activateMaterial(m_item->window(), QQuickShapeGenericStrokeFillNode::MatSolidColor);
        // fast path for updating only color values when no change in vertex positions
        if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyFillGeom)) {
            ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData());
            for (int i = 0; i < g->vertexCount(); ++i)
                vdst[i].set(vdst[i].x, vdst[i].y, d->fillColor);
            n->markDirty(QSGNode::DirtyGeometry);
            return;
        }
    }

    const int indexCount = d->indexType == QSGGeometry::UnsignedShortType
            ? d->fillIndices.count() * 2 : d->fillIndices.count();
    if (g->indexType() != d->indexType) {
        g = new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(),
                            d->fillVertices.count(), indexCount, d->indexType);
        n->setGeometry(g);
    } else {
        g->allocate(d->fillVertices.count(), indexCount);
    }
    g->setDrawingMode(QSGGeometry::DrawTriangles);
    memcpy(g->vertexData(), d->fillVertices.constData(), g->vertexCount() * g->sizeOfVertex());
    memcpy(g->indexData(), d->fillIndices.constData(), g->indexCount() * g->sizeOfIndex());

    n->markDirty(QSGNode::DirtyGeometry);
}
Exemple #15
0
void QSGBasicInternalImageNode::updateGeometry()
{
    Q_ASSERT(!m_targetRect.isEmpty());
    const QSGTexture *t = materialTexture();
    if (!t) {
        QSGGeometry *g = geometry();
        g->allocate(4);
        g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
        memset(g->vertexData(), 0, g->sizeOfVertex() * 4);
    } else {
        QRectF sourceRect = t->normalizedTextureSubRect();

        QRectF innerSourceRect(sourceRect.x() + m_innerSourceRect.x() * sourceRect.width(),
                               sourceRect.y() + m_innerSourceRect.y() * sourceRect.height(),
                               m_innerSourceRect.width() * sourceRect.width(),
                               m_innerSourceRect.height() * sourceRect.height());

        bool hasMargins = m_targetRect != m_innerTargetRect;

        int floorLeft = qFloor(m_subSourceRect.left());
        int ceilRight = qCeil(m_subSourceRect.right());
        int floorTop = qFloor(m_subSourceRect.top());
        int ceilBottom = qCeil(m_subSourceRect.bottom());
        int hTiles = ceilRight - floorLeft;
        int vTiles = ceilBottom - floorTop;

        bool hasTiles = hTiles != 1 || vTiles != 1;
        bool fullTexture = innerSourceRect == QRectF(0, 0, 1, 1);

        // An image can be rendered as a single quad if:
        // - There are no margins, and either:
        //   - the image isn't repeated
        //   - the source rectangle fills the entire texture so that texture wrapping can be used,
        //     and NPOT is supported
        if (!hasMargins && (!hasTiles || (fullTexture && supportsWrap(t->textureSize())))) {
            QRectF sr;
            if (!fullTexture) {
                sr = QRectF(innerSourceRect.x() + (m_subSourceRect.left() - floorLeft) * innerSourceRect.width(),
                            innerSourceRect.y() + (m_subSourceRect.top() - floorTop) * innerSourceRect.height(),
                            m_subSourceRect.width() * innerSourceRect.width(),
                            m_subSourceRect.height() * innerSourceRect.height());
            } else {
                sr = QRectF(m_subSourceRect.left() - floorLeft, m_subSourceRect.top() - floorTop,
                            m_subSourceRect.width(), m_subSourceRect.height());
            }
            if (m_mirror) {
                qreal oldLeft = sr.left();
                sr.setLeft(sr.right());
                sr.setRight(oldLeft);
            }

            if (m_antialiasing) {
                QSGGeometry *g = geometry();
                Q_ASSERT(g != &m_geometry);
                g->allocate(8, 14);
                g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
                SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData());
                float delta = float(qAbs(m_targetRect.width()) < qAbs(m_targetRect.height())
                        ? m_targetRect.width() : m_targetRect.height()) * 0.5f;
                float sx = float(sr.width() / m_targetRect.width());
                float sy = float(sr.height() / m_targetRect.height());
                for (int d = -1; d <= 1; d += 2) {
                    for (int j = 0; j < 2; ++j) {
                        for (int i = 0; i < 2; ++i, ++vertices) {
                            vertices->x = m_targetRect.x() + i * m_targetRect.width();
                            vertices->y = m_targetRect.y() + j * m_targetRect.height();
                            vertices->u = sr.x() + i * sr.width();
                            vertices->v = sr.y() + j * sr.height();
                            vertices->dx = (i == 0 ? delta : -delta) * d;
                            vertices->dy = (j == 0 ? delta : -delta) * d;
                            vertices->du = (d < 0 ? 0 : vertices->dx * sx);
                            vertices->dv = (d < 0 ? 0 : vertices->dy * sy);
                        }
                    }
                }
                Q_ASSERT(vertices - g->vertexCount() == g->vertexData());
                static const quint16 indices[] = {
                    0, 4, 1, 5, 3, 7, 2, 6, 0, 4,
                    4, 6, 5, 7
                };
                Q_ASSERT(g->sizeOfIndex() * g->indexCount() == sizeof(indices));
                memcpy(g->indexDataAsUShort(), indices, sizeof(indices));
            } else {
                m_geometry.allocate(4);
                m_geometry.setDrawingMode(QSGGeometry::DrawTriangleStrip);
                QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_targetRect, sr);
            }
        } else {
            QSGGeometry *g = m_antialiasing ? geometry() : &m_geometry;
            updateGeometry(m_targetRect, m_innerTargetRect,
                           sourceRect, innerSourceRect, m_subSourceRect,
                           g, m_mirror, m_antialiasing);
        }
    }
    markDirty(DirtyGeometry);
    m_dirtyGeometry = false;
}
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
}
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;
}