| 1 | /**************************************************************************** | 
|---|
| 2 | ** | 
|---|
| 3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). | 
|---|
| 4 | ** All rights reserved. | 
|---|
| 5 | ** Contact: Nokia Corporation (qt-info@nokia.com) | 
|---|
| 6 | ** | 
|---|
| 7 | ** This file is part of the documentation of the Qt Toolkit. | 
|---|
| 8 | ** | 
|---|
| 9 | ** $QT_BEGIN_LICENSE:LGPL$ | 
|---|
| 10 | ** Commercial Usage | 
|---|
| 11 | ** Licensees holding valid Qt Commercial licenses may use this file in | 
|---|
| 12 | ** accordance with the Qt Commercial License Agreement provided with the | 
|---|
| 13 | ** Software or, alternatively, in accordance with the terms contained in | 
|---|
| 14 | ** a written agreement between you and Nokia. | 
|---|
| 15 | ** | 
|---|
| 16 | ** GNU Lesser General Public License Usage | 
|---|
| 17 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
|---|
| 18 | ** General Public License version 2.1 as published by the Free Software | 
|---|
| 19 | ** Foundation and appearing in the file LICENSE.LGPL included in the | 
|---|
| 20 | ** packaging of this file.  Please review the following information to | 
|---|
| 21 | ** ensure the GNU Lesser General Public License version 2.1 requirements | 
|---|
| 22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | 
|---|
| 23 | ** | 
|---|
| 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 | ** | 
|---|
| 28 | ** GNU General Public License Usage | 
|---|
| 29 | ** Alternatively, this file may be used under the terms of the GNU | 
|---|
| 30 | ** General Public License version 3.0 as published by the Free Software | 
|---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL included in the | 
|---|
| 32 | ** packaging of this file.  Please review the following information to | 
|---|
| 33 | ** ensure the GNU General Public License version 3.0 requirements will be | 
|---|
| 34 | ** met: http://www.gnu.org/copyleft/gpl.html. | 
|---|
| 35 | ** | 
|---|
| 36 | ** If you have questions regarding the use of this file, please contact | 
|---|
| 37 | ** Nokia at qt-info@nokia.com. | 
|---|
| 38 | ** $QT_END_LICENSE$ | 
|---|
| 39 | ** | 
|---|
| 40 | ****************************************************************************/ | 
|---|
| 41 |  | 
|---|
| 42 | /*! | 
|---|
| 43 | \example opengl/overpainting | 
|---|
| 44 | \title Overpainting Example | 
|---|
| 45 |  | 
|---|
| 46 | The Overpainting example shows how QPainter can be used | 
|---|
| 47 | to overpaint a scene rendered using OpenGL in a QGLWidget. | 
|---|
| 48 |  | 
|---|
| 49 | \image overpainting-example.png | 
|---|
| 50 |  | 
|---|
| 51 | QGLWidget provides a widget with integrated OpenGL graphics support | 
|---|
| 52 | that enables 3D graphics to be displayed using normal OpenGL calls, | 
|---|
| 53 | yet also behaves like any other standard Qt widget with support for | 
|---|
| 54 | signals and slots, properties, and Qt's action system. | 
|---|
| 55 |  | 
|---|
| 56 | Usually, QGLWidget is subclassed to display a pure 3D scene.  The | 
|---|
| 57 | developer reimplements \l{QGLWidget::initializeGL()}{initializeGL()} | 
|---|
| 58 | to initialize any required resources, \l{QGLWidget::resizeGL()}{resizeGL()} | 
|---|
| 59 | to set up the projection and viewport, and | 
|---|
| 60 | \l{QGLWidget::paintGL()}{paintGL()} to perform the OpenGL calls needed | 
|---|
| 61 | to render the scene. However, it is possible to subclass QGLWidget | 
|---|
| 62 | differently to allow 2D graphics, drawn using QPainter, to be | 
|---|
| 63 | painted over a scene rendered using OpenGL. | 
|---|
| 64 |  | 
|---|
| 65 | In this example, we demonstrate how this is done by reusing the code | 
|---|
| 66 | from the \l{Hello GL Example}{Hello GL} example to provide a 3D scene, | 
|---|
| 67 | and painting over it with some translucent 2D graphics. Instead of | 
|---|
| 68 | examining each class in detail, we only cover the parts of the | 
|---|
| 69 | \c GLWidget class that enable overpainting, and provide more detailed | 
|---|
| 70 | discussion in the final section of this document. | 
|---|
| 71 |  | 
|---|
| 72 | \section1 GLWidget Class Definition | 
|---|
| 73 |  | 
|---|
| 74 | The \c GLWidget class is a subclass of QGLWidget, based on the one used | 
|---|
| 75 | in the \l{Hello GL Example}{Hello GL} example. Rather than describe the | 
|---|
| 76 | class as a whole, we show the first few lines of the class and only | 
|---|
| 77 | discuss the changes we have made to the rest of it: | 
|---|
| 78 |  | 
|---|
| 79 | \snippet examples/opengl/overpainting/glwidget.h 0 | 
|---|
| 80 | \dots | 
|---|
| 81 | \snippet examples/opengl/overpainting/glwidget.h 1 | 
|---|
| 82 | \dots | 
|---|
| 83 | \snippet examples/opengl/overpainting/glwidget.h 4 | 
|---|
| 84 |  | 
|---|
| 85 | As usual, the widget uses \l{QGLWidget::initializeGL()}{initializeGL()} | 
|---|
| 86 | to set up geometry for our scene and perform OpenGL initialization tasks. | 
|---|
| 87 | The \l{QGLWidget::resizeGL()}{resizeGL()} function is used to ensure that | 
|---|
| 88 | the 3D graphics in the scene are transformed correctly to the 2D viewport | 
|---|
| 89 | displayed in the widget. | 
|---|
| 90 |  | 
|---|
| 91 | Instead of implementing \l{QGLWidget::paintGL()}{paintGL()} to handle updates | 
|---|
| 92 | to the widget, we implement a normal QWidget::paintEvent(). This | 
|---|
| 93 | allows us to mix OpenGL calls and QPainter operations in a controlled way. | 
|---|
| 94 |  | 
|---|
| 95 | In this example, we also implement QWidget::showEvent() to help with the | 
|---|
| 96 | initialization of the 2D graphics used. | 
|---|
| 97 |  | 
|---|
| 98 | The new private member functions and variables relate exclusively to the | 
|---|
| 99 | 2D graphics and animation. The \c animate() slot is called periodically by the | 
|---|
| 100 | \c animationTimer to update the widget; the \c createBubbles() function | 
|---|
| 101 | initializes the \c bubbles list with instances of a helper class used to | 
|---|
| 102 | draw the animation; the \c drawInstructions() function is responsible for | 
|---|
| 103 | a semi-transparent message that is also overpainted onto the OpenGL scene. | 
|---|
| 104 |  | 
|---|
| 105 | \section1 GLWidget Class Implementation | 
|---|
| 106 |  | 
|---|
| 107 | Again, we only show the parts of the \c GLWidget implementation that are | 
|---|
| 108 | relevant to this example. In the constructor, we initialize a QTimer to | 
|---|
| 109 | control the animation: | 
|---|
| 110 |  | 
|---|
| 111 | \snippet examples/opengl/overpainting/glwidget.cpp 0 | 
|---|
| 112 |  | 
|---|
| 113 | We turn off the widget's \l{QWidget::autoFillBackground}{autoFillBackground} property to | 
|---|
| 114 | instruct OpenGL not to paint a background for the widget when | 
|---|
| 115 | \l{QPainter::begin()}{QPainter::begin()} is called. | 
|---|
| 116 |  | 
|---|
| 117 | As in the \l{Hello GL Example}{Hello GL} example, the destructor is responsible | 
|---|
| 118 | for freeing any OpenGL-related resources: | 
|---|
| 119 |  | 
|---|
| 120 | \snippet examples/opengl/overpainting/glwidget.cpp 1 | 
|---|
| 121 |  | 
|---|
| 122 | The \c initializeGL() function is fairly minimal, only setting up the QtLogo | 
|---|
| 123 | object used in the scene.  See the \l{Hello GL Example}{Hello GL} example | 
|---|
| 124 | for details of the QtLogo class. | 
|---|
| 125 |  | 
|---|
| 126 | \snippet examples/opengl/overpainting/glwidget.cpp 2 | 
|---|
| 127 |  | 
|---|
| 128 | To cooperate fully with QPainter, we defer matrix stack operations and attribute | 
|---|
| 129 | initialization until the widget needs to be updated. | 
|---|
| 130 |  | 
|---|
| 131 | In this example, we implement \l{QWidget::paintEvent()}{paintEvent()} rather | 
|---|
| 132 | than \l{QGLWidget::paintGL()}{paintGL()} to render | 
|---|
| 133 | our scene. When drawing on a QGLWidget, the paint engine used by QPainter | 
|---|
| 134 | performs certain operations that change the states of the OpenGL | 
|---|
| 135 | implementation's matrix and property stacks. Therefore, it is necessary to | 
|---|
| 136 | make all the OpenGL calls to display the 3D graphics before we construct | 
|---|
| 137 | a QPainter to draw the 2D overlay. | 
|---|
| 138 |  | 
|---|
| 139 | We render a 3D scene by setting up model and projection transformations | 
|---|
| 140 | and other attributes. We use an OpenGL stack operation to preserve the | 
|---|
| 141 | original matrix state, allowing us to recover it later: | 
|---|
| 142 |  | 
|---|
| 143 | \snippet examples/opengl/overpainting/glwidget.cpp 4 | 
|---|
| 144 |  | 
|---|
| 145 | We define a color to use for the widget's background, and set up various | 
|---|
| 146 | attributes that define how the scene will be rendered. | 
|---|
| 147 |  | 
|---|
| 148 | \snippet examples/opengl/overpainting/glwidget.cpp 6 | 
|---|
| 149 |  | 
|---|
| 150 | We call the \c setupViewport() private function to set up the | 
|---|
| 151 | projection used for the scene. This is unnecessary in OpenGL | 
|---|
| 152 | examples that implement the \l{QGLWidget::paintGL()}{paintGL()} | 
|---|
| 153 | function because the matrix stacks are usually unmodified between | 
|---|
| 154 | calls to \l{QGLWidget::resizeGL()}{resizeGL()} and | 
|---|
| 155 | \l{QGLWidget::paintGL()}{paintGL()}. | 
|---|
| 156 |  | 
|---|
| 157 | Since the widget's background is not drawn by the system or by Qt, we use | 
|---|
| 158 | an OpenGL call to paint it before positioning the object defined earlier | 
|---|
| 159 | in the scene: | 
|---|
| 160 |  | 
|---|
| 161 | \snippet examples/opengl/overpainting/glwidget.cpp 7 | 
|---|
| 162 |  | 
|---|
| 163 | Once the QtLogo object's draw method has been executed, the GL | 
|---|
| 164 | states we changed and the matrix stack needs to be restored to its | 
|---|
| 165 | original state at the start of this function before we can begin | 
|---|
| 166 | overpainting: | 
|---|
| 167 |  | 
|---|
| 168 | \snippet examples/opengl/overpainting/glwidget.cpp 8 | 
|---|
| 169 |  | 
|---|
| 170 | With the 3D graphics done, we construct a QPainter for use on the widget | 
|---|
| 171 | and simply overpaint the widget with 2D graphics; in this case, using a | 
|---|
| 172 | helper class to draw a number of translucent bubbles onto the widget, | 
|---|
| 173 | and calling \c drawInstructions() to overlay some instructions: | 
|---|
| 174 |  | 
|---|
| 175 | \snippet examples/opengl/overpainting/glwidget.cpp 10 | 
|---|
| 176 |  | 
|---|
| 177 | When QPainter::end() is called, suitable OpenGL-specific calls are made to | 
|---|
| 178 | write the scene, and its additional contents, onto the widget. | 
|---|
| 179 |  | 
|---|
| 180 | With \l{QGLWidget::paintGL()}{paintGL()} the | 
|---|
| 181 | \l{QGLWidget::swapBuffers()}{swapBuffers()} call is done for us.  But an explicit | 
|---|
| 182 | call to swapBuffers() is still not required because in the | 
|---|
| 183 | \l{QWidget::paintEvent()}{paintEvent()} method the QPainter on the OpenGL | 
|---|
| 184 | widget takes care of this for us. | 
|---|
| 185 |  | 
|---|
| 186 | The implementation of the \l{QGLWidget::resizeGL()}{resizeGL()} function | 
|---|
| 187 | sets up the dimensions of the viewport and defines a projection | 
|---|
| 188 | transformation: | 
|---|
| 189 |  | 
|---|
| 190 | \snippet examples/opengl/overpainting/glwidget.cpp 11 | 
|---|
| 191 |  | 
|---|
| 192 | Ideally, we want to arrange the 2D graphics to suit the widget's dimensions. | 
|---|
| 193 | To achieve this, we implement the \l{QWidget::showEvent()}{showEvent()} handler, | 
|---|
| 194 | creating new graphic elements (bubbles) if necessary at appropriate positions | 
|---|
| 195 | in the widget. | 
|---|
| 196 |  | 
|---|
| 197 | \snippet examples/opengl/overpainting/glwidget.cpp 12 | 
|---|
| 198 |  | 
|---|
| 199 | This function only has an effect if less than 20 bubbles have already been | 
|---|
| 200 | created. | 
|---|
| 201 |  | 
|---|
| 202 | The \c animate() slot is called every time the widget's \c animationTimer emits | 
|---|
| 203 | the \l{QTimer::timeout()}{timeout()} signal. This keeps the bubbles moving | 
|---|
| 204 | around. | 
|---|
| 205 |  | 
|---|
| 206 | \snippet examples/opengl/overpainting/glwidget.cpp 13 | 
|---|
| 207 |  | 
|---|
| 208 | We simply iterate over the bubbles in the \c bubbles list, updating the | 
|---|
| 209 | widget before and after each of them is moved. | 
|---|
| 210 |  | 
|---|
| 211 | The \c setupViewport() function is called from \c paintEvent() | 
|---|
| 212 | and \c resizeGL(). | 
|---|
| 213 |  | 
|---|
| 214 | \snippet examples/opengl/overpainting/glwidget.cpp 14 | 
|---|
| 215 |  | 
|---|
| 216 | The \c drawInstructions() function is used to prepare some basic | 
|---|
| 217 | instructions that will be painted with the other 2D graphics over | 
|---|
| 218 | the 3D scene. | 
|---|
| 219 |  | 
|---|
| 220 | \snippet examples/opengl/overpainting/glwidget.cpp 15 | 
|---|
| 221 |  | 
|---|
| 222 | \section1 Summary | 
|---|
| 223 |  | 
|---|
| 224 | When overpainting 2D content onto 3D content, we need to use a QPainter | 
|---|
| 225 | \e and make OpenGL calls to achieve the desired effect. Since QPainter | 
|---|
| 226 | itself uses OpenGL calls when used on a QGLWidget subclass, we need to | 
|---|
| 227 | preserve the state of various OpenGL stacks when we perform our own | 
|---|
| 228 | calls, using the following approach: | 
|---|
| 229 |  | 
|---|
| 230 | \list | 
|---|
| 231 | \o Reimplement QGLWidget::initializeGL(), but only perform minimal | 
|---|
| 232 | initialization. QPainter will perform its own initialization | 
|---|
| 233 | routines, modifying the matrix and property stacks, so it is better | 
|---|
| 234 | to defer certain initialization tasks until just before you render | 
|---|
| 235 | the 3D scene. | 
|---|
| 236 | \o Reimplement QGLWidget::resizeGL() as in the pure 3D case. | 
|---|
| 237 | \o Reimplement QWidget::paintEvent() to draw both 2D and 3D graphics. | 
|---|
| 238 | \endlist | 
|---|
| 239 |  | 
|---|
| 240 | The \l{QWidget::paintEvent()}{paintEvent()} implementation performs the | 
|---|
| 241 | following tasks: | 
|---|
| 242 |  | 
|---|
| 243 | \list | 
|---|
| 244 | \o Push the current OpenGL modelview matrix onto a stack. | 
|---|
| 245 | \o Perform initialization tasks usually done in the | 
|---|
| 246 | \l{QGLWidget::initializeGL()}{initializeGL()} function. | 
|---|
| 247 | \o Perform code that would normally be located in the widget's | 
|---|
| 248 | \l{QGLWidget::resizeGL()}{resizeGL()} function to set the correct | 
|---|
| 249 | perspective transformation and set up the viewport. | 
|---|
| 250 | \o Render the scene using OpenGL calls. | 
|---|
| 251 | \o Pop the OpenGL modelview matrix off the stack. | 
|---|
| 252 | \o Construct a QPainter object. | 
|---|
| 253 | \o Initialize it for use on the widget with the QPainter::begin() function. | 
|---|
| 254 | \o Draw primitives using QPainter's member functions. | 
|---|
| 255 | \o Call QPainter::end() to finish painting. | 
|---|
| 256 | \endlist | 
|---|
| 257 | */ | 
|---|