From 033725f5947d4a4e0c21f426664851b42b164d08 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= <trond@trolltech.com>
Date: Fri, 28 Aug 2009 13:28:43 +0200
Subject: Fixed QGLWidget::renderText() when using the GL 2 paint engine.

QGLWidget::renderText() needs to respect the current depth and scissor
tests that the user has set. Therefore we needs some special casing in
the GL 2 paint engine to handle the custom depth testing. The private
setRenderTextActive() has been added for this purpose.

Reviewed-by: Samuel
---
 .../gl2paintengineex/qpaintengineex_opengl2.cpp    | 85 +++++++++++++++++-----
 .../gl2paintengineex/qpaintengineex_opengl2_p.h    |  8 +-
 src/opengl/qgl.cpp                                 | 36 ++++++++-
 src/opengl/qglframebufferobject.cpp                |  2 +-
 4 files changed, 108 insertions(+), 23 deletions(-)

diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index cc9b014..b5a6b1f 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -219,6 +219,11 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
 
     pex->transferMode(BrushDrawingMode);
 
+#ifndef QT_OPENGL_ES_2
+    if (pex->inRenderText)
+        glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_SCISSOR_BIT);
+#endif
+
     glDisable(GL_DEPTH_TEST);
     glDisable(GL_SCISSOR_TEST);
 
@@ -268,6 +273,11 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
 
     glViewport(0, 0, pex->width, pex->height);
     pex->updateDepthScissorTest();
+
+#ifndef QT_OPENGL_ES_2
+    if (pex->inRenderText)
+        glPopAttrib();
+#endif
 }
 
 void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
@@ -836,6 +846,11 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
 
         glEnable(GL_STENCIL_TEST);
         prepareForDraw(currentBrush->isOpaque());
+
+#ifndef QT_OPENGL_ES_2
+        if (inRenderText)
+            shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Depth), zValueForRenderText());
+#endif
         composite(vertexCoordinateArray.boundingRect());
         glDisable(GL_STENCIL_TEST);
 
@@ -873,9 +888,21 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve
     glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
     glDisable(GL_BLEND);
 
+#ifndef QT_OPENGL_ES_2
+    if (inRenderText) {
+        glPushAttrib(GL_ENABLE_BIT);
+        glDisable(GL_DEPTH_TEST);
+    }
+#endif
+
     // Draw the vertecies into the stencil buffer:
     drawVertexArrays(vertexArray, GL_TRIANGLE_FAN);
 
+#ifndef QT_OPENGL_ES_2
+    if (inRenderText)
+        glPopAttrib();
+#endif
+
     // Enable color writes & disable stencil writes
     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 }
@@ -981,9 +1008,19 @@ void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray,
     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
 }
 
-
-
-
+float QGL2PaintEngineExPrivate::zValueForRenderText() const
+{
+#ifndef QT_OPENGL_ES_2
+    // Get the z translation value from the model view matrix and
+    // transform it using the ortogonal projection with z-near = 0,
+    // and z-far = 1, which is used in QGLWidget::renderText()
+    GLdouble model[4][4];
+    glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
+    return -2 * model[3][2] - 1;
+#else
+    return 0;
+#endif
+}
 
 /////////////////////////////////// Public Methods //////////////////////////////////////////
 
@@ -1002,8 +1039,8 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush)
 
     if (brush.style() == Qt::NoBrush)
         return;
-
-    ensureActive();
+    if (!d->inRenderText)
+        ensureActive();
     d->setBrush(&brush);
     d->fill(path);
     d->setBrush(&(state()->brush)); // reset back to the state's brush
@@ -1154,7 +1191,8 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem
 {
     Q_D(QGL2PaintEngineEx);
 
-    ensureActive();
+    if (!d->inRenderText)
+        ensureActive();
     QOpenGL2PaintEngineState *s = state();
 
     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
@@ -1203,6 +1241,8 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextIte
     if (cache->width() == 0 || cache->height() == 0)
         return;
 
+    if (inRenderText)
+        transferMode(BrushDrawingMode);
     transferMode(TextDrawingMode);
 
     if (glyphType == QFontEngineGlyphCache::Raster_A8)
@@ -1241,6 +1281,11 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextIte
 
     prepareForDraw(false); // Text always causes src pixels to be transparent
 
+#ifndef QT_OPENGL_ES_2
+    if (inRenderText)
+        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Depth), zValueForRenderText());
+#endif
+
     shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
 
     if (vertexCoordinateArray.data() != oldVertexCoordinateDataPtr)
@@ -1286,12 +1331,6 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
 
     glViewport(0, 0, d->width, d->height);
 
-//     glClearColor(0.0, 1.0, 0.0, 1.0);
-//     glClear(GL_COLOR_BUFFER_BIT);
-//     d->ctx->swapBuffers();
-//     qDebug("You should see green now");
-//     sleep(5);
-
     d->brushTextureDirty = true;
     d->brushUniformsDirty = true;
     d->matrixDirty = true;
@@ -1304,10 +1343,12 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
 
     d->use_system_clip = !systemClip().isEmpty();
 
-    glDisable(GL_DEPTH_TEST);
-    glDisable(GL_SCISSOR_TEST);
-    glDepthFunc(GL_LEQUAL);
-    glDepthMask(false);
+    if (!d->inRenderText) {
+        glDisable(GL_DEPTH_TEST);
+        glDisable(GL_SCISSOR_TEST);
+        glDepthFunc(GL_LEQUAL);
+        glDepthMask(false);
+    }
 
 #if !defined(QT_OPENGL_ES_2)
     glDisable(GL_MULTISAMPLE);
