/src/threed/painting/qglpainter.cpp
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