source: trunk/doc/src/examples/overpainting.qdoc@ 357

Last change on this file since 357 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 11.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** This file is part of the documentation of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
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.
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 are unsure which license is appropriate for your use, please
37** contact the sales department at qt-sales@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 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.
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 messages 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 display
123 list used in the scene.
124
125 \snippet examples/opengl/overpainting/glwidget.cpp 2
126
127 To cooperate fully with QPainter, we defer matrix stack operations and attribute
128 initialization until the widget needs to be updated.
129
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.
137
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:
141
142 \snippet examples/opengl/overpainting/glwidget.cpp 4
143
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.
146
147 \snippet examples/opengl/overpainting/glwidget.cpp 6
148
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()}.
155
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
158 in the scene:
159
160 \snippet examples/opengl/overpainting/glwidget.cpp 7
161
162 Once the list containing the object has been executed, the matrix stack
163 needs to be restored to its original state at the start of this function
164 before we can begin overpainting:
165
166 \snippet examples/opengl/overpainting/glwidget.cpp 8
167
168 With the 3D graphics done, we construct a QPainter for use on the widget
169 and simply overpaint the widget with 2D graphics; in this case, using a
170 helper class to draw a number of translucent bubbles onto the widget,
171 and calling \c drawInstructions() to overlay some instructions:
172
173 \snippet examples/opengl/overpainting/glwidget.cpp 10
174
175 When QPainter::end() is called, suitable OpenGL-specific calls are made to
176 write the scene, and its additional contents, onto the widget.
177
178 The implementation of the \l{QGLWidget::resizeGL()}{resizeGL()} function
179 sets up the dimensions of the viewport and defines a projection
180 transformation:
181
182 \snippet examples/opengl/overpainting/glwidget.cpp 11
183
184 Ideally, we want to arrange the 2D graphics to suit the widget's dimensions.
185 To achieve this, we implement the \l{QWidget::showEvent()}{showEvent()} handler,
186 creating new graphic elements (bubbles) if necessary at appropriate positions
187 in the widget.
188
189 \snippet examples/opengl/overpainting/glwidget.cpp 12
190
191 This function only has an effect if less than 20 bubbles have already been
192 created.
193
194 The \c animate() slot is called every time the widget's \c animationTimer emits
195 the \l{QTimer::timeout()}{timeout()} signal. This keeps the bubbles moving
196 around.
197
198 \snippet examples/opengl/overpainting/glwidget.cpp 13
199
200 We simply iterate over the bubbles in the \c bubbles list, updating the
201 widget before and after each of them is moved.
202
203 The \c setupViewport() function is called from \c paintEvent()
204 and \c resizeGL().
205
206 \snippet examples/opengl/overpainting/glwidget.cpp 14
207
208 The \c drawInstructions() function is used to prepare some basic
209 instructions that will be painted with the other 2D graphics over
210 the 3D scene.
211
212 \snippet examples/opengl/overpainting/glwidget.cpp 15
213
214 \section1 Summary
215
216 When overpainting 2D content onto 3D content, we need to use a QPainter
217 \e and make OpenGL calls to achieve the desired effect. Since QPainter
218 itself uses OpenGL calls when used on a QGLWidget subclass, we need to
219 preserve the state of various OpenGL stacks when we perform our own
220 calls, using the following approach:
221
222 \list
223 \o Reimplement QGLWidget::initializeGL(), but only perform minimal
224 initialization. QPainter will perform its own initialization
225 routines, modifying the matrix and property stacks, so it is better
226 to defer certain initialization tasks until just before you render
227 the 3D scene.
228 \o Reimplement QGLWidget::resizeGL() as in the pure 3D case.
229 \o Reimplement QWidget::paintEvent() to draw both 2D and 3D graphics.
230 \endlist
231
232 The \l{QWidget::paintEvent()}{paintEvent()} implementation performs the
233 following tasks:
234
235 \list
236 \o Push the current OpenGL modelview matrix onto a stack.
237 \o Perform initialization tasks usually done in the
238 \l{QGLWidget::initializeGL()}{initializeGL()} function.
239 \o Perform code that would normally be located in the widget's
240 \l{QGLWidget::resizeGL()}{resizeGL()} function to set the correct
241 perspective transformation and set up the viewport.
242 \o Render the scene using OpenGL calls.
243 \o Pop the OpenGL modelview matrix off the stack.
244 \o Construct a QPainter object.
245 \o Initialize it for use on the widget with the QPainter::begin() function.
246 \o Draw primitives using QPainter's member functions.
247 \o Call QPainter::end() to finish painting.
248 \endlist
249*/
Note: See TracBrowser for help on using the repository browser.