PageRenderTime 5ms CodeModel.GetById 31ms app.highlight 49ms RepoModel.GetById 0ms app.codeStats 0ms

/src/threed/painting/qglpainter.cpp

https://bitbucket.org/manctl/qt3d
C++ | 2366 lines | 1308 code | 148 blank | 910 comment | 222 complexity | ec43ac14b87db2d542b2b8f4bf4379f7 MD5 | raw file
Possible License(s): CC-BY-SA-4.0, LGPL-2.1, GPL-3.0, AGPL-3.0, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

   1/****************************************************************************
   2**
   3** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
   4** Contact: http://www.qt-project.org/
   5**
   6** This file is part of the Qt3D module of the Qt Toolkit.
   7**
   8** $QT_BEGIN_LICENSE:LGPL$
   9** GNU Lesser General Public License Usage
  10** This file may be used under the terms of the GNU Lesser General Public
  11** License version 2.1 as published by the Free Software Foundation and
  12** appearing in the file LICENSE.LGPL included in the packaging of this
  13** file. Please review the following information to ensure the GNU Lesser
  14** General Public License version 2.1 requirements will be met:
  15** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  16**
  17** In addition, as a special exception, Nokia gives you certain additional
  18** rights. These rights are described in the Nokia Qt LGPL Exception
  19** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  20**
  21** GNU General Public License Usage
  22** Alternatively, this file may be used under the terms of the GNU General
  23** Public License version 3.0 as published by the Free Software Foundation
  24** and appearing in the file LICENSE.GPL included in the packaging of this
  25** file. Please review the following information to ensure the GNU General
  26** Public License version 3.0 requirements will be met:
  27** http://www.gnu.org/copyleft/gpl.html.
  28**
  29** Other Usage
  30** Alternatively, this file may be used in accordance with the terms and
  31** conditions contained in a signed written agreement between you and Nokia.
  32**
  33**
  34**
  35**
  36**
  37**
  38** $QT_END_LICENSE$
  39**
  40****************************************************************************/
  41
  42#include "qglpainter.h"
  43#include "qglpainter_p.h"
  44#include "qglabstracteffect.h"
  45#include "qglext_p.h"
  46
  47#include <QOpenGLContext>
  48#include <QOpenGLShaderProgram>
  49#include <QOpenGLFramebufferObject>
  50#include <QPainter>
  51#include <QPaintEngine>
  52#include <QVarLengthArray>
  53#include <QMap>
  54#include <QDebug>
  55
  56#if !defined(QT_NO_THREAD)
  57#include <QThreadStorage>
  58#include <QThread>
  59#endif
  60
  61#include "qglflatcoloreffect_p.h"
  62#include "qglflattextureeffect_p.h"
  63#include "qgllitmaterialeffect_p.h"
  64#include "qgllittextureeffect_p.h"
  65#include "qglpickcolors_p.h"
  66#include "qgltexture2d.h"
  67#include "qgltexturecube.h"
  68#include "qgeometrydata.h"
  69#include "qglvertexbundle_p.h"
  70#include "qmatrix4x4stack_p.h"
  71#include "qglwindowsurface.h"
  72#include "qglpaintersurface_p.h"
  73
  74#undef glActiveTexture
  75
  76QT_BEGIN_NAMESPACE
  77
  78/*!
  79    \class QGLPainter
  80    \brief The QGLPainter class provides portable API's for rendering into a GL context.
  81    \since 4.8
  82    \ingroup qt3d
  83    \ingroup qt3d::painting
  84
  85    TBD - lots of TBD
  86
  87    All QGLPainter instances on a context share the same context state:
  88    matrices, effects, vertex attributes, etc.  For example, calling
  89    ortho() on one QGLPainter instance for a context will alter the
  90    projectionMatrix() as seen by the other QGLPainter instances.
  91*/
  92
  93/*!
  94    \enum QGLPainter::Update
  95    This enum defines the values that were changed since the last QGLPainter::update().
  96
  97    \value UpdateColor The color has been updated.
  98    \value UpdateModelViewMatrix The modelview matrix has been updated.
  99    \value UpdateProjectionMatrix The projection matrix has been updated.
 100    \value UpdateMatrices The combination of UpdateModelViewMatrix and
 101           UpdateProjectionMatrix.
 102    \value UpdateLights The lights have been updated.
 103    \value UpdateMaterials The material parameters have been updated.
 104    \value UpdateViewport The viewport needs to be updated because the
 105           drawing surface has changed.
 106    \value UpdateAll All values have been updated.  This is specified
 107           when an effect is activated.
 108*/
 109
 110#define QGLPAINTER_CHECK_PRIVATE() \
 111    Q_ASSERT_X(d, "QGLPainter", "begin() has not been called or it failed")
 112
 113QGLPainterPrivate::QGLPainterPrivate()
 114    : ref(1),
 115      badShaderCount(0),
 116      eye(QGL::NoEye),
 117      lightModel(0),
 118      defaultLightModel(0),
 119      defaultLight(0),
 120      frontMaterial(0),
 121      backMaterial(0),
 122      defaultMaterial(0),
 123      frontColorMaterial(0),
 124      backColorMaterial(0),
 125      viewingCube(QVector3D(-1, -1, -1), QVector3D(1, 1, 1)),
 126      color(255, 255, 255, 255),
 127      updates(QGLPainter::UpdateAll),
 128      pick(0),
 129      boundVertexBuffer(0),
 130      boundIndexBuffer(0),
 131      renderSequencer(0),
 132      isFixedFunction(true) // Updated by QGLPainter::begin()
 133{
 134    context = 0;
 135    effect = 0;
 136    userEffect = 0;
 137    standardEffect = QGL::FlatColor;
 138    memset(stdeffects, 0, sizeof(stdeffects));
 139}
 140
 141QGLPainterPrivate::~QGLPainterPrivate()
 142{
 143    delete defaultLightModel;
 144    delete defaultLight;
 145    delete defaultMaterial;
 146    delete frontColorMaterial;
 147    delete backColorMaterial;
 148    for (int effect = 0; effect < QGL_MAX_STD_EFFECTS; ++effect)
 149        delete stdeffects[effect];
 150    delete pick;
 151    qDeleteAll(cachedPrograms);
 152    delete renderSequencer;
 153}
 154
 155QGLPainterPickPrivate::QGLPainterPickPrivate()
 156{
 157    isPicking = false;
 158    objectPickId = -1;
 159    pickColorIndex = -1;
 160    pickColor = 0;
 161    defaultPickEffect = new QGLFlatColorEffect();
 162}
 163
 164QGLPainterPickPrivate::~QGLPainterPickPrivate()
 165{
 166    delete defaultPickEffect;
 167}
 168
 169#if !defined(QT_NO_THREAD)
 170
 171// QOpenGLContext's are thread-specific, so QGLPainterPrivateCache should be too.
 172
 173typedef QThreadStorage<QGLPainterPrivateCache *> QGLPainterPrivateStorage;
 174Q_GLOBAL_STATIC(QGLPainterPrivateStorage, painterPrivateStorage)
 175static QGLPainterPrivateCache *painterPrivateCache()
 176{
 177    QGLPainterPrivateCache *cache = painterPrivateStorage()->localData();
 178    if (!cache) {
 179        cache = new QGLPainterPrivateCache();
 180        painterPrivateStorage()->setLocalData(cache);
 181    }
 182    return cache;
 183}
 184
 185#else
 186
 187Q_GLOBAL_STATIC(QGLPainterPrivateCache, painterPrivateCache)
 188
 189#endif
 190
 191QGLPainterPrivateCache::QGLPainterPrivateCache()
 192{
 193}
 194
 195QGLPainterPrivateCache::~QGLPainterPrivateCache()
 196{
 197}
 198
 199QGLPainterPrivate *QGLPainterPrivateCache::fromContext(QOpenGLContext *context)
 200{
 201    QGLPainterPrivate *priv = cache.value(context, 0);
 202    if (priv)
 203        return priv;
 204#ifndef QT_NO_THREAD
 205    Q_ASSERT_X(context->thread() == QThread::currentThread(),
 206               Q_FUNC_INFO,
 207               "Attempt to fetch painter state for context outside contexts thread");
 208#endif
 209    // since we assert this is the same thread then this is bound to be a direct
 210    // connection, not a queued (asynchronous) connection
 211    connect(context, SIGNAL(destroyed()), this, SLOT(contextDestroyed()));
 212    priv = new QGLPainterPrivate();
 213    priv->context = context;
 214    cache.insert(context, priv);
 215    return priv;
 216}
 217
 218QGLPainterPrivateCache *QGLPainterPrivateCache::instance()
 219{
 220    return painterPrivateCache();
 221}
 222
 223void QGLPainterPrivateCache::contextDestroyed()
 224{
 225    QOpenGLContext *context = qobject_cast<QOpenGLContext *>(sender());
 226    QGLPainterPrivate *priv = cache.value(context, 0);
 227    if (priv) {
 228        priv->context = 0;
 229        cache.remove(context);
 230        if (!priv->ref.deref())
 231            delete priv;
 232    }
 233    emit destroyedContext(context);
 234}
 235
 236/*!
 237    Constructs a new GL painter.  Call begin() to attach the
 238    painter to a GL context.
 239
 240    \sa begin()
 241*/
 242QGLPainter::QGLPainter()
 243    : d_ptr(0)
 244{
 245}
 246
 247/*!
 248    Constructs a new GL painter and attaches it to \a context.
 249    It is not necessary to call begin() after construction.
 250
 251    \sa begin()
 252*/
 253QGLPainter::QGLPainter(QOpenGLContext *context)
 254    : d_ptr(0)
 255{
 256    begin(context);
 257}
 258
 259/*!
 260    Constructs a new GL painter and attaches it to the GL
 261    context associated with \a window.  It is not necessary to
 262    call begin() after construction.
 263
 264    \sa begin(), isActive()
 265*/
 266QGLPainter::QGLPainter(QWindow *window)
 267    : d_ptr(0)
 268{
 269    begin(window);
 270}
 271
 272/*!
 273    Constructs a new GL painter and attaches it to the GL context associated
 274    with \a painter.  It is assumed that \a painter is the currently
 275    active painter and that it is associated with the current GL context.
 276
 277    If \a painter is not using an OpenGL paint engine, then isActive()
 278    will return false; true otherwise.
 279
 280    This constructor is typically used when mixing regular Qt painting
 281    operations and GL painting operations on a widget that is being
 282    drawn using the OpenGL graphics system.
 283
 284    \sa begin(), isActive()
 285*/
 286QGLPainter::QGLPainter(QPainter *painter)
 287    : d_ptr(0)
 288{
 289    begin(painter);
 290}
 291
 292/*!
 293    Constructs a new GL painter and attaches it to the GL context associated
 294    with \a surface.
 295
 296    \sa begin(), isActive()
 297*/
 298QGLPainter::QGLPainter(QGLAbstractSurface *surface)
 299    : d_ptr(0)
 300{
 301    begin(surface);
 302}
 303
 304/*!
 305    Destroys this GL painter.
 306*/
 307QGLPainter::~QGLPainter()
 308{
 309    end();
 310}
 311
 312/*!
 313    Begins painting on the current GL context.  Returns false
 314    if there is no GL context current.
 315
 316    \sa end()
 317*/
 318bool QGLPainter::begin()
 319{
 320    return begin(QOpenGLContext::currentContext());
 321}
 322
 323/*!
 324    Begins painting on \a context.  If painting was already in progress,
 325    then this function will call end() first.  The \a context will be
 326    made current if it is not already current.
 327
 328    Returns true if painting can begin; false otherwise.
 329
 330    All QGLPainter instances on a context share the same context state:
 331    matrices, the effect(), vertex attributes, etc.  For example,
 332    calling ortho() on one QGLPainter instance for a context will
 333    alter the projectionMatrix() as seen by the other QGLPainter instances.
 334
 335    \sa end(), isActive()
 336*/
 337bool QGLPainter::begin(QOpenGLContext *context)
 338{
 339    if (!context)
 340        return false;
 341    end();
 342    return begin(context, QGLAbstractSurface::createSurfaceForContext(context));
 343}
 344
 345/*!
 346    \internal
 347*/
 348bool QGLPainter::begin
 349    (QOpenGLContext *context, QGLAbstractSurface *surface,
 350     bool destroySurface)
 351{
 352    // If we don't have a context specified, then use the one
 353    // that the surface just made current.
 354    if (!context)
 355        context = QOpenGLContext::currentContext();
 356
 357    if (!context)
 358    {
 359        qWarning() << "##### Attempt to begin painter with no GL context!";
 360        return false;
 361    }
 362
 363    // Initialize the QOpenGLFunctions parent class.
 364    initializeGLFunctions();
 365
 366    // Determine if the OpenGL implementation is fixed-function or not.
 367    bool isFixedFunction = !hasOpenGLFeature(QOpenGLFunctions::Shaders);
 368    if (!isFixedFunction)
 369        isFixedFunction = !QOpenGLShaderProgram::hasOpenGLShaderPrograms();
 370    if (!isFixedFunction)
 371    {
 372        QOpenGLContext *ctx = QOpenGLContext::currentContext();
 373        QFunctionPointer res = ctx->getProcAddress("glCreateShader");
 374        if (!res)
 375        {
 376            res = ctx->getProcAddress("glCreateShaderObject");
 377            if (!res)
 378            {
 379                res = ctx->getProcAddress("glCreateShaderObjectARB");
 380            }
 381        }
 382        if (!res)
 383            isFixedFunction = !res;
 384    }
 385
 386    // Find the QGLPainterPrivate for the context, or create a new one.
 387    d_ptr = painterPrivateCache()->fromContext(context);
 388    d_ptr->ref.ref();
 389    d_ptr->isFixedFunction = isFixedFunction;
 390    if (d_ptr->renderSequencer)
 391    {
 392        d_ptr->renderSequencer->reset();
 393        d_ptr->renderSequencer->setPainter(this);
 394    }
 395
 396    // Activate the main surface for the context.
 397    QGLAbstractSurface *prevSurface;
 398    if (d_ptr->surfaceStack.isEmpty()) {
 399        prevSurface = 0;
 400    } else {
 401        // We are starting a nested begin()/end() scope, so switch
 402        // to the new main surface rather than activate from scratch.
 403        prevSurface = d_ptr->surfaceStack.last().surface;
 404        prevSurface->deactivate(surface);
 405    }
 406    if (!surface->activate(prevSurface)) {
 407        if (prevSurface)
 408            prevSurface->activate(surface);
 409        if (destroySurface)
 410            delete surface;
 411        if (!d_ptr->ref.deref())
 412            delete d_ptr;
 413        d_ptr = 0;
 414        return false;
 415    }
 416
 417    // Push a main surface descriptor onto the surface stack.
 418    QGLPainterSurfaceInfo psurf;
 419    psurf.surface = surface;
 420    psurf.destroySurface = destroySurface;
 421    psurf.mainSurface = true;
 422    d_ptr->surfaceStack.append(psurf);
 423
 424    // Force the matrices to be updated the first time we use them.
 425    d_ptr->modelViewMatrix.setDirty(true);
 426    d_ptr->projectionMatrix.setDirty(true);
 427
 428    return true;
 429}
 430
 431/*!
 432    Begins GL painting on \a widget.  Returns false if \a widget is null.
 433
 434    \sa end()
 435*/
 436bool QGLPainter::begin(QWindow *window)
 437{
 438    bool result = false;
 439    if (window)
 440    {
 441        end();
 442        result = begin(0, new QGLWindowSurface(window));
 443    }
 444    return result;
 445}
 446
 447/*!
 448    Begins painting on the GL context associated with \a painter.
 449    Returns false if \a painter is not using an OpenGL paint engine.
 450    It is assumed that \a painter is the currently active painter
 451    and that it is associated with the current GL context.
 452
 453    This function is typically used when mixing regular Qt painting
 454    operations and GL painting operations on a widget that is being
 455    drawn using the OpenGL graphics system.
 456
 457    \sa end()
 458*/
 459bool QGLPainter::begin(QPainter *painter)
 460{
 461    // Validate that the painting is OpenGL-based.
 462    if (!painter)
 463        return false;
 464    QPaintEngine *engine = painter->paintEngine();
 465    if (!engine)
 466        return false;
 467    if (engine->type() != QPaintEngine::OpenGL &&
 468            engine->type() != QPaintEngine::OpenGL2)
 469        return false;
 470
 471    // Begin GL painting operations.
 472    return begin(0, new QGLPainterSurface(painter));
 473}
 474
 475/*!
 476    Begins painting to \a surface.  Returns false if \a surface is
 477    null or could not be activated.
 478
 479    \sa end(), QGLAbstractSurface::activate()
 480*/
 481bool QGLPainter::begin(QGLAbstractSurface *surface)
 482{
 483    if (!surface)
 484        return false;
 485    end();
 486    return begin(0, surface, false);
 487}
 488
 489/*!
 490    Ends GL painting.  Returns true if painting was ended successfully;
 491    false if this painter was not bound to a GL context.
 492
 493    The GL context that was bound to this painter will not have
 494    QOpenGLContext::doneCurrent() called on it.  It is the responsibility
 495    of the caller to terminate context operations.
 496
 497    The effect() will be left active in the GL context and will be
 498    assumed to still be active the next time begin() is called.
 499    If this assumption doesn't apply, then call disableEffect()
 500    to disable the effect before calling end().
 501
 502    This function will pop all surfaces from the surface stack,
 503    and return currentSurface() to null (the default drawing surface).
 504
 505    \sa begin(), isActive(), disableEffect()
 506*/
 507bool QGLPainter::end()
 508{
 509    Q_D(QGLPainter);
 510    if (!d)
 511        return false;
 512
 513    // Unbind the current vertex and index buffers.
 514    if (d->boundVertexBuffer) {
 515        QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
 516        d->boundVertexBuffer = 0;
 517    }
 518    if (d->boundIndexBuffer) {
 519        QOpenGLBuffer::release(QOpenGLBuffer::IndexBuffer);
 520        d->boundIndexBuffer = 0;
 521    }
 522
 523    // Pop surfaces from the surface stack until we reach a
 524    // main surface.  Then deactivate the main surface.
 525    int size = d->surfaceStack.size();
 526    while (size > 0) {
 527        --size;
 528        QGLPainterSurfaceInfo &surf = d->surfaceStack[size];
 529        if (surf.mainSurface) {
 530            if (size > 0) {
 531                // There are still other surfaces on the stack, probably
 532                // because we are within a nested begin()/end() scope.
 533                // Re-activate the next surface down in the outer scope.
 534                QGLPainterSurfaceInfo &nextSurf = d->surfaceStack[size - 1];
 535                surf.surface->switchTo(nextSurf.surface);
 536            } else {
 537                // Last surface on the stack, so deactivate it permanently.
 538                surf.surface->deactivate();
 539            }
 540            if (surf.destroySurface)
 541                delete surf.surface;
 542            break;
 543        } else if (size > 0) {
 544            surf.surface->deactivate(d->surfaceStack[size - 1].surface);
 545        }
 546    }
 547    d->surfaceStack.resize(size);
 548
 549    // Force a viewport update if we are within a nested begin()/end().
 550    d->updates |= UpdateViewport;
 551
 552    // Destroy the QGLPainterPrivate if this is the last reference.
 553    if (!d->ref.deref())
 554        delete d;
 555    d_ptr = 0;
 556    return true;
 557}
 558
 559/*!
 560    Returns true if this painter is currently bound to a GL context;
 561    false otherwise.
 562
 563    \sa begin(), end()
 564*/
 565bool QGLPainter::isActive() const
 566{
 567    return (d_ptr != 0 && d_ptr->context != 0);
 568}
 569
 570/*!
 571    Returns the GL context that is bound to this painter, or null
 572    if it is not currently bound.
 573*/
 574QOpenGLContext *QGLPainter::context() const
 575{
 576    if (d_ptr)
 577        return d_ptr->context;
 578    else
 579        return 0;
 580}
 581
 582/*!
 583    Returns true if the underlying OpenGL implementation is OpenGL 1.x
 584    or OpenGL/ES 1.x and only supports fixed-function OpenGL operations.
 585    Returns false if the underlying OpenGL implementation is using
 586    GLSL or GLSL/ES shaders.
 587
 588    If this function returns false, then the built-in effects will
 589    use shaders and QGLPainter will not update the fixed-function
 590    matrices in the OpenGL context when update() is called.
 591    User-supplied effects will need to use shaders also or update
 592    the fixed-function matrices themselves or call updateFixedFunction().
 593
 594    \sa update(), updateFixedFunction()
 595*/
 596bool QGLPainter::isFixedFunction() const
 597{
 598#if defined(QT_OPENGL_ES_2)
 599    return false;
 600#else
 601    Q_D(const QGLPainter);
 602    if (d)
 603        return d->isFixedFunction;
 604    else
 605        return true;
 606#endif
 607}
 608
 609/*!
 610    Sets the \a color to use to clear the color buffer when \c{glClear()}
 611    is called.
 612*/
 613void QGLPainter::setClearColor(const QColor& color)
 614{
 615    glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
 616}
 617
 618/*!
 619    Sets the scissor \a rect for the current drawing surface
 620    to use when \c{GL_SCISSOR_TEST} is enabled.  If \a rect is empty,
 621    then the scissor will be set to clip away all drawing.
 622
 623    Note that \a rect is in Qt co-ordinates with the origin
 624    at the top-left of the drawing surface's viewport rectangle.
 625    If the currentSurface() is an instance of QGLSubsurface,
 626    then \a rect will be adjusted relative to the subsurface's position.
 627
 628    \sa currentSurface(), QGLAbstractSurface::viewportGL()
 629*/
 630void QGLPainter::setScissor(const QRect& rect)
 631{
 632    if (!rect.isEmpty()) {
 633        // Adjust the rectangle by the position of the surface viewport.
 634        QGLAbstractSurface *surface = currentSurface();
 635        QRect viewport = surface->viewportGL();
 636        QRect r(viewport.x() + rect.x(),
 637                viewport.y() + viewport.height() - (rect.y() + rect.height()),
 638                rect.width(), rect.height());
 639        if (!r.isEmpty())
 640            glScissor(r.x(), r.y(), r.width(), r.height());
 641        else
 642            glScissor(0, 0, 0, 0);
 643    } else {
 644        glScissor(0, 0, 0, 0);
 645    }
 646}
 647
 648/*!
 649    Returns a reference to the projection matrix stack.
 650
 651    It is recommended that setCamera() be used to set the projection
 652    matrix at the beginning of a scene rendering pass so that the
 653    eye position can be adjusted for stereo.
 654
 655    \sa modelViewMatrix(), combinedMatrix(), setCamera()
 656*/
 657QMatrix4x4Stack& QGLPainter::projectionMatrix()
 658{
 659    Q_D(QGLPainter);
 660    QGLPAINTER_CHECK_PRIVATE();
 661    return d->projectionMatrix;
 662}
 663
 664/*!
 665    Returns a reference to the modelview matrix stack.
 666
 667    \sa projectionMatrix(), combinedMatrix(), normalMatrix(), setCamera()
 668    \sa worldMatrix()
 669*/
 670QMatrix4x4Stack& QGLPainter::modelViewMatrix()
 671{
 672    Q_D(QGLPainter);
 673    QGLPAINTER_CHECK_PRIVATE();
 674    return d->modelViewMatrix;
 675}
 676
 677/*!
 678    \fn QMatrix4x4 QGLPainter::combinedMatrix() const
 679
 680    Returns the result of multiplying the projectionMatrix()
 681    and the modelViewMatrix().  This combined matrix value is
 682    useful for setting uniform matrix values on shader programs.
 683
 684    Calling this function is more efficient than calling
 685    projectionMatrix() and modelViewMatrix() separately and
 686    multiplying the return values.
 687
 688    \sa projectionMatrix(), modelViewMatrix(), normalMatrix()
 689*/
 690QMatrix4x4 QGLPainter::combinedMatrix() const
 691{
 692    const QGLPainterPrivate *d = d_func();
 693    if (!d)
 694        return QMatrix4x4();
 695    const QMatrix4x4StackPrivate *proj = d->projectionMatrix.d_func();
 696    const QMatrix4x4StackPrivate *mv = d->modelViewMatrix.d_func();
 697    return proj->matrix * mv->matrix;
 698}
 699
 700// Inverting the eye transformation will often result in values like
 701// 1.5e-15 in the world matrix.  Clamp these to zero to make worldMatrix()
 702// more stable when removing the eye component of the modelViewMatrix().
 703static inline qreal qt_gl_stablize_value(qreal value)
 704{
 705    return (qAbs(value) >= 0.00001f) ? value : 0.0f;
 706}
 707static inline QMatrix4x4 qt_gl_stablize_matrix(const QMatrix4x4 &m)
 708{
 709    return QMatrix4x4(qt_gl_stablize_value(m(0, 0)),
 710                      qt_gl_stablize_value(m(0, 1)),
 711                      qt_gl_stablize_value(m(0, 2)),
 712                      qt_gl_stablize_value(m(0, 3)),
 713                      qt_gl_stablize_value(m(1, 0)),
 714                      qt_gl_stablize_value(m(1, 1)),
 715                      qt_gl_stablize_value(m(1, 2)),
 716                      qt_gl_stablize_value(m(1, 3)),
 717                      qt_gl_stablize_value(m(2, 0)),
 718                      qt_gl_stablize_value(m(2, 1)),
 719                      qt_gl_stablize_value(m(2, 2)),
 720                      qt_gl_stablize_value(m(2, 3)),
 721                      qt_gl_stablize_value(m(3, 0)),
 722                      qt_gl_stablize_value(m(3, 1)),
 723                      qt_gl_stablize_value(m(3, 2)),
 724                      qt_gl_stablize_value(m(3, 3)));
 725}
 726
 727/*!
 728    Returns the world matrix, which is the modelViewMatrix() without
 729    the eye transformation that was set in the previous call to
 730    setCamera().
 731
 732    In the following example, the \c{world} variable will be set to the
 733    translation and scale component of the modelview transformation,
 734    without the "look at" component from the camera:
 735
 736    \code
 737    painter.setCamera(camera);
 738    painter.modelViewMatrix().translate(0.0f, 5.0f, 0.0f);
 739    painter.modelViewMatrix().scale(1.5f);
 740    QMatrix4x4 world = painter.worldMatrix();
 741    \endcode
 742
 743    Note: the world matrix is determined by multiplying the inverse of
 744    the camera's look at component with the current modelview matrix.
 745    Thus, the result may not be precisely the same as constructing a
 746    matrix from translate and scale operations starting with the identity.
 747
 748    \sa modelViewMatrix(), setCamera()
 749*/
 750QMatrix4x4 QGLPainter::worldMatrix() const
 751{
 752    Q_D(const QGLPainter);
 753    QGLPAINTER_CHECK_PRIVATE();
 754    return qt_gl_stablize_matrix
 755        (d->inverseEyeMatrix * d->modelViewMatrix.top());
 756}
 757
 758/*!
 759    \fn QMatrix3x3 QGLPainter::normalMatrix() const
 760
 761    Returns the normal matrix corresponding to modelViewMatrix().
 762
 763    The normal matrix is the transpose of the inverse of the top-left
 764    3x3 part of the 4x4 modelview matrix.  If the 3x3 sub-matrix is not
 765    invertible, this function returns the identity.
 766
 767    \sa modelViewMatrix(), combinedMatrix()
 768*/
 769QMatrix3x3 QGLPainter::normalMatrix() const
 770{
 771    const QGLPainterPrivate *d = d_func();
 772    if (!d)
 773        return QMatrix3x3();
 774    const QMatrix4x4StackPrivate *mv = d->modelViewMatrix.d_func();
 775    return mv->matrix.normalMatrix();
 776}
 777
 778/*!
 779    Returns the camera eye that is currently being used for stereo
 780    rendering.  The default is QGL::NoEye.
 781
 782    The eye is used to adjust the camera position by a small amount
 783    when setCamera() is called.
 784
 785    \sa setEye(), setCamera()
 786*/
 787QGL::Eye QGLPainter::eye() const
 788{
 789    Q_D(const QGLPainter);
 790    QGLPAINTER_CHECK_PRIVATE();
 791    return d->eye;
 792}
 793
 794/*!
 795    Sets the camera \a eye that is currently being used for stereo
 796    rendering.
 797
 798    The \a eye is used to adjust the camera position by a small amount
 799    when setCamera() is called.
 800
 801    \sa eye(), setCamera()
 802*/
 803void QGLPainter::setEye(QGL::Eye eye)
 804{
 805    Q_D(QGLPainter);
 806    QGLPAINTER_CHECK_PRIVATE();
 807    d->eye = eye;
 808}
 809
 810/*!
 811    Sets the modelViewMatrix() and projectionMatrix() to the view
 812    defined by \a camera.  If eye() is not QGL::NoEye, then the view
 813    will be adjusted for the camera's eye separation.
 814
 815    This function is typically called at the beginning of a scene rendering
 816    pass to initialize the modelview and projection matrices.
 817
 818    Note that this does not cause the painter to take ownership of the camera
 819    and it does not save the pointer value.  The \a camera may be safely
 820    deleted after calling this function.
 821
 822    \sa eye(), modelViewMatrix(), projectionMatrix(), worldMatrix()
 823*/
 824void QGLPainter::setCamera(const QGLCamera *camera)
 825{
 826    Q_ASSERT(camera);
 827    Q_D(QGLPainter);
 828    QGLPAINTER_CHECK_PRIVATE();
 829    QMatrix4x4 lookAt = camera->modelViewMatrix(d->eye);
 830    d->modelViewMatrix = lookAt;
 831    d->projectionMatrix = camera->projectionMatrix(aspectRatio());
 832    d->inverseEyeMatrix = lookAt.inverted();
 833}
 834
 835/*!
 836    Returns true if \a point is outside the current viewing volume.
 837    This is used to perform object culling checks.
 838*/
 839bool QGLPainter::isCullable(const QVector3D& point) const
 840{
 841    Q_D(const QGLPainter);
 842    QGLPAINTER_CHECK_PRIVATE();
 843    QVector3D projected = d->modelViewMatrix * point;
 844    projected = d->projectionMatrix * projected;
 845    return !d->viewingCube.contains(projected);
 846}
 847
 848static inline uint outcode(const QVector4D &v)
 849{
 850    // For a discussion of outcodes see pg 388 Dunn & Parberry.
 851    // For why you can't just test if the point is in a bounding box
 852    // consider the case where a view frustum with view-size 1.5 x 1.5
 853    // is tested against a 2x2 box which encloses the near-plane, while
 854    // all the points in the box are outside the frustum.
 855    // TODO: optimise this with assembler - according to D&P this can
 856    // be done in one line of assembler on some platforms
 857    uint code = 0;
 858    if (v.x() < -v.w()) code |= 0x01;
 859    if (v.x() > v.w())  code |= 0x02;
 860    if (v.y() < -v.w()) code |= 0x04;
 861    if (v.y() > v.w())  code |= 0x08;
 862    if (v.z() < -v.w()) code |= 0x10;
 863    if (v.z() > v.w())  code |= 0x20;
 864    return code;
 865}
 866
 867/*!
 868    Returns true if \a box is completely outside the current viewing volume.
 869    This is used to perform object culling checks.
 870*/
 871bool QGLPainter::isCullable(const QBox3D& box) const
 872{
 873    Q_D(const QGLPainter);
 874    QGLPAINTER_CHECK_PRIVATE();
 875    // This function uses the technique of view frustum culling known as
 876    // clip space testing.  Since the normal QVector3D representation
 877    // of the points throws away the w value needed, we convert the box
 878    // into a set of 8 points represented as QVector4D's and then apply
 879    // the test.  The test is to transform the points into clip space
 880    // by applying the MV and Proj matrices, then test to see if the 4D
 881    // points are outside the clip space by testing x, y & z against w.
 882    QArray<QVector4D> box4d;
 883    QVector3D n = box.minimum();
 884    QVector3D x = box.maximum();
 885    box4d.append(QVector4D(n.x(), n.y(), x.z(), 1), QVector4D(x.x(), n.y(), x.z(), 1),
 886                 QVector4D(x.x(), x.y(), x.z(), 1), QVector4D(n.x(), x.y(), x.z(), 1));
 887    box4d.append(QVector4D(n.x(), n.y(), n.z(), 1), QVector4D(x.x(), n.y(), n.z(), 1),
 888                 QVector4D(x.x(), x.y(), n.z(), 1), QVector4D(n.x(), x.y(), n.z(), 1));
 889    QMatrix4x4 mvp = d->projectionMatrix.top() * d->modelViewMatrix.top();
 890    for (int i = 0; i < box4d.size(); ++i)
 891    {
 892        box4d[i] = mvp * box4d.at(i);
 893    }
 894    // if the logical AND of all the outcodes is non-zero then the BB is
 895    // definitely outside the view frustum.
 896    uint out = 0xff;
 897    for (int i = 0; i < box4d.size(); ++i)
 898    {
 899        out = out & outcode(box4d.at(i));
 900    }
 901    return out;
 902}
 903
 904/*!
 905    Returns the current render order sequencer.
 906
 907    \sa QGLRenderSequencer
 908*/
 909QGLRenderSequencer *QGLPainter::renderSequencer()
 910{
 911    Q_D(QGLPainter);
 912    if (!d->renderSequencer)
 913        d->renderSequencer = new QGLRenderSequencer(this);
 914    return d->renderSequencer;
 915}
 916
 917/*!
 918    Returns the aspect ratio of the viewport for adjusting projection
 919    transformations.
 920*/
 921qreal QGLPainter::aspectRatio() const
 922{
 923    return currentSurface()->aspectRatio();
 924}
 925
 926/*!
 927    Returns the current effect that is in use, which is userEffect()
 928    if it is not null, or the effect object associated with
 929    standardEffect() otherwise.
 930
 931    If isPicking() is true, then this will return the effect object
 932    that is being used to generate pick colors.
 933
 934    \sa userEffect(), standardEffect(), isPicking()
 935*/
 936QGLAbstractEffect *QGLPainter::effect() const
 937{
 938    Q_D(QGLPainter);
 939    QGLPAINTER_CHECK_PRIVATE();
 940    d->ensureEffect(const_cast<QGLPainter *>(this));
 941    return d->effect;
 942}
 943
 944/*!
 945    Returns the user-defined effect that is being used for drawing
 946    operations, or null if standardEffect() is in use.
 947
 948    \sa setUserEffect(), standardEffect(), effect()
 949*/
 950QGLAbstractEffect *QGLPainter::userEffect() const
 951{
 952    Q_D(QGLPainter);
 953    QGLPAINTER_CHECK_PRIVATE();
 954    return d->userEffect;
 955}
 956
 957/*!
 958    Sets a user-defined \a effect to use for drawing operations
 959    in the current GL context.  If \a effect is null, this will
 960    disable user-defined effects and return to using standardEffect().
 961
 962    \sa effect(), draw(), setStandardEffect()
 963*/
 964void QGLPainter::setUserEffect(QGLAbstractEffect *effect)
 965{
 966    Q_D(QGLPainter);
 967    QGLPAINTER_CHECK_PRIVATE();
 968    if (d->userEffect == effect)
 969        return;
 970    if (d->effect)
 971        d->effect->setActive(this, false);
 972    d->userEffect = effect;
 973    if (effect && (!d->pick || !d->pick->isPicking)) {
 974        d->effect = effect;
 975        d->effect->setActive(this, true);
 976        d->updates = UpdateAll;
 977    } else {
 978        // Revert to the effect associated with standardEffect().
 979        d->effect = 0;
 980        d->ensureEffect(this);
 981    }
 982}
 983
 984/*!
 985    Returns the standard effect to use for rendering fragments in
 986    the current GL context when userEffect() is null.
 987
 988    \sa setStandardEffect(), userEffect()
 989*/
 990QGL::StandardEffect QGLPainter::standardEffect() const
 991{
 992    Q_D(QGLPainter);
 993    QGLPAINTER_CHECK_PRIVATE();
 994    return d->standardEffect;
 995}
 996
 997/*!
 998    Sets a standard \a effect to use for rendering fragments
 999    in the current GL context.  This will also set userEffect()
1000    to null.  If \a effect is an invalid value, then the behavior
1001    of QGL::FlatColor will be used instead.
1002
1003    \sa standardEffect(), setUserEffect()
1004*/
1005void QGLPainter::setStandardEffect(QGL::StandardEffect effect)
1006{
1007    Q_D(QGLPainter);
1008    QGLPAINTER_CHECK_PRIVATE();
1009    if (d->standardEffect == effect && d->effect && d->userEffect == 0)
1010        return;
1011    if (d->effect)
1012        d->effect->setActive(this, false);
1013    d->standardEffect = effect;
1014    d->userEffect = 0;
1015    d->effect = 0;
1016    d->ensureEffect(this);
1017}
1018
1019/*!
1020    Disables the current effect and sets userEffect() to null.
1021    Unlike setUserEffect() this not activate the standardEffect()
1022    until the next time effect() is called.
1023
1024    This function can be used to disable all effect-based drawing
1025    operations prior to performing raw GL calls.  The next time
1026    effect() is called on this QGLPainter, the standardEffect()
1027    will be reactivated.  An effect can also be reactivated by
1028    calling setUserEffect() or setStandardEffect().
1029
1030    \sa userEffect(), standardEffect()
1031*/
1032void QGLPainter::disableEffect()
1033{
1034    Q_D(QGLPainter);
1035    QGLPAINTER_CHECK_PRIVATE();
1036    if (d->effect)
1037        d->effect->setActive(this, false);
1038    d->userEffect = 0;
1039    d->effect = 0;
1040}
1041
1042/*!
1043    Returns the cached shader program associated with \a name; or null
1044    if \a name is not currently associated with a shader program.
1045
1046    \sa setCachedProgram()
1047*/
1048QOpenGLShaderProgram *QGLPainter::cachedProgram(const QString& name) const
1049{
1050    Q_D(const QGLPainter);
1051    QGLPAINTER_CHECK_PRIVATE();
1052    return d->cachedPrograms.value(name, 0);
1053}
1054
1055/*!
1056    Sets the cached shader \a program associated with \a name.
1057
1058    Effect objects can use this function to store pre-compiled
1059    and pre-linked shader programs in the painter for future
1060    use by the same effect.  The \a program will be destroyed
1061    when context() is destroyed.
1062
1063    If \a program is null, then the program associated with \a name
1064    will be destroyed.  If \a name is already present as a cached
1065    program, then it will be replaced with \a program.
1066
1067    Names that start with "\c{qt.}" are reserved for use by Qt's
1068    internal effects.
1069
1070    \sa cachedProgram()
1071*/
1072void QGLPainter::setCachedProgram
1073    (const QString& name, QOpenGLShaderProgram *program)
1074{
1075    Q_D(QGLPainter);
1076    QGLPAINTER_CHECK_PRIVATE();
1077    QOpenGLShaderProgram *current = d->cachedPrograms.value(name, 0);
1078    if (current != program) {
1079        if (program)
1080            d->cachedPrograms[name] = program;
1081        else
1082            d->cachedPrograms.remove(name);
1083        delete current;
1084    }
1085}
1086
1087void QGLPainterPrivate::createEffect(QGLPainter *painter)
1088{
1089    if (userEffect) {
1090        if (!pick || !pick->isPicking) {
1091            effect = userEffect;
1092            effect->setActive(painter, true);
1093            updates = QGLPainter::UpdateAll;
1094            return;
1095        }
1096        if (userEffect->supportsPicking()) {
1097            effect = userEffect;
1098            effect->setActive(painter, true);
1099            updates = QGLPainter::UpdateAll;
1100            return;
1101        }
1102        effect = pick->defaultPickEffect;
1103        effect->setActive(painter, true);
1104        updates = QGLPainter::UpdateAll;
1105        return;
1106    }
1107    if (uint(standardEffect) >= QGL_MAX_STD_EFFECTS)
1108        effect = stdeffects[int(QGL::FlatColor)];
1109    else
1110        effect = stdeffects[int(standardEffect)];
1111    if (!effect) {
1112        switch (standardEffect) {
1113        case QGL::FlatColor: default:
1114            effect = new QGLFlatColorEffect();
1115            break;
1116        case QGL::FlatPerVertexColor:
1117            effect = new QGLPerVertexColorEffect();
1118            break;
1119        case QGL::FlatReplaceTexture2D:
1120            effect = new QGLFlatTextureEffect();
1121            break;
1122        case QGL::FlatDecalTexture2D:
1123            effect = new QGLFlatDecalTextureEffect();
1124            break;
1125        case QGL::LitMaterial:
1126            effect = new QGLLitMaterialEffect();
1127            break;
1128        case QGL::LitDecalTexture2D:
1129            effect = new QGLLitDecalTextureEffect();
1130            break;
1131        case QGL::LitModulateTexture2D:
1132            effect = new QGLLitModulateTextureEffect();
1133            break;
1134        }
1135        if (uint(standardEffect) >= QGL_MAX_STD_EFFECTS)
1136            stdeffects[int(QGL::FlatColor)] = effect;
1137        else
1138            stdeffects[int(standardEffect)] = effect;
1139    }
1140    if (!pick || !pick->isPicking || effect->supportsPicking()) {
1141        effect->setActive(painter, true);
1142    } else {
1143        effect = pick->defaultPickEffect;
1144        effect->setActive(painter, true);
1145    }
1146    updates = QGLPainter::UpdateAll;
1147}
1148
1149/*!
1150    Returns the last color that was set with setColor().  The default
1151    value is (1, 1, 1, 1).
1152
1153    \sa setColor()
1154*/
1155QColor QGLPainter::color() const
1156{
1157    Q_D(QGLPainter);
1158    QGLPAINTER_CHECK_PRIVATE();
1159    return d->color;
1160}
1161
1162/*!
1163    Sets the default fragment \a color for effects associated
1164    with this painter.  This function does not apply the color
1165    to the effect until update() is called.
1166
1167    \sa color(), update()
1168*/
1169void QGLPainter::setColor(const QColor& color)
1170{
1171    Q_D(QGLPainter);
1172    QGLPAINTER_CHECK_PRIVATE();
1173    d->color = color;
1174    d->updates |= UpdateColor;
1175}
1176
1177static void qt_gl_setVertexAttribute(QGL::VertexAttribute attribute, const QGLAttributeValue& value)
1178{
1179#if !defined(QT_OPENGL_ES_2)
1180    switch (attribute) {
1181    case QGL::Position:
1182        glVertexPointer(value.tupleSize(), value.type(),
1183                        value.stride(), value.data());
1184        break;
1185
1186    case QGL::Normal:
1187        if (value.tupleSize() == 3)
1188            glNormalPointer(value.type(), value.stride(), value.data());
1189        break;
1190
1191    case QGL::Color:
1192        glColorPointer(value.tupleSize(), value.type(),
1193                       value.stride(), value.data());
1194        break;
1195
1196#ifdef GL_TEXTURE_COORD_ARRAY
1197    case QGL::TextureCoord0:
1198    case QGL::TextureCoord1:
1199    case QGL::TextureCoord2:
1200    {
1201        int unit = (int)(attribute - QGL::TextureCoord0);
1202        qt_gl_ClientActiveTexture(GL_TEXTURE0 + unit);
1203        glTexCoordPointer(value.tupleSize(), value.type(),
1204                          value.stride(), value.data());
1205        if (unit != 0)  // Stay on unit 0 between requests.
1206            qt_gl_ClientActiveTexture(GL_TEXTURE0);
1207    }
1208    break;
1209#endif
1210
1211    default: break;
1212    }
1213#else
1214    Q_UNUSED(attribute);
1215    Q_UNUSED(value);
1216#endif
1217}
1218
1219/*!
1220    Returns the set of vertex attributes that have been set on the
1221    painter state by setVertexAttribute() and setVertexBundle()
1222    since the last call to clearAttributes().
1223
1224    The most common use for this function is to determine if specific
1225    attributes have been supplied on the painter so as to adjust the
1226    current drawing effect accordingly.  The following example will
1227    use a lit texture effect if texture co-ordinates were provided
1228    in the vertex bundle, or a simple lit material effect if
1229    texture co-ordinates were not provided:
1230
1231    \code
1232    painter.clearAttributes();
1233    painter.setVertexBundle(bundle);
1234    if (painter.attributes().contains(QGL::TextureCoord0))
1235        painter.setStandardEffect(QGL::LitModulateTexture2D);
1236    else
1237        painter.setStandardEffect(QGL::LitMaterial);
1238    \endcode
1239
1240    It is important to clear the attributes before setting the vertex
1241    bundle, so that attributes from a previous bundle will not leak
1242    through.  Multiple vertex bundles may be supplied if they contain
1243    different parts of the same logical piece of geometry.
1244
1245    \sa clearAttributes(), setVertexBundle()
1246*/
1247QGLAttributeSet QGLPainter::attributes() const
1248{
1249    Q_D(const QGLPainter);
1250    QGLPAINTER_CHECK_PRIVATE();
1251    return d->attributeSet;
1252}
1253
1254/*!
1255    Clears the set of vertex attributes that have been set on the
1256    painter state by setVertexAttribute() and setVertexBundle().
1257    See the documentation for attributes() for more information.
1258
1259    \sa attributes()
1260*/
1261void QGLPainter::clearAttributes()
1262{
1263    Q_D(QGLPainter);
1264    QGLPAINTER_CHECK_PRIVATE();
1265    d->attributeSet.clear();
1266}
1267
1268/*!
1269    Sets a vertex \a attribute on the current GL context to \a value.
1270
1271    The vertex attribute is bound to the GL state on the index
1272    corresponding to \a attribute.  For example, QGL::Position
1273    will be bound to index 0, QGL::TextureCoord0 will be bound
1274    to index 3, etc.
1275
1276    Vertex attributes are independent of the effect() and can be
1277    bound once and then used with multiple effects.
1278
1279    If this is the first attribute in a new piece of geometry,
1280    it is recommended that clearAttributes() be called before this
1281    function.  This will inform QGLPainter that a new piece of geometry
1282    is being provided and that the previous geometry is now invalid.
1283    See the documentation for attributes() for more information.
1284
1285    \sa setVertexBundle(), draw(), clearAttributes(), attributes()
1286*/
1287void QGLPainter::setVertexAttribute
1288    (QGL::VertexAttribute attribute, const QGLAttributeValue& value)
1289{
1290    Q_D(QGLPainter);
1291    QGLPAINTER_CHECK_PRIVATE();
1292    d->ensureEffect(this);
1293    if (d->boundVertexBuffer) {
1294        QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
1295        d->boundVertexBuffer = 0;
1296    }
1297    if (d->isFixedFunction) {
1298        qt_gl_setVertexAttribute(attribute, value);
1299    } else {
1300        glVertexAttribPointer(GLuint(attribute), value.tupleSize(),
1301                              value.type(), GL_TRUE,
1302                              value.stride(), value.data());
1303    }
1304    d->attributeSet.insert(attribute);
1305}
1306
1307/*!
1308    Sets the vertex attributes on the current GL context that are
1309    stored in \a buffer.
1310
1311    The vertex attributes are bound to the GL state on the indexes
1312    that are specified within \a buffer; QGL::Position will be
1313    bound to index 0, QGL::TextureCoord0 will be bound to index 3, etc.
1314
1315    Vertex attributes are independent of the effect() and can be
1316    bound once and then used with multiple effects.
1317
1318    It is recommended that clearAttributes() be called before this
1319    function to inform QGLPainter that a new piece of geometry is
1320    being provided and that the previous geometry is now invalid.
1321    See the documentation for attributes() for more information.
1322
1323    \sa setVertexAttribute(), draw(), clearAttributes(), attributes()
1324*/
1325void QGLPainter::setVertexBundle(const QGLVertexBundle& buffer)
1326{
1327    Q_D(QGLPainter);
1328    QGLPAINTER_CHECK_PRIVATE();
1329    d->ensureEffect(this);
1330    QGLVertexBundlePrivate *bd = const_cast<QGLVertexBundlePrivate *>(buffer.d_func());
1331    if (bd->buffer.isCreated()) {
1332        GLuint id = bd->buffer.bufferId();
1333        if (id != d->boundVertexBuffer) {
1334            bd->buffer.bind();
1335            d->boundVertexBuffer = id;
1336        }
1337    } else if (d->boundVertexBuffer) {
1338        QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
1339        d->boundVertexBuffer = 0;
1340    }
1341    for (int index = 0; index < bd->attributes.size(); ++index) {
1342        QGLVertexBundleAttribute *attr = bd->attributes[index];
1343        if (d->isFixedFunction) {
1344            qt_gl_setVertexAttribute(attr->attribute, attr->value);
1345        } else {
1346            glVertexAttribPointer(GLuint(attr->attribute),
1347                                  attr->value.tupleSize(),
1348                                  attr->value.type(), GL_TRUE,
1349                                  attr->value.stride(), attr->value.data());
1350        }
1351    }
1352    d->attributeSet.unite(buffer.attributes());
1353}
1354
1355/*!
1356    Updates the projection matrix, modelview matrix, and lighting
1357    conditions in the currently active effect() object by calling
1358    QGLAbstractEffect::update().  Also updates \c{glViewport()}
1359    to cover the currentSurface() if necessary.
1360
1361    Normally this function is called automatically by draw().
1362    However, if the user wishes to use raw GL functions to draw fragments,
1363    it will be necessary to explicitly call this function to ensure that
1364    the matrix state and lighting conditions have been set on the
1365    active effect().
1366
1367    Note that this function informs the effect that an update is needed.
1368    It does not change the GL state itself, except for \c{glViewport()}.
1369    In particular, the modelview and projection matrices in the
1370    fixed-function pipeline are not changed unless the effect or
1371    application calls updateFixedFunction().
1372
1373    \sa setUserEffect(), projectionMatrix(), modelViewMatrix()
1374    \sa draw(), updateFixedFunction()
1375*/
1376void QGLPainter::update()
1377{
1378    Q_D(QGLPainter);
1379    QGLPAINTER_CHECK_PRIVATE();
1380    d->ensureEffect(this);
1381    QGLPainter::Updates updates = d->updates;
1382    d->updates = 0;
1383    if (d->modelViewMatrix.isDirty()) {
1384        updates |= UpdateModelViewMatrix;
1385        d->modelViewMatrix.setDirty(false);
1386    }
1387    if (d->projectionMatrix.isDirty()) {
1388        updates |= UpdateProjectionMatrix;
1389        d->projectionMatrix.setDirty(false);
1390    }
1391    if ((updates & UpdateViewport) != 0) {
1392        QRect viewport = currentSurface()->viewportGL();
1393        glViewport(0, 0, viewport.width(), viewport.height());
1394    }
1395    if (updates != 0)
1396        d->effect->update(this, updates);
1397}
1398
1399#if !defined(QT_OPENGL_ES_2)
1400
1401static void setLight(int light, const QGLLightParameters *parameters,
1402                     const QMatrix4x4& transform)
1403{
1404    GLfloat params[4];
1405
1406    QColor color = parameters->ambientColor();
1407    params[0] = color.redF();
1408    params[1] = color.greenF();
1409    params[2] = color.blueF();
1410    params[3] = color.alphaF();
1411    glLightfv(light, GL_AMBIENT, params);
1412
1413    color = parameters->diffuseColor();
1414    params[0] = color.redF();
1415    params[1] = color.greenF();
1416    params[2] = color.blueF();
1417    params[3] = color.alphaF();
1418    glLightfv(light, GL_DIFFUSE, params);
1419
1420    color = parameters->specularColor();
1421    params[0] = color.redF();
1422    params[1] = color.greenF();
1423    params[2] = color.blueF();
1424    params[3] = color.alphaF();
1425    glLightfv(light, GL_SPECULAR, params);
1426
1427    QVector4D vector = parameters->eyePosition(transform);
1428    params[0] = vector.x();
1429    params[1] = vector.y();
1430    params[2] = vector.z();
1431    params[3] = vector.w();
1432    glLightfv(light, GL_POSITION, params);
1433
1434    QVector3D spotDirection = parameters->eyeSpotDirection(transform);
1435    params[0] = spotDirection.x();
1436    params[1] = spotDirection.y();
1437    params[2] = spotDirection.z();
1438    glLightfv(light, GL_SPOT_DIRECTION, params);
1439
1440    params[0] = parameters->spotExponent();
1441    glLightfv(light, GL_SPOT_EXPONENT, params);
1442
1443    params[0] = parameters->spotAngle();
1444    glLightfv(light, GL_SPOT_CUTOFF, params);
1445
1446    params[0] = parameters->constantAttenuation();
1447    glLightfv(light, GL_CONSTANT_ATTENUATION, params);
1448
1449    params[0] = parameters->linearAttenuation();
1450    glLightfv(light, GL_LINEAR_ATTENUATION, params);
1451
1452    params[0] = parameters->quadraticAttenuation();
1453    glLightfv(light, GL_QUADRATIC_ATTENUATION, params);
1454}
1455
1456static void setMaterial(int face, const QGLMaterial *parameters)
1457{
1458    GLfloat params[17];
1459
1460    QColor mcolor = parameters->ambientColor();
1461    params[0] = mcolor.redF();
1462    params[1] = mcolor.greenF();
1463    params[2] = mcolor.blueF();
1464    params[3] = mcolor.alphaF();
1465
1466    mcolor = parameters->diffuseColor();
1467    params[4] = mcolor.redF();
1468    params[5] = mcolor.greenF();
1469    params[6] = mcolor.blueF();
1470    params[7] = mcolor.alphaF();
1471
1472    mcolor = parameters->specularColor();
1473    params[8] = mcolor.redF();
1474    params[9] = mcolor.greenF();
1475    params[10] = mcolor.blueF();
1476    params[11] = mcolor.alphaF();
1477
1478    mcolor = parameters->emittedLight();
1479    params[12] = mcolor.redF();
1480    params[13] = mcolor.greenF();
1481    params[14] = mcolor.blueF();
1482    params[15] = mcolor.alphaF();
1483
1484    params[16] = parameters->shininess();
1485
1486    glMaterialfv(face, GL_AMBIENT, params);
1487    glMaterialfv(face, GL_DIFFUSE, params + 4);
1488    glMaterialfv(face, GL_SPECULAR, params + 8);
1489    glMaterialfv(face, GL_EMISSION, params + 12);
1490    glMaterialfv(face, GL_SHININESS, params + 16);
1491}
1492
1493#endif // !QT_OPENGL_ES_2
1494
1495/*!
1496    Updates the fixed-function pipeline with the current painting
1497    state according to the flags in \a updates.
1498
1499    This function is intended for use by effects in their
1500    QGLAbstractEffect::update() override if they are using the
1501    fixed-function pipeline.  It can also be used by user
1502    applications if they need the QGLPainter state to be
1503    set in the fixed-function pipeline.
1504
1505    If the OpenGL implementation does not have a fixed-function
1506    pipeline, e.g. OpenGL/ES 2.0, this function does nothing.
1507
1508    \sa update()
1509*/
1510void QGLPainter::updateFixedFunction(QGLPainter::Updates updates)
1511{
1512#if defined(QT_OPENGL_ES_2)
1513    Q_UNUSED(updates);
1514#else
1515    Q_D(QGLPainter);
1516    QGLPAINTER_CHECK_PRIVATE();
1517    if ((updates & QGLPainter::UpdateColor) != 0) {
1518        QColor color;
1519        if (isPicking())
1520            color = pickColor();
1521        else
1522            color = this->color();
1523        glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
1524    }
1525    if ((updates & QGLPainter::UpdateModelViewMatrix) != 0) {
1526        const QMatrix4x4 &matrix = d->modelViewMatrix.top();
1527        glMatrixMode(GL_MODELVIEW);
1528        if (sizeof(qreal) == sizeof(GLfloat)) {
1529            glLoadMatrixf(reinterpret_cast<const GLfloat *>
1530                (matrix.constData()));
1531        } else {
1532            GLfloat mat[16];
1533            const qreal *m = matrix.constData();
1534            for (int index = 0; index < 16; ++index)
1535                mat[index] = m[index];
1536            glLoadMatrixf(mat);
1537        }
1538    }
1539    if ((updates & QGLPainter::UpdateProjectionMatrix) != 0) {
1540        const QMatrix4x4 &matrix = d->projectionMatrix.top();
1541        glMatrixMode(GL_PROJECTION);
1542        if (sizeof(qreal) == sizeof(GLfloat)) {
1543            glLoadMatrixf(reinterpret_cast<const GLfloat *>
1544                (matrix.constData()));
1545        } else {
1546            GLfloat mat[16];
1547            const qreal *m = matrix.constData();
1548            for (int index = 0; index < 16; ++index)
1549                mat[index] = m[index];
1550            glLoadMatrixf(mat);
1551        }
1552    }
1553    if ((updates & QGLPainter::UpdateLights) != 0) {
1554        // Save the current modelview matrix and load the identity.
1555        // We need to apply the light in the modelview transformation
1556        // that was active when the light was specified.
1557        glMatrixMode(GL_MODELVIEW);
1558        glPushMatrix();
1559        glLoadIdentity();
1560
1561        // Enable the main light.
1562        const QGLLightParameters *params = mainLight();
1563        setLight(GL_LIGHT0, params, mainLightTransform());
1564
1565        // Restore the previous modelview transformation.
1566        glPopMatrix();
1567
1568        // Set up the light model parameters if at least one light is enabled.
1569        const QGLLightModel *lightModel = this->lightModel();
1570        GLfloat values[4];
1571#ifdef GL_LIGHT_MODEL_TWO_SIDE
1572        if (lightModel->model() == QGLLightModel::TwoSided)
1573            values[0] = 1.0f;
1574        else
1575            values[0] = 0.0f;
1576        glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, values);
1577#endif
1578#ifdef GL_LIGHT_MODEL_COLOR_CONTROL
1579        if (lightModel->colorControl() == QGLLightModel::SeparateSpecularColor)
1580            values[0] = GL_SEPARATE_SPECULAR_COLOR;
1581        else
1582            values[0] = GL_SINGLE_COLOR;
1583        glLightModelfv(GL_LIGHT_MODEL_COLOR_CONTROL, values);
1584#endif
1585#ifdef GL_LIGHT_MODEL_LOCAL_VIEWER
1586        if (lightModel->viewerPosition() == QGLLightModel::LocalViewer)
1587            values[0] = 1.0f;
1588        else
1589            values[0] = 0.0f;
1590        glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, values);
1591#endif
1592#ifdef GL_LIGHT_MODEL_AMBIENT
1593        QColor color = lightModel->ambientSceneColor();
1594        values[0] = color.redF();
1595        values[1] = color.blueF();
1596        values[2] = color.greenF();
1597     

Large files files are truncated, but you can click here to view the full file