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

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 11.6 KB
Line 
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*/
Note: See TracBrowser for help on using the repository browser.