diff -r 000000000000 -r 1918ee327afb doc/src/examples/overpainting.qdoc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/src/examples/overpainting.qdoc Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example opengl/overpainting + \title Overpainting Example + + The Overpainting example shows how QPainter can be used + to overpaint a scene rendered using OpenGL in a QGLWidget. + + \image overpainting-example.png + + QGLWidget provides a widget with integrated OpenGL graphics support + that enables 3D graphics to be displayed using normal OpenGL calls, + yet also behaves like any other standard Qt widget with support for + signals and slots, properties, and Qt's action system. + + Usually, QGLWidget is subclassed to display a pure 3D scene. The + developer reimplements \l{QGLWidget::initializeGL()}{initializeGL()} + to initialize any required resources, \l{QGLWidget::resizeGL()}{resizeGL()} + to set up the projection and viewport, and + \l{QGLWidget::paintGL()}{paintGL()} to perform the OpenGL calls needed + to render the scene. However, it is possible to subclass QGLWidget + differently to allow 2D graphics, drawn using QPainter, to be + painted over a scene rendered using OpenGL. + + In this example, we demonstrate how this is done by reusing the code + from the \l{Hello GL Example}{Hello GL} example to provide a 3D scene, + and painting over it with some translucent 2D graphics. Instead of + examining each class in detail, we only cover the parts of the + \c GLWidget class that enable overpainting, and provide more detailed + discussion in the final section of this document. + + \section1 GLWidget Class Definition + + The \c GLWidget class is a subclass of QGLWidget, based on the one used + in the \l{Hello GL Example}{Hello GL} example. Rather than describe the + class as a whole, we show the first few lines of the class and only + discuss the changes we have made to the rest of it: + + \snippet examples/opengl/overpainting/glwidget.h 0 + \dots + \snippet examples/opengl/overpainting/glwidget.h 1 + \dots + \snippet examples/opengl/overpainting/glwidget.h 4 + + As usual, the widget uses \l{QGLWidget::initializeGL()}{initializeGL()} + to set up geometry for our scene and perform OpenGL initialization tasks. + The \l{QGLWidget::resizeGL()}{resizeGL()} function is used to ensure that + the 3D graphics in the scene are transformed correctly to the 2D viewport + displayed in the widget. + + Instead of implementing \l{QGLWidget::paintGL()}{paintGL()} to handle updates + to the widget, we implement a normal QWidget::paintEvent(). This + allows us to mix OpenGL calls and QPainter operations in a controlled way. + + In this example, we also implement QWidget::showEvent() to help with the + initialization of the 2D graphics used. + + The new private member functions and variables relate exclusively to the + 2D graphics and animation. The \c animate() slot is called periodically by the + \c animationTimer to update the widget; the \c createBubbles() function + initializes the \c bubbles list with instances of a helper class used to + draw the animation; the \c drawInstructions() function is responsible for + a semi-transparent message that is also overpainted onto the OpenGL scene. + + \section1 GLWidget Class Implementation + + Again, we only show the parts of the \c GLWidget implementation that are + relevant to this example. In the constructor, we initialize a QTimer to + control the animation: + + \snippet examples/opengl/overpainting/glwidget.cpp 0 + + We turn off the widget's \l{QWidget::autoFillBackground}{autoFillBackground} property to + instruct OpenGL not to paint a background for the widget when + \l{QPainter::begin()}{QPainter::begin()} is called. + + As in the \l{Hello GL Example}{Hello GL} example, the destructor is responsible + for freeing any OpenGL-related resources: + + \snippet examples/opengl/overpainting/glwidget.cpp 1 + + The \c initializeGL() function is fairly minimal, only setting up the QtLogo + object used in the scene. See the \l{Hello GL Example}{Hello GL} example + for details of the QtLogo class. + + \snippet examples/opengl/overpainting/glwidget.cpp 2 + + To cooperate fully with QPainter, we defer matrix stack operations and attribute + initialization until the widget needs to be updated. + + In this example, we implement \l{QWidget::paintEvent()}{paintEvent()} rather + than \l{QGLWidget::paintGL()}{paintGL()} to render + our scene. When drawing on a QGLWidget, the paint engine used by QPainter + performs certain operations that change the states of the OpenGL + implementation's matrix and property stacks. Therefore, it is necessary to + make all the OpenGL calls to display the 3D graphics before we construct + a QPainter to draw the 2D overlay. + + We render a 3D scene by setting up model and projection transformations + and other attributes. We use an OpenGL stack operation to preserve the + original matrix state, allowing us to recover it later: + + \snippet examples/opengl/overpainting/glwidget.cpp 4 + + We define a color to use for the widget's background, and set up various + attributes that define how the scene will be rendered. + + \snippet examples/opengl/overpainting/glwidget.cpp 6 + + We call the \c setupViewport() private function to set up the + projection used for the scene. This is unnecessary in OpenGL + examples that implement the \l{QGLWidget::paintGL()}{paintGL()} + function because the matrix stacks are usually unmodified between + calls to \l{QGLWidget::resizeGL()}{resizeGL()} and + \l{QGLWidget::paintGL()}{paintGL()}. + + Since the widget's background is not drawn by the system or by Qt, we use + an OpenGL call to paint it before positioning the object defined earlier + in the scene: + + \snippet examples/opengl/overpainting/glwidget.cpp 7 + + Once the QtLogo object's draw method has been executed, the GL + states we changed and the matrix stack needs to be restored to its + original state at the start of this function before we can begin + overpainting: + + \snippet examples/opengl/overpainting/glwidget.cpp 8 + + With the 3D graphics done, we construct a QPainter for use on the widget + and simply overpaint the widget with 2D graphics; in this case, using a + helper class to draw a number of translucent bubbles onto the widget, + and calling \c drawInstructions() to overlay some instructions: + + \snippet examples/opengl/overpainting/glwidget.cpp 10 + + When QPainter::end() is called, suitable OpenGL-specific calls are made to + write the scene, and its additional contents, onto the widget. + + With \l{QGLWidget::paintGL()}{paintGL()} the + \l{QGLWidget::swapBuffers()}{swapBuffers()} call is done for us. But an explicit + call to swapBuffers() is still not required because in the + \l{QWidget::paintEvent()}{paintEvent()} method the QPainter on the OpenGL + widget takes care of this for us. + + The implementation of the \l{QGLWidget::resizeGL()}{resizeGL()} function + sets up the dimensions of the viewport and defines a projection + transformation: + + \snippet examples/opengl/overpainting/glwidget.cpp 11 + + Ideally, we want to arrange the 2D graphics to suit the widget's dimensions. + To achieve this, we implement the \l{QWidget::showEvent()}{showEvent()} handler, + creating new graphic elements (bubbles) if necessary at appropriate positions + in the widget. + + \snippet examples/opengl/overpainting/glwidget.cpp 12 + + This function only has an effect if less than 20 bubbles have already been + created. + + The \c animate() slot is called every time the widget's \c animationTimer emits + the \l{QTimer::timeout()}{timeout()} signal. This keeps the bubbles moving + around. + + \snippet examples/opengl/overpainting/glwidget.cpp 13 + + We simply iterate over the bubbles in the \c bubbles list, updating the + widget before and after each of them is moved. + + The \c setupViewport() function is called from \c paintEvent() + and \c resizeGL(). + + \snippet examples/opengl/overpainting/glwidget.cpp 14 + + The \c drawInstructions() function is used to prepare some basic + instructions that will be painted with the other 2D graphics over + the 3D scene. + + \snippet examples/opengl/overpainting/glwidget.cpp 15 + + \section1 Summary + + When overpainting 2D content onto 3D content, we need to use a QPainter + \e and make OpenGL calls to achieve the desired effect. Since QPainter + itself uses OpenGL calls when used on a QGLWidget subclass, we need to + preserve the state of various OpenGL stacks when we perform our own + calls, using the following approach: + + \list + \o Reimplement QGLWidget::initializeGL(), but only perform minimal + initialization. QPainter will perform its own initialization + routines, modifying the matrix and property stacks, so it is better + to defer certain initialization tasks until just before you render + the 3D scene. + \o Reimplement QGLWidget::resizeGL() as in the pure 3D case. + \o Reimplement QWidget::paintEvent() to draw both 2D and 3D graphics. + \endlist + + The \l{QWidget::paintEvent()}{paintEvent()} implementation performs the + following tasks: + + \list + \o Push the current OpenGL modelview matrix onto a stack. + \o Perform initialization tasks usually done in the + \l{QGLWidget::initializeGL()}{initializeGL()} function. + \o Perform code that would normally be located in the widget's + \l{QGLWidget::resizeGL()}{resizeGL()} function to set the correct + perspective transformation and set up the viewport. + \o Render the scene using OpenGL calls. + \o Pop the OpenGL modelview matrix off the stack. + \o Construct a QPainter object. + \o Initialize it for use on the widget with the QPainter::begin() function. + \o Draw primitives using QPainter's member functions. + \o Call QPainter::end() to finish painting. + \endlist +*/