1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the documentation of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
43 \example opengl/overpainting
44 \title Overpainting Example
46 The Overpainting example shows how QPainter can be used
47 to overpaint a scene rendered using OpenGL in a QGLWidget.
49 \image overpainting-example.png
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.
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.
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.
72 \section1 GLWidget Class Definition
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:
79 \snippet examples/opengl/overpainting/glwidget.h 0
81 \snippet examples/opengl/overpainting/glwidget.h 1
83 \snippet examples/opengl/overpainting/glwidget.h 4
85 As usual, the widget uses \l{QGLWidget::initializeGL()}{initializeGL()}
86 to set up objects for our scene and perform other 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.
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.
95 In this example, we also implement QWidget::showEvent() to help with the
96 initialization of the 2D graphics used.
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 messages that is also overpainted onto the OpenGL scene.
105 \section1 GLWidget Class Implementation
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:
111 \snippet examples/opengl/overpainting/glwidget.cpp 0
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.
117 As in the \l{Hello GL Example}{Hello GL} example, the destructor is responsible
118 for freeing any OpenGL-related resources:
120 \snippet examples/opengl/overpainting/glwidget.cpp 1
122 The \c initializeGL() function is fairly minimal, only setting up the display
123 list used in the scene.
125 \snippet examples/opengl/overpainting/glwidget.cpp 2
127 To cooperate fully with QPainter, we defer matrix stack operations and attribute
128 initialization until the widget needs to be updated.
130 In this example, we implement \l{QWidget::paintEvent()}{paintEvent()} rather
131 than \l{QGLWidget::paintGL()}{paintGL()} to render
132 our scene. When drawing on a QGLWidget, the paint engine used by QPainter
133 performs certain operations that change the states of the OpenGL
134 implementation's matrix and property stacks. Therefore, it is necessary to
135 make all the OpenGL calls to display the 3D graphics before we construct
136 a QPainter to draw the 2D overlay.
138 We render a 3D scene by setting up model and projection transformations
139 and other attributes. We use an OpenGL stack operation to preserve the
140 original matrix state, allowing us to recover it later:
142 \snippet examples/opengl/overpainting/glwidget.cpp 4
144 We define a color to use for the widget's background, and set up various
145 attributes that define how the scene will be rendered.
147 \snippet examples/opengl/overpainting/glwidget.cpp 6
149 We call the \c setupViewport() private function to set up the
150 projection used for the scene. This is unnecessary in OpenGL
151 examples that implement the \l{QGLWidget::paintGL()}{paintGL()}
152 function because the matrix stacks are usually unmodified between
153 calls to \l{QGLWidget::resizeGL()}{resizeGL()} and
154 \l{QGLWidget::paintGL()}{paintGL()}.
156 Since the widget's background is not drawn by the system or by Qt, we use
157 an OpenGL call to paint it before positioning the object defined earlier
160 \snippet examples/opengl/overpainting/glwidget.cpp 7
162 Once the list containing the object has been executed, the GL
163 states we changed and the matrix stack needs to be restored to its
164 original state at the start of this function before we can begin
167 \snippet examples/opengl/overpainting/glwidget.cpp 8
169 With the 3D graphics done, we construct a QPainter for use on the widget
170 and simply overpaint the widget with 2D graphics; in this case, using a
171 helper class to draw a number of translucent bubbles onto the widget,
172 and calling \c drawInstructions() to overlay some instructions:
174 \snippet examples/opengl/overpainting/glwidget.cpp 10
176 When QPainter::end() is called, suitable OpenGL-specific calls are made to
177 write the scene, and its additional contents, onto the widget.
179 The implementation of the \l{QGLWidget::resizeGL()}{resizeGL()} function
180 sets up the dimensions of the viewport and defines a projection
183 \snippet examples/opengl/overpainting/glwidget.cpp 11
185 Ideally, we want to arrange the 2D graphics to suit the widget's dimensions.
186 To achieve this, we implement the \l{QWidget::showEvent()}{showEvent()} handler,
187 creating new graphic elements (bubbles) if necessary at appropriate positions
190 \snippet examples/opengl/overpainting/glwidget.cpp 12
192 This function only has an effect if less than 20 bubbles have already been
195 The \c animate() slot is called every time the widget's \c animationTimer emits
196 the \l{QTimer::timeout()}{timeout()} signal. This keeps the bubbles moving
199 \snippet examples/opengl/overpainting/glwidget.cpp 13
201 We simply iterate over the bubbles in the \c bubbles list, updating the
202 widget before and after each of them is moved.
204 The \c setupViewport() function is called from \c paintEvent()
207 \snippet examples/opengl/overpainting/glwidget.cpp 14
209 The \c drawInstructions() function is used to prepare some basic
210 instructions that will be painted with the other 2D graphics over
213 \snippet examples/opengl/overpainting/glwidget.cpp 15
217 When overpainting 2D content onto 3D content, we need to use a QPainter
218 \e and make OpenGL calls to achieve the desired effect. Since QPainter
219 itself uses OpenGL calls when used on a QGLWidget subclass, we need to
220 preserve the state of various OpenGL stacks when we perform our own
221 calls, using the following approach:
224 \o Reimplement QGLWidget::initializeGL(), but only perform minimal
225 initialization. QPainter will perform its own initialization
226 routines, modifying the matrix and property stacks, so it is better
227 to defer certain initialization tasks until just before you render
229 \o Reimplement QGLWidget::resizeGL() as in the pure 3D case.
230 \o Reimplement QWidget::paintEvent() to draw both 2D and 3D graphics.
233 The \l{QWidget::paintEvent()}{paintEvent()} implementation performs the
237 \o Push the current OpenGL modelview matrix onto a stack.
238 \o Perform initialization tasks usually done in the
239 \l{QGLWidget::initializeGL()}{initializeGL()} function.
240 \o Perform code that would normally be located in the widget's
241 \l{QGLWidget::resizeGL()}{resizeGL()} function to set the correct
242 perspective transformation and set up the viewport.
243 \o Render the scene using OpenGL calls.
244 \o Pop the OpenGL modelview matrix off the stack.
245 \o Construct a QPainter object.
246 \o Initialize it for use on the widget with the QPainter::begin() function.
247 \o Draw primitives using QPainter's member functions.
248 \o Call QPainter::end() to finish painting.