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

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

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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