diff options
-rw-r--r-- | src/quick/scenegraph/qsgdefaultglyphnode.cpp | 128 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgdefaultglyphnode_p.h | 23 |
2 files changed, 151 insertions, 0 deletions
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode.cpp b/src/quick/scenegraph/qsgdefaultglyphnode.cpp index b856d99bc1..0d42102f36 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode.cpp @@ -42,11 +42,33 @@ QT_BEGIN_NAMESPACE +QSGDefaultGlyphNode::QSGDefaultGlyphNode() + : m_glyphNodeType(RootGlyphNode) + , m_dirtyGeometry(false) +{ + setFlag(UsePreprocess); +} + +QSGDefaultGlyphNode::~QSGDefaultGlyphNode() +{ + if (m_glyphNodeType == SubGlyphNode) + return; + + qDeleteAll(m_nodesToDelete); + m_nodesToDelete.clear(); +} + void QSGDefaultGlyphNode::setMaterialColor(const QColor &color) { static_cast<QSGTextMaskMaterial *>(m_material)->setColor(color); } +void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs) +{ + QSGBasicGlyphNode::setGlyphs(position, glyphs); + m_dirtyGeometry = true; +} + void QSGDefaultGlyphNode::update() { QRawFont font = m_glyphs.rawFont(); @@ -84,4 +106,110 @@ void QSGDefaultGlyphNode::update() markDirty(DirtyGeometry); } +void QSGDefaultGlyphNode::preprocess() +{ + qDeleteAll(m_nodesToDelete); + m_nodesToDelete.clear(); + + if (m_dirtyGeometry) + updateGeometry(); +} + +void QSGDefaultGlyphNode::updateGeometry() +{ + // Remove previously created sub glyph nodes + // We assume all the children are sub glyph nodes + QSGNode *subnode = firstChild(); + while (subnode) { + // We can't delete the node now as it might be in the preprocess list + // It will be deleted in the next preprocess + m_nodesToDelete.append(subnode); + subnode = subnode->nextSibling(); + } + removeAllChildNodes(); + + GlyphInfo glyphInfo; + + const QVector<quint32> indexes = m_glyphs.glyphIndexes(); + const QVector<QPointF> positions = m_glyphs.positions(); + + const int maxGlyphs = (USHRT_MAX + 1) / 4; // 16384 + const int maxVertices = maxGlyphs * 4; // 65536 + const int maxIndexes = maxGlyphs * 6; // 98304 + + for (int i = 0; i < indexes.size(); ++i) { + const int glyphIndex = indexes.at(i); + const QPointF position = positions.at(i); + + // As we use UNSIGNED_SHORT indexing in the geometry, we overload the + // "glyphsInOtherNodes" concept as overflow for if there are more than + // 65536 (16384 * 4) vertices to render which would otherwise exceed + // the maximum index size. This will cause sub-nodes to be recursively + // created to handle any number of glyphs. + if (i >= maxGlyphs) { + glyphInfo.indexes.append(glyphIndex); + glyphInfo.positions.append(position); + continue; + } + } + + if (!glyphInfo.indexes.isEmpty()) { + QGlyphRun subNodeGlyphRun(m_glyphs); + subNodeGlyphRun.setGlyphIndexes(glyphInfo.indexes); + subNodeGlyphRun.setPositions(glyphInfo.positions); + + QSGDefaultGlyphNode *subNode = new QSGDefaultGlyphNode(); + subNode->setGlyphNodeType(SubGlyphNode); + subNode->setColor(m_color); + subNode->setStyle(m_style); + subNode->setStyleColor(m_styleColor); + subNode->setGlyphs(m_position, subNodeGlyphRun); + subNode->update(); + subNode->updateGeometry(); // we have to explicitly call this now as preprocess won't be called before it's rendered + appendChildNode(subNode); + + QSGGeometry *g = geometry(); + + QSGGeometry::TexturedPoint2D *vertexData = g->vertexDataAsTexturedPoint2D(); + quint16 *indexData = g->indexDataAsUShort(); + + QVector<QSGGeometry::TexturedPoint2D> tempVertexData(maxVertices); + QVector<quint16> tempIndexData(maxIndexes); + + for (int i = 0; i < maxGlyphs; i++) { + tempVertexData[i * 4 + 0] = vertexData[i * 4 + 0]; + tempVertexData[i * 4 + 1] = vertexData[i * 4 + 1]; + tempVertexData[i * 4 + 2] = vertexData[i * 4 + 2]; + tempVertexData[i * 4 + 3] = vertexData[i * 4 + 3]; + + tempIndexData[i * 6 + 0] = indexData[i * 6 + 0]; + tempIndexData[i * 6 + 1] = indexData[i * 6 + 1]; + tempIndexData[i * 6 + 2] = indexData[i * 6 + 2]; + tempIndexData[i * 6 + 3] = indexData[i * 6 + 3]; + tempIndexData[i * 6 + 4] = indexData[i * 6 + 4]; + tempIndexData[i * 6 + 5] = indexData[i * 6 + 5]; + } + + g->allocate(maxVertices, maxIndexes); + vertexData = g->vertexDataAsTexturedPoint2D(); + indexData = g->indexDataAsUShort(); + + for (int i = 0; i < maxGlyphs; i++) { + vertexData[i * 4 + 0] = tempVertexData[i * 4 + 0]; + vertexData[i * 4 + 1] = tempVertexData[i * 4 + 1]; + vertexData[i * 4 + 2] = tempVertexData[i * 4 + 2]; + vertexData[i * 4 + 3] = tempVertexData[i * 4 + 3]; + + indexData[i * 6 + 0] = tempIndexData[i * 6 + 0]; + indexData[i * 6 + 1] = tempIndexData[i * 6 + 1]; + indexData[i * 6 + 2] = tempIndexData[i * 6 + 2]; + indexData[i * 6 + 3] = tempIndexData[i * 6 + 3]; + indexData[i * 6 + 4] = tempIndexData[i * 6 + 4]; + indexData[i * 6 + 5] = tempIndexData[i * 6 + 5]; + } + } + + m_dirtyGeometry = false; +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.h b/src/quick/scenegraph/qsgdefaultglyphnode_p.h index 0eb7a4e4bd..37a89c70b9 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.h +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.h @@ -59,8 +59,31 @@ QT_BEGIN_NAMESPACE class QSGDefaultGlyphNode : public QSGBasicGlyphNode { public: + QSGDefaultGlyphNode(); + ~QSGDefaultGlyphNode(); void setMaterialColor(const QColor &color) override; + void setGlyphs(const QPointF &position, const QGlyphRun &glyphs) override; void update() override; + void preprocess() override; + void updateGeometry(); + +private: + enum DefaultGlyphNodeType { + RootGlyphNode, + SubGlyphNode + }; + + void setGlyphNodeType(DefaultGlyphNodeType type) { m_glyphNodeType = type; } + + DefaultGlyphNodeType m_glyphNodeType; + QLinkedList<QSGNode *> m_nodesToDelete; + + struct GlyphInfo { + QVector<quint32> indexes; + QVector<QPointF> positions; + }; + + uint m_dirtyGeometry: 1; }; QT_END_NAMESPACE |