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; } }
/* * 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; }
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); }
//! [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; }
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; }
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); }
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; }