doc/src/examples/overpainting.qdoc
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 */