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 | */
|
---|