559 glDepthFunc(GL_LESS); |
571 glDepthFunc(GL_LESS); |
560 glClearDepth(1); |
572 glClearDepth(1); |
561 glStencilMask(0xff); |
573 glStencilMask(0xff); |
562 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
574 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
563 glStencilFunc(GL_ALWAYS, 0, 0xff); |
575 glStencilFunc(GL_ALWAYS, 0, 0xff); |
564 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
576 ctx->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false); |
565 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
577 ctx->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false); |
566 glDisableVertexAttribArray(QT_OPACITY_ATTR); |
578 ctx->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); |
567 #ifndef QT_OPENGL_ES_2 |
579 #ifndef QT_OPENGL_ES_2 |
568 glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // color may have been changed by glVertexAttrib() |
580 glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // color may have been changed by glVertexAttrib() |
569 #endif |
581 #endif |
570 } |
582 } |
571 |
583 |
572 void QGL2PaintEngineEx::endNativePainting() |
584 void QGL2PaintEngineEx::endNativePainting() |
573 { |
585 { |
574 Q_D(QGL2PaintEngineEx); |
586 Q_D(QGL2PaintEngineEx); |
575 d->needsSync = true; |
587 d->needsSync = true; |
|
588 d->nativePaintingActive = false; |
|
589 } |
|
590 |
|
591 bool QGL2PaintEngineEx::isNativePaintingActive() const { |
|
592 Q_D(const QGL2PaintEngineEx); |
|
593 return d->nativePaintingActive; |
576 } |
594 } |
577 |
595 |
578 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) |
596 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) |
579 { |
597 { |
580 if (newMode == mode) |
598 if (newMode == mode) |
666 } else if (path.isConvex()) { |
696 } else if (path.isConvex()) { |
667 |
697 |
668 if (path.isCacheable()) { |
698 if (path.isCacheable()) { |
669 QVectorPath::CacheEntry *data = path.lookupCacheData(q); |
699 QVectorPath::CacheEntry *data = path.lookupCacheData(q); |
670 QGL2PEVectorPathCache *cache; |
700 QGL2PEVectorPathCache *cache; |
|
701 |
|
702 bool updateCache = false; |
671 |
703 |
672 if (data) { |
704 if (data) { |
673 cache = (QGL2PEVectorPathCache *) data->data; |
705 cache = (QGL2PEVectorPathCache *) data->data; |
674 // Check if scale factor is exceeded for curved paths and generate curves if so... |
706 // Check if scale factor is exceeded for curved paths and generate curves if so... |
675 if (path.isCurved()) { |
707 if (path.isCurved()) { |
676 qreal scaleFactor = cache->iscale / inverseScale; |
708 qreal scaleFactor = cache->iscale / inverseScale; |
677 if (scaleFactor < 0.5 || scaleFactor > 2.0) { |
709 if (scaleFactor < 0.5 || scaleFactor > 2.0) { |
678 #ifdef QT_OPENGL_CACHE_AS_VBOS |
710 #ifdef QT_OPENGL_CACHE_AS_VBOS |
679 glDeleteBuffers(1, &cache->vbo); |
711 glDeleteBuffers(1, &cache->vbo); |
680 cache->vbo = 0; |
712 cache->vbo = 0; |
|
713 Q_ASSERT(cache->ibo == 0); |
681 #else |
714 #else |
682 qFree(cache->vertices); |
715 qFree(cache->vertices); |
683 #endif |
716 Q_ASSERT(cache->indices == 0); |
684 cache->vertexCount = 0; |
717 #endif |
|
718 updateCache = true; |
685 } |
719 } |
686 } |
720 } |
687 } else { |
721 } else { |
688 cache = new QGL2PEVectorPathCache; |
722 cache = new QGL2PEVectorPathCache; |
689 cache->vertexCount = 0; |
|
690 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath); |
723 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath); |
|
724 updateCache = true; |
691 } |
725 } |
692 |
726 |
693 // Flatten the path at the current scale factor and fill it into the cache struct. |
727 // Flatten the path at the current scale factor and fill it into the cache struct. |
694 if (!cache->vertexCount) { |
728 if (updateCache) { |
695 vertexCoordinateArray.clear(); |
729 vertexCoordinateArray.clear(); |
696 vertexCoordinateArray.addPath(path, inverseScale, false); |
730 vertexCoordinateArray.addPath(path, inverseScale, false); |
697 int vertexCount = vertexCoordinateArray.vertexCount(); |
731 int vertexCount = vertexCoordinateArray.vertexCount(); |
698 int floatSizeInBytes = vertexCount * 2 * sizeof(float); |
732 int floatSizeInBytes = vertexCount * 2 * sizeof(float); |
699 cache->vertexCount = vertexCount; |
733 cache->vertexCount = vertexCount; |
|
734 cache->indexCount = 0; |
700 cache->primitiveType = GL_TRIANGLE_FAN; |
735 cache->primitiveType = GL_TRIANGLE_FAN; |
701 cache->iscale = inverseScale; |
736 cache->iscale = inverseScale; |
702 #ifdef QT_OPENGL_CACHE_AS_VBOS |
737 #ifdef QT_OPENGL_CACHE_AS_VBOS |
703 glGenBuffers(1, &cache->vbo); |
738 glGenBuffers(1, &cache->vbo); |
704 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); |
739 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); |
705 glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW); |
740 glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW); |
|
741 cache->ibo = 0; |
706 #else |
742 #else |
707 cache->vertices = (float *) qMalloc(floatSizeInBytes); |
743 cache->vertices = (float *) qMalloc(floatSizeInBytes); |
708 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes); |
744 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes); |
|
745 cache->indices = 0; |
709 #endif |
746 #endif |
710 } |
747 } |
711 |
748 |
712 prepareForDraw(currentBrush.isOpaque()); |
749 prepareForDraw(currentBrush.isOpaque()); |
713 #ifdef QT_OPENGL_CACHE_AS_VBOS |
750 #ifdef QT_OPENGL_CACHE_AS_VBOS |
719 glDrawArrays(cache->primitiveType, 0, cache->vertexCount); |
756 glDrawArrays(cache->primitiveType, 0, cache->vertexCount); |
720 |
757 |
721 } else { |
758 } else { |
722 // printf(" - Marking path as cachable...\n"); |
759 // printf(" - Marking path as cachable...\n"); |
723 // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable |
760 // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable |
724 // ### Remove before release... |
|
725 static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty(); |
|
726 if (do_vectorpath_cache) |
761 if (do_vectorpath_cache) |
727 path.makeCacheable(); |
762 path.makeCacheable(); |
728 vertexCoordinateArray.clear(); |
763 vertexCoordinateArray.clear(); |
729 vertexCoordinateArray.addPath(path, inverseScale, false); |
764 vertexCoordinateArray.addPath(path, inverseScale, false); |
730 prepareForDraw(currentBrush.isOpaque()); |
765 prepareForDraw(currentBrush.isOpaque()); |
731 drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); |
766 drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); |
732 } |
767 } |
733 |
768 |
734 } else { |
769 } else { |
735 // The path is too complicated & needs the stencil technique |
770 bool useCache = path.isCacheable(); |
736 vertexCoordinateArray.clear(); |
771 if (useCache) { |
737 vertexCoordinateArray.addPath(path, inverseScale, false); |
772 QRectF bbox = path.controlPointRect(); |
738 |
773 // If the path doesn't fit within these limits, it is possible that the triangulation will fail. |
739 fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); |
774 useCache &= (bbox.left() > -0x8000 * inverseScale) |
740 |
775 && (bbox.right() < 0x8000 * inverseScale) |
741 glStencilMask(0xff); |
776 && (bbox.top() > -0x8000 * inverseScale) |
742 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); |
777 && (bbox.bottom() < 0x8000 * inverseScale); |
743 |
778 } |
744 if (q->state()->clipTestEnabled) { |
779 |
745 // Pass when high bit is set, replace stencil value with current clip |
780 if (useCache) { |
746 glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT); |
781 QVectorPath::CacheEntry *data = path.lookupCacheData(q); |
747 } else if (path.hasWindingFill()) { |
782 QGL2PEVectorPathCache *cache; |
748 // Pass when any bit is set, replace stencil value with 0 |
783 |
749 glStencilFunc(GL_NOTEQUAL, 0, 0xff); |
784 bool updateCache = false; |
|
785 |
|
786 if (data) { |
|
787 cache = (QGL2PEVectorPathCache *) data->data; |
|
788 // Check if scale factor is exceeded for curved paths and generate curves if so... |
|
789 if (path.isCurved()) { |
|
790 qreal scaleFactor = cache->iscale / inverseScale; |
|
791 if (scaleFactor < 0.5 || scaleFactor > 2.0) { |
|
792 #ifdef QT_OPENGL_CACHE_AS_VBOS |
|
793 glDeleteBuffers(1, &cache->vbo); |
|
794 glDeleteBuffers(1, &cache->ibo); |
|
795 #else |
|
796 qFree(cache->vertices); |
|
797 qFree(cache->indices); |
|
798 #endif |
|
799 updateCache = true; |
|
800 } |
|
801 } |
|
802 } else { |
|
803 cache = new QGL2PEVectorPathCache; |
|
804 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath); |
|
805 updateCache = true; |
|
806 } |
|
807 |
|
808 // Flatten the path at the current scale factor and fill it into the cache struct. |
|
809 if (updateCache) { |
|
810 QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale)); |
|
811 cache->vertexCount = polys.vertices.size() / 2; |
|
812 cache->indexCount = polys.indices.size(); |
|
813 cache->primitiveType = GL_TRIANGLES; |
|
814 cache->iscale = inverseScale; |
|
815 |
|
816 #ifdef QT_OPENGL_CACHE_AS_VBOS |
|
817 glGenBuffers(1, &cache->vbo); |
|
818 glGenBuffers(1, &cache->ibo); |
|
819 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); |
|
820 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo); |
|
821 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quint32) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW); |
|
822 |
|
823 QVarLengthArray<float> vertices(polys.vertices.size()); |
|
824 for (int i = 0; i < polys.vertices.size(); ++i) |
|
825 vertices[i] = float(inverseScale * polys.vertices.at(i)); |
|
826 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW); |
|
827 #else |
|
828 cache->vertices = (float *) qMalloc(sizeof(float) * polys.vertices.size()); |
|
829 cache->indices = (quint32 *) qMalloc(sizeof(quint32) * polys.indices.size()); |
|
830 memcpy(cache->indices, polys.indices.data(), sizeof(quint32) * polys.indices.size()); |
|
831 for (int i = 0; i < polys.vertices.size(); ++i) |
|
832 cache->vertices[i] = float(inverseScale * polys.vertices.at(i)); |
|
833 #endif |
|
834 } |
|
835 |
|
836 prepareForDraw(currentBrush.isOpaque()); |
|
837 #ifdef QT_OPENGL_CACHE_AS_VBOS |
|
838 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); |
|
839 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo); |
|
840 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); |
|
841 glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0); |
|
842 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
|
843 glBindBuffer(GL_ARRAY_BUFFER, 0); |
|
844 #else |
|
845 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices); |
|
846 glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, cache->indices); |
|
847 #endif |
|
848 |
750 } else { |
849 } else { |
751 // Pass when high bit is set, replace stencil value with 0 |
850 // printf(" - Marking path as cachable...\n"); |
752 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); |
851 // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable |
753 } |
852 if (do_vectorpath_cache) |
754 prepareForDraw(currentBrush.isOpaque()); |
853 path.makeCacheable(); |
755 |
854 |
756 // Stencil the brush onto the dest buffer |
855 // The path is too complicated & needs the stencil technique |
757 composite(vertexCoordinateArray.boundingRect()); |
856 vertexCoordinateArray.clear(); |
758 glStencilMask(0); |
857 vertexCoordinateArray.addPath(path, inverseScale, false); |
759 updateClipScissorTest(); |
858 |
|
859 fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); |
|
860 |
|
861 glStencilMask(0xff); |
|
862 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); |
|
863 |
|
864 if (q->state()->clipTestEnabled) { |
|
865 // Pass when high bit is set, replace stencil value with current clip |
|
866 glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT); |
|
867 } else if (path.hasWindingFill()) { |
|
868 // Pass when any bit is set, replace stencil value with 0 |
|
869 glStencilFunc(GL_NOTEQUAL, 0, 0xff); |
|
870 } else { |
|
871 // Pass when high bit is set, replace stencil value with 0 |
|
872 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); |
|
873 } |
|
874 prepareForDraw(currentBrush.isOpaque()); |
|
875 |
|
876 // Stencil the brush onto the dest buffer |
|
877 composite(vertexCoordinateArray.boundingRect()); |
|
878 glStencilMask(0); |
|
879 updateClipScissorTest(); |
|
880 } |
760 } |
881 } |
761 } |
882 } |
762 |
883 |
763 |
884 |
764 void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, |
885 void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, |
1046 // updateMatrix() is responsible for setting the inverse scale on |
1174 // updateMatrix() is responsible for setting the inverse scale on |
1047 // the strokers, so we need to call it here and not wait for |
1175 // the strokers, so we need to call it here and not wait for |
1048 // prepareForDraw() down below. |
1176 // prepareForDraw() down below. |
1049 updateMatrix(); |
1177 updateMatrix(); |
1050 |
1178 |
|
1179 QRectF clip = q->state()->matrix.inverted().mapRect(q->state()->clipEnabled |
|
1180 ? q->state()->rectangleClip |
|
1181 : QRectF(0, 0, width, height)); |
|
1182 |
1051 if (penStyle == Qt::SolidLine) { |
1183 if (penStyle == Qt::SolidLine) { |
1052 stroker.process(path, pen); |
1184 stroker.process(path, pen, clip); |
1053 |
1185 |
1054 } else { // Some sort of dash |
1186 } else { // Some sort of dash |
1055 dasher.process(path, pen); |
1187 dasher.process(path, pen, clip); |
1056 |
1188 |
1057 QVectorPath dashStroke(dasher.points(), |
1189 QVectorPath dashStroke(dasher.points(), |
1058 dasher.elementCount(), |
1190 dasher.elementCount(), |
1059 dasher.elementTypes()); |
1191 dasher.elementTypes()); |
1060 stroker.process(dashStroke, pen); |
1192 stroker.process(dashStroke, pen, clip); |
1061 } |
1193 } |
1062 |
1194 |
1063 if (opaque) { |
1195 if (opaque) { |
1064 prepareForDraw(opaque); |
1196 prepareForDraw(opaque); |
1065 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices()); |
1197 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices()); |
1190 d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, |
1322 d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, |
1191 state()->renderHints & QPainter::SmoothPixmapTransform, id); |
1323 state()->renderHints & QPainter::SmoothPixmapTransform, id); |
1192 d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); |
1324 d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); |
1193 } |
1325 } |
1194 |
1326 |
1195 void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) |
1327 void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) |
1196 { |
1328 { |
1197 Q_D(QGL2PaintEngineEx); |
1329 Q_D(QGL2PaintEngineEx); |
|
1330 |
|
1331 ensureActive(); |
|
1332 |
|
1333 QFontEngineGlyphCache::Type glyphType = textItem->fontEngine->glyphFormat >= 0 |
|
1334 ? QFontEngineGlyphCache::Type(textItem->fontEngine->glyphFormat) |
|
1335 : d->glyphCacheType; |
|
1336 |
|
1337 d->drawCachedGlyphs(glyphType, textItem, true); |
|
1338 } |
|
1339 |
|
1340 bool QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) |
|
1341 { |
|
1342 Q_D(QGL2PaintEngineEx); |
|
1343 if (!d->shaderManager) |
|
1344 return false; |
|
1345 |
1198 ensureActive(); |
1346 ensureActive(); |
1199 d->transferMode(ImageDrawingMode); |
1347 d->transferMode(ImageDrawingMode); |
1200 |
1348 |
1201 #ifndef QT_OPENGL_ES_2 |
1349 #ifndef QT_OPENGL_ES_2 |
1202 QGLContext *ctx = d->ctx; |
1350 QGLContext *ctx = d->ctx; |
1243 glyphType = QFontEngineGlyphCache::Raster_A8; |
1392 glyphType = QFontEngineGlyphCache::Raster_A8; |
1244 } |
1393 } |
1245 } |
1394 } |
1246 |
1395 |
1247 if (drawCached) { |
1396 if (drawCached) { |
1248 d->drawCachedGlyphs(p, glyphType, ti); |
1397 QVarLengthArray<QFixedPoint> positions; |
|
1398 QVarLengthArray<glyph_t> glyphs; |
|
1399 QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); |
|
1400 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); |
|
1401 |
|
1402 { |
|
1403 QStaticTextItem staticTextItem; |
|
1404 staticTextItem.chars = ti.chars; |
|
1405 staticTextItem.fontEngine = ti.fontEngine; |
|
1406 staticTextItem.glyphs = glyphs.data(); |
|
1407 staticTextItem.numChars = ti.num_chars; |
|
1408 staticTextItem.numGlyphs = glyphs.size(); |
|
1409 staticTextItem.glyphPositions = positions.data(); |
|
1410 |
|
1411 d->drawCachedGlyphs(glyphType, &staticTextItem, false); |
|
1412 } |
1249 return; |
1413 return; |
1250 } |
1414 } |
1251 |
1415 |
1252 QPaintEngineEx::drawTextItem(p, ti); |
1416 QPaintEngineEx::drawTextItem(p, ti); |
1253 } |
1417 } |
1254 |
1418 |
1255 void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, |
1419 namespace { |
1256 const QTextItemInt &ti) |
1420 |
|
1421 class QOpenGLStaticTextUserData: public QStaticTextUserData |
|
1422 { |
|
1423 public: |
|
1424 QOpenGLStaticTextUserData() |
|
1425 : QStaticTextUserData(OpenGLUserData) |
|
1426 { |
|
1427 } |
|
1428 |
|
1429 ~QOpenGLStaticTextUserData() |
|
1430 { |
|
1431 } |
|
1432 |
|
1433 QGL2PEXVertexArray vertexCoordinateArray; |
|
1434 QGL2PEXVertexArray textureCoordinateArray; |
|
1435 }; |
|
1436 |
|
1437 } |
|
1438 |
|
1439 // #define QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO |
|
1440 |
|
1441 void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, |
|
1442 QStaticTextItem *staticTextItem, |
|
1443 bool includeMatrixInCache) |
1257 { |
1444 { |
1258 Q_Q(QGL2PaintEngineEx); |
1445 Q_Q(QGL2PaintEngineEx); |
1259 |
1446 |
1260 QVarLengthArray<QFixedPoint> positions; |
1447 QOpenGL2PaintEngineState *s = q->state(); |
1261 QVarLengthArray<glyph_t> glyphs; |
|
1262 QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); |
|
1263 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); |
|
1264 |
1448 |
1265 QGLTextureGlyphCache *cache = |
1449 QGLTextureGlyphCache *cache = |
1266 (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform()); |
1450 (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, |
1267 |
1451 includeMatrixInCache |
|
1452 ? s->matrix |
|
1453 : QTransform()); |
1268 if (!cache || cache->cacheType() != glyphType) { |
1454 if (!cache || cache->cacheType() != glyphType) { |
1269 cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); |
1455 cache = new QGLTextureGlyphCache(ctx, glyphType, |
1270 ti.fontEngine->setGlyphCache(ctx, cache); |
1456 includeMatrixInCache ? s->matrix : QTransform()); |
|
1457 staticTextItem->fontEngine->setGlyphCache(ctx, cache); |
1271 } |
1458 } |
1272 |
1459 |
1273 cache->setPaintEnginePrivate(this); |
1460 cache->setPaintEnginePrivate(this); |
1274 cache->populate(ti, glyphs, positions); |
1461 cache->populate(staticTextItem->fontEngine, staticTextItem->numGlyphs, staticTextItem->glyphs, |
|
1462 staticTextItem->glyphPositions); |
1275 |
1463 |
1276 if (cache->width() == 0 || cache->height() == 0) |
1464 if (cache->width() == 0 || cache->height() == 0) |
1277 return; |
1465 return; |
1278 |
1466 |
1279 transferMode(TextDrawingMode); |
1467 transferMode(TextDrawingMode); |
1281 int margin = cache->glyphMargin(); |
1469 int margin = cache->glyphMargin(); |
1282 |
1470 |
1283 GLfloat dx = 1.0 / cache->width(); |
1471 GLfloat dx = 1.0 / cache->width(); |
1284 GLfloat dy = 1.0 / cache->height(); |
1472 GLfloat dy = 1.0 / cache->height(); |
1285 |
1473 |
1286 vertexCoordinateArray.clear(); |
1474 bool recreateVertexArrays = false; |
1287 textureCoordinateArray.clear(); |
1475 if (staticTextItem->userDataNeedsUpdate) |
1288 |
1476 recreateVertexArrays = true; |
1289 for (int i=0; i<glyphs.size(); ++i) { |
1477 else if (staticTextItem->userData == 0) |
1290 const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]); |
1478 recreateVertexArrays = true; |
1291 int x = positions[i].x.toInt() + c.baseLineX - margin; |
1479 else if (staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData) |
1292 int y = positions[i].y.toInt() - c.baseLineY - margin; |
1480 recreateVertexArrays = true; |
1293 |
1481 |
1294 vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); |
1482 // Use global arrays by default |
1295 textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); |
1483 QGL2PEXVertexArray *vertexCoordinates = &vertexCoordinateArray; |
1296 } |
1484 QGL2PEXVertexArray *textureCoordinates = &textureCoordinateArray; |
1297 |
1485 |
1298 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); |
1486 if (staticTextItem->useBackendOptimizations) { |
1299 setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); |
1487 QOpenGLStaticTextUserData *userData = 0; |
|
1488 |
|
1489 if (staticTextItem->userData == 0 |
|
1490 || staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData) { |
|
1491 |
|
1492 userData = new QOpenGLStaticTextUserData(); |
|
1493 staticTextItem->setUserData(userData); |
|
1494 |
|
1495 } else { |
|
1496 userData = static_cast<QOpenGLStaticTextUserData*>(staticTextItem->userData); |
|
1497 } |
|
1498 |
|
1499 // Use cache if backend optimizations is turned on |
|
1500 vertexCoordinates = &userData->vertexCoordinateArray; |
|
1501 textureCoordinates = &userData->textureCoordinateArray; |
|
1502 } |
|
1503 |
|
1504 |
|
1505 if (recreateVertexArrays) { |
|
1506 vertexCoordinates->clear(); |
|
1507 textureCoordinates->clear(); |
|
1508 |
|
1509 for (int i=0; i<staticTextItem->numGlyphs; ++i) { |
|
1510 const QTextureGlyphCache::Coord &c = cache->coords.value(staticTextItem->glyphs[i]); |
|
1511 int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin; |
|
1512 int y = staticTextItem->glyphPositions[i].y.toInt() - c.baseLineY - margin; |
|
1513 |
|
1514 vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h)); |
|
1515 textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); |
|
1516 } |
|
1517 |
|
1518 staticTextItem->userDataNeedsUpdate = false; |
|
1519 } |
|
1520 |
|
1521 if (elementIndices.size() < staticTextItem->numGlyphs*6) { |
|
1522 Q_ASSERT(elementIndices.size() % 6 == 0); |
|
1523 int j = elementIndices.size() / 6 * 4; |
|
1524 while (j < staticTextItem->numGlyphs*4) { |
|
1525 elementIndices.append(j + 0); |
|
1526 elementIndices.append(j + 0); |
|
1527 elementIndices.append(j + 1); |
|
1528 elementIndices.append(j + 2); |
|
1529 elementIndices.append(j + 3); |
|
1530 elementIndices.append(j + 3); |
|
1531 |
|
1532 j += 4; |
|
1533 } |
|
1534 |
|
1535 #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) |
|
1536 if (elementIndicesVBOId == 0) |
|
1537 glGenBuffers(1, &elementIndicesVBOId); |
|
1538 |
|
1539 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId); |
|
1540 glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementIndices.size() * sizeof(GLushort), |
|
1541 elementIndices.constData(), GL_STATIC_DRAW); |
|
1542 #endif |
|
1543 } else { |
|
1544 #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) |
|
1545 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId); |
|
1546 #endif |
|
1547 } |
|
1548 |
|
1549 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data()); |
|
1550 setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data()); |
1300 |
1551 |
1301 if (addOffset) { |
1552 if (addOffset) { |
1302 addOffset = false; |
1553 addOffset = false; |
1303 matrixDirty = true; |
1554 matrixDirty = true; |
1304 } |
1555 } |
1387 prepareForDraw(false); // Text always causes src pixels to be transparent |
1649 prepareForDraw(false); // Text always causes src pixels to be transparent |
1388 } |
1650 } |
1389 //### TODO: Gamma correction |
1651 //### TODO: Gamma correction |
1390 |
1652 |
1391 glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); |
1653 glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); |
1392 glBindTexture(GL_TEXTURE_2D, cache->texture()); |
1654 if (lastMaskTextureUsed != cache->texture()) { |
1393 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); |
1655 glBindTexture(GL_TEXTURE_2D, cache->texture()); |
1394 |
1656 lastMaskTextureUsed = cache->texture(); |
|
1657 } |
|
1658 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, s->matrix.type() > QTransform::TxTranslate); |
1395 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); |
1659 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); |
1396 glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); |
1660 |
1397 } |
1661 #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) |
1398 |
1662 glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, 0); |
1399 void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) |
1663 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
|
1664 #else |
|
1665 glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); |
|
1666 #endif |
|
1667 |
|
1668 if (includeMatrixInCache) |
|
1669 s->matrix = old; |
|
1670 } |
|
1671 |
|
1672 void QGL2PaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, |
|
1673 QPainter::PixmapFragmentHints hints) |
1400 { |
1674 { |
1401 Q_D(QGL2PaintEngineEx); |
1675 Q_D(QGL2PaintEngineEx); |
1402 // Use fallback for extended composition modes. |
1676 // Use fallback for extended composition modes. |
1403 if (state()->composition_mode > QPainter::CompositionMode_Plus) { |
1677 if (state()->composition_mode > QPainter::CompositionMode_Plus) { |
1404 QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints); |
1678 QPaintEngineEx::drawPixmapFragments(fragments, fragmentCount, pixmap, hints); |
1405 return; |
1679 return; |
1406 } |
1680 } |
1407 |
1681 |
1408 ensureActive(); |
1682 ensureActive(); |
1409 d->drawPixmaps(drawingData, dataCount, pixmap, hints); |
1683 d->drawPixmapFragments(fragments, fragmentCount, pixmap, hints); |
1410 } |
1684 } |
1411 |
1685 |
1412 |
1686 |
1413 void QGL2PaintEngineExPrivate::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) |
1687 void QGL2PaintEngineExPrivate::drawPixmapFragments(const QPainter::PixmapFragment *fragments, |
|
1688 int fragmentCount, const QPixmap &pixmap, |
|
1689 QPainter::PixmapFragmentHints hints) |
1414 { |
1690 { |
1415 GLfloat dx = 1.0f / pixmap.size().width(); |
1691 GLfloat dx = 1.0f / pixmap.size().width(); |
1416 GLfloat dy = 1.0f / pixmap.size().height(); |
1692 GLfloat dy = 1.0f / pixmap.size().height(); |
1417 |
1693 |
1418 vertexCoordinateArray.clear(); |
1694 vertexCoordinateArray.clear(); |
1429 matrixDirty = true; |
1705 matrixDirty = true; |
1430 } |
1706 } |
1431 |
1707 |
1432 bool allOpaque = true; |
1708 bool allOpaque = true; |
1433 |
1709 |
1434 for (int i = 0; i < dataCount; ++i) { |
1710 for (int i = 0; i < fragmentCount; ++i) { |
1435 qreal s = 0; |
1711 qreal s = 0; |
1436 qreal c = 1; |
1712 qreal c = 1; |
1437 if (drawingData[i].rotation != 0) { |
1713 if (fragments[i].rotation != 0) { |
1438 s = qFastSin(drawingData[i].rotation * Q_PI / 180); |
1714 s = qFastSin(fragments[i].rotation * Q_PI / 180); |
1439 c = qFastCos(drawingData[i].rotation * Q_PI / 180); |
1715 c = qFastCos(fragments[i].rotation * Q_PI / 180); |
1440 } |
1716 } |
1441 |
1717 |
1442 qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width(); |
1718 qreal right = 0.5 * fragments[i].scaleX * fragments[i].width; |
1443 qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height(); |
1719 qreal bottom = 0.5 * fragments[i].scaleY * fragments[i].height; |
1444 QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c); |
1720 QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c); |
1445 QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c); |
1721 QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c); |
1446 |
1722 |
1447 vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); |
1723 vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y); |
1448 vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y()); |
1724 vertexCoordinateArray.addVertex(-bottomLeft.x + fragments[i].x, -bottomLeft.y + fragments[i].y); |
1449 vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); |
1725 vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y); |
1450 vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); |
1726 vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y); |
1451 vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y()); |
1727 vertexCoordinateArray.addVertex(bottomLeft.x + fragments[i].x, bottomLeft.y + fragments[i].y); |
1452 vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); |
1728 vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y); |
1453 |
1729 |
1454 QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy, |
1730 QGLRect src(fragments[i].sourceLeft * dx, fragments[i].sourceTop * dy, |
1455 drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy); |
1731 (fragments[i].sourceLeft + fragments[i].width) * dx, |
1456 |
1732 (fragments[i].sourceTop + fragments[i].height) * dy); |
1457 textureCoordinateArray.lineToArray(src.right, src.bottom); |
1733 |
1458 textureCoordinateArray.lineToArray(src.right, src.top); |
1734 textureCoordinateArray.addVertex(src.right, src.bottom); |
1459 textureCoordinateArray.lineToArray(src.left, src.top); |
1735 textureCoordinateArray.addVertex(src.right, src.top); |
1460 textureCoordinateArray.lineToArray(src.left, src.top); |
1736 textureCoordinateArray.addVertex(src.left, src.top); |
1461 textureCoordinateArray.lineToArray(src.left, src.bottom); |
1737 textureCoordinateArray.addVertex(src.left, src.top); |
1462 textureCoordinateArray.lineToArray(src.right, src.bottom); |
1738 textureCoordinateArray.addVertex(src.left, src.bottom); |
1463 |
1739 textureCoordinateArray.addVertex(src.right, src.bottom); |
1464 qreal opacity = drawingData[i].opacity * q->state()->opacity; |
1740 |
|
1741 qreal opacity = fragments[i].opacity * q->state()->opacity; |
1465 opacityArray << opacity << opacity << opacity << opacity << opacity << opacity; |
1742 opacityArray << opacity << opacity << opacity << opacity << opacity << opacity; |
1466 allOpaque &= (opacity >= 0.99f); |
1743 allOpaque &= (opacity >= 0.99f); |
1467 } |
1744 } |
1468 |
1745 |
1469 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); |
1746 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); |
1472 | QGLContext::CanFlipNativePixmapBindOption); |
1749 | QGLContext::CanFlipNativePixmapBindOption); |
1473 |
1750 |
1474 if (texture->options & QGLContext::InvertedYBindOption) { |
1751 if (texture->options & QGLContext::InvertedYBindOption) { |
1475 // Flip texture y-coordinate. |
1752 // Flip texture y-coordinate. |
1476 QGLPoint *data = textureCoordinateArray.data(); |
1753 QGLPoint *data = textureCoordinateArray.data(); |
1477 for (int i = 0; i < 6 * dataCount; ++i) |
1754 for (int i = 0; i < 6 * fragmentCount; ++i) |
1478 data[i].y = 1 - data[i].y; |
1755 data[i].y = 1 - data[i].y; |
1479 } |
1756 } |
1480 |
1757 |
1481 transferMode(ImageArrayDrawingMode); |
1758 transferMode(ImageArrayDrawingMode); |
1482 |
1759 |
1483 bool isBitmap = pixmap.isQBitmap(); |
1760 bool isBitmap = pixmap.isQBitmap(); |
1484 bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque; |
1761 bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QPainter::OpaqueHint)) && allOpaque; |
1485 |
1762 |
1486 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, |
1763 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, |
1487 q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); |
1764 q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); |
1488 |
1765 |
1489 // Setup for texture drawing |
1766 // Setup for texture drawing |
1490 currentBrush = noBrush; |
1767 currentBrush = noBrush; |
1491 shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc); |
1768 shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc |
|
1769 : QGLEngineShaderManager::ImageSrc); |
1492 if (prepareForDraw(isOpaque)) |
1770 if (prepareForDraw(isOpaque)) |
1493 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); |
1771 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); |
1494 |
1772 |
1495 if (isBitmap) { |
1773 if (isBitmap) { |
1496 QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); |
1774 QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); |
1497 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); |
1775 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); |
1498 } |
1776 } |
1499 |
1777 |
1500 glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount); |
1778 glDrawArrays(GL_TRIANGLES, 0, 6 * fragmentCount); |
1501 } |
1779 } |
1502 |
1780 |
1503 bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) |
1781 bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) |
1504 { |
1782 { |
1505 Q_D(QGL2PaintEngineEx); |
1783 Q_D(QGL2PaintEngineEx); |