@@ -1612,7 +1653,11 @@ void QGL2PaintEngineExPrivate::regenerateDepthClip()
 void QGL2PaintEngineExPrivate::systemStateChanged()
 {
     Q_Q(QGL2PaintEngineEx);
-    use_system_clip = !systemClip.isEmpty();
+
+    if (q->paintDevice()->devType() == QInternal::Widget)
+        use_system_clip = false;
+    else
+        use_system_clip = !systemClip.isEmpty();
 
     glDisable(GL_DEPTH_TEST);
     q->state()->depthTestEnabled = false;
@@ -1728,6 +1773,12 @@ QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const
     return s;
 }
 
+void QGL2PaintEngineEx::setRenderTextActive(bool active)
+{
+    Q_D(QGL2PaintEngineEx);
+    d->inRenderText = active;
+}
+
 QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other)
     : QPainterState(other)
 {
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 66e7a51..68447bc 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -141,6 +141,8 @@ public:
 
     QPixmapFilter *createPixmapFilter(int type) const;
 
+    void setRenderTextActive(bool);
+
 private:
     Q_DISABLE_COPY(QGL2PaintEngineEx)
 };
@@ -156,7 +158,8 @@ public:
             ctx(0),
             currentBrush(0),
             inverseScale(1),
-            shaderManager(0)
+            shaderManager(0),
+            inRenderText(false)
     { }
 
     ~QGL2PaintEngineExPrivate();
@@ -191,6 +194,8 @@ public:
     inline void useSimpleShader();
     inline QColor premultiplyColor(QColor c, GLfloat opacity);
 
+    float zValueForRenderText() const;
+
     QGL2PaintEngineEx* q;
     QGLDrawable drawable;
     int width, height;
@@ -240,6 +245,7 @@ public:
     GLuint lastTexture;
 
     bool needsSync;
+    bool inRenderText;
 };
 
 QT_END_NAMESPACE
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 8cf3b45..4324371 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -1666,7 +1666,6 @@ QGLContext::QGLContext(const QGLFormat &format)
 
 QGLContext::~QGLContext()
 {
-    Q_D(QGLContext);
     // remove any textures cached in this context
     QGLTextureCache::instance()->removeContextTextures(this);
     QGLTextureCache::deleteIfEmpty(); // ### thread safety
@@ -4073,6 +4072,10 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
     bool auto_swap = autoBufferSwap();
 
     QPaintEngine *engine = paintEngine();
+#ifndef QT_OPENGL_ES
+    if (engine->type() == QPaintEngine::OpenGL2)
+        static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
+#endif
     QPainter *p;
     bool reuse_painter = false;
     if (engine->isActive()) {
@@ -4098,6 +4101,13 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
         setAutoBufferSwap(false);
         // disable glClear() as a result of QPainter::begin()
         d->glcx->d_func()->clear_on_painter_begin = false;
+        if (engine->type() == QPaintEngine::OpenGL2) {
+            qt_save_gl_state();
+#ifndef QT_OPENGL_ES_2
+            glMatrixMode(GL_MODELVIEW);
+            glLoadIdentity();
+#endif
+        }
         p = new QPainter(this);
     }
 
@@ -4121,7 +4131,13 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
         delete p;
         setAutoBufferSwap(auto_swap);
         d->glcx->d_func()->clear_on_painter_begin = true;
+        if (engine->type() == QPaintEngine::OpenGL2)
+            qt_restore_gl_state();
     }
+#ifndef QT_OPENGL_ES
+    if (engine->type() == QPaintEngine::OpenGL2)
+        static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+#endif
 }
 
 /*! \overload
@@ -4154,6 +4170,10 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
     win_y = height - win_y; // y is inverted
 
     QPaintEngine *engine = paintEngine();
+#ifndef QT_OPENGL_ES
+    if (engine->type() == QPaintEngine::OpenGL2)
+        static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
+#endif
     QPainter *p;
     bool reuse_painter = false;
 #ifndef QT_OPENGL_ES
@@ -4172,6 +4192,8 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
         setAutoBufferSwap(false);
         // disable glClear() as a result of QPainter::begin()
         d->glcx->d_func()->clear_on_painter_begin = false;
+        if (engine->type() == QPaintEngine::OpenGL2)
+            qt_save_gl_state();
         p = new QPainter(this);
     }
 
@@ -4210,9 +4232,15 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
     } else {
         p->end();
         delete p;
+        if (engine->type() == QPaintEngine::OpenGL2)
+            qt_restore_gl_state();
         setAutoBufferSwap(auto_swap);
         d->glcx->d_func()->clear_on_painter_begin = true;
     }
+#ifndef QT_OPENGL_ES
+    if (engine->type() == QPaintEngine::OpenGL2)
+        static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+#endif
 }
 
 QGLFormat QGLWidget::format() const
@@ -4443,10 +4471,10 @@ QPaintEngine *QGLWidget::paintEngine() const
 #elif defined(QT_OPENGL_ES_2)
     return qt_gl_2_engine();
 #else
-    if (!qt_gl_preferGL2Engine())
-        return qt_gl_engine();
-    else
+    if (qt_gl_preferGL2Engine())
         return qt_gl_2_engine();
+    else
+        return qt_gl_engine();
 #endif
 }
 
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index 0db5659..2b38e3d 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -896,7 +896,7 @@ QPaintEngine *QGLFramebufferObject::paintEngine() const
     return qt_buffer_2_engine();
 #else
     Q_D(const QGLFramebufferObject);
-    if (d->ctx->d_func()->internal_context || qt_gl_preferGL2Engine())
+    if (qt_gl_preferGL2Engine())
         return qt_buffer_2_engine();
     else
         return qt_buffer_engine();
-- 
cgit v0.12