Changeset 561 for trunk/src/opengl/gl2paintengineex
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 5 deleted
- 7 edited
- 7 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information ([email protected]) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation ([email protected]) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you 37 ** @nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 44 44 #include <private/qbezier_p.h> 45 45 46 47 46 48 void QGL2PEXVertexArray::clear() 47 49 { 48 50 vertexArray.reset(); 49 vertexArrayStops. clear();51 vertexArrayStops.(); 50 52 boundingRectDirty = true; 51 53 } … … 60 62 } 61 63 62 void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale) 64 void QGL2PEXVertexArray::addRect(const QRectF &rect) 65 { 66 vertexArray << rect.topLeft() << rect.topRight() << rect.bottomRight() 67 << rect.bottomRight() << rect.bottomLeft() << rect.topLeft(); 68 } 69 70 void QGL2PEXVertexArray::addClosingLine(int index) 71 { 72 if (QPointF(vertexArray.at(index)) != QPointF(vertexArray.last())) 73 vertexArray.add(vertexArray.at(index)); 74 } 75 76 void QGL2PEXVertexArray::addCentroid(const QVectorPath &path, int subPathIndex) 77 { 78 const QPointF *const points = reinterpret_cast<const QPointF *>(path.points()); 79 const QPainterPath::ElementType *const elements = path.elements(); 80 81 QPointF sum = points[subPathIndex]; 82 int count = 1; 83 84 for (int i = subPathIndex + 1; i < path.elementCount() && (!elements || elements[i] != QPainterPath::MoveToElement); ++i) { 85 sum += points[i]; 86 ++count; 87 } 88 89 const QPointF centroid = sum / qreal(count); 90 vertexArray.add(centroid); 91 } 92 93 void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline) 63 94 { 64 95 const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); … … 71 102 } 72 103 104 105 106 107 73 108 vertexArray.add(points[0]); // The first element is always a moveTo 74 109 … … 86 121 87 122 for (int i=1; i<path.elementCount(); ++i) { 88 const QPainterPath::ElementType elementType = elements[i]; 89 switch (elementType) { 123 switch (elements[i]) { 90 124 case QPainterPath::MoveToElement: 125 126 91 127 // qDebug("element[%d] is a MoveToElement", i); 92 vertexArrayStops.append(vertexArray.size()); 93 vertexArray.add(points[i]); // Add the moveTo as a new vertex 128 vertexArrayStops.add(vertexArray.size()); 129 if (!outline) { 130 if (!path.isConvex()) addCentroid(path, i); 131 lastMoveTo = vertexArray.size(); 132 } 133 lineToArray(points[i].x(), points[i].y()); // Add the moveTo as a new vertex 94 134 break; 95 135 case QPainterPath::LineToElement: … … 97 137 lineToArray(points[i].x(), points[i].y()); 98 138 break; 99 case QPainterPath::CurveToElement: 100 // qDebug("element[%d] is a CurveToElement", i); 101 curveToArray(points[i], points[i+1], points[i+2], curveInverseScale); 102 i+=2; 103 break; 139 case QPainterPath::CurveToElement: { 140 QBezier b = QBezier::fromPoints(*(((const QPointF *) points) + i - 1), 141 points[i], 142 points[i+1], 143 points[i+2]); 144 QRectF bounds = b.bounds(); 145 // threshold based on same algorithm as in qtriangulatingstroker.cpp 146 int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * 3.14f / (curveInverseScale * 6)); 147 if (threshold < 3) threshold = 3; 148 qreal one_over_threshold_minus_1 = 1.f / (threshold - 1); 149 for (int t=0; t<threshold; ++t) { 150 QPointF pt = b.pointAt(t * one_over_threshold_minus_1); 151 lineToArray(pt.x(), pt.y()); 152 } 153 i += 2; 154 break; } 104 155 default: 105 156 break; … … 108 159 } while (0); 109 160 110 vertexArrayStops.append(vertexArray.size()); 161 if (!outline) 162 addClosingLine(lastMoveTo); 163 vertexArrayStops.add(vertexArray.size()); 111 164 } 112 165 … … 125 178 } 126 179 127 void QGL2PEXVertexArray::curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale) 128 { 129 qreal inverseScaleHalf = inverseScale / 2; 130 131 QBezier beziers[32]; 132 beziers[0] = QBezier::fromPoints(vertexArray.last(), cp1, cp2, ep); 133 QBezier *b = beziers; 134 while (b >= beziers) { 135 // check if we can pop the top bezier curve from the stack 136 qreal l = qAbs(b->x4 - b->x1) + qAbs(b->y4 - b->y1); 137 qreal d; 138 if (l > inverseScale) { 139 d = qAbs( (b->x4 - b->x1)*(b->y1 - b->y2) - (b->y4 - b->y1)*(b->x1 - b->x2) ) 140 + qAbs( (b->x4 - b->x1)*(b->y1 - b->y3) - (b->y4 - b->y1)*(b->x1 - b->x3) ); 141 d /= l; 142 } else { 143 d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) + 144 qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3); 145 } 146 if (d < inverseScaleHalf || b == beziers + 31) { 147 // good enough, we pop it off and add the endpoint 148 lineToArray(b->x4, b->y4); 149 --b; 150 } else { 151 // split, second half of the polygon goes lower into the stack 152 b->split(b+1, b); 153 ++b; 154 } 155 } 156 } 180 QT_END_NAMESPACE -
trunk/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information ([email protected]) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation ([email protected]) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you 37 ** @nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 51 51 // 52 52 53 54 55 53 56 #include <QRectF> 54 57 … … 56 59 #include <private/qvectorpath_p.h> 57 60 #include <private/qgl_p.h> 61 62 58 63 59 64 class QGLPoint … … 63 68 x(new_x), y(new_y) {}; 64 69 65 QGLPoint( QPointFp) :70 QGLPoint(p) : 66 71 x(p.x()), y(p.y()) {}; 67 72 … … 78 83 struct QGLRect 79 84 { 80 QGLRect( QRectFr)85 QGLRect(r) 81 86 : left(r.left()), top(r.top()), right(r.right()), bottom(r.bottom()) {} 82 87 … … 99 104 boundingRectDirty(true) {} 100 105 101 void addPath(const QVectorPath &path, GLfloat curveInverseScale); 106 void addRect(const QRectF &rect); 107 void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true); 102 108 void clear(); 103 109 104 110 QGLPoint* data() {return vertexArray.data();} 105 QVector<int>& stops() {return vertexArrayStops;} 111 int *stops() const { return vertexArrayStops.data(); } 112 int stopCount() const { return vertexArrayStops.size(); } 106 113 QGLRect boundingRect() const; 114 115 107 116 108 117 void lineToArray(const GLfloat x, const GLfloat y); … … 110 119 private: 111 120 QDataBuffer<QGLPoint> vertexArray; 112 Q Vector<int>vertexArrayStops;121 Q vertexArrayStops; 113 122 114 123 GLfloat maxX; … … 117 126 GLfloat minY; 118 127 bool boundingRectDirty; 128 129 130 119 131 120 inline void curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale); 121 }; 132 QT_END_NAMESPACE 133 134 #endif -
trunk/src/opengl/gl2paintengineex/qglgradientcache.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information ([email protected]) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation ([email protected]) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you 37 ** @nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 45 45 #include "qglgradientcache_p.h" 46 46 47 void QGLGradientCache::cleanCache() { 47 QT_BEGIN_NAMESPACE 48 49 static void QGL2GradientCache_free(void *ptr) 50 { 51 delete reinterpret_cast<QGL2GradientCache *>(ptr); 52 } 53 54 Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_gradient_caches, (QGL2GradientCache_free)) 55 56 QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context) 57 { 58 QGL2GradientCache *p = reinterpret_cast<QGL2GradientCache *>(qt_gradient_caches()->value(context)); 59 if (!p) { 60 QGLShareContextScope scope(context); 61 p = new QGL2GradientCache; 62 qt_gradient_caches()->insert(context, p); 63 } 64 return p; 65 } 66 67 void QGL2GradientCache::cleanCache() { 48 68 QGLGradientColorTableHash::const_iterator it = cache.constBegin(); 49 69 for (; it != cache.constEnd(); ++it) { … … 54 74 } 55 75 56 GLuint QGL GradientCache::getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx)76 GLuint QGL) 57 77 { 58 if (buffer_ctx && !qgl_share_reg()->checkSharing(buffer_ctx, ctx))59 cleanCache();60 61 buffer_ctx = ctx;62 63 78 quint64 hash_val = 0; 64 79 … … 85 100 86 101 87 GLuint QGL GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity)102 GLuint QGLGradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity) 88 103 { 89 104 if (cache.size() == maxCacheSize()) { … … 110 125 111 126 112 // GL's expects pixels in RGBA , bin-endian (ABGR on x86).113 // Qt stores in ARGB using whateverbyte-order the mancine uses.127 // GL's expects pixels in RGBA, bin-endian (ABGR on x86). 128 // Qt byte-order the mancine uses. 114 129 static inline uint qtToGlColor(uint c) 115 130 { 116 131 uint o; 117 132 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN 118 o = c & 0xFF00FF00; // alpha & green already in the right place 119 o |= (c >> 16) & 0x000000FF; // red 120 o |= (c << 16) & 0x00FF0000; // blue 121 133 o = (c & 0xff00ff00) // alpha & green already in the right place 134 | ((c >> 16) & 0x000000ff) // red 135 | ((c << 16) & 0x00ff0000); // blue 122 136 #else //Q_BIG_ENDIAN 123 o = c & 0x00FF00FF; // alpha & green already in the right place 124 o |= (c << 16) & 0xFF000000; // red 125 o |= (c >> 16) & 0x0000FF00; // blue 126 #error big endian not tested with QGLGraphicsContext 137 o = (c << 8) 138 | ((c >> 24) & 0x000000ff); 127 139 #endif // Q_BYTE_ORDER 128 140 return o; … … 130 142 131 143 //TODO: Let GL generate the texture using an FBO 132 void QGL GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const144 void QGLGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const 133 145 { 134 146 int pos = 0; … … 137 149 138 150 for (int i = 0; i < s.size(); ++i) 139 colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB 151 colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB 140 152 141 153 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); … … 184 196 colorTable[size-1] = last_color; 185 197 } 198 199 -
trunk/src/opengl/gl2paintengineex/qglgradientcache_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information ([email protected]) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation ([email protected]) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you 37 ** @nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 53 53 #include <QMultiHash> 54 54 #include <QObject> 55 #include <QtOpenGL> 55 #include <QtOpenGL/QtOpenGL> 56 #include <private/qgl_p.h> 56 57 57 class QGLGradientCache : public QObject 58 QT_BEGIN_NAMESPACE 59 60 class QGL2GradientCache 58 61 { 59 Q_OBJECT60 62 struct CacheInfo 61 63 { … … 72 74 73 75 public: 74 QGLGradientCache() : QObject(), buffer_ctx(0) 75 { 76 /* 77 connect(QGLSignalProxy::instance(), 78 SIGNAL(aboutToDestroyContext(const QGLContext *)), 79 SLOT(cleanupGLContextRefs(const QGLContext *))); 80 */ 81 } 76 static QGL2GradientCache *cacheForContext(const QGLContext *context); 82 77 83 GLuint getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx); 78 QGL2GradientCache() { } 79 ~QGL2GradientCache() {cleanCache();} 80 81 GLuint getBuffer(const QGradient &gradient, qreal opacity); 84 82 inline int paletteSize() const { return 1024; } 85 83 … … 94 92 95 93 QGLGradientColorTableHash cache; 96 const QGLContext *buffer_ctx;97 98 public slots:99 void cleanupGLContextRefs(const QGLContext *context) {100 if (context == buffer_ctx) {101 cleanCache();102 buffer_ctx = 0;103 }104 }105 94 }; 106 95 96 107 97 108 -
trunk/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information ([email protected]) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation ([email protected]) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you 37 ** @nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 63 63 */ 64 64 65 65 66 66 67 #include "qpaintengineex_opengl2_p.h" … … 76 77 #include <private/qfontengine_p.h> 77 78 #include <private/qtextureglyphcache_p.h> 79 80 78 81 79 82 #include "qglgradientcache_p.h" 80 #include "qgl pexshadermanager_p.h"83 #include "qglshadermanager_p.h" 81 84 #include "qgl2pexvertexarray_p.h" 82 85 83 84 extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp 85 86 #include "qtriangulatingstroker_p.h" 86 87 87 88 #include <QDebug> 88 89 89 90 static const GLuint QT_VERTEX_COORDS_ATTR = 0; 91 static const GLuint QT_TEXTURE_COORDS_ATTR = 1; 92 static const GLuint QT_BRUSH_TEXTURE_UNIT = 0; 93 94 class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate 95 { 96 Q_DECLARE_PUBLIC(QGL2PaintEngineEx) 90 QT_BEGIN_NAMESPACE 91 92 //#define QT_GL_NO_SCISSOR_TEST 93 94 static const GLuint GL_STENCIL_HIGH_BIT = 0x80; 95 static const GLuint QT_BRUSH_TEXTURE_UNIT = 0; 96 static const GLuint QT_IMAGE_TEXTURE_UNIT = 0; //Can be the same as brush texture unit 97 static const GLuint QT_MASK_TEXTURE_UNIT = 1; 98 static const GLuint QT_BACKGROUND_TEXTURE_UNIT = 2; 99 100 #ifdef Q_WS_WIN 101 extern Q_GUI_EXPORT bool qt_cleartype_enabled; 102 #endif 103 104 class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache 105 { 106 Q_OBJECT 97 107 public: 98 QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) : 99 q(q_ptr), 100 width(0), height(0), 101 ctx(0), 102 currentBrush( &(q->state()->brush) ), 103 inverseScale(1), 104 shaderManager(0) 105 { } 106 107 ~QGL2PaintEngineExPrivate(); 108 109 void updateBrushTexture(); 110 void updateBrushUniforms(); 111 void updateMatrix(); 112 void updateCompositionMode(); 113 void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform); 114 115 void setBrush(const QBrush* brush); 116 117 void drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight); 118 119 void fill(const QVectorPath &path); 120 void drawOutline(const QVectorPath& path); 121 122 void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive); 123 // ^ draws whatever is in the vertex array 124 void composite(const QGLRect& boundingRect); 125 // ^ Composites the bounding rect onto dest buffer 126 void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill); 127 // ^ Calls drawVertexArrays to render into stencil buffer 128 void cleanStencilBuffer(const QGLRect& area); 129 130 void prepareForDraw(); 131 132 inline void useSimpleShader(); 133 inline QColor premultiplyColor(QColor c, GLfloat opacity); 134 135 QGL2PaintEngineEx* q; 136 137 //### Move into QGLDrawable 138 int width, height; 139 QGLContext* ctx; 140 141 // Dirty flags 142 bool matrixDirty; // Implies matrix uniforms are also dirty 143 bool compositionModeDirty; 144 bool brushTextureDirty; 145 bool brushUniformsDirty; 146 bool simpleShaderMatrixUniformDirty; 147 bool brushShaderMatrixUniformDirty; 148 bool imageShaderMatrixUniformDirty; 149 bool textShaderMatrixUniformDirty; 150 bool stencilBuferDirty; 151 152 const QBrush* currentBrush; // May not be the state's brush! 153 154 GLfloat inverseScale; 155 156 QGL2PEXVertexArray pathVertexArray; 157 158 GLfloat pmvMatrix[4][4]; 159 160 QGLPEXShaderManager* shaderManager; 161 162 // Clipping & state stuff stolen from QOpenGLPaintEngine: 163 void updateDepthClip(); 164 uint use_system_clip : 1; 108 QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix); 109 ~QGLTextureGlyphCache(); 110 111 virtual void createTextureData(int width, int height); 112 virtual void resizeTextureData(int width, int height); 113 virtual void fillTexture(const Coord &c, glyph_t glyph); 114 virtual int glyphMargin() const; 115 116 inline GLuint texture() const { return m_texture; } 117 118 inline int width() const { return m_width; } 119 inline int height() const { return m_height; } 120 121 inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; } 122 123 124 public Q_SLOTS: 125 void contextDestroyed(const QGLContext *context) { 126 if (context == ctx) { 127 QList<const QGLContext *> shares = qgl_share_reg()->shares(ctx); 128 if (shares.isEmpty()) { 129 glDeleteFramebuffers(1, &m_fbo); 130 if (m_width || m_height) 131 glDeleteTextures(1, &m_texture); 132 ctx = 0; 133 } else { 134 // since the context holding the texture is shared, and 135 // about to be destroyed, we have to transfer ownership 136 // of the texture to one of the share contexts 137 ctx = const_cast<QGLContext *>((ctx == shares.at(0)) ? shares.at(1) : shares.at(0)); 138 } 139 } 140 } 141 142 private: 143 QGLContext *ctx; 144 145 QGL2PaintEngineExPrivate *pex; 146 147 GLuint m_texture; 148 GLuint m_fbo; 149 150 int m_width; 151 int m_height; 152 153 QGLShaderProgram *m_program; 165 154 }; 166 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 167 333 168 334 ////////////////////////////////// Private Methods ////////////////////////////////////////// … … 170 336 QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate() 171 337 { 172 if (shaderManager) { 173 delete shaderManager; 174 shaderManager = 0; 175 } 176 } 177 178 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform) 179 { 180 glActiveTexture(QT_BRUSH_TEXTURE_UNIT); 338 delete shaderManager; 339 340 while (pathCaches.size()) { 341 QVectorPath::CacheEntry *e = *(pathCaches.constBegin()); 342 e->cleanup(e->engine, e->data); 343 e->data = 0; 344 e->engine = 0; 345 } 346 } 347 348 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id) 349 { 350 // glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit? 351 if (id != GLuint(-1) && id == lastTextureUsed) 352 return; 353 354 lastTextureUsed = id; 181 355 182 356 if (smoothPixmapTransform) { … … 192 366 193 367 194 QColor QGL2PaintEngineExPrivate::premultiplyColor(QColor c, GLfloat opacity) 195 { 196 uint alpha = qRound(c.alpha() * opacity); 197 return QColor ( ((c.red() * alpha + 128) >> 8), 198 ((c.green() * alpha + 128) >> 8), 199 ((c.blue() * alpha + 128) >> 8), 200 alpha); 201 } 202 203 204 void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush) 205 { 368 inline QColor qt_premultiplyColor(QColor c, GLfloat opacity) 369 { 370 qreal alpha = c.alphaF() * opacity; 371 c.setAlphaF(alpha); 372 c.setRedF(c.redF() * alpha); 373 c.setGreenF(c.greenF() * alpha); 374 c.setBlueF(c.blueF() * alpha); 375 return c; 376 } 377 378 379 void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush) 380 { 381 if (qbrush_fast_equals(currentBrush, brush)) 382 return; 383 384 const Qt::BrushStyle newStyle = qbrush_style(brush); 385 Q_ASSERT(newStyle != Qt::NoBrush); 386 206 387 currentBrush = brush; 207 brushTextureDirty = true; 208 brushUniformsDirty = true; 209 shaderManager->setBrushStyle(currentBrush->style()); 210 shaderManager->setAffineOnlyBrushTransform(currentBrush->transform().isAffine()); 211 } 212 213 214 // Unless this gets used elsewhere, it's probably best to merge it into fillStencilWithVertexArray 388 brushUniformsDirty = true; // All brushes have at least one uniform 389 390 if (newStyle > Qt::SolidPattern) 391 brushTextureDirty = true; 392 393 if (currentBrush.style() == Qt::TexturePattern 394 && qHasPixmapTexture(brush) && brush.texture().isQBitmap()) 395 { 396 shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern); 397 } else { 398 shaderManager->setSrcPixelType(newStyle); 399 } 400 shaderManager->optimiseForBrushTransform(currentBrush.transform().type()); 401 } 402 403 215 404 void QGL2PaintEngineExPrivate::useSimpleShader() 216 405 { 217 shaderManager->simpleShader()->use(); 406 shaderManager->simpleProgram()->bind(); 407 shaderManager->setDirty(); 218 408 219 409 if (matrixDirty) … … 221 411 222 412 if (simpleShaderMatrixUniformDirty) { 223 shaderManager->simpleShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix; 413 const GLuint location = shaderManager->simpleProgram()->uniformLocation("pmvMatrix"); 414 glUniformMatrix3fv(location, 1, GL_FALSE, (GLfloat*)pmvMatrix); 224 415 simpleShaderMatrixUniformDirty = false; 225 416 } 226 417 } 227 418 228 229 Q_GLOBAL_STATIC(QGLGradientCache, qt_opengl_gradient_cache)230 231 419 void QGL2PaintEngineExPrivate::updateBrushTexture() 232 420 { 421 233 422 // qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()"); 234 Qt::BrushStyle style = currentBrush ->style();423 Qt::BrushStyle style = currentBrushstyle(); 235 424 236 425 if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) { 237 426 // Get the image data for the pattern 238 QImage texImage = qt_imageForBrush(style, true);239 240 glActiveTexture( QT_BRUSH_TEXTURE_UNIT);241 ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true );242 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);427 QImage texImage = qt_imageForBrush(style, e); 428 429 glActiveTexture(QT_BRUSH_TEXTURE_UNIT); 430 ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true); 431 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, ); 243 432 } 244 433 else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { 245 434 // Gradiant brush: All the gradiants use the same texture 246 435 247 const QGradient* g = currentBrush ->gradient();436 const QGradient* g = currentBrushgradient(); 248 437 249 438 // We apply global opacity in the fragment shaders, so we always pass 1.0 250 439 // for opacity to the cache. 251 GLuint texId = qt_opengl_gradient_cache()->getBuffer(*g, 1.0, ctx); 440 GLuint texId = QGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0); 441 442 glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); 443 glBindTexture(GL_TEXTURE_2D, texId); 252 444 253 445 if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient) 254 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);446 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, ); 255 447 else if (g->spread() == QGradient::ReflectSpread) 256 updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, true);448 updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, ); 257 449 else 258 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, true); 259 260 glBindTexture(GL_TEXTURE_2D, texId); 450 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform); 261 451 } 262 452 else if (style == Qt::TexturePattern) { 263 const QPixmap& texPixmap = currentBrush->texture(); 264 265 glActiveTexture(QT_BRUSH_TEXTURE_UNIT); 266 ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, true); 267 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true); 453 const QPixmap& texPixmap = currentBrush.texture(); 454 455 glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); 456 QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); 457 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); 458 textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1; 268 459 } 269 460 brushTextureDirty = false; … … 274 465 { 275 466 // qDebug("QGL2PaintEngineExPrivate::updateBrushUniforms()"); 276 Qt::BrushStyle style = currentBrush ->style();467 Qt::BrushStyle style = currentBrushstyle(); 277 468 278 469 if (style == Qt::NoBrush) 279 470 return; 280 471 281 GLfloat opacity = 1.0; 282 if (q->state()->opacity < 0.99f) 283 opacity = (GLfloat)q->state()->opacity; 284 bool setOpacity = true; 285 286 QTransform brushQTransform = currentBrush->transform(); 472 QTransform brushQTransform = currentBrush.transform(); 287 473 288 474 if (style == Qt::SolidPattern) { 289 QColor col = premultiplyColor(currentBrush->color(), opacity); 290 shaderManager->brushShader()->uniforms()[QLatin1String("fragmentColor")] = col; 291 setOpacity = false; 475 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); 476 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::FragmentColor), col); 292 477 } 293 478 else { … … 296 481 297 482 if (style <= Qt::DiagCrossPattern) { 298 translationPoint = q->state()->brushOrigin; 299 300 QColor col = premultiplyColor(currentBrush->color(), opacity); 301 302 shaderManager->brushShader()->uniforms()[QLatin1String("patternColor")] = col; 303 setOpacity = false; //So code below doesn't try to set the opacity uniform 304 305 QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; 306 shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; 483 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); 484 485 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); 486 487 QVector2D halfViewportSize(width*0.5, height*0.5); 488 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); 307 489 } 308 490 else if (style == Qt::LinearGradientPattern) { 309 const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush ->gradient());491 const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrushgradient()); 310 492 311 493 QPointF realStart = g->start(); … … 315 497 QPointF l = realFinal - realStart; 316 498 317 // ### 318 QGLVec3 linearData = { 499 QVector3D linearData( 319 500 l.x(), 320 501 l.y(), 321 502 1.0f / (l.x() * l.x() + l.y() * l.y()) 322 };323 324 shaderManager-> brushShader()->uniforms()[QLatin1String("linearData")] = linearData;325 326 Q GLVec2 halfViewportSize = { width*0.5, height*0.5 };327 shaderManager-> brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;503 ; 504 505 shaderManager->; 506 507 Q; 508 shaderManager->; 328 509 } 329 510 else if (style == Qt::ConicalGradientPattern) { 330 const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush ->gradient());511 const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrushgradient()); 331 512 translationPoint = g->center(); 332 513 333 514 GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0; 334 515 335 shaderManager-> brushShader()->uniforms()[QLatin1String("angle")] = angle;336 337 Q GLVec2 halfViewportSize = { width*0.5, height*0.5 };338 shaderManager-> brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;516 shaderManager->; 517 518 Q; 519 shaderManager->; 339 520 } 340 521 else if (style == Qt::RadialGradientPattern) { 341 const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush ->gradient());522 const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrushgradient()); 342 523 QPointF realCenter = g->center(); 343 524 QPointF realFocal = g->focalPoint(); … … 346 527 347 528 QPointF fmp = realCenter - realFocal; 348 shaderManager-> brushShader()->uniforms()[QLatin1String("fmp")] = fmp;529 shaderManager->; 349 530 350 531 GLfloat fmp2_m_radius2 = -fmp.x() * fmp.x() - fmp.y() * fmp.y() + realRadius*realRadius; 351 shaderManager->brushShader()->uniforms()[QLatin1String("fmp2_m_radius2")] = fmp2_m_radius2; 352 353 shaderManager->brushShader()->uniforms()[QLatin1String("inverse_2_fmp2_m_radius2")] = 354 GLfloat(1.0 / (2.0*fmp2_m_radius2)); 355 356 QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; 357 shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; 532 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Fmp2MRadius2), fmp2_m_radius2); 533 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Inverse2Fmp2MRadius2), 534 GLfloat(1.0 / (2.0*fmp2_m_radius2))); 535 536 QVector2D halfViewportSize(width*0.5, height*0.5); 537 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); 358 538 } 359 539 else if (style == Qt::TexturePattern) { 360 translationPoint = q->state()->brushOrigin; 361 362 const QPixmap& texPixmap = currentBrush->texture(); 363 364 QSizeF invertedTextureSize( 1.0 / texPixmap.width(), 1.0 / texPixmap.height() ); 365 shaderManager->brushShader()->uniforms()[QLatin1String("invertedTextureSize")] = invertedTextureSize; 366 367 QGLVec2 halfViewportSize = { width*0.5, height*0.5 }; 368 shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize; 540 const QPixmap& texPixmap = currentBrush.texture(); 541 542 if (qHasPixmapTexture(currentBrush) && currentBrush.texture().isQBitmap()) { 543 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); 544 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); 545 } 546 547 QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 / texPixmap.height()); 548 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::InvertedTextureSize), invertedTextureSize); 549 550 QVector2D halfViewportSize(width*0.5, height*0.5); 551 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); 369 552 } 370 553 else 371 554 qWarning("QGL2PaintEngineEx: Unimplemented fill style"); 372 555 556 557 558 559 373 560 QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y()); 374 561 QTransform gl_to_qt(1, 0, 0, -1, 0, height); 375 QTransform inv_matrix = gl_to_qt * (brushQTransform * q->state()->matrix).inverted() * translate; 376 377 shaderManager->brushShader()->uniforms()[QLatin1String("brushTransform")] = inv_matrix; 378 shaderManager->brushShader()->uniforms()[QLatin1String("brushTexture")] = QT_BRUSH_TEXTURE_UNIT; 379 380 if (setOpacity) 381 shaderManager->brushShader()->uniforms()[QLatin1String("opacity")] = opacity; 562 QTransform inv_matrix; 563 if (style == Qt::TexturePattern && textureInvertedY == -1) 564 inv_matrix = gl_to_qt * (QTransform(1, 0, 0, -1, 0, currentBrush.texture().height()) * brushQTransform * matrix).inverted() * translate; 565 else 566 inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate; 567 568 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTransform), inv_matrix); 569 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT); 382 570 } 383 571 brushUniformsDirty = false; … … 390 578 // qDebug("QGL2PaintEngineExPrivate::updateMatrix()"); 391 579 392 // We setup the Projection matrix to be the equivilant of glOrtho(0, w, h, 0, -1, 1):393 GLfloat P[4][4] = {394 {2.0/width, 0.0, 0.0, -1.0},395 {0.0, -2.0/height, 0.0, 1.0},396 {0.0, 0.0, -1.0, 0.0},397 {0.0, 0.0, 0.0, 1.0}398 };399 400 // Use the (3x3) transform for the Model~View matrix:401 580 const QTransform& transform = q->state()->matrix; 402 GLfloat MV[4][4] = { 403 {transform.m11(), transform.m21(), 0.0, transform.dx() + 0.5}, 404 {transform.m12(), transform.m22(), 0.0, transform.dy() + 0.5}, 405 {0.0, 0.0, 1.0, 0.0}, 406 {transform.m13(), transform.m23(), 0.0, transform.m33()} 407 }; 408 409 // NOTE: OpenGL ES works with column-major matrices, so when we multiply the matrices, 410 // we also transpose them ready for GL. 411 for (int row = 0; row < 4; ++row) { 412 for (int col = 0; col < 4; ++col) { 413 pmvMatrix[col][row] = 0.0; 414 for (int n = 0; n < 4; ++n) 415 pmvMatrix[col][row] += P[row][n] * MV[n][col]; 416 } 417 } 581 582 // The projection matrix converts from Qt's coordinate system to GL's coordinate system 583 // * GL's viewport is 2x2, Qt's is width x height 584 // * GL has +y -> -y going from bottom -> top, Qt is the other way round 585 // * GL has [0,0] in the center, Qt has it in the top-left 586 // 587 // This results in the Projection matrix below, which is multiplied by the painter's 588 // transformation matrix, as shown below: 589 // 590 // Projection Matrix Painter Transform 591 // ------------------------------------------------ ------------------------ 592 // | 2.0 / width | 0.0 | -1.0 | | m11 | m21 | dx | 593 // | 0.0 | -2.0 / height | 1.0 | * | m12 | m22 | dy | 594 // | 0.0 | 0.0 | 1.0 | | m13 | m23 | m33 | 595 // ------------------------------------------------ ------------------------ 596 // 597 // NOTE: The resultant matrix is also transposed, as GL expects column-major matracies 598 599 const GLfloat wfactor = 2.0f / width; 600 const GLfloat hfactor = -2.0f / height; 601 GLfloat dx = transform.dx(); 602 GLfloat dy = transform.dy(); 603 604 // Non-integer translates can have strange effects for some rendering operations such as 605 // anti-aliased text rendering. In such cases, we snap the translate to the pixel grid. 606 if (snapToPixelGrid && transform.type() == QTransform::TxTranslate) { 607 // 0.50 needs to rounded down to 0.0 for consistency with raster engine: 608 dx = ceilf(dx - 0.5f); 609 dy = ceilf(dy - 0.5f); 610 } 611 612 if (addOffset) { 613 dx += 0.49f; 614 dy += 0.49f; 615 } 616 617 pmvMatrix[0][0] = (wfactor * transform.m11()) - transform.m13(); 618 pmvMatrix[1][0] = (wfactor * transform.m21()) - transform.m23(); 619 pmvMatrix[2][0] = (wfactor * dx) - transform.m33(); 620 pmvMatrix[0][1] = (hfactor * transform.m12()) + transform.m13(); 621 pmvMatrix[1][1] = (hfactor * transform.m22()) + transform.m23(); 622 pmvMatrix[2][1] = (hfactor * dy) + transform.m33(); 623 pmvMatrix[0][2] = transform.m13(); 624 pmvMatrix[1][2] = transform.m23(); 625 pmvMatrix[2][2] = transform.m33(); 418 626 419 627 // 1/10000 == 0.0001, so we have good enough res to cover curves … … 427 635 // The actual data has been updated so both shader program's uniforms need updating 428 636 simpleShaderMatrixUniformDirty = true; 429 brushShaderMatrixUniformDirty = true; 430 imageShaderMatrixUniformDirty = true; 431 textShaderMatrixUniformDirty = true; 637 shaderMatrixUniformDirty = true; 638 639 dasher.setInvScale(inverseScale); 640 stroker.setInvScale(inverseScale); 432 641 } 433 642 … … 486 695 } 487 696 488 489 void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight) 490 { 491 // qDebug("QGL2PaintEngineExPrivate::drawImage()"); 492 493 // We have a shader specifically for drawPixmap/drawImage... 494 shaderManager->imageShader()->use(); 495 496 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); 497 498 if (compositionModeDirty) 499 updateCompositionMode(); 500 697 static inline void setCoords(GLfloat *coords, const QGLRect &rect) 698 { 699 coords[0] = rect.left; 700 coords[1] = rect.top; 701 coords[2] = rect.right; 702 coords[3] = rect.top; 703 coords[4] = rect.right; 704 coords[5] = rect.bottom; 705 coords[6] = rect.left; 706 coords[7] = rect.bottom; 707 } 708 709 void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern) 710 { 711 // Setup for texture drawing 712 currentBrush = noBrush; 713 shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc); 714 715 if (addOffset) { 716 addOffset = false; 717 matrixDirty = true; 718 } 719 720 if (snapToPixelGrid) { 721 snapToPixelGrid = false; 722 matrixDirty = true; 723 } 724 725 if (prepareForDraw(opaque)) 726 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); 727 728 if (pattern) { 729 QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); 730 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); 731 } 732 733 GLfloat dx = 1.0 / textureSize.width(); 734 GLfloat dy = 1.0 / textureSize.height(); 735 736 QGLRect srcTextureRect(src.left*dx, src.top*dy, src.right*dx, src.bottom*dy); 737 738 setCoords(staticVertexCoordinateArray, dest); 739 setCoords(staticTextureCoordinateArray, srcTextureRect); 740 741 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 742 } 743 744 void QGL2PaintEngineEx::beginNativePainting() 745 { 746 Q_D(QGL2PaintEngineEx); 747 ensureActive(); 748 d->transferMode(BrushDrawingMode); 749 750 QGLContext *ctx = d->ctx; 751 glUseProgram(0); 752 753 #ifndef QT_OPENGL_ES_2 754 // be nice to people who mix OpenGL 1.x code with QPainter commands 755 // by setting modelview and projection matrices to mirror the GL 1 756 // paint engine 757 const QTransform& mtx = state()->matrix; 758 759 float mv_matrix[4][4] = 760 { 761 { mtx.m11(), mtx.m12(), 0, mtx.m13() }, 762 { mtx.m21(), mtx.m22(), 0, mtx.m23() }, 763 { 0, 0, 1, 0 }, 764 { mtx.dx(), mtx.dy(), 0, mtx.m33() } 765 }; 766 767 const QSize sz = d->device->size(); 768 769 glMatrixMode(GL_PROJECTION); 770 glLoadIdentity(); 771 glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999); 772 773 glMatrixMode(GL_MODELVIEW); 774 glLoadMatrixf(&mv_matrix[0][0]); 775 #else 776 Q_UNUSED(ctx); 777 #endif 778 779 d->lastTextureUsed = GLuint(-1); 780 d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); 781 d->resetGLState(); 782 783 d->shaderManager->setDirty(); 784 785 d->needsSync = true; 786 } 787 788 void QGL2PaintEngineExPrivate::resetGLState() 789 { 790 glDisable(GL_BLEND); 791 glActiveTexture(GL_TEXTURE0); 792 glDisable(GL_STENCIL_TEST); 793 glDisable(GL_DEPTH_TEST); 794 glDisable(GL_SCISSOR_TEST); 795 glDepthMask(true); 796 glDepthFunc(GL_LESS); 797 glClearDepth(1); 798 } 799 800 void QGL2PaintEngineEx::endNativePainting() 801 { 802 Q_D(QGL2PaintEngineEx); 803 d->needsSync = true; 804 } 805 806 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) 807 { 808 if (newMode == mode) 809 return; 810 811 if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) { 812 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 813 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 814 glDisableVertexAttribArray(QT_OPACITY_ATTR); 815 816 lastTextureUsed = GLuint(-1); 817 } 818 819 if (newMode == TextDrawingMode) { 820 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 821 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 822 823 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); 824 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); 825 } 826 827 if (newMode == ImageDrawingMode) { 828 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 829 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 830 831 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticVertexCoordinateArray); 832 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticTextureCoordinateArray); 833 } 834 835 if (newMode == ImageArrayDrawingMode) { 836 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 837 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 838 glEnableVertexAttribArray(QT_OPACITY_ATTR); 839 840 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); 841 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); 842 glVertexAttribPointer(QT_OPACITY_ATTR, 1, GL_FLOAT, GL_FALSE, 0, opacityArray.data()); 843 } 844 845 // This needs to change when we implement high-quality anti-aliasing... 846 if (newMode != TextDrawingMode) 847 shaderManager->setMaskType(QGLEngineShaderManager::NoMask); 848 849 mode = newMode; 850 } 851 852 struct QGL2PEVectorPathCache 853 { 854 #ifdef QT_OPENGL_CACHE_AS_VBOS 855 GLuint vbo; 856 #else 857 float *vertices; 858 #endif 859 int vertexCount; 860 GLenum primitiveType; 861 qreal iscale; 862 }; 863 864 void QGL2PaintEngineExPrivate::cleanupVectorPath(QPaintEngineEx *engine, void *data) 865 { 866 QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data; 867 #ifdef QT_OPENGL_CACHE_AS_VBOS 868 Q_ASSERT(engine->type() == QPaintEngine::OpenGL2); 869 static_cast<QGL2PaintEngineEx *>(engine)->d_func()->unusedVBOSToClean << c->vbo; 870 #else 871 Q_UNUSED(engine); 872 qFree(c->vertices); 873 #endif 874 delete c; 875 } 876 877 // Assumes everything is configured for the brush you want to use 878 void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) 879 { 880 transferMode(BrushDrawingMode); 881 882 const QOpenGL2PaintEngineState *s = q->state(); 883 const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) && 884 (qbrush_style(currentBrush) == Qt::SolidPattern) && 885 !multisamplingAlwaysEnabled; 886 887 if (addOffset != newAddOffset) { 888 addOffset = newAddOffset; 889 matrixDirty = true; 890 } 891 892 if (snapToPixelGrid) { 893 snapToPixelGrid = false; 894 matrixDirty = true; 895 } 896 897 // Might need to call updateMatrix to re-calculate inverseScale 501 898 if (matrixDirty) 502 899 updateMatrix(); 503 900 504 if (imageShaderMatrixUniformDirty) {505 shaderManager->imageShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;506 imageShaderMatrixUniformDirty = false;507 }508 509 shaderManager->imageShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT;510 511 // if (q->state()->opacity < 0.99f)512 shaderManager->imageShader()->uniforms()[QLatin1String("opacity")] = (GLfloat)q->state()->opacity;513 514 GLfloat vertexCoords[] = {515 dest.left, dest.top,516 dest.left, dest.bottom,517 dest.right, dest.bottom,518 dest.right, dest.top519 };520 521 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);522 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);523 524 GLfloat dx = 1.0 / txtWidth;525 GLfloat dy = 1.0 / txtHeight;526 527 QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);528 529 GLfloat textureCoords[] = {530 srcTextureRect.left, srcTextureRect.top,531 srcTextureRect.left, srcTextureRect.bottom,532 srcTextureRect.right, srcTextureRect.bottom,533 srcTextureRect.right, srcTextureRect.top534 };535 536 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);537 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);538 539 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);540 541 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);542 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);543 }544 545 546 void QGL2PaintEngineExPrivate::drawOutline(const QVectorPath& path)547 {548 // qDebug("QGL2PaintEngineExPrivate::drawOutline()");549 if (matrixDirty)550 updateMatrix();551 552 pathVertexArray.clear();553 pathVertexArray.addPath(path, inverseScale);554 555 if (path.hasImplicitClose()) {556 // Close the path's outline557 pathVertexArray.lineToArray(path.points()[0], path.points()[1]);558 pathVertexArray.stops().last() += 1;559 }560 561 prepareForDraw();562 drawVertexArrays(pathVertexArray, GL_LINE_STRIP);563 }564 565 566 // Assumes everything is configured for the brush you want to use567 void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)568 {569 if (matrixDirty)570 updateMatrix();571 572 901 const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); 573 574 902 575 903 // Check to see if there's any hints 576 904 if (path.shape() == QVectorPath::RectangleHint) { 577 905 QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y()); 578 prepareForDraw( );906 prepareForDraw(); 579 907 composite(rect); 580 } 581 else if (path.shape() == QVectorPath::EllipseHint) { 582 pathVertexArray.clear(); 583 pathVertexArray.addPath(path, inverseScale); 584 prepareForDraw(); 585 drawVertexArrays(pathVertexArray, GL_TRIANGLE_FAN); 586 } 587 else { 908 } else if (path.isConvex()) { 909 910 if (path.isCacheable()) { 911 QVectorPath::CacheEntry *data = path.lookupCacheData(q); 912 QGL2PEVectorPathCache *cache; 913 914 if (data) { 915 cache = (QGL2PEVectorPathCache *) data->data; 916 // Check if scale factor is exceeded for curved paths and generate curves if so... 917 if (path.isCurved()) { 918 qreal scaleFactor = cache->iscale / inverseScale; 919 if (scaleFactor < 0.5 || scaleFactor > 2.0) { 920 #ifdef QT_OPENGL_CACHE_AS_VBOS 921 glDeleteBuffers(1, &cache->vbo); 922 cache->vbo = 0; 923 #else 924 qFree(cache->vertices); 925 #endif 926 cache->vertexCount = 0; 927 } 928 } 929 } else { 930 cache = new QGL2PEVectorPathCache; 931 cache->vertexCount = 0; 932 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath); 933 } 934 935 // Flatten the path at the current scale factor and fill it into the cache struct. 936 if (!cache->vertexCount) { 937 vertexCoordinateArray.clear(); 938 vertexCoordinateArray.addPath(path, inverseScale, false); 939 int vertexCount = vertexCoordinateArray.vertexCount(); 940 int floatSizeInBytes = vertexCount * 2 * sizeof(float); 941 cache->vertexCount = vertexCount; 942 cache->primitiveType = GL_TRIANGLE_FAN; 943 cache->iscale = inverseScale; 944 #ifdef QT_OPENGL_CACHE_AS_VBOS 945 glGenBuffers(1, &cache->vbo); 946 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); 947 glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW); 948 #else 949 cache->vertices = (float *) qMalloc(floatSizeInBytes); 950 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes); 951 #endif 952 } 953 954 prepareForDraw(currentBrush.isOpaque()); 955 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 956 #ifdef QT_OPENGL_CACHE_AS_VBOS 957 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); 958 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0); 959 #else 960 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, cache->vertices); 961 #endif 962 glDrawArrays(cache->primitiveType, 0, cache->vertexCount); 963 964 } else { 965 // printf(" - Marking path as cachable...\n"); 966 // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable 967 // ### Remove before release... 968 static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty(); 969 if (do_vectorpath_cache) 970 path.makeCacheable(); 971 vertexCoordinateArray.clear(); 972 vertexCoordinateArray.addPath(path, inverseScale, false); 973 prepareForDraw(currentBrush.isOpaque()); 974 drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); 975 } 976 977 } else { 588 978 // The path is too complicated & needs the stencil technique 589 pathVertexArray.clear(); 590 pathVertexArray.addPath(path, inverseScale); 591 592 fillStencilWithVertexArray(pathVertexArray, path.hasWindingFill()); 979 vertexCoordinateArray.clear(); 980 vertexCoordinateArray.addPath(path, inverseScale, false); 981 982 fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); 983 984 glStencilMask(0xff); 985 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); 986 987 if (q->state()->clipTestEnabled) { 988 // Pass when high bit is set, replace stencil value with current clip 989 glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT); 990 } else if (path.hasWindingFill()) { 991 // Pass when any bit is set, replace stencil value with 0 992 glStencilFunc(GL_NOTEQUAL, 0, 0xff); 993 } else { 994 // Pass when high bit is set, replace stencil value with 0 995 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); 996 } 997 prepareForDraw(currentBrush.isOpaque()); 593 998 594 999 // Stencil the brush onto the dest buffer 595 glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0 596 glEnable(GL_STENCIL_TEST); 597 prepareForDraw(); 598 composite(pathVertexArray.boundingRect()); 599 glDisable(GL_STENCIL_TEST); 600 601 cleanStencilBuffer(pathVertexArray.boundingRect()); 602 } 603 } 604 605 606 void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) 607 { 1000 composite(vertexCoordinateArray.boundingRect()); 1001 glStencilMask(0); 1002 updateClipScissorTest(); 1003 } 1004 } 1005 1006 1007 void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, 1008 int count, 1009 int *stops, 1010 int stopCount, 1011 const QGLRect &bounds, 1012 StencilFillMode mode) 1013 { 1014 Q_ASSERT(count || stops); 1015 608 1016 // qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); 609 if (stencilBuferDirty) {610 // Clear the stencil buffer to zeros 611 glDisable(GL_STENCIL_TEST);612 glStencilMask(0xFFFF); // Enable writing to stencil buffer, otherwise glClear wont do anything.1017 1018 1019 1020 613 1021 glClearStencil(0); // Clear to zero 614 glClear(GL_STENCIL_BUFFER_BIT); 615 stencilBuferDirty = false; 1022 for (int i = 0; i < clearRegion.size(); ++i) { 1023 #ifndef QT_GL_NO_SCISSOR_TEST 1024 setScissor(clearRegion.at(i)); 1025 #endif 1026 glClear(GL_STENCIL_BUFFER_BIT); 1027 } 1028 1029 dirtyStencilRegion -= currentScissorBounds; 1030 1031 #ifndef QT_GL_NO_SCISSOR_TEST 1032 updateClipScissorTest(); 1033 #endif 616 1034 } 617 1035 618 1036 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes 619 glStencilMask(0xFFFF); // Enable stencil writes 620 glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test 621 622 // Setup the stencil op: 623 if (useWindingFill) { 624 glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); // Inc. for front-facing triangle 625 glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); //Dec. for back-facing "holes" 626 } else 1037 useSimpleShader(); 1038 glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d 1039 1040 if (mode == WindingFillMode) { 1041 Q_ASSERT(stops && !count); 1042 if (q->state()->clipTestEnabled) { 1043 // Flatten clip values higher than current clip, and set high bit to match current clip 1044 glStencilFunc(GL_LEQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); 1045 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); 1046 composite(bounds); 1047 1048 glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT, GL_STENCIL_HIGH_BIT); 1049 } else if (!stencilClean) { 1050 // Clear stencil buffer within bounding rect 1051 glStencilFunc(GL_ALWAYS, 0, 0xff); 1052 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); 1053 composite(bounds); 1054 } 1055 1056 // Inc. for front-facing triangle 1057 glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP); 1058 // Dec. for back-facing "holes" 1059 glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP); 1060 glStencilMask(~GL_STENCIL_HIGH_BIT); 1061 drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); 1062 1063 if (q->state()->clipTestEnabled) { 1064 // Clear high bit of stencil outside of path 1065 glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); 1066 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); 1067 glStencilMask(GL_STENCIL_HIGH_BIT); 1068 composite(bounds); 1069 } 1070 } else if (mode == OddEvenFillMode) { 1071 glStencilMask(GL_STENCIL_HIGH_BIT); 627 1072 glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit 628 629 // No point in using a fancy gradiant shader for writing into the stencil buffer! 630 useSimpleShader(); 631 632 glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d 633 glDisable(GL_BLEND); 634 635 // Draw the vertecies into the stencil buffer: 636 drawVertexArrays(vertexArray, GL_TRIANGLE_FAN); 1073 drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); 1074 1075 } else { // TriStripStrokeFillMode 1076 Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops 1077 glStencilMask(GL_STENCIL_HIGH_BIT); 1078 #if 0 1079 glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit 1080 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1081 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); 1082 glDrawArrays(GL_TRIANGLE_STRIP, 0, count); 1083 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1084 #else 1085 1086 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); 1087 if (q->state()->clipTestEnabled) { 1088 glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT, 1089 ~GL_STENCIL_HIGH_BIT); 1090 } else { 1091 glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff); 1092 } 1093 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1094 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); 1095 glDrawArrays(GL_TRIANGLE_STRIP, 0, count); 1096 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1097 #endif 1098 } 637 1099 638 1100 // Enable color writes & disable stencil writes 639 1101 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 640 glStencilMask(0); 641 } 642 643 void QGL2PaintEngineExPrivate::cleanStencilBuffer(const QGLRect& area) 644 { 645 // qDebug("QGL2PaintEngineExPrivate::cleanStencilBuffer()"); 1102 } 1103 1104 /* 1105 If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1, 1106 restore the stencil buffer to a pristine state. The current clip region 1107 is set to 1, and the rest to 0. 1108 */ 1109 void QGL2PaintEngineExPrivate::resetClipIfNeeded() 1110 { 1111 if (maxClip != (GL_STENCIL_HIGH_BIT - 1)) 1112 return; 1113 1114 Q_Q(QGL2PaintEngineEx); 1115 646 1116 useSimpleShader(); 647 648 GLfloat rectVerts[] = {649 area.left, area.top,650 area.left, area.bottom,651 area.right, area.bottom,652 area.right, area.top653 };654 655 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);656 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, rectVerts);657 658 1117 glEnable(GL_STENCIL_TEST); 659 glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test 660 661 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes 662 glStencilMask(0xFFFF); // Enable writing to stencil buffer 663 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // Write 0's to stencil buffer 664 665 glDisable(GL_BLEND); 666 667 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 668 669 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 670 671 // Enable color writes & disable stencil writes 1118 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 1119 1120 QRectF bounds = q->state()->matrix.inverted().mapRect(QRectF(0, 0, width, height)); 1121 QGLRect rect(bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); 1122 1123 // Set high bit on clip region 1124 glStencilFunc(GL_LEQUAL, q->state()->currentClip, 0xff); 1125 glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); 1126 glStencilMask(GL_STENCIL_HIGH_BIT); 1127 composite(rect); 1128 1129 // Reset clipping to 1 and everything else to zero 1130 glStencilFunc(GL_NOTEQUAL, 0x01, GL_STENCIL_HIGH_BIT); 1131 glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE); 1132 glStencilMask(0xff); 1133 composite(rect); 1134 1135 q->state()->currentClip = 1; 1136 q->state()->canRestoreClip = false; 1137 1138 maxClip = 1; 1139 1140 glStencilMask(0x0); 672 1141 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 673 glStencilMask(0); 674 glDisable(GL_STENCIL_TEST); 675 } 676 677 void QGL2PaintEngineExPrivate::prepareForDraw() 678 { 679 if (brushTextureDirty) 1142 } 1143 1144 bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) 1145 { 1146 if (brushTextureDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode) 680 1147 updateBrushTexture(); 681 1148 … … 683 1150 updateCompositionMode(); 684 1151 685 if (shaderManager->useCorrectShaderProg()) { 1152 if (matrixDirty) 1153 updateMatrix(); 1154 1155 const bool stateHasOpacity = q->state()->opacity < 0.99f; 1156 if (q->state()->composition_mode == QPainter::CompositionMode_Source 1157 || (q->state()->composition_mode == QPainter::CompositionMode_SourceOver 1158 && srcPixelsAreOpaque && !stateHasOpacity)) 1159 { 1160 glDisable(GL_BLEND); 1161 } else { 1162 glEnable(GL_BLEND); 1163 } 1164 1165 QGLEngineShaderManager::OpacityMode opacityMode; 1166 if (mode == ImageArrayDrawingMode) { 1167 opacityMode = QGLEngineShaderManager::AttributeOpacity; 1168 } else { 1169 opacityMode = stateHasOpacity ? QGLEngineShaderManager::UniformOpacity 1170 : QGLEngineShaderManager::NoOpacity; 1171 if (stateHasOpacity && (mode != ImageDrawingMode)) { 1172 // Using a brush 1173 bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) && 1174 (currentBrush.style() <= Qt::DiagCrossPattern); 1175 1176 if ((currentBrush.style() == Qt::SolidPattern) || brushIsPattern) 1177 opacityMode = QGLEngineShaderManager::NoOpacity; // Global opacity handled by srcPixel shader 1178 } 1179 } 1180 shaderManager->setOpacityMode(opacityMode); 1181 1182 bool changed = shaderManager->useCorrectShaderProg(); 1183 // If the shader program needs changing, we change it and mark all uniforms as dirty 1184 if (changed) { 686 1185 // The shader program has changed so mark all uniforms as dirty: 687 1186 brushUniformsDirty = true; 688 brushShaderMatrixUniformDirty = true; 689 } 690 691 if (brushUniformsDirty) 1187 shaderMatrixUniformDirty = true; 1188 opacityUniformDirty = true; 1189 } 1190 1191 if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode) 692 1192 updateBrushUniforms(); 693 1193 694 if (brushShaderMatrixUniformDirty) { 695 shaderManager->brushShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix; 696 brushShaderMatrixUniformDirty = false; 697 } 698 699 if ((q->state()->opacity < 0.99f) || !currentBrush->isOpaque()) 700 glEnable(GL_BLEND); 701 else 702 glDisable(GL_BLEND); 1194 if (shaderMatrixUniformDirty) { 1195 glUniformMatrix3fv(location(QGLEngineShaderManager::PmvMatrix), 1, GL_FALSE, (GLfloat*)pmvMatrix); 1196 shaderMatrixUniformDirty = false; 1197 } 1198 1199 if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) { 1200 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity); 1201 opacityUniformDirty = false; 1202 } 1203 1204 return changed; 703 1205 } 704 1206 … … 722 1224 723 1225 // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans. 724 void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive) 1226 void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount, 1227 GLenum primitive) 725 1228 { 726 1229 // Now setup the pointer to the vertex array: 727 1230 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 728 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray.data());1231 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, ); 729 1232 730 1233 int previousStop = 0; 731 foreach(int stop, vertexArray.stops()) { 1234 for (int i=0; i<stopCount; ++i) { 1235 int stop = stops[i]; 732 1236 /* 733 1237 qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1); … … 741 1245 } 742 1246 743 744 745 746 747 1247 /////////////////////////////////// Public Methods ////////////////////////////////////////// 748 1248 … … 750 1250 : QPaintEngineEx(*(new QGL2PaintEngineExPrivate(this))) 751 1251 { 752 qDebug("QGL2PaintEngineEx::QGL2PaintEngineEx()");753 754 1252 } 755 1253 … … 762 1260 Q_D(QGL2PaintEngineEx); 763 1261 764 QTime startTime = QTime::currentTime(); 765 766 d->setBrush(&brush); 1262 if (qbrush_style(brush) == Qt::NoBrush) 1263 return; 1264 ensureActive(); 1265 d->setBrush(brush); 767 1266 d->fill(path); 768 d->setBrush(&(state()->brush)); // reset back to the state's brush 769 } 1267 } 1268 1269 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp 1270 770 1271 771 1272 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) … … 773 1274 Q_D(QGL2PaintEngineEx); 774 1275 775 if (pen.style() == Qt::NoPen) 1276 const QBrush &penBrush = qpen_brush(pen); 1277 if (qpen_style(pen) == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) 776 1278 return; 777 1279 778 if ( (pen.isCosmetic() && (pen.style() == Qt::SolidLine)) && (pen.widthF() < 2.5f) ) 779 { 780 // We only handle solid, cosmetic pens with a width of 1 pixel 781 const QBrush& brush = pen.brush(); 782 d->setBrush(&brush); 783 784 if (pen.widthF() < 0.01f) 785 glLineWidth(1.0); 786 else 787 glLineWidth(pen.widthF()); 788 789 d->drawOutline(path); 790 d->setBrush(&(state()->brush)); 791 } else 792 return QPaintEngineEx::stroke(path, pen); 793 794 } 795 796 void QGL2PaintEngineEx::penChanged() 797 { 798 // qDebug("QGL2PaintEngineEx::penChanged() not implemented!"); 799 } 800 801 802 void QGL2PaintEngineEx::brushChanged() 803 { 804 // qDebug("QGL2PaintEngineEx::brushChanged()"); 805 Q_D(QGL2PaintEngineEx); 806 d->setBrush(&(state()->brush)); 807 } 808 809 void QGL2PaintEngineEx::brushOriginChanged() 810 { 811 // qDebug("QGL2PaintEngineEx::brushOriginChanged()"); 812 Q_D(QGL2PaintEngineEx); 813 d->brushUniformsDirty = true; 814 } 1280 QOpenGL2PaintEngineState *s = state(); 1281 if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) { 1282 // QTriangulatingStroker class is not meant to support cosmetically sheared strokes. 1283 QPaintEngineEx::stroke(path, pen); 1284 return; 1285 } 1286 1287 ensureActive(); 1288 d->setBrush(penBrush); 1289 d->stroke(path, pen); 1290 } 1291 1292 void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen) 1293 { 1294 const QOpenGL2PaintEngineState *s = q->state(); 1295 const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) && !multisamplingAlwaysEnabled; 1296 if (addOffset != newAddOffset) { 1297 addOffset = newAddOffset; 1298 matrixDirty = true; 1299 } 1300 1301 if (snapToPixelGrid) { 1302 snapToPixelGrid = false; 1303 matrixDirty = true; 1304 } 1305 1306 const Qt::PenStyle penStyle = qpen_style(pen); 1307 const QBrush &penBrush = qpen_brush(pen); 1308 const bool opaque = penBrush.isOpaque() && s->opacity > 0.99; 1309 1310 transferMode(BrushDrawingMode); 1311 1312 // updateMatrix() is responsible for setting the inverse scale on 1313 // the strokers, so we need to call it here and not wait for 1314 // prepareForDraw() down below. 1315 updateMatrix(); 1316 1317 if (penStyle == Qt::SolidLine) { 1318 stroker.process(path, pen); 1319 1320 } else { // Some sort of dash 1321 dasher.process(path, pen); 1322 1323 QVectorPath dashStroke(dasher.points(), 1324 dasher.elementCount(), 1325 dasher.elementTypes()); 1326 stroker.process(dashStroke, pen); 1327 } 1328 1329 if (opaque) { 1330 prepareForDraw(opaque); 1331 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1332 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, stroker.vertices()); 1333 glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2); 1334 1335 // QBrush b(Qt::green); 1336 // d->setBrush(&b); 1337 // d->prepareForDraw(true); 1338 // glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2); 1339 1340 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1341 1342 } else { 1343 qreal width = qpen_widthf(pen) / 2; 1344 if (width == 0) 1345 width = 0.5; 1346 qreal extra = pen.joinStyle() == Qt::MiterJoin 1347 ? qMax(pen.miterLimit() * width, width) 1348 : width; 1349 1350 if (pen.isCosmetic()) 1351 extra = extra * inverseScale; 1352 1353 QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); 1354 1355 fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2, 1356 0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode); 1357 1358 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); 1359 1360 // Pass when any bit is set, replace stencil value with 0 1361 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); 1362 prepareForDraw(false); 1363 1364 // Stencil the brush onto the dest buffer 1365 composite(bounds); 1366 1367 glStencilMask(0); 1368 1369 updateClipScissorTest(); 1370 } 1371 } 1372 1373 void QGL2PaintEngineEx::penChanged() { } 1374 void QGL2PaintEngineEx::brushChanged() { } 1375 void QGL2PaintEngineEx::brushOriginChanged() { } 815 1376 816 1377 void QGL2PaintEngineEx::opacityChanged() … … 818 1379 // qDebug("QGL2PaintEngineEx::opacityChanged()"); 819 1380 Q_D(QGL2PaintEngineEx); 1381 820 1382 821 1383 Q_ASSERT(d->shaderManager); 822 d->shaderManager->setUseGlobalOpacity(state()->opacity > 0.999);823 1384 d->brushUniformsDirty = true; 1385 824 1386 } 825 1387 … … 828 1390 // qDebug("QGL2PaintEngineEx::compositionModeChanged()"); 829 1391 Q_D(QGL2PaintEngineEx); 1392 830 1393 d->compositionModeDirty = true; 831 1394 } … … 833 1396 void QGL2PaintEngineEx::renderHintsChanged() 834 1397 { 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 835 1411 // qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!"); 836 1412 } … … 840 1416 Q_D(QGL2PaintEngineEx); 841 1417 d->matrixDirty = true; 1418 842 1419 } 843 1420 … … 846 1423 { 847 1424 Q_D(QGL2PaintEngineEx); 848 glActiveTexture(QT_BRUSH_TEXTURE_UNIT); 849 850 d->ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true); 851 852 //FIXME: we should use hasAlpha() instead, but that's SLOW at the moment 853 if ((state()->opacity < 0.99f) || pixmap.hasAlphaChannel()) 854 glEnable(GL_BLEND); 855 else 856 glDisable(GL_BLEND); 857 858 d->drawTexture(dest, src, pixmap.width(), pixmap.height()); 1425 ensureActive(); 1426 d->transferMode(ImageDrawingMode); 1427 1428 QGLContext *ctx = d->ctx; 1429 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); 1430 QGLTexture *texture = 1431 ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, 1432 QGLContext::InternalBindOption 1433 | QGLContext::CanFlipNativePixmapBindOption); 1434 1435 GLfloat top = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.top()) : src.top(); 1436 GLfloat bottom = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.bottom()) : src.bottom(); 1437 QGLRect srcRect(src.left(), top, src.right(), bottom); 1438 1439 bool isBitmap = pixmap.isQBitmap(); 1440 bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel(); 1441 1442 d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, 1443 state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); 1444 d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap); 859 1445 } 860 1446 … … 863 1449 { 864 1450 Q_D(QGL2PaintEngineEx); 865 glActiveTexture(QT_BRUSH_TEXTURE_UNIT); 866 d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); 867 868 if ((state()->opacity < 0.99f) || image.hasAlphaChannel()) 869 glEnable(GL_BLEND); 870 else 871 glDisable(GL_BLEND); 872 873 d->drawTexture(dest, src, image.width(), image.height()); 1451 ensureActive(); 1452 d->transferMode(ImageDrawingMode); 1453 1454 QGLContext *ctx = d->ctx; 1455 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); 1456 QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); 1457 GLuint id = texture->id; 1458 1459 d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, 1460 state()->renderHints & QPainter::SmoothPixmapTransform, id); 1461 d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); 1462 } 1463 1464 void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) 1465 { 1466 Q_D(QGL2PaintEngineEx); 1467 ensureActive(); 1468 d->transferMode(ImageDrawingMode); 1469 1470 #ifndef QT_OPENGL_ES_2 1471 QGLContext *ctx = d->ctx; 1472 #endif 1473 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); 1474 glBindTexture(GL_TEXTURE_2D, textureId); 1475 1476 QGLRect srcRect(src.left(), src.bottom(), src.right(), src.top()); 1477 1478 d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, 1479 state()->renderHints & QPainter::SmoothPixmapTransform, textureId); 1480 d->drawTexture(dest, srcRect, size, false); 874 1481 } 875 1482 876 1483 void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem) 877 1484 { 878 QOpenGLPaintEngineState *s = state(); 1485 Q_D(QGL2PaintEngineEx); 1486 1487 ensureActive(); 1488 QOpenGL2PaintEngineState *s = state(); 879 1489 880 1490 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); 881 1491 882 bool drawCached = true; 883 884 if (state()->pen.brush().style() != Qt::SolidPattern) 1492 QTransform::TransformationType txtype = s->matrix.type(); 1493 1494 float det = s->matrix.determinant(); 1495 bool drawCached = txtype < QTransform::TxProject; 1496 1497 // don't try to cache huge fonts or vastly transformed fonts 1498 const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; 1499 if (pixelSize * pixelSize * qAbs(det) >= 64 * 64 || det < 0.25f || det > 4.f) 885 1500 drawCached = false; 886 1501 887 if (s->matrix.type() > QTransform::TxTranslate) 1502 QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 1503 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) 1504 : d->glyphCacheType; 1505 1506 if (txtype > QTransform::TxTranslate) 1507 glyphType = QFontEngineGlyphCache::Raster_A8; 1508 1509 if (glyphType == QFontEngineGlyphCache::Raster_RGBMask 1510 && state()->composition_mode != QPainter::CompositionMode_Source 1511 && state()->composition_mode != QPainter::CompositionMode_SourceOver) 1512 { 888 1513 drawCached = false; 889 890 // don't try to cache huge fonts 891 if (ti.fontEngine->fontDef.pixelSize * qSqrt(s->matrix.determinant()) >= 64) 892 drawCached = false; 1514 } 893 1515 894 1516 if (drawCached) { 895 d rawCachedGlyphs(p, ti);1517 d, ti); 896 1518 return; 897 1519 } … … 900 1522 } 901 1523 902 void QGL2PaintEngineEx ::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti)903 { 904 Q_D(QGL2PaintEngineEx); 905 Q OpenGLPaintEngineState *s = state();1524 void QGL2PaintEngineEx 1525 const QTextItemInt &ti) 1526 { 1527 Q); 906 1528 907 1529 QVarLengthArray<QFixedPoint> positions; 908 1530 QVarLengthArray<glyph_t> glyphs; 909 QTransform matrix; 910 matrix.translate(p.x(), p.y()); 1531 QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); 911 1532 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); 912 1533 913 QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 914 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) 915 : QFontEngineGlyphCache::Raster_A8; 916 917 QImageTextureGlyphCache *cache = 918 (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(glyphType, s->matrix); 919 if (!cache) { 920 cache = new QImageTextureGlyphCache(glyphType, s->matrix); 921 ti.fontEngine->setGlyphCache(glyphType, cache); 922 } 923 1534 QGLTextureGlyphCache *cache = 1535 (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform()); 1536 1537 if (!cache || cache->cacheType() != glyphType) { 1538 cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); 1539 ti.fontEngine->setGlyphCache(ctx, cache); 1540 } 1541 1542 cache->setPaintEnginePrivate(this); 924 1543 cache->populate(ti, glyphs, positions); 925 1544 926 const QImage &image = cache->image(); 1545 if (cache->width() == 0 || cache->height() == 0) 1546 return; 1547 1548 transferMode(TextDrawingMode); 1549 927 1550 int margin = cache->glyphMargin(); 928 1551 929 glActiveTexture(QT_BRUSH_TEXTURE_UNIT); 930 d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true); 931 932 glEnable(GL_BLEND); 933 934 d->shaderManager->textShader()->use(); 935 d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); 936 937 if (d->compositionModeDirty) 938 d->updateCompositionMode(); 939 940 if (d->matrixDirty) 941 d->updateMatrix(); 942 943 if (d->textShaderMatrixUniformDirty) { 944 d->shaderManager->textShader()->uniforms()[QLatin1String("pmvMatrix")] = d->pmvMatrix; 945 d->textShaderMatrixUniformDirty = false; 946 } 947 948 d->shaderManager->textShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT; 949 QColor col = d->premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity); 950 d->shaderManager->textShader()->uniforms()[QLatin1String("fragmentColor")] = col; 951 952 GLfloat dx = 1.0 / image.width(); 953 GLfloat dy = 1.0 / image.height(); 954 955 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 956 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 1552 GLfloat dx = 1.0 / cache->width(); 1553 GLfloat dy = 1.0 / cache->height(); 1554 1555 QGLPoint *oldVertexCoordinateDataPtr = vertexCoordinateArray.data(); 1556 QGLPoint *oldTextureCoordinateDataPtr = textureCoordinateArray.data(); 1557 1558 vertexCoordinateArray.clear(); 1559 textureCoordinateArray.clear(); 1560 957 1561 for (int i=0; i<glyphs.size(); ++i) { 958 1562 const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]); … … 960 1564 int y = positions[i].y.toInt() - c.baseLineY - margin; 961 1565 962 QGLRect dest = QRectF(x, y, c.w, c.h); 963 QGLRect src = QRectF(c.x, c.y, c.w, c.h); 964 965 GLfloat vertexCoords[] = { 966 dest.left, dest.top, 967 dest.left, dest.bottom, 968 dest.right, dest.bottom, 969 dest.right, dest.top 970 }; 971 972 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords); 973 974 QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy); 975 976 GLfloat textureCoords[] = { 977 srcTextureRect.left, srcTextureRect.top, 978 srcTextureRect.left, srcTextureRect.bottom, 979 srcTextureRect.right, srcTextureRect.bottom, 980 srcTextureRect.right, srcTextureRect.top 981 }; 982 983 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); 984 985 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 986 } 987 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); 988 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); 1566 vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); 1567 textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); 1568 } 1569 1570 if (vertexCoordinateArray.data() != oldVertexCoordinateDataPtr) 1571 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); 1572 if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr) 1573 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); 1574 1575 if (addOffset) { 1576 addOffset = false; 1577 matrixDirty = true; 1578 } 1579 if (!snapToPixelGrid) { 1580 snapToPixelGrid = true; 1581 matrixDirty = true; 1582 } 1583 1584 QBrush pensBrush = q->state()->pen.brush(); 1585 setBrush(pensBrush); 1586 1587 if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { 1588 1589 // Subpixel antialiasing without gamma correction 1590 1591 QPainter::CompositionMode compMode = q->state()->composition_mode; 1592 Q_ASSERT(compMode == QPainter::CompositionMode_Source 1593 || compMode == QPainter::CompositionMode_SourceOver); 1594 1595 shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass1); 1596 1597 if (pensBrush.style() == Qt::SolidPattern) { 1598 // Solid patterns can get away with only one pass. 1599 QColor c = pensBrush.color(); 1600 qreal oldOpacity = q->state()->opacity; 1601 if (compMode == QPainter::CompositionMode_Source) { 1602 c = qt_premultiplyColor(c, q->state()->opacity); 1603 q->state()->opacity = 1; 1604 opacityUniformDirty = true; 1605 } 1606 1607 compositionModeDirty = false; // I can handle this myself, thank you very much 1608 prepareForDraw(false); // Text always causes src pixels to be transparent 1609 1610 // prepareForDraw() have set the opacity on the current shader, so the opacity state can now be reset. 1611 if (compMode == QPainter::CompositionMode_Source) { 1612 q->state()->opacity = oldOpacity; 1613 opacityUniformDirty = true; 1614 } 1615 1616 glEnable(GL_BLEND); 1617 glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR); 1618 glBlendColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()); 1619 } else { 1620 // Other brush styles need two passes. 1621 1622 qreal oldOpacity = q->state()->opacity; 1623 if (compMode == QPainter::CompositionMode_Source) { 1624 q->state()->opacity = 1; 1625 opacityUniformDirty = true; 1626 pensBrush = Qt::white; 1627 setBrush(pensBrush); 1628 } 1629 1630 compositionModeDirty = false; // I can handle this myself, thank you very much 1631 prepareForDraw(false); // Text always causes src pixels to be transparent 1632 glEnable(GL_BLEND); 1633 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); 1634 1635 glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); 1636 glBindTexture(GL_TEXTURE_2D, cache->texture()); 1637 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); 1638 1639 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); 1640 glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); 1641 1642 shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2); 1643 1644 if (compMode == QPainter::CompositionMode_Source) { 1645 q->state()->opacity = oldOpacity; 1646 opacityUniformDirty = true; 1647 pensBrush = q->state()->pen.brush(); 1648 setBrush(pensBrush); 1649 } 1650 1651 compositionModeDirty = false; 1652 prepareForDraw(false); // Text always causes src pixels to be transparent 1653 glEnable(GL_BLEND); 1654 glBlendFunc(GL_ONE, GL_ONE); 1655 } 1656 compositionModeDirty = true; 1657 } else { 1658 // Greyscale/mono glyphs 1659 1660 shaderManager->setMaskType(QGLEngineShaderManager::PixelMask); 1661 prepareForDraw(false); // Text always causes src pixels to be transparent 1662 } 1663 //### TODO: Gamma correction 1664 1665 glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); 1666 glBindTexture(GL_TEXTURE_2D, cache->texture()); 1667 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); 1668 1669 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); 1670 glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); 1671 } 1672 1673 void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) 1674 { 1675 Q_D(QGL2PaintEngineEx); 1676 // Use fallback for extended composition modes. 1677 if (state()->composition_mode > QPainter::CompositionMode_Plus) { 1678 QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints); 1679 return; 1680 } 1681 1682 ensureActive(); 1683 d->drawPixmaps(drawingData, dataCount, pixmap, hints); 1684 } 1685 1686 1687 void QGL2PaintEngineExPrivate::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) 1688 { 1689 GLfloat dx = 1.0f / pixmap.size().width(); 1690 GLfloat dy = 1.0f / pixmap.size().height(); 1691 1692 vertexCoordinateArray.clear(); 1693 textureCoordinateArray.clear(); 1694 opacityArray.reset(); 1695 1696 if (addOffset) { 1697 addOffset = false; 1698 matrixDirty = true; 1699 } 1700 1701 if (snapToPixelGrid) { 1702 snapToPixelGrid = false; 1703 matrixDirty = true; 1704 } 1705 1706 bool allOpaque = true; 1707 1708 for (int i = 0; i < dataCount; ++i) { 1709 qreal s = 0; 1710 qreal c = 1; 1711 if (drawingData[i].rotation != 0) { 1712 s = qFastSin(drawingData[i].rotation * Q_PI / 180); 1713 c = qFastCos(drawingData[i].rotation * Q_PI / 180); 1714 } 1715 1716 qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width(); 1717 qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height(); 1718 QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c); 1719 QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c); 1720 1721 vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); 1722 vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y()); 1723 vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); 1724 vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); 1725 vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y()); 1726 vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); 1727 1728 QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy, 1729 drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy); 1730 1731 textureCoordinateArray.lineToArray(src.right, src.bottom); 1732 textureCoordinateArray.lineToArray(src.right, src.top); 1733 textureCoordinateArray.lineToArray(src.left, src.top); 1734 textureCoordinateArray.lineToArray(src.left, src.top); 1735 textureCoordinateArray.lineToArray(src.left, src.bottom); 1736 textureCoordinateArray.lineToArray(src.right, src.bottom); 1737 1738 qreal opacity = drawingData[i].opacity * q->state()->opacity; 1739 opacityArray << opacity << opacity << opacity << opacity << opacity << opacity; 1740 allOpaque &= (opacity >= 0.99f); 1741 } 1742 1743 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); 1744 QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, 1745 QGLContext::InternalBindOption 1746 | QGLContext::CanFlipNativePixmapBindOption); 1747 1748 if (texture->options & QGLContext::InvertedYBindOption) { 1749 // Flip texture y-coordinate. 1750 QGLPoint *data = textureCoordinateArray.data(); 1751 for (int i = 0; i < 6 * dataCount; ++i) 1752 data[i].y = 1 - data[i].y; 1753 } 1754 1755 transferMode(ImageArrayDrawingMode); 1756 1757 bool isBitmap = pixmap.isQBitmap(); 1758 bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque; 1759 1760 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, 1761 q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); 1762 1763 // Setup for texture drawing 1764 currentBrush = noBrush; 1765 shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc); 1766 if (prepareForDraw(isOpaque)) 1767 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); 1768 1769 if (isBitmap) { 1770 QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); 1771 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); 1772 } 1773 1774 glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount); 989 1775 } 990 1776 … … 994 1780 995 1781 // qDebug("QGL2PaintEngineEx::begin()"); 996 997 QGLWidget* widget = static_cast<QGLWidget*>(pdev); 998 d->ctx = const_cast<QGLContext*>(widget->context()); 999 d->ctx->makeCurrent(); 1000 d->width = widget->width(); 1001 d->height = widget->height(); 1002 1003 if (!d->shaderManager) 1004 d->shaderManager = new QGLPEXShaderManager(d->ctx); 1005 1006 glViewport(0, 0, d->width, d->height); 1007 1008 // glClearColor(0.0, 1.0, 0.0, 1.0); 1009 // glClear(GL_COLOR_BUFFER_BIT); 1010 // d->ctx->swapBuffers(); 1011 // qDebug("You should see green now"); 1012 // sleep(5); 1013 1782 if (pdev->devType() == QInternal::OpenGL) 1783 d->device = static_cast<QGLPaintDevice*>(pdev); 1784 else 1785 d->device = QGLPaintDevice::getDevice(pdev); 1786 1787 if (!d->device) 1788 return false; 1789 1790 d->ctx = d->device->context(); 1791 d->ctx->d_ptr->active_engine = this; 1792 1793 const QSize sz = d->device->size(); 1794 d->width = sz.width(); 1795 d->height = sz.height(); 1796 d->mode = BrushDrawingMode; 1014 1797 d->brushTextureDirty = true; 1015 1798 d->brushUniformsDirty = true; 1016 1799 d->matrixDirty = true; 1017 1800 d->compositionModeDirty = true; 1018 d->stencilBuferDirty = true; 1019 1020 d->use_system_clip = !systemClip().isEmpty(); 1021 1801 d->opacityUniformDirty = true; 1802 d->needsSync = true; 1803 d->useSystemClip = !systemClip().isEmpty(); 1804 d->currentBrush = QBrush(); 1805 1806 d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); 1807 d->stencilClean = true; 1808 1809 // Calling begin paint should make the correct context current. So, any 1810 // code which calls into GL or otherwise needs a current context *must* 1811 // go after beginPaint: 1812 d->device->beginPaint(); 1813 1814 #if !defined(QT_OPENGL_ES_2) 1815 bool success = qt_resolve_version_2_0_functions(d->ctx) 1816 && qt_resolve_buffer_extensions(d->ctx); 1817 Q_ASSERT(success); 1818 Q_UNUSED(success); 1819 #endif 1820 1821 d->shaderManager = new QGLEngineShaderManager(d->ctx); 1822 1823 glDisable(GL_STENCIL_TEST); 1022 1824 glDisable(GL_DEPTH_TEST); 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1023 1847 1024 1848 return true; … … 1028 1852 { 1029 1853 Q_D(QGL2PaintEngineEx); 1030 d->ctx->swapBuffers(); 1854 QGLContext *ctx = d->ctx; 1855 1856 glUseProgram(0); 1857 d->transferMode(BrushDrawingMode); 1858 d->device->endPaint(); 1859 1860 #if defined(Q_WS_X11) 1861 // On some (probably all) drivers, deleting an X pixmap which has been bound to a texture 1862 // before calling glFinish/swapBuffers renders garbage. Presumably this is because X deletes 1863 // the pixmap behind the driver's back before it's had a chance to use it. To fix this, we 1864 // reference all QPixmaps which have been bound to stop them being deleted and only deref 1865 // them here, after swapBuffers, where they can be safely deleted. 1866 ctx->d_func()->boundPixmaps.clear(); 1867 #endif 1868 d->ctx->d_ptr->active_engine = 0; 1869 1870 d->resetGLState(); 1871 1872 delete d->shaderManager; 1873 d->shaderManager = 0; 1874 1875 #ifdef QT_OPENGL_CACHE_AS_VBOS 1876 if (!d->unusedVBOSToClean.isEmpty()) { 1877 glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData()); 1878 d->unusedVBOSToClean.clear(); 1879 } 1880 #endif 1881 1031 1882 return false; 1032 1883 } 1033 1884 1034 1035 /////////////////////////////////// State/Clipping stolen from QOpenGLPaintEngine ////////////////////////////////////////// 1885 void QGL2PaintEngineEx::ensureActive() 1886 { 1887 Q_D(QGL2PaintEngineEx); 1888 QGLContext *ctx = d->ctx; 1889 1890 if (isActive() && ctx->d_ptr->active_engine != this) { 1891 ctx->d_ptr->active_engine = this; 1892 d->needsSync = true; 1893 } 1894 1895 d->device->ensureActiveTarget(); 1896 1897 if (d->needsSync) { 1898 d->transferMode(BrushDrawingMode); 1899 glViewport(0, 0, d->width, d->height); 1900 d->needsSync = false; 1901 d->shaderManager->setDirty(); 1902 setState(state()); 1903 } 1904 } 1905 1906 void QGL2PaintEngineExPrivate::updateClipScissorTest() 1907 { 1908 Q_Q(QGL2PaintEngineEx); 1909 if (q->state()->clipTestEnabled) { 1910 glEnable(GL_STENCIL_TEST); 1911 glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); 1912 } else { 1913 glDisable(GL_STENCIL_TEST); 1914 glStencilFunc(GL_ALWAYS, 0, 0xff); 1915 } 1916 1917 #ifdef QT_GL_NO_SCISSOR_TEST 1918 currentScissorBounds = QRect(0, 0, width, height); 1919 #else 1920 QRect bounds = q->state()->rectangleClip; 1921 if (!q->state()->clipEnabled) { 1922 if (useSystemClip) 1923 bounds = systemClip.boundingRect(); 1924 else 1925 bounds = QRect(0, 0, width, height); 1926 } else { 1927 if (useSystemClip) 1928 bounds = bounds.intersected(systemClip.boundingRect()); 1929 else 1930 bounds = bounds.intersected(QRect(0, 0, width, height)); 1931 } 1932 1933 currentScissorBounds = bounds; 1934 1935 if (bounds == QRect(0, 0, width, height)) { 1936 glDisable(GL_SCISSOR_TEST); 1937 } else { 1938 glEnable(GL_SCISSOR_TEST); 1939 setScissor(bounds); 1940 } 1941 #endif 1942 } 1943 1944 void QGL2PaintEngineExPrivate::setScissor(const QRect &rect) 1945 { 1946 const int left = rect.left(); 1947 const int width = rect.width(); 1948 const int bottom = height - (rect.top() + rect.height()); 1949 const int height = rect.height(); 1950 1951 glScissor(left, bottom, width, height); 1952 } 1036 1953 1037 1954 void QGL2PaintEngineEx::clipEnabledChanged() … … 1039 1956 Q_D(QGL2PaintEngineEx); 1040 1957 1041 d->updateDepthClip(); 1958 state()->clipChanged = true; 1959 1960 if (painter()->hasClipping()) 1961 d->regenerateClip(); 1962 else 1963 d->systemStateChanged(); 1964 } 1965 1966 void QGL2PaintEngineExPrivate::clearClip(uint value) 1967 { 1968 dirtyStencilRegion -= currentScissorBounds; 1969 1970 glStencilMask(0xff); 1971 glClearStencil(value); 1972 glClear(GL_STENCIL_BUFFER_BIT); 1973 glStencilMask(0x0); 1974 1975 q->state()->needsClipBufferClear = false; 1976 } 1977 1978 void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value) 1979 { 1980 transferMode(BrushDrawingMode); 1981 1982 if (addOffset) { 1983 addOffset = false; 1984 matrixDirty = true; 1985 } 1986 if (snapToPixelGrid) { 1987 snapToPixelGrid = false; 1988 matrixDirty = true; 1989 } 1990 1991 if (matrixDirty) 1992 updateMatrix(); 1993 1994 stencilClean = false; 1995 1996 const bool singlePass = !path.hasWindingFill() 1997 && (((q->state()->currentClip == maxClip - 1) && q->state()->clipTestEnabled) 1998 || q->state()->needsClipBufferClear); 1999 const uint referenceClipValue = q->state()->needsClipBufferClear ? 1 : q->state()->currentClip; 2000 2001 if (q->state()->needsClipBufferClear) 2002 clearClip(1); 2003 2004 if (path.isEmpty()) { 2005 glEnable(GL_STENCIL_TEST); 2006 glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT); 2007 return; 2008 } 2009 2010 if (q->state()->clipTestEnabled) 2011 glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); 2012 else 2013 glStencilFunc(GL_ALWAYS, 0, 0xff); 2014 2015 vertexCoordinateArray.clear(); 2016 vertexCoordinateArray.addPath(path, inverseScale, false); 2017 2018 if (!singlePass) 2019 fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); 2020 2021 glColorMask(false, false, false, false); 2022 glEnable(GL_STENCIL_TEST); 2023 useSimpleShader(); 2024 2025 if (singlePass) { 2026 // Under these conditions we can set the new stencil value in a single 2027 // pass, by using the current value and the "new value" as the toggles 2028 2029 glStencilFunc(GL_LEQUAL, referenceClipValue, ~GL_STENCIL_HIGH_BIT); 2030 glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); 2031 glStencilMask(value ^ referenceClipValue); 2032 2033 drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); 2034 } else { 2035 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); 2036 glStencilMask(0xff); 2037 2038 if (!q->state()->clipTestEnabled && path.hasWindingFill()) { 2039 // Pass when any clip bit is set, set high bit 2040 glStencilFunc(GL_NOTEQUAL, GL_STENCIL_HIGH_BIT, ~GL_STENCIL_HIGH_BIT); 2041 composite(vertexCoordinateArray.boundingRect()); 2042 } 2043 2044 // Pass when high bit is set, replace stencil value with new clip value 2045 glStencilFunc(GL_NOTEQUAL, value, GL_STENCIL_HIGH_BIT); 2046 2047 composite(vertexCoordinateArray.boundingRect()); 2048 } 2049 2050 glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT); 2051 glStencilMask(0); 2052 2053 glColorMask(true, true, true, true); 1042 2054 } 1043 2055 … … 1045 2057 { 1046 2058 // qDebug("QGL2PaintEngineEx::clip()"); 1047 const qreal *points = path.points();1048 const QPainterPath::ElementType *types = path.elements();1049 if (!types && path.shape() == QVectorPath::RectangleHint) {1050 QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);1051 updateClipRegion(QRegion(r.toRect()), op);1052 return;1053 }1054 1055 QPainterPath p;1056 if (types) {1057 int id = 0;1058 for (int i=0; i<path.elementCount(); ++i) {1059 switch(types[i]) {1060 case QPainterPath::MoveToElement:1061 p.moveTo(QPointF(points[id], points[id+1]));1062 id+=2;1063 break;1064 case QPainterPath::LineToElement:1065 p.lineTo(QPointF(points[id], points[id+1]));1066 id+=2;1067 break;1068 case QPainterPath::CurveToElement: {1069 QPointF p1(points[id], points[id+1]);1070 QPointF p2(points[id+2], points[id+3]);1071 QPointF p3(points[id+4], points[id+5]);1072 p.cubicTo(p1, p2, p3);1073 id+=6;1074 break;1075 }1076 case QPainterPath::CurveToDataElement:1077 ;1078 break;1079 }1080 }1081 } else if (!path.isEmpty()) {1082 p.moveTo(QPointF(points[0], points[1]));1083 int id = 2;1084 for (int i=1; i<path.elementCount(); ++i) {1085 p.lineTo(QPointF(points[id], points[id+1]));1086 id+=2;1087 }1088 }1089 if (path.hints() & QVectorPath::WindingFill)1090 p.setFillRule(Qt::WindingFill);1091 1092 updateClipRegion(QRegion(p.toFillPolygon().toPolygon(), p.fillRule()), op);1093 return;1094 }1095 1096 void QGL2PaintEngineEx::updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op)1097 {1098 // qDebug("QGL2PaintEngineEx::updateClipRegion()");1099 2059 Q_D(QGL2PaintEngineEx); 1100 2060 1101 QRegion sysClip = systemClip();1102 if (op == Qt::NoClip && !d->use_system_clip) { 1103 state()->hasClipping = false;1104 state()->clipRegion = QRegion(); 1105 d->updateDepthClip();1106 return;1107 }1108 1109 bool isScreenClip = false;1110 if (!d->use_system_clip) {1111 QVector<QRect> untransformedRects = clipRegion.rects();1112 1113 if (untransformedRects.size() == 1) { 1114 QPainterPath path;1115 path.addRect(untransformedRects[0]);1116 //path = d->matrix.map(path);1117 path = state()->matrix.map(path); 1118 1119 // if (path.contains(QRectF(QPointF(), d->drawable.size()))) 1120 // isScreenClip = true;1121 if (path.contains(QRectF(0.0, 0.0, d->width, d->height)))1122 isScreenClip = true;1123 1124 } 1125 1126 // QRegion region = isScreenClip ? QRegion() : clipRegion * d->matrix;1127 QRegion region = isScreenClip ? QRegion() : clipRegion * state()->matrix; 2061 ; 2062 2063 ; 2064 2065 2066 ; 2067 2068 d->systemStateChanged(); 2069 Clip = false; 2070 2071 2072 2073 #ifndef QT_GL_NO_SCISSOR_TEST 2074 2075 ); 2076 ); 2077 2078 if (state()->matrix.type() <= QTransform::TxScale) { 2079 state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect()); 2080 ; 2081 2082 2083 } 2084 #endif 2085 2086 ; 2087 1128 2088 switch (op) { 1129 2089 case Qt::NoClip: 1130 if (!d->use_system_clip) 1131 break; 1132 state()->clipRegion = sysClip; 2090 if (d->useSystemClip) { 2091 state()->clipTestEnabled = true; 2092 state()->currentClip = 1; 2093 } else { 2094 state()->clipTestEnabled = false; 2095 } 2096 state()->rectangleClip = QRect(0, 0, d->width, d->height); 2097 state()->canRestoreClip = false; 2098 d->updateClipScissorTest(); 1133 2099 break; 1134 2100 case Qt::IntersectClip: 1135 if (isScreenClip) 1136 return; 1137 if (state()->hasClipping) { 1138 state()->clipRegion &= region; 1139 break; 1140 } 1141 // fall through 1142 case Qt::ReplaceClip: 1143 if (d->use_system_clip && !sysClip.isEmpty()) 1144 state()->clipRegion = region & sysClip; 1145 else 1146 state()->clipRegion = region; 2101 state()->rectangleClip = state()->rectangleClip.intersected(pathRect); 2102 d->updateClipScissorTest(); 2103 d->resetClipIfNeeded(); 2104 ++d->maxClip; 2105 d->writeClip(path, d->maxClip); 2106 state()->currentClip = d->maxClip; 2107 state()->clipTestEnabled = true; 1147 2108 break; 1148 case Qt::UniteClip: 1149 state()->clipRegion |= region; 1150 if (d->use_system_clip && !sysClip.isEmpty()) 1151 state()->clipRegion &= sysClip; 2109 case Qt::UniteClip: { 2110 d->resetClipIfNeeded(); 2111 ++d->maxClip; 2112 if (state()->rectangleClip.isValid()) { 2113 QPainterPath path; 2114 path.addRect(state()->rectangleClip); 2115 2116 // flush the existing clip rectangle to the depth buffer 2117 d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(path)), d->maxClip); 2118 } 2119 2120 state()->clipTestEnabled = false; 2121 #ifndef QT_GL_NO_SCISSOR_TEST 2122 QRect oldRectangleClip = state()->rectangleClip; 2123 2124 state()->rectangleClip = state()->rectangleClip.united(pathRect); 2125 d->updateClipScissorTest(); 2126 2127 QRegion extendRegion = QRegion(state()->rectangleClip) - oldRectangleClip; 2128 2129 if (!extendRegion.isEmpty()) { 2130 QPainterPath extendPath; 2131 extendPath.addRegion(extendRegion); 2132 2133 // first clear the depth buffer in the extended region 2134 d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(extendPath)), 0); 2135 } 2136 #endif 2137 // now write the clip path 2138 d->writeClip(path, d->maxClip); 2139 state()->canRestoreClip = false; 2140 state()->currentClip = d->maxClip; 2141 state()->clipTestEnabled = true; 1152 2142 break; 2143 1153 2144 default: 1154 2145 break; 1155 2146 } 1156 1157 if (isScreenClip) { 1158 state()->hasClipping = false; 1159 state()->clipRegion = QRegion(); 2147 } 2148 2149 void QGL2PaintEngineExPrivate::regenerateClip() 2150 { 2151 systemStateChanged(); 2152 replayClipOperations(); 2153 } 2154 2155 void QGL2PaintEngineExPrivate::systemStateChanged() 2156 { 2157 Q_Q(QGL2PaintEngineEx); 2158 2159 q->state()->clipChanged = true; 2160 2161 if (systemClip.isEmpty()) { 2162 useSystemClip = false; 1160 2163 } else { 1161 state()->hasClipping = op != Qt::NoClip || d->use_system_clip; 1162 } 1163 1164 if (state()->hasClipping && state()->clipRegion.rects().size() == 1) 1165 state()->fastClip = state()->clipRegion.rects().at(0); 2164 if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) { 2165 QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window()); 2166 useSystemClip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter; 2167 } else { 2168 useSystemClip = true; 2169 } 2170 } 2171 2172 q->state()->clipTestEnabled = false; 2173 q->state()->needsClipBufferClear = true; 2174 2175 q->state()->currentClip = 1; 2176 maxClip = 1; 2177 2178 q->state()->rectangleClip = useSystemClip ? systemClip.boundingRect() : QRect(0, 0, width, height); 2179 updateClipScissorTest(); 2180 2181 if (systemClip.rectCount() == 1) { 2182 if (systemClip.boundingRect() == QRect(0, 0, width, height)) 2183 useSystemClip = false; 2184 #ifndef QT_GL_NO_SCISSOR_TEST 2185 // scissoring takes care of the system clip 2186 return; 2187 #endif 2188 } 2189 2190 if (useSystemClip) { 2191 clearClip(0); 2192 2193 QPainterPath path; 2194 path.addRegion(systemClip); 2195 2196 q->state()->currentClip = 0; 2197 writeClip(qtVectorPathForPath(q->state()->matrix.inverted().map(path)), 1); 2198 q->state()->currentClip = 1; 2199 q->state()->clipTestEnabled = true; 2200 } 2201 } 2202 2203 void QGL2PaintEngineEx::setState(QPainterState *new_state) 2204 { 2205 // qDebug("QGL2PaintEngineEx::setState()"); 2206 2207 Q_D(QGL2PaintEngineEx); 2208 2209 QOpenGL2PaintEngineState *s = static_cast<QOpenGL2PaintEngineState *>(new_state); 2210 QOpenGL2PaintEngineState *old_state = state(); 2211 2212 QPaintEngineEx::setState(s); 2213 2214 if (s->isNew) { 2215 // Newly created state object. The call to setState() 2216 // will either be followed by a call to begin(), or we are 2217 // setting the state as part of a save(). 2218 s->isNew = false; 2219 return; 2220 } 2221 2222 // Setting the state as part of a restore(). 2223 2224 if (old_state == s || old_state->renderHintsChanged) 2225 renderHintsChanged(); 2226 2227 if (old_state == s || old_state->matrixChanged) { 2228 d->matrixDirty = true; 2229 d->simpleShaderMatrixUniformDirty = true; 2230 d->shaderMatrixUniformDirty = true; 2231 } 2232 2233 if (old_state == s || old_state->compositionModeChanged) 2234 d->compositionModeDirty = true; 2235 2236 if (old_state == s || old_state->opacityChanged) 2237 d->opacityUniformDirty = true; 2238 2239 if (old_state == s || old_state->clipChanged) { 2240 if (old_state && old_state != s && old_state->canRestoreClip) { 2241 d->updateClipScissorTest(); 2242 glDepthFunc(GL_LEQUAL); 2243 } else { 2244 d->regenerateClip(); 2245 } 2246 } 2247 } 2248 2249 QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const 2250 { 2251 if (orig) 2252 const_cast<QGL2PaintEngineEx *>(this)->ensureActive(); 2253 2254 QOpenGL2PaintEngineState *s; 2255 if (!orig) 2256 s = new QOpenGL2PaintEngineState(); 1166 2257 else 1167 state()->fastClip = QRect(); 1168 1169 d->updateDepthClip(); 1170 } 1171 1172 1173 void QGL2PaintEngineExPrivate::updateDepthClip() 1174 { 1175 // qDebug("QGL2PaintEngineExPrivate::updateDepthClip()"); 1176 1177 Q_Q(QGL2PaintEngineEx); 1178 1179 glDisable(GL_DEPTH_TEST); 1180 glDisable(GL_SCISSOR_TEST); 1181 1182 if (!q->state()->hasClipping) 1183 return; 1184 1185 QRect fastClip; 1186 if (q->state()->clipEnabled) { 1187 fastClip = q->state()->fastClip; 1188 } else if (use_system_clip && q->systemClip().rects().count() == 1) { 1189 fastClip = q->systemClip().rects().at(0); 1190 } 1191 1192 if (!fastClip.isEmpty()) { 1193 glEnable(GL_SCISSOR_TEST); 1194 1195 const int left = fastClip.left(); 1196 const int width = fastClip.width(); 1197 const int bottom = height - (fastClip.bottom() + 1); 1198 const int height = fastClip.height(); 1199 1200 glScissor(left, bottom, width, height); 1201 return; 1202 } 1203 1204 glClearDepthf(0x0); 1205 glDepthMask(true); 1206 glClear(GL_DEPTH_BUFFER_BIT); 1207 glClearDepthf(0x1); 1208 1209 const QVector<QRect> rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects(); 1210 glEnable(GL_SCISSOR_TEST); 1211 for (int i = 0; i < rects.size(); ++i) { 1212 QRect rect = rects.at(i); 1213 1214 const int left = rect.left(); 1215 const int width = rect.width(); 1216 const int bottom = height - (rect.bottom() + 1); 1217 const int height = rect.height(); 1218 1219 glScissor(left, bottom, width, height); 1220 1221 glClear(GL_DEPTH_BUFFER_BIT); 1222 } 1223 glDisable(GL_SCISSOR_TEST); 1224 1225 glDepthMask(false); 1226 glDepthFunc(GL_LEQUAL); 1227 glEnable(GL_DEPTH_TEST); 1228 } 1229 1230 1231 1232 void QGL2PaintEngineEx::setState(QPainterState *s) 1233 { 1234 // qDebug("QGL2PaintEngineEx::setState()"); 1235 1236 Q_D(QGL2PaintEngineEx); 1237 QPaintEngineEx::setState(s); 1238 1239 d->updateDepthClip(); 1240 1241 d->matrixDirty = true; 1242 d->compositionModeDirty = true; 1243 d->brushTextureDirty = true; 1244 d->brushUniformsDirty = true; 1245 d->simpleShaderMatrixUniformDirty = true; 1246 d->brushShaderMatrixUniformDirty = true; 1247 d->imageShaderMatrixUniformDirty = true; 1248 d->textShaderMatrixUniformDirty = true; 1249 } 1250 1251 QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const 1252 { 1253 QOpenGLPaintEngineState *s; 1254 if (!orig) 1255 s = new QOpenGLPaintEngineState(); 1256 else 1257 s = new QOpenGLPaintEngineState(*static_cast<QOpenGLPaintEngineState *>(orig)); 2258 s = new QOpenGL2PaintEngineState(*static_cast<QOpenGL2PaintEngineState *>(orig)); 2259 2260 s->matrixChanged = false; 2261 s->compositionModeChanged = false; 2262 s->opacityChanged = false; 2263 s->renderHintsChanged = false; 2264 s->clipChanged = false; 1258 2265 1259 2266 return s; 1260 2267 } 1261 2268 1262 QOpenGL PaintEngineState::QOpenGLPaintEngineState(QOpenGLPaintEngineState &other)2269 QOpenGLPaintEngineState &other) 1263 2270 : QPainterState(other) 1264 2271 { 1265 clipRegion = other.clipRegion; 1266 hasClipping = other.hasClipping; 1267 fastClip = other.fastClip; 1268 } 1269 1270 QOpenGLPaintEngineState::QOpenGLPaintEngineState() 1271 { 1272 hasClipping = false; 1273 } 1274 1275 QOpenGLPaintEngineState::~QOpenGLPaintEngineState() 1276 { 1277 } 1278 2272 isNew = true; 2273 needsClipBufferClear = other.needsClipBufferClear; 2274 clipTestEnabled = other.clipTestEnabled; 2275 currentClip = other.currentClip; 2276 canRestoreClip = other.canRestoreClip; 2277 rectangleClip = other.rectangleClip; 2278 } 2279 2280 QOpenGL2PaintEngineState::QOpenGL2PaintEngineState() 2281 { 2282 isNew = true; 2283 needsClipBufferClear = true; 2284 clipTestEnabled = false; 2285 canRestoreClip = true; 2286 } 2287 2288 QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() 2289 { 2290 } 2291 2292 QT_END_NAMESPACE 2293 2294 #include "qpaintengineex_opengl2.moc" -
trunk/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information ([email protected]) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation ([email protected]) 5 6 ** 6 7 ** This file is part of the QtOpenGL module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you 37 ** @nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 54 54 // 55 55 56 57 56 58 #include <private/qpaintengineex_p.h> 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 57 75 58 76 class QGL2PaintEngineExPrivate; 59 77 60 78 61 class QOpenGL PaintEngineState : public QPainterState79 class QOpenGLPaintEngineState : public QPainterState 62 80 { 63 81 public: 64 QOpenGLPaintEngineState(QOpenGLPaintEngineState &other); 65 QOpenGLPaintEngineState(); 66 ~QOpenGLPaintEngineState(); 67 68 QRegion clipRegion; 69 bool hasClipping; 70 QRect fastClip; 71 }; 72 73 74 class QGL2PaintEngineEx : public QPaintEngineEx 82 QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other); 83 QOpenGL2PaintEngineState(); 84 ~QOpenGL2PaintEngineState(); 85 86 uint isNew : 1; 87 uint needsClipBufferClear : 1; 88 uint clipTestEnabled : 1; 89 uint canRestoreClip : 1; 90 uint matrixChanged : 1; 91 uint compositionModeChanged : 1; 92 uint opacityChanged : 1; 93 uint renderHintsChanged : 1; 94 uint clipChanged : 1; 95 uint currentClip : 8; 96 97 QRect rectangleClip; 98 }; 99 100 class Q_OPENGL_EXPORT QGL2PaintEngineEx : public QPaintEngineEx 75 101 { 76 102 Q_DECLARE_PRIVATE(QGL2PaintEngineEx) … … 80 106 81 107 bool begin(QPaintDevice *device); 108 82 109 bool end(); 83 84 virtual void fill(const QVectorPath &path, const QBrush &brush);85 virtual void stroke(const QVectorPath &path, const QPen &pen);86 virtual void clip(const QVectorPath &path, Qt::ClipOperation op);87 110 88 111 virtual void clipEnabledChanged(); … … 95 118 virtual void transformChanged(); 96 119 97 120 virtual void drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr); 98 121 virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); 99 122 virtual void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints); 100 123 virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, 101 124 Qt::ImageConversionFlags flags = Qt::AutoColor); 102 125 virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); 103 void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti); 104 105 Type type() const { return OpenGL; } 106 107 108 // State stuff is just for clipping and ripped off from QGLPaintEngine 109 void setState(QPainterState *s); 110 QPainterState *createState(QPainterState *orig) const; 111 inline QOpenGLPaintEngineState *state() { 112 return static_cast<QOpenGLPaintEngineState *>(QPaintEngineEx::state()); 113 } 114 inline const QOpenGLPaintEngineState *state() const { 115 return static_cast<const QOpenGLPaintEngineState *>(QPaintEngineEx::state()); 116 } 117 void updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op); 126 virtual void fill(const QVectorPath &path, const QBrush &brush); 127 virtual void stroke(const QVectorPath &path, const QPen &pen); 128 virtual void clip(const QVectorPath &path, Qt::ClipOperation op); 129 130 131 Type type() const { return OpenGL2; } 132 133 virtual void setState(QPainterState *s); 134 virtual QPainterState *createState(QPainterState *orig) const; 135 inline QOpenGL2PaintEngineState *state() { 136 return static_cast<QOpenGL2PaintEngineState *>(QPaintEngineEx::state()); 137 } 138 inline const QOpenGL2PaintEngineState *state() const { 139 return static_cast<const QOpenGL2PaintEngineState *>(QPaintEngineEx::state()); 140 } 141 142 void beginNativePainting(); 143 void endNativePainting(); 144 145 QPixmapFilter *pixmapFilter(int type, const QPixmapFilter *prototype); 146 147 void setRenderTextActive(bool); 118 148 119 149 private: … … 122 152 123 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 124 291 125 292 #endif
Note:
See TracChangeset
for help on using the changeset viewer.