source: trunk/src/opengl/qgl.cpp@ 842

Last change on this file since 842 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

File size: 162.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qapplication.h"
43#include "qplatformdefs.h"
44#include "qgl.h"
45#include <qdebug.h>
46
47#if defined(Q_WS_X11)
48#include "private/qt_x11_p.h"
49#include "private/qpixmap_x11_p.h"
50#define INT32 dummy_INT32
51#define INT8 dummy_INT8
52#if !defined(QT_OPENGL_ES)
53# include <GL/glx.h>
54#endif
55#undef INT32
56#undef INT8
57#include "qx11info_x11.h"
58#elif defined(Q_WS_MAC)
59# include <private/qt_mac_p.h>
60#endif
61
62#include <qdatetime.h>
63
64#include <stdlib.h> // malloc
65
66#include "qpixmap.h"
67#include "qimage.h"
68#include "qgl_p.h"
69
70#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
71#include "gl2paintengineex/qpaintengineex_opengl2_p.h"
72#endif
73
74#ifndef QT_OPENGL_ES_2
75#include <private/qpaintengine_opengl_p.h>
76#endif
77
78#ifdef Q_WS_QWS
79#include <private/qglwindowsurface_qws_p.h>
80#endif
81
82#include <qglpixelbuffer.h>
83#include <qglframebufferobject.h>
84
85#include <private/qimage_p.h>
86#include <private/qpixmapdata_p.h>
87#include <private/qpixmapdata_gl_p.h>
88#include <private/qglpixelbuffer_p.h>
89#include <private/qwindowsurface_gl_p.h>
90#include <private/qimagepixmapcleanuphooks_p.h>
91#include "qcolormap.h"
92#include "qfile.h"
93#include "qlibrary.h"
94
95
96QT_BEGIN_NAMESPACE
97
98#ifdef QT_OPENGL_ES_1_CL
99#include "qgl_cl_p.h"
100#endif
101
102
103#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
104QGLExtensionFuncs QGLContextPrivate::qt_extensionFuncs;
105#endif
106
107#ifdef Q_WS_X11
108extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
109#endif
110
111struct QGLThreadContext {
112 QGLContext *context;
113};
114
115static QThreadStorage<QGLThreadContext *> qgl_context_storage;
116
117Q_GLOBAL_STATIC(QGLFormat, qgl_default_format)
118
119class QGLDefaultOverlayFormat: public QGLFormat
120{
121public:
122 inline QGLDefaultOverlayFormat()
123 {
124 setOption(QGL::FormatOption(0xffff << 16)); // turn off all options
125 setOption(QGL::DirectRendering);
126 setPlane(1);
127 }
128};
129Q_GLOBAL_STATIC(QGLDefaultOverlayFormat, defaultOverlayFormatInstance)
130
131Q_GLOBAL_STATIC(QGLSignalProxy, theSignalProxy)
132QGLSignalProxy *QGLSignalProxy::instance()
133{
134 return theSignalProxy();
135}
136
137
138class QGLEngineSelector
139{
140public:
141 QGLEngineSelector() : engineType(QPaintEngine::MaxUser)
142 {
143 }
144
145 void setPreferredPaintEngine(QPaintEngine::Type type) {
146 if (type == QPaintEngine::OpenGL || type == QPaintEngine::OpenGL2)
147 engineType = type;
148 }
149
150 QPaintEngine::Type preferredPaintEngine() {
151#ifdef Q_WS_MAC
152 // The ATI X1600 driver for Mac OS X does not support return
153 // values from functions in GLSL. Since working around this in
154 // the GL2 engine would require a big, ugly rewrite, we're
155 // falling back to the GL 1 engine..
156 static bool mac_x1600_check_done = false;
157 if (!mac_x1600_check_done) {
158 QGLTemporaryContext *tmp = 0;
159 if (!QGLContext::currentContext())
160 tmp = new QGLTemporaryContext();
161 if (strstr((char *) glGetString(GL_RENDERER), "X1600"))
162 engineType = QPaintEngine::OpenGL;
163 if (tmp)
164 delete tmp;
165 mac_x1600_check_done = true;
166 }
167#endif
168 if (engineType == QPaintEngine::MaxUser) {
169 // No user-set engine - use the defaults
170#if defined(QT_OPENGL_ES_2)
171 engineType = QPaintEngine::OpenGL2;
172#else
173 // We can't do this in the constructor for this object because it
174 // needs to be called *before* the QApplication constructor.
175 // Also check for the FragmentShader extension in conjunction with
176 // the 2.0 version flag, to cover the case where we export the display
177 // from an old GL 1.1 server to a GL 2.x client. In that case we can't
178 // use GL 2.0.
179 if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)
180 && (QGLExtensions::glExtensions() & QGLExtensions::FragmentShader)
181 && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty())
182 engineType = QPaintEngine::OpenGL2;
183 else
184 engineType = QPaintEngine::OpenGL;
185#endif
186 }
187 return engineType;
188 }
189
190private:
191 QPaintEngine::Type engineType;
192};
193
194Q_GLOBAL_STATIC(QGLEngineSelector, qgl_engine_selector)
195
196
197bool qt_gl_preferGL2Engine()
198{
199 return qgl_engine_selector()->preferredPaintEngine() == QPaintEngine::OpenGL2;
200}
201
202
203/*!
204 \namespace QGL
205 \inmodule QtOpenGL
206
207 \brief The QGL namespace specifies miscellaneous identifiers used
208 in the Qt OpenGL module.
209
210 \ingroup painting-3D
211*/
212
213/*!
214 \enum QGL::FormatOption
215
216 This enum specifies the format options that can be used to configure an OpenGL
217 context. These are set using QGLFormat::setOption().
218
219 \value DoubleBuffer Specifies the use of double buffering.
220 \value DepthBuffer Enables the use of a depth buffer.
221 \value Rgba Specifies that the context should use RGBA as its pixel format.
222 \value AlphaChannel Enables the use of an alpha channel.
223 \value AccumBuffer Enables the use of an accumulation buffer.
224 \value StencilBuffer Enables the use of a stencil buffer.
225 \value StereoBuffers Enables the use of a stereo buffers for use with visualization hardware.
226 \value DirectRendering Specifies that the context is used for direct rendering to a display.
227 \value HasOverlay Enables the use of an overlay.
228 \value SampleBuffers Enables the use of sample buffers.
229 \value SingleBuffer Specifies the use of a single buffer, as opposed to double buffers.
230 \value NoDepthBuffer Disables the use of a depth buffer.
231 \value ColorIndex Specifies that the context should use a color index as its pixel format.
232 \value NoAlphaChannel Disables the use of an alpha channel.
233 \value NoAccumBuffer Disables the use of an accumulation buffer.
234 \value NoStencilBuffer Disables the use of a stencil buffer.
235 \value NoStereoBuffers Disables the use of stereo buffers.
236 \value IndirectRendering Specifies that the context is used for indirect rendering to a buffer.
237 \value NoOverlay Disables the use of an overlay.
238 \value NoSampleBuffers Disables the use of sample buffers.
239
240 \sa {Sample Buffers Example}
241*/
242
243/*!
244 \fn void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType)
245
246 \since 4.6
247
248 Sets the preferred OpenGL paint engine that is used to draw onto
249 QGLWidget, QGLPixelBuffer and QGLFramebufferObject targets with QPainter
250 in Qt.
251
252 The \a engineType parameter specifies which of the GL engines to
253 use. Only \c QPaintEngine::OpenGL and \c QPaintEngine::OpenGL2 are
254 valid parameters to this function. All other values are ignored.
255
256 By default, the \c QPaintEngine::OpenGL2 engine is used if GL/GLES
257 version 2.0 is available, otherwise \c QPaintEngine::OpenGL is
258 used.
259
260 \warning This function must be called before the QApplication
261 constructor is called.
262*/
263void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType)
264{
265 qgl_engine_selector()->setPreferredPaintEngine(engineType);
266}
267
268
269/*****************************************************************************
270 QGLFormat implementation
271 *****************************************************************************/
272
273
274/*!
275 \class QGLFormat
276 \brief The QGLFormat class specifies the display format of an OpenGL
277 rendering context.
278
279 \ingroup painting-3D
280
281 A display format has several characteristics:
282 \list
283 \i \link setDoubleBuffer() Double or single buffering.\endlink
284 \i \link setDepth() Depth buffer.\endlink
285 \i \link setRgba() RGBA or color index mode.\endlink
286 \i \link setAlpha() Alpha channel.\endlink
287 \i \link setAccum() Accumulation buffer.\endlink
288 \i \link setStencil() Stencil buffer.\endlink
289 \i \link setStereo() Stereo buffers.\endlink
290 \i \link setDirectRendering() Direct rendering.\endlink
291 \i \link setOverlay() Presence of an overlay.\endlink
292 \i \link setPlane() Plane of an overlay.\endlink
293 \i \link setSampleBuffers() Multisample buffers.\endlink
294 \endlist
295
296 You can also specify preferred bit depths for the color buffer,
297 depth buffer, alpha buffer, accumulation buffer and the stencil
298 buffer with the functions: setRedBufferSize(), setGreenBufferSize(),
299 setBlueBufferSize(), setDepthBufferSize(), setAlphaBufferSize(),
300 setAccumBufferSize() and setStencilBufferSize().
301
302 Note that even if you specify that you prefer a 32 bit depth
303 buffer (e.g. with setDepthBufferSize(32)), the format that is
304 chosen may not have a 32 bit depth buffer, even if there is a
305 format available with a 32 bit depth buffer. The main reason for
306 this is how the system dependant picking algorithms work on the
307 different platforms, and some format options may have higher
308 precedence than others.
309
310 You create and tell a QGLFormat object what rendering options you
311 want from an OpenGL rendering context.
312
313 OpenGL drivers or accelerated hardware may or may not support
314 advanced features such as alpha channel or stereographic viewing.
315 If you request some features that the driver/hardware does not
316 provide when you create a QGLWidget, you will get a rendering
317 context with the nearest subset of features.
318
319 There are different ways to define the display characteristics of
320 a rendering context. One is to create a QGLFormat and make it the
321 default for the entire application:
322 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 0
323
324 Or you can specify the desired format when creating an object of
325 your QGLWidget subclass:
326 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 1
327
328 After the widget has been created, you can find out which of the
329 requested features the system was able to provide:
330 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 2
331
332 \legalese
333 OpenGL is a trademark of Silicon Graphics, Inc. in the
334 United States and other countries.
335 \endlegalese
336
337 \sa QGLContext, QGLWidget
338*/
339
340#ifndef QT_OPENGL_ES
341
342static inline void transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4])
343{
344#define M(row,col) m[col*4+row]
345 out[0] =
346 M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
347 out[1] =
348 M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
349 out[2] =
350 M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
351 out[3] =
352 M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
353#undef M
354}
355
356static inline GLint qgluProject(GLdouble objx, GLdouble objy, GLdouble objz,
357 const GLdouble model[16], const GLdouble proj[16],
358 const GLint viewport[4],
359 GLdouble * winx, GLdouble * winy, GLdouble * winz)
360{
361 GLdouble in[4], out[4];
362
363 in[0] = objx;
364 in[1] = objy;
365 in[2] = objz;
366 in[3] = 1.0;
367 transform_point(out, model, in);
368 transform_point(in, proj, out);
369
370 if (in[3] == 0.0)
371 return GL_FALSE;
372
373 in[0] /= in[3];
374 in[1] /= in[3];
375 in[2] /= in[3];
376
377 *winx = viewport[0] + (1 + in[0]) * viewport[2] / 2;
378 *winy = viewport[1] + (1 + in[1]) * viewport[3] / 2;
379
380 *winz = (1 + in[2]) / 2;
381 return GL_TRUE;
382}
383
384#endif // !QT_OPENGL_ES
385
386/*!
387 Constructs a QGLFormat object with the following default settings:
388 \list
389 \i \link setDoubleBuffer() Double buffer:\endlink Enabled.
390 \i \link setDepth() Depth buffer:\endlink Enabled.
391 \i \link setRgba() RGBA:\endlink Enabled (i.e., color index disabled).
392 \i \link setAlpha() Alpha channel:\endlink Disabled.
393 \i \link setAccum() Accumulator buffer:\endlink Disabled.
394 \i \link setStencil() Stencil buffer:\endlink Enabled.
395 \i \link setStereo() Stereo:\endlink Disabled.
396 \i \link setDirectRendering() Direct rendering:\endlink Enabled.
397 \i \link setOverlay() Overlay:\endlink Disabled.
398 \i \link setPlane() Plane:\endlink 0 (i.e., normal plane).
399 \i \link setSampleBuffers() Multisample buffers:\endlink Disabled.
400 \endlist
401*/
402
403QGLFormat::QGLFormat()
404{
405 d = new QGLFormatPrivate;
406}
407
408
409/*!
410 Creates a QGLFormat object that is a copy of the current
411 defaultFormat().
412
413 If \a options is not 0, the default format is modified by the
414 specified format options. The \a options parameter should be
415 QGL::FormatOption values OR'ed together.
416
417 This constructor makes it easy to specify a certain desired format
418 in classes derived from QGLWidget, for example:
419 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 3
420
421 Note that there are QGL::FormatOption values to turn format settings
422 both on and off, e.g. QGL::DepthBuffer and QGL::NoDepthBuffer,
423 QGL::DirectRendering and QGL::IndirectRendering, etc.
424
425 The \a plane parameter defaults to 0 and is the plane which this
426 format should be associated with. Not all OpenGL implementations
427 supports overlay/underlay rendering planes.
428
429 \sa defaultFormat(), setOption(), setPlane()
430*/
431
432QGLFormat::QGLFormat(QGL::FormatOptions options, int plane)
433{
434 d = new QGLFormatPrivate;
435 QGL::FormatOptions newOpts = options;
436 d->opts = defaultFormat().d->opts;
437 d->opts |= (newOpts & 0xffff);
438 d->opts &= ~(newOpts >> 16);
439 d->pln = plane;
440}
441
442/*!
443 \internal
444*/
445void QGLFormat::detach()
446{
447 if (d->ref != 1) {
448 QGLFormatPrivate *newd = new QGLFormatPrivate(d);
449 if (!d->ref.deref())
450 delete d;
451 d = newd;
452 }
453}
454
455/*!
456 Constructs a copy of \a other.
457*/
458
459QGLFormat::QGLFormat(const QGLFormat &other)
460{
461 d = other.d;
462 d->ref.ref();
463}
464
465/*!
466 Assigns \a other to this object.
467*/
468
469QGLFormat &QGLFormat::operator=(const QGLFormat &other)
470{
471 if (d != other.d) {
472 other.d->ref.ref();
473 if (!d->ref.deref())
474 delete d;
475 d = other.d;
476 }
477 return *this;
478}
479
480/*!
481 Destroys the QGLFormat.
482*/
483QGLFormat::~QGLFormat()
484{
485 if (!d->ref.deref())
486 delete d;
487}
488
489/*!
490 \fn bool QGLFormat::doubleBuffer() const
491
492 Returns true if double buffering is enabled; otherwise returns
493 false. Double buffering is enabled by default.
494
495 \sa setDoubleBuffer()
496*/
497
498/*!
499 If \a enable is true sets double buffering; otherwise sets single
500 buffering.
501
502 Double buffering is enabled by default.
503
504 Double buffering is a technique where graphics are rendered on an
505 off-screen buffer and not directly to the screen. When the drawing
506 has been completed, the program calls a swapBuffers() function to
507 exchange the screen contents with the buffer. The result is
508 flicker-free drawing and often better performance.
509
510 \sa doubleBuffer(), QGLContext::swapBuffers(),
511 QGLWidget::swapBuffers()
512*/
513
514void QGLFormat::setDoubleBuffer(bool enable)
515{
516 setOption(enable ? QGL::DoubleBuffer : QGL::SingleBuffer);
517}
518
519
520/*!
521 \fn bool QGLFormat::depth() const
522
523 Returns true if the depth buffer is enabled; otherwise returns
524 false. The depth buffer is enabled by default.
525
526 \sa setDepth(), setDepthBufferSize()
527*/
528
529/*!
530 If \a enable is true enables the depth buffer; otherwise disables
531 the depth buffer.
532
533 The depth buffer is enabled by default.
534
535 The purpose of a depth buffer (or Z-buffering) is to remove hidden
536 surfaces. Pixels are assigned Z values based on the distance to
537 the viewer. A pixel with a high Z value is closer to the viewer
538 than a pixel with a low Z value. This information is used to
539 decide whether to draw a pixel or not.
540
541 \sa depth(), setDepthBufferSize()
542*/
543
544void QGLFormat::setDepth(bool enable)
545{
546 setOption(enable ? QGL::DepthBuffer : QGL::NoDepthBuffer);
547}
548
549
550/*!
551 \fn bool QGLFormat::rgba() const
552
553 Returns true if RGBA color mode is set. Returns false if color
554 index mode is set. The default color mode is RGBA.
555
556 \sa setRgba()
557*/
558
559/*!
560 If \a enable is true sets RGBA mode. If \a enable is false sets
561 color index mode.
562
563 The default color mode is RGBA.
564
565 RGBA is the preferred mode for most OpenGL applications. In RGBA
566 color mode you specify colors as red + green + blue + alpha
567 quadruplets.
568
569 In color index mode you specify an index into a color lookup
570 table.
571
572 \sa rgba()
573*/
574
575void QGLFormat::setRgba(bool enable)
576{
577 setOption(enable ? QGL::Rgba : QGL::ColorIndex);
578}
579
580
581/*!
582 \fn bool QGLFormat::alpha() const
583
584 Returns true if the alpha buffer in the framebuffer is enabled;
585 otherwise returns false. The alpha buffer is disabled by default.
586
587 \sa setAlpha(), setAlphaBufferSize()
588*/
589
590/*!
591 If \a enable is true enables the alpha buffer; otherwise disables
592 the alpha buffer.
593
594 The alpha buffer is disabled by default.
595
596 The alpha buffer is typically used for implementing transparency
597 or translucency. The A in RGBA specifies the transparency of a
598 pixel.
599
600 \sa alpha(), setAlphaBufferSize()
601*/
602
603void QGLFormat::setAlpha(bool enable)
604{
605 setOption(enable ? QGL::AlphaChannel : QGL::NoAlphaChannel);
606}
607
608
609/*!
610 \fn bool QGLFormat::accum() const
611
612 Returns true if the accumulation buffer is enabled; otherwise
613 returns false. The accumulation buffer is disabled by default.
614
615 \sa setAccum(), setAccumBufferSize()
616*/
617
618/*!
619 If \a enable is true enables the accumulation buffer; otherwise
620 disables the accumulation buffer.
621
622 The accumulation buffer is disabled by default.
623
624 The accumulation buffer is used to create blur effects and
625 multiple exposures.
626
627 \sa accum(), setAccumBufferSize()
628*/
629
630void QGLFormat::setAccum(bool enable)
631{
632 setOption(enable ? QGL::AccumBuffer : QGL::NoAccumBuffer);
633}
634
635
636/*!
637 \fn bool QGLFormat::stencil() const
638
639 Returns true if the stencil buffer is enabled; otherwise returns
640 false. The stencil buffer is enabled by default.
641
642 \sa setStencil(), setStencilBufferSize()
643*/
644
645/*!
646 If \a enable is true enables the stencil buffer; otherwise
647 disables the stencil buffer.
648
649 The stencil buffer is enabled by default.
650
651 The stencil buffer masks certain parts of the drawing area so that
652 masked parts are not drawn on.
653
654 \sa stencil(), setStencilBufferSize()
655*/
656
657void QGLFormat::setStencil(bool enable)
658{
659 setOption(enable ? QGL::StencilBuffer: QGL::NoStencilBuffer);
660}
661
662
663/*!
664 \fn bool QGLFormat::stereo() const
665
666 Returns true if stereo buffering is enabled; otherwise returns
667 false. Stereo buffering is disabled by default.
668
669 \sa setStereo()
670*/
671
672/*!
673 If \a enable is true enables stereo buffering; otherwise disables
674 stereo buffering.
675
676 Stereo buffering is disabled by default.
677
678 Stereo buffering provides extra color buffers to generate left-eye
679 and right-eye images.
680
681 \sa stereo()
682*/
683
684void QGLFormat::setStereo(bool enable)
685{
686 setOption(enable ? QGL::StereoBuffers : QGL::NoStereoBuffers);
687}
688
689
690/*!
691 \fn bool QGLFormat::directRendering() const
692
693 Returns true if direct rendering is enabled; otherwise returns
694 false.
695
696 Direct rendering is enabled by default.
697
698 \sa setDirectRendering()
699*/
700
701/*!
702 If \a enable is true enables direct rendering; otherwise disables
703 direct rendering.
704
705 Direct rendering is enabled by default.
706
707 Enabling this option will make OpenGL bypass the underlying window
708 system and render directly from hardware to the screen, if this is
709 supported by the system.
710
711 \sa directRendering()
712*/
713
714void QGLFormat::setDirectRendering(bool enable)
715{
716 setOption(enable ? QGL::DirectRendering : QGL::IndirectRendering);
717}
718
719/*!
720 \fn bool QGLFormat::sampleBuffers() const
721
722 Returns true if multisample buffer support is enabled; otherwise
723 returns false.
724
725 The multisample buffer is disabled by default.
726
727 \sa setSampleBuffers()
728*/
729
730/*!
731 If \a enable is true, a GL context with multisample buffer support
732 is picked; otherwise ignored.
733
734 \sa sampleBuffers(), setSamples(), samples()
735*/
736void QGLFormat::setSampleBuffers(bool enable)
737{
738 setOption(enable ? QGL::SampleBuffers : QGL::NoSampleBuffers);
739}
740
741/*!
742 Returns the number of samples per pixel when multisampling is
743 enabled. By default, the highest number of samples that is
744 available is used.
745
746 \sa setSampleBuffers(), sampleBuffers(), setSamples()
747*/
748int QGLFormat::samples() const
749{
750 return d->numSamples;
751}
752
753/*!
754 Set the preferred number of samples per pixel when multisampling
755 is enabled to \a numSamples. By default, the highest number of
756 samples available is used.
757
758 \sa setSampleBuffers(), sampleBuffers(), samples()
759*/
760void QGLFormat::setSamples(int numSamples)
761{
762 detach();
763 if (numSamples < 0) {
764 qWarning("QGLFormat::setSamples: Cannot have negative number of samples per pixel %d", numSamples);
765 return;
766 }
767 d->numSamples = numSamples;
768}
769
770/*!
771 \since 4.2
772
773 Set the preferred swap interval. This can be used to sync the GL
774 drawing into a system window to the vertical refresh of the screen.
775 Setting an \a interval value of 0 will turn the vertical refresh syncing
776 off, any value higher than 0 will turn the vertical syncing on.
777
778 Under Windows and under X11, where the \c{WGL_EXT_swap_control}
779 and \c{GLX_SGI_video_sync} extensions are used, the \a interval
780 parameter can be used to set the minimum number of video frames
781 that are displayed before a buffer swap will occur. In effect,
782 setting the \a interval to 10, means there will be 10 vertical
783 retraces between every buffer swap.
784
785 Under Windows the \c{WGL_EXT_swap_control} extension has to be present,
786 and under X11 the \c{GLX_SGI_video_sync} extension has to be present.
787*/
788void QGLFormat::setSwapInterval(int interval)
789{
790 detach();
791 d->swapInterval = interval;
792}
793
794/*!
795 \since 4.2
796
797 Returns the currently set swap interval. -1 is returned if setting
798 the swap interval isn't supported in the system GL implementation.
799*/
800int QGLFormat::swapInterval() const
801{
802 return d->swapInterval;
803}
804
805/*!
806 \fn bool QGLFormat::hasOverlay() const
807
808 Returns true if overlay plane is enabled; otherwise returns false.
809
810 Overlay is disabled by default.
811
812 \sa setOverlay()
813*/
814
815/*!
816 If \a enable is true enables an overlay plane; otherwise disables
817 the overlay plane.
818
819 Enabling the overlay plane will cause QGLWidget to create an
820 additional context in an overlay plane. See the QGLWidget
821 documentation for further information.
822
823 \sa hasOverlay()
824*/
825
826void QGLFormat::setOverlay(bool enable)
827{
828 setOption(enable ? QGL::HasOverlay : QGL::NoOverlay);
829}
830
831/*!
832 Returns the plane of this format. The default for normal formats
833 is 0, which means the normal plane. The default for overlay
834 formats is 1, which is the first overlay plane.
835
836 \sa setPlane(), defaultOverlayFormat()
837*/
838int QGLFormat::plane() const
839{
840 return d->pln;
841}
842
843/*!
844 Sets the requested plane to \a plane. 0 is the normal plane, 1 is
845 the first overlay plane, 2 is the second overlay plane, etc.; -1,
846 -2, etc. are underlay planes.
847
848 Note that in contrast to other format specifications, the plane
849 specifications will be matched exactly. This means that if you
850 specify a plane that the underlying OpenGL system cannot provide,
851 an \link QGLWidget::isValid() invalid\endlink QGLWidget will be
852 created.
853
854 \sa plane()
855*/
856void QGLFormat::setPlane(int plane)
857{
858 detach();
859 d->pln = plane;
860}
861
862/*!
863 Sets the format option to \a opt.
864
865 \sa testOption()
866*/
867
868void QGLFormat::setOption(QGL::FormatOptions opt)
869{
870 detach();
871 if (opt & 0xffff)
872 d->opts |= opt;
873 else
874 d->opts &= ~(opt >> 16);
875}
876
877
878
879/*!
880 Returns true if format option \a opt is set; otherwise returns false.
881
882 \sa setOption()
883*/
884
885bool QGLFormat::testOption(QGL::FormatOptions opt) const
886{
887 if (opt & 0xffff)
888 return (d->opts & opt) != 0;
889 else
890 return (d->opts & (opt >> 16)) == 0;
891}
892
893/*!
894 Set the minimum depth buffer size to \a size.
895
896 \sa depthBufferSize(), setDepth(), depth()
897*/
898void QGLFormat::setDepthBufferSize(int size)
899{
900 detach();
901 if (size < 0) {
902 qWarning("QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size %d", size);
903 return;
904 }
905 d->depthSize = size;
906}
907
908/*!
909 Returns the depth buffer size.
910
911 \sa depth(), setDepth(), setDepthBufferSize()
912*/
913int QGLFormat::depthBufferSize() const
914{
915 return d->depthSize;
916}
917
918/*!
919 \since 4.2
920
921 Set the preferred red buffer size to \a size.
922
923 \sa setGreenBufferSize(), setBlueBufferSize(), setAlphaBufferSize()
924*/
925void QGLFormat::setRedBufferSize(int size)
926{
927 detach();
928 if (size < 0) {
929 qWarning("QGLFormat::setRedBufferSize: Cannot set negative red buffer size %d", size);
930 return;
931 }
932 d->redSize = size;
933}
934
935/*!
936 \since 4.2
937
938 Returns the red buffer size.
939
940 \sa setRedBufferSize()
941*/
942int QGLFormat::redBufferSize() const
943{
944 return d->redSize;
945}
946
947/*!
948 \since 4.2
949
950 Set the preferred green buffer size to \a size.
951
952 \sa setRedBufferSize(), setBlueBufferSize(), setAlphaBufferSize()
953*/
954void QGLFormat::setGreenBufferSize(int size)
955{
956 detach();
957 if (size < 0) {
958 qWarning("QGLFormat::setGreenBufferSize: Cannot set negative green buffer size %d", size);
959 return;
960 }
961 d->greenSize = size;
962}
963
964/*!
965 \since 4.2
966
967 Returns the green buffer size.
968
969 \sa setGreenBufferSize()
970*/
971int QGLFormat::greenBufferSize() const
972{
973 return d->greenSize;
974}
975
976/*!
977 \since 4.2
978
979 Set the preferred blue buffer size to \a size.
980
981 \sa setRedBufferSize(), setGreenBufferSize(), setAlphaBufferSize()
982*/
983void QGLFormat::setBlueBufferSize(int size)
984{
985 detach();
986 if (size < 0) {
987 qWarning("QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size %d", size);
988 return;
989 }
990 d->blueSize = size;
991}
992
993/*!
994 \since 4.2
995
996 Returns the blue buffer size.
997
998 \sa setBlueBufferSize()
999*/
1000int QGLFormat::blueBufferSize() const
1001{
1002 return d->blueSize;
1003}
1004
1005/*!
1006 Set the preferred alpha buffer size to \a size.
1007 This function implicitly enables the alpha channel.
1008
1009 \sa setRedBufferSize(), setGreenBufferSize(), alphaBufferSize()
1010*/
1011void QGLFormat::setAlphaBufferSize(int size)
1012{
1013 detach();
1014 if (size < 0) {
1015 qWarning("QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size %d", size);
1016 return;
1017 }
1018 d->alphaSize = size;
1019 setOption(QGL::AlphaChannel);
1020}
1021
1022/*!
1023 Returns the alpha buffer size.
1024
1025 \sa alpha(), setAlpha(), setAlphaBufferSize()
1026*/
1027int QGLFormat::alphaBufferSize() const
1028{
1029 return d->alphaSize;
1030}
1031
1032/*!
1033 Set the preferred accumulation buffer size, where \a size is the
1034 bit depth for each RGBA component.
1035
1036 \sa accum(), setAccum(), accumBufferSize()
1037*/
1038void QGLFormat::setAccumBufferSize(int size)
1039{
1040 detach();
1041 if (size < 0) {
1042 qWarning("QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size %d", size);
1043 return;
1044 }
1045 d->accumSize = size;
1046}
1047
1048/*!
1049 Returns the accumulation buffer size.
1050
1051 \sa setAccumBufferSize(), accum(), setAccum()
1052*/
1053int QGLFormat::accumBufferSize() const
1054{
1055 return d->accumSize;
1056}
1057
1058/*!
1059 Set the preferred stencil buffer size to \a size.
1060
1061 \sa stencilBufferSize(), setStencil(), stencil()
1062*/
1063void QGLFormat::setStencilBufferSize(int size)
1064{
1065 detach();
1066 if (size < 0) {
1067 qWarning("QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size %d", size);
1068 return;
1069 }
1070 d->stencilSize = size;
1071}
1072
1073/*!
1074 Returns the stencil buffer size.
1075
1076 \sa stencil(), setStencil(), setStencilBufferSize()
1077*/
1078int QGLFormat::stencilBufferSize() const
1079{
1080 return d->stencilSize;
1081}
1082
1083/*!
1084 \fn bool QGLFormat::hasOpenGL()
1085
1086 Returns true if the window system has any OpenGL support;
1087 otherwise returns false.
1088
1089 \warning This function must not be called until the QApplication
1090 object has been created.
1091*/
1092
1093
1094
1095/*!
1096 \fn bool QGLFormat::hasOpenGLOverlays()
1097
1098 Returns true if the window system supports OpenGL overlays;
1099 otherwise returns false.
1100
1101 \warning This function must not be called until the QApplication
1102 object has been created.
1103*/
1104
1105QGLFormat::OpenGLVersionFlags Q_AUTOTEST_EXPORT qOpenGLVersionFlagsFromString(const QString &versionString)
1106{
1107 QGLFormat::OpenGLVersionFlags versionFlags = QGLFormat::OpenGL_Version_None;
1108
1109 if (versionString.startsWith(QLatin1String("OpenGL ES"))) {
1110 QStringList parts = versionString.split(QLatin1Char(' '));
1111 if (parts.size() >= 3) {
1112 if (parts[2].startsWith(QLatin1String("1."))) {
1113 if (parts[1].endsWith(QLatin1String("-CM"))) {
1114 versionFlags |= QGLFormat::OpenGL_ES_Common_Version_1_0 |
1115 QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
1116 if (parts[2].startsWith(QLatin1String("1.1")))
1117 versionFlags |= QGLFormat::OpenGL_ES_Common_Version_1_1 |
1118 QGLFormat::OpenGL_ES_CommonLite_Version_1_1;
1119 }
1120 else {
1121 // Not -CM, must be CL, CommonLite
1122 versionFlags |= QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
1123 if (parts[2].startsWith(QLatin1String("1.1")))
1124 versionFlags |= QGLFormat::OpenGL_ES_CommonLite_Version_1_1;
1125 }
1126 }
1127 else {
1128 // OpenGL ES version 2.0 or higher
1129 versionFlags |= QGLFormat::OpenGL_ES_Version_2_0;
1130 }
1131 }
1132 else {
1133 // if < 3 parts to the name, it is an unrecognised OpenGL ES
1134 qWarning("Unrecognised OpenGL ES version");
1135 }
1136 }
1137 else {
1138 // not ES, regular OpenGL, the version numbers are first in the string
1139 if (versionString.startsWith(QLatin1String("1."))) {
1140 switch (versionString[2].toAscii()) {
1141 case '5':
1142 versionFlags |= QGLFormat::OpenGL_Version_1_5;
1143 case '4':
1144 versionFlags |= QGLFormat::OpenGL_Version_1_4;
1145 case '3':
1146 versionFlags |= QGLFormat::OpenGL_Version_1_3;
1147 case '2':
1148 versionFlags |= QGLFormat::OpenGL_Version_1_2;
1149 case '1':
1150 versionFlags |= QGLFormat::OpenGL_Version_1_1;
1151 default:
1152 break;
1153 }
1154 }
1155 else if (versionString.startsWith(QLatin1String("2."))) {
1156 versionFlags |= QGLFormat::OpenGL_Version_1_1 |
1157 QGLFormat::OpenGL_Version_1_2 |
1158 QGLFormat::OpenGL_Version_1_3 |
1159 QGLFormat::OpenGL_Version_1_4 |
1160 QGLFormat::OpenGL_Version_1_5 |
1161 QGLFormat::OpenGL_Version_2_0;
1162 QString minorVersion = versionString.section(QLatin1Char(' '), 0, 0).section(QLatin1Char('.'), 1, 1);
1163 if (minorVersion == QChar(QLatin1Char('1')))
1164 versionFlags |= QGLFormat::OpenGL_Version_2_1;
1165 }
1166 else if (versionString.startsWith(QLatin1String("3."))) {
1167 versionFlags |= QGLFormat::OpenGL_Version_1_1 |
1168 QGLFormat::OpenGL_Version_1_2 |
1169 QGLFormat::OpenGL_Version_1_3 |
1170 QGLFormat::OpenGL_Version_1_4 |
1171 QGLFormat::OpenGL_Version_1_5 |
1172 QGLFormat::OpenGL_Version_2_0 |
1173 QGLFormat::OpenGL_Version_2_1 |
1174 QGLFormat::OpenGL_Version_3_0;
1175 }
1176 else
1177 qWarning("Unrecognised OpenGL version");
1178 }
1179 return versionFlags;
1180}
1181
1182/*!
1183 \enum QGLFormat::OpenGLVersionFlag
1184 \since 4.2
1185
1186 This enum describes the various OpenGL versions that are
1187 recognized by Qt. Use the QGLFormat::openGLVersionFlags() function
1188 to identify which versions that are supported at runtime.
1189
1190 \value OpenGL_Version_None If no OpenGL is present or if no OpenGL context is current.
1191
1192 \value OpenGL_Version_1_1 OpenGL version 1.1 or higher is present.
1193
1194 \value OpenGL_Version_1_2 OpenGL version 1.2 or higher is present.
1195
1196 \value OpenGL_Version_1_3 OpenGL version 1.3 or higher is present.
1197
1198 \value OpenGL_Version_1_4 OpenGL version 1.4 or higher is present.
1199
1200 \value OpenGL_Version_1_5 OpenGL version 1.5 or higher is present.
1201
1202 \value OpenGL_Version_2_0 OpenGL version 2.0 or higher is present.
1203 Note that version 2.0 supports all the functionality of version 1.5.
1204
1205 \value OpenGL_Version_2_1 OpenGL version 2.1 or higher is present.
1206
1207 \value OpenGL_Version_3_0 OpenGL version 3.0 or higher is present.
1208
1209 \value OpenGL_ES_CommonLite_Version_1_0 OpenGL ES version 1.0 Common Lite or higher is present.
1210
1211 \value OpenGL_ES_Common_Version_1_0 OpenGL ES version 1.0 Common or higher is present.
1212 The Common profile supports all the features of Common Lite.
1213
1214 \value OpenGL_ES_CommonLite_Version_1_1 OpenGL ES version 1.1 Common Lite or higher is present.
1215
1216 \value OpenGL_ES_Common_Version_1_1 OpenGL ES version 1.1 Common or higher is present.
1217 The Common profile supports all the features of Common Lite.
1218
1219 \value OpenGL_ES_Version_2_0 OpenGL ES version 2.0 or higher is present.
1220 Note that OpenGL ES version 2.0 does not support all the features of OpenGL ES 1.x.
1221 So if OpenGL_ES_Version_2_0 is returned, none of the ES 1.x flags are returned.
1222
1223 See also \l{http://www.opengl.org} for more information about the different
1224 revisions of OpenGL.
1225
1226 \sa openGLVersionFlags()
1227*/
1228
1229/*!
1230 \since 4.2
1231
1232 Identifies, at runtime, which OpenGL versions that are supported
1233 by the current platform.
1234
1235 Note that if OpenGL version 1.5 is supported, its predecessors
1236 (i.e., version 1.4 and lower) are also supported. To identify the
1237 support of a particular feature, like multi texturing, test for
1238 the version in which the feature was first introduced (i.e.,
1239 version 1.3 in the case of multi texturing) to adapt to the largest
1240 possible group of runtime platforms.
1241
1242 This function needs a valid current OpenGL context to work;
1243 otherwise it will return OpenGL_Version_None.
1244
1245 \sa hasOpenGL(), hasOpenGLOverlays()
1246*/
1247QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags()
1248{
1249 static bool cachedDefault = false;
1250 static OpenGLVersionFlags defaultVersionFlags = OpenGL_Version_None;
1251 QGLContext *currentCtx = const_cast<QGLContext *>(QGLContext::currentContext());
1252 QGLTemporaryContext *tmpContext = 0;
1253
1254 if (currentCtx && currentCtx->d_func()->version_flags_cached)
1255 return currentCtx->d_func()->version_flags;
1256
1257 if (!currentCtx) {
1258 if (cachedDefault) {
1259 return defaultVersionFlags;
1260 } else {
1261 if (!hasOpenGL())
1262 return defaultVersionFlags;
1263 tmpContext = new QGLTemporaryContext;
1264 cachedDefault = true;
1265 }
1266 }
1267
1268 QString versionString(QLatin1String(reinterpret_cast<const char*>(glGetString(GL_VERSION))));
1269 OpenGLVersionFlags versionFlags = qOpenGLVersionFlagsFromString(versionString);
1270 if (currentCtx) {
1271 currentCtx->d_func()->version_flags_cached = true;
1272 currentCtx->d_func()->version_flags = versionFlags;
1273 }
1274 if (tmpContext) {
1275 defaultVersionFlags = versionFlags;
1276 delete tmpContext;
1277 }
1278
1279 return versionFlags;
1280}
1281
1282
1283/*!
1284 Returns the default QGLFormat for the application. All QGLWidget
1285 objects that are created use this format unless another format is
1286 specified, e.g. when they are constructed.
1287
1288 If no special default format has been set using
1289 setDefaultFormat(), the default format is the same as that created
1290 with QGLFormat().
1291
1292 \sa setDefaultFormat()
1293*/
1294
1295QGLFormat QGLFormat::defaultFormat()
1296{
1297 return *qgl_default_format();
1298}
1299
1300/*!
1301 Sets a new default QGLFormat for the application to \a f. For
1302 example, to set single buffering as the default instead of double
1303 buffering, your main() might contain code like this:
1304 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 4
1305
1306 \sa defaultFormat()
1307*/
1308
1309void QGLFormat::setDefaultFormat(const QGLFormat &f)
1310{
1311 *qgl_default_format() = f;
1312}
1313
1314
1315/*!
1316 Returns the default QGLFormat for overlay contexts.
1317
1318 The default overlay format is:
1319 \list
1320 \i \link setDoubleBuffer() Double buffer:\endlink Disabled.
1321 \i \link setDepth() Depth buffer:\endlink Disabled.
1322 \i \link setRgba() RGBA:\endlink Disabled (i.e., color index enabled).
1323 \i \link setAlpha() Alpha channel:\endlink Disabled.
1324 \i \link setAccum() Accumulator buffer:\endlink Disabled.
1325 \i \link setStencil() Stencil buffer:\endlink Disabled.
1326 \i \link setStereo() Stereo:\endlink Disabled.
1327 \i \link setDirectRendering() Direct rendering:\endlink Enabled.
1328 \i \link setOverlay() Overlay:\endlink Disabled.
1329 \i \link setSampleBuffers() Multisample buffers:\endlink Disabled.
1330 \i \link setPlane() Plane:\endlink 1 (i.e., first overlay plane).
1331 \endlist
1332
1333 \sa setDefaultFormat()
1334*/
1335
1336QGLFormat QGLFormat::defaultOverlayFormat()
1337{
1338 return *defaultOverlayFormatInstance();
1339}
1340
1341/*!
1342 Sets a new default QGLFormat for overlay contexts to \a f. This
1343 format is used whenever a QGLWidget is created with a format that
1344 hasOverlay() enabled.
1345
1346 For example, to get a double buffered overlay context (if
1347 available), use code like this:
1348
1349 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 5
1350
1351 As usual, you can find out after widget creation whether the
1352 underlying OpenGL system was able to provide the requested
1353 specification:
1354
1355 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 6
1356
1357 \sa defaultOverlayFormat()
1358*/
1359
1360void QGLFormat::setDefaultOverlayFormat(const QGLFormat &f)
1361{
1362 QGLFormat *defaultFormat = defaultOverlayFormatInstance();
1363 *defaultFormat = f;
1364 // Make sure the user doesn't request that the overlays themselves
1365 // have overlays, since it is unlikely that the system supports
1366 // infinitely many planes...
1367 defaultFormat->setOverlay(false);
1368}
1369
1370
1371/*!
1372 Returns true if all the options of the two QGLFormat objects
1373 \a a and \a b are equal; otherwise returns false.
1374
1375 \relates QGLFormat
1376*/
1377
1378bool operator==(const QGLFormat& a, const QGLFormat& b)
1379{
1380 return (int) a.d->opts == (int) b.d->opts && a.d->pln == b.d->pln && a.d->alphaSize == b.d->alphaSize
1381 && a.d->accumSize == b.d->accumSize && a.d->stencilSize == b.d->stencilSize
1382 && a.d->depthSize == b.d->depthSize
1383 && a.d->redSize == b.d->redSize
1384 && a.d->greenSize == b.d->greenSize
1385 && a.d->blueSize == b.d->blueSize
1386 && a.d->numSamples == b.d->numSamples
1387 && a.d->swapInterval == b.d->swapInterval;
1388}
1389
1390
1391/*!
1392 Returns false if all the options of the two QGLFormat objects
1393 \a a and \a b are equal; otherwise returns true.
1394
1395 \relates QGLFormat
1396*/
1397
1398bool operator!=(const QGLFormat& a, const QGLFormat& b)
1399{
1400 return !(a == b);
1401}
1402
1403/*****************************************************************************
1404 QGLContext implementation
1405 *****************************************************************************/
1406
1407QGLContextGroup::~QGLContextGroup()
1408{
1409 // Clear any remaining QGLSharedResourceGuard objects on the group.
1410 QGLSharedResourceGuard *guard = m_guards;
1411 while (guard != 0) {
1412 guard->m_group = 0;
1413 guard->m_id = 0;
1414 guard = guard->m_next;
1415 }
1416}
1417
1418void QGLContextGroup::addGuard(QGLSharedResourceGuard *guard)
1419{
1420 if (m_guards)
1421 m_guards->m_prev = guard;
1422 guard->m_next = m_guards;
1423 guard->m_prev = 0;
1424 m_guards = guard;
1425}
1426
1427void QGLContextGroup::removeGuard(QGLSharedResourceGuard *guard)
1428{
1429 if (guard->m_next)
1430 guard->m_next->m_prev = guard->m_prev;
1431 if (guard->m_prev)
1432 guard->m_prev->m_next = guard->m_next;
1433 else
1434 m_guards = guard->m_next;
1435}
1436
1437const QGLContext *qt_gl_transfer_context(const QGLContext *ctx)
1438{
1439 if (!ctx)
1440 return 0;
1441 QList<const QGLContext *> shares
1442 (QGLContextPrivate::contextGroup(ctx)->shares());
1443 if (shares.size() >= 2)
1444 return (ctx == shares.at(0)) ? shares.at(1) : shares.at(0);
1445 else
1446 return 0;
1447}
1448
1449QGLContextPrivate::~QGLContextPrivate()
1450{
1451 if (!group->m_refs.deref()) {
1452 Q_ASSERT(group->context() == q_ptr);
1453 delete group;
1454 }
1455}
1456
1457void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
1458{
1459 Q_Q(QGLContext);
1460 glFormat = reqFormat = format;
1461 valid = false;
1462 q->setDevice(dev);
1463#if defined(Q_WS_X11)
1464 pbuf = 0;
1465 gpm = 0;
1466 vi = 0;
1467 screen = QX11Info::appScreen();
1468#endif
1469#if defined(Q_WS_WIN)
1470 dc = 0;
1471 win = 0;
1472 pixelFormatId = 0;
1473 cmap = 0;
1474 hbitmap = 0;
1475 hbitmap_hdc = 0;
1476#endif
1477#if defined(Q_WS_MAC)
1478# ifndef QT_MAC_USE_COCOA
1479 update = false;
1480# endif
1481 vi = 0;
1482#endif
1483#if defined(QT_OPENGL_ES)
1484 eglContext = 0;
1485 eglSurface = EGL_NO_SURFACE;
1486#endif
1487 fbo = 0;
1488 crWin = false;
1489 initDone = false;
1490 sharing = false;
1491 max_texture_size = -1;
1492 version_flags_cached = false;
1493 version_flags = QGLFormat::OpenGL_Version_None;
1494 extension_flags_cached = false;
1495 extension_flags = 0;
1496 current_fbo = 0;
1497 default_fbo = 0;
1498 active_engine = 0;
1499 for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
1500 vertexAttributeArraysEnabledState[i] = false;
1501}
1502
1503QGLContext* QGLContext::currentCtx = 0;
1504
1505/*
1506 Read back the contents of the currently bound framebuffer, used in
1507 QGLWidget::grabFrameBuffer(), QGLPixelbuffer::toImage() and
1508 QGLFramebufferObject::toImage()
1509*/
1510
1511static void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, bool include_alpha)
1512{
1513 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
1514 // OpenGL gives RGBA; Qt wants ARGB
1515 uint *p = (uint*)img.bits();
1516 uint *end = p + w*h;
1517 if (alpha_format && include_alpha) {
1518 while (p < end) {
1519 uint a = *p << 24;
1520 *p = (*p >> 8) | a;
1521 p++;
1522 }
1523 } else {
1524 // This is an old legacy fix for PowerPC based Macs, which
1525 // we shouldn't remove
1526 while (p < end) {
1527 *p = 0xff000000 | (*p>>8);
1528 ++p;
1529 }
1530 }
1531 } else {
1532 // OpenGL gives ABGR (i.e. RGBA backwards); Qt wants ARGB
1533 for (int y = 0; y < h; y++) {
1534 uint *q = (uint*)img.scanLine(y);
1535 for (int x=0; x < w; ++x) {
1536 const uint pixel = *q;
1537 if (alpha_format && include_alpha) {
1538 *q = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff)
1539 | (pixel & 0xff00ff00);
1540 } else {
1541 *q = 0xff000000 | ((pixel << 16) & 0xff0000)
1542 | ((pixel >> 16) & 0xff) | (pixel & 0x00ff00);
1543 }
1544
1545 q++;
1546 }
1547 }
1548
1549 }
1550 img = img.mirrored();
1551}
1552
1553QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha)
1554{
1555 QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32
1556 : QImage::Format_RGB32);
1557 int w = size.width();
1558 int h = size.height();
1559 glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
1560 convertFromGLImage(img, w, h, alpha_format, include_alpha);
1561 return img;
1562}
1563
1564QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha)
1565{
1566 QImage img(size, alpha_format ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
1567 int w = size.width();
1568 int h = size.height();
1569#if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
1570 //### glGetTexImage not in GL ES 2.0, need to do something else here!
1571 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
1572#endif
1573 convertFromGLImage(img, w, h, alpha_format, include_alpha);
1574 return img;
1575}
1576
1577// returns the highest number closest to v, which is a power of 2
1578// NB! assumes 32 bit ints
1579int qt_next_power_of_two(int v)
1580{
1581 v--;
1582 v |= v >> 1;
1583 v |= v >> 2;
1584 v |= v >> 4;
1585 v |= v >> 8;
1586 v |= v >> 16;
1587 ++v;
1588 return v;
1589}
1590
1591typedef void (*_qt_pixmap_cleanup_hook_64)(qint64);
1592typedef void (*_qt_image_cleanup_hook_64)(qint64);
1593
1594extern Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64;
1595extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64;
1596
1597static QGLTextureCache *qt_gl_texture_cache = 0;
1598
1599QGLTextureCache::QGLTextureCache()
1600 : m_cache(64*1024) // cache ~64 MB worth of textures - this is not accurate though
1601{
1602 Q_ASSERT(qt_gl_texture_cache == 0);
1603 qt_gl_texture_cache = this;
1604
1605 QImagePixmapCleanupHooks::instance()->addPixmapDataModificationHook(cleanupTexturesForPixampData);
1606 QImagePixmapCleanupHooks::instance()->addPixmapDataDestructionHook(cleanupBeforePixmapDestruction);
1607 QImagePixmapCleanupHooks::instance()->addImageHook(cleanupTexturesForCacheKey);
1608}
1609
1610QGLTextureCache::~QGLTextureCache()
1611{
1612 qt_gl_texture_cache = 0;
1613
1614 QImagePixmapCleanupHooks::instance()->removePixmapDataModificationHook(cleanupTexturesForPixampData);
1615 QImagePixmapCleanupHooks::instance()->removePixmapDataDestructionHook(cleanupBeforePixmapDestruction);
1616 QImagePixmapCleanupHooks::instance()->removeImageHook(cleanupTexturesForCacheKey);
1617}
1618
1619void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost)
1620{
1621 if (m_cache.totalCost() + cost > m_cache.maxCost()) {
1622 // the cache is full - make an attempt to remove something
1623 const QList<qint64> keys = m_cache.keys();
1624 int i = 0;
1625 while (i < m_cache.count()
1626 && (m_cache.totalCost() + cost > m_cache.maxCost())) {
1627 QGLTexture *tex = m_cache.object(keys.at(i));
1628 if (tex->context == ctx)
1629 m_cache.remove(keys.at(i));
1630 ++i;
1631 }
1632 }
1633 m_cache.insert(key, texture, cost);
1634}
1635
1636bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId)
1637{
1638 QList<qint64> keys = m_cache.keys();
1639 for (int i = 0; i < keys.size(); ++i) {
1640 QGLTexture *tex = m_cache.object(keys.at(i));
1641 if (tex->id == textureId && tex->context == ctx) {
1642 tex->options |= QGLContext::MemoryManagedBindOption; // forces a glDeleteTextures() call
1643 m_cache.remove(keys.at(i));
1644 return true;
1645 }
1646 }
1647 return false;
1648}
1649
1650void QGLTextureCache::removeContextTextures(QGLContext* ctx)
1651{
1652 QList<qint64> keys = m_cache.keys();
1653 for (int i = 0; i < keys.size(); ++i) {
1654 const qint64 &key = keys.at(i);
1655 if (m_cache.object(key)->context == ctx)
1656 m_cache.remove(key);
1657 }
1658}
1659
1660QGLTextureCache* QGLTextureCache::instance()
1661{
1662 if (!qt_gl_texture_cache)
1663 qt_gl_texture_cache = new QGLTextureCache;
1664
1665 return qt_gl_texture_cache;
1666}
1667
1668/*
1669 a hook that removes textures from the cache when a pixmap/image
1670 is deref'ed
1671*/
1672void QGLTextureCache::cleanupTexturesForCacheKey(qint64 cacheKey)
1673{
1674 // ### remove when the GL texture cache becomes thread-safe
1675 if (qApp->thread() == QThread::currentThread()) {
1676 instance()->remove(cacheKey);
1677 Q_ASSERT(instance()->getTexture(cacheKey) == 0);
1678 }
1679}
1680
1681
1682void QGLTextureCache::cleanupTexturesForPixampData(QPixmapData* pmd)
1683{
1684 cleanupTexturesForCacheKey(pmd->cacheKey());
1685}
1686
1687void QGLTextureCache::cleanupBeforePixmapDestruction(QPixmapData* pmd)
1688{
1689 // Remove any bound textures first:
1690 cleanupTexturesForPixampData(pmd);
1691
1692#if defined(Q_WS_X11)
1693 if (pmd->classId() == QPixmapData::X11Class) {
1694 Q_ASSERT(pmd->ref == 0); // Make sure reference counting isn't broken
1695 QGLContextPrivate::destroyGlSurfaceForPixmap(pmd);
1696 }
1697#endif
1698}
1699
1700void QGLTextureCache::deleteIfEmpty()
1701{
1702 if (instance()->size() == 0)
1703 delete instance();
1704}
1705
1706// DDS format structure
1707struct DDSFormat {
1708 quint32 dwSize;
1709 quint32 dwFlags;
1710 quint32 dwHeight;
1711 quint32 dwWidth;
1712 quint32 dwLinearSize;
1713 quint32 dummy1;
1714 quint32 dwMipMapCount;
1715 quint32 dummy2[11];
1716 struct {
1717 quint32 dummy3[2];
1718 quint32 dwFourCC;
1719 quint32 dummy4[5];
1720 } ddsPixelFormat;
1721};
1722
1723// compressed texture pixel formats
1724#define FOURCC_DXT1 0x31545844
1725#define FOURCC_DXT2 0x32545844
1726#define FOURCC_DXT3 0x33545844
1727#define FOURCC_DXT4 0x34545844
1728#define FOURCC_DXT5 0x35545844
1729
1730#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
1731#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
1732#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
1733#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
1734#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
1735#endif
1736
1737#ifndef GL_GENERATE_MIPMAP_SGIS
1738#define GL_GENERATE_MIPMAP_SGIS 0x8191
1739#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
1740#endif
1741
1742/*!
1743 \class QGLContext
1744 \brief The QGLContext class encapsulates an OpenGL rendering context.
1745
1746 \ingroup painting-3D
1747
1748 An OpenGL rendering context is a complete set of OpenGL state
1749 variables. The rendering context's \l {QGL::FormatOption} {format}
1750 is set in the constructor, but it can also be set later with
1751 setFormat(). The format options that are actually set are returned
1752 by format(); the options you asked for are returned by
1753 requestedFormat(). Note that after a QGLContext object has been
1754 constructed, the actual OpenGL context must be created by
1755 explicitly calling the \link create() create()\endlink
1756 function. The makeCurrent() function makes this context the
1757 current rendering context. You can make \e no context current
1758 using doneCurrent(). The reset() function will reset the context
1759 and make it invalid.
1760
1761 You can examine properties of the context with, e.g. isValid(),
1762 isSharing(), initialized(), windowCreated() and
1763 overlayTransparentColor().
1764
1765 If you're using double buffering you can swap the screen contents
1766 with the off-screen buffer using swapBuffers().
1767
1768 Please note that QGLContext is not thread safe.
1769*/
1770
1771/*!
1772 \enum QGLContext::BindOption
1773 \since 4.6
1774
1775 A set of options to decide how to bind a texture using bindTexture().
1776
1777 \value NoBindOption Don't do anything, pass the texture straight
1778 through.
1779
1780 \value InvertedYBindOption Specifies that the texture should be flipped
1781 over the X axis so that the texture coordinate 0,0 corresponds to
1782 the top left corner. Inverting the texture implies a deep copy
1783 prior to upload.
1784
1785 \value MipmapBindOption Specifies that bindTexture() should try
1786 to generate mipmaps. If the GL implementation supports the \c
1787 GL_SGIS_generate_mipmap extension, mipmaps will be automatically
1788 generated for the texture. Mipmap generation is only supported for
1789 the \c GL_TEXTURE_2D target.
1790
1791 \value PremultipliedAlphaBindOption Specifies that the image should be
1792 uploaded with premultiplied alpha and does a conversion accordingly.
1793
1794 \value LinearFilteringBindOption Specifies that the texture filtering
1795 should be set to GL_LINEAR. Default is GL_NEAREST. If mipmap is
1796 also enabled, filtering will be set to GL_LINEAR_MIPMAP_LINEAR.
1797
1798 \value DefaultBindOption In Qt 4.5 and earlier, bindTexture()
1799 would mirror the image and automatically generate mipmaps. This
1800 option helps preserve this default behavior.
1801
1802 \omitvalue CanFlipNativePixmapBindOption Used by x11 from pixmap to choose
1803 wether or not it can bind the pixmap upside down or not.
1804
1805 \omitvalue MemoryManagedBindOption Used by paint engines to
1806 indicate that the pixmap should be memory managed along side with
1807 the pixmap/image that it stems from, e.g. installing destruction
1808 hooks in them.
1809
1810 \omitvalue InternalBindOption
1811*/
1812
1813/*!
1814 \obsolete
1815
1816 Constructs an OpenGL context for the given paint \a device, which
1817 can be a widget or a pixmap. The \a format specifies several
1818 display options for the context.
1819
1820 If the underlying OpenGL/Window system cannot satisfy all the
1821 features requested in \a format, the nearest subset of features
1822 will be used. After creation, the format() method will return the
1823 actual format obtained.
1824
1825 Note that after a QGLContext object has been constructed, \l
1826 create() must be called explicitly to create the actual OpenGL
1827 context. The context will be \l {isValid()}{invalid} if it was not
1828 possible to obtain a GL context at all.
1829*/
1830
1831QGLContext::QGLContext(const QGLFormat &format, QPaintDevice *device)
1832 : d_ptr(new QGLContextPrivate(this))
1833{
1834 Q_D(QGLContext);
1835 d->init(device, format);
1836}
1837
1838/*!
1839 Constructs an OpenGL context with the given \a format which
1840 specifies several display options for the context.
1841
1842 If the underlying OpenGL/Window system cannot satisfy all the
1843 features requested in \a format, the nearest subset of features
1844 will be used. After creation, the format() method will return the
1845 actual format obtained.
1846
1847 Note that after a QGLContext object has been constructed, \l
1848 create() must be called explicitly to create the actual OpenGL
1849 context. The context will be \l {isValid()}{invalid} if it was not
1850 possible to obtain a GL context at all.
1851
1852 \sa format(), isValid()
1853*/
1854QGLContext::QGLContext(const QGLFormat &format)
1855 : d_ptr(new QGLContextPrivate(this))
1856{
1857 Q_D(QGLContext);
1858 d->init(0, format);
1859}
1860
1861/*!
1862 Destroys the OpenGL context and frees its resources.
1863*/
1864
1865QGLContext::~QGLContext()
1866{
1867 // remove any textures cached in this context
1868 QGLTextureCache::instance()->removeContextTextures(this);
1869 QGLTextureCache::deleteIfEmpty(); // ### thread safety
1870
1871 d_ptr->group->cleanupResources(this);
1872
1873 QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
1874 reset();
1875}
1876
1877void QGLContextPrivate::cleanup()
1878{
1879}
1880
1881#define ctx q_ptr
1882void QGLContextPrivate::setVertexAttribArrayEnabled(int arrayIndex, bool enabled)
1883{
1884 Q_ASSERT(arrayIndex < QT_GL_VERTEX_ARRAY_TRACKED_COUNT);
1885 Q_ASSERT(glEnableVertexAttribArray);
1886
1887 if (vertexAttributeArraysEnabledState[arrayIndex] && !enabled)
1888 glDisableVertexAttribArray(arrayIndex);
1889
1890 if (!vertexAttributeArraysEnabledState[arrayIndex] && enabled)
1891 glEnableVertexAttribArray(arrayIndex);
1892
1893 vertexAttributeArraysEnabledState[arrayIndex] = enabled;
1894}
1895
1896void QGLContextPrivate::syncGlState()
1897{
1898 Q_ASSERT(glEnableVertexAttribArray);
1899 for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) {
1900 if (vertexAttributeArraysEnabledState[i])
1901 glEnableVertexAttribArray(i);
1902 else
1903 glDisableVertexAttribArray(i);
1904 }
1905
1906}
1907#undef ctx
1908
1909
1910/*!
1911 \overload
1912
1913 Reads the compressed texture file \a fileName and generates a 2D GL
1914 texture from it.
1915
1916 This function can load DirectDrawSurface (DDS) textures in the
1917 DXT1, DXT3 and DXT5 DDS formats if the \c GL_ARB_texture_compression
1918 and \c GL_EXT_texture_compression_s3tc extensions are supported.
1919
1920 Since 4.6.1, textures in the ETC1 format can be loaded if the
1921 \c GL_OES_compressed_ETC1_RGB8_texture extension is supported
1922 and the ETC1 texture has been encapsulated in the PVR container format.
1923 Also, textures in the PVRTC2 and PVRTC4 formats can be loaded
1924 if the \c GL_IMG_texture_compression_pvrtc extension is supported.
1925
1926 \sa deleteTexture()
1927*/
1928
1929GLuint QGLContext::bindTexture(const QString &fileName)
1930{
1931 Q_D(QGLContext);
1932 QGLDDSCache *dds_cache = &(d->group->m_dds_cache);
1933 QGLDDSCache::const_iterator it = dds_cache->constFind(fileName);
1934 if (it != dds_cache->constEnd()) {
1935 glBindTexture(GL_TEXTURE_2D, it.value());
1936 return it.value();
1937 }
1938
1939 QGLTexture texture(this);
1940 QSize size = texture.bindCompressedTexture(fileName);
1941 if (!size.isValid())
1942 return 0;
1943
1944 dds_cache->insert(fileName, texture.id);
1945 return texture.id;
1946}
1947
1948static inline QRgb qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format)
1949{
1950 if (texture_format == GL_BGRA) {
1951 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
1952 return ((src_pixel << 24) & 0xff000000)
1953 | ((src_pixel >> 24) & 0x000000ff)
1954 | ((src_pixel << 8) & 0x00ff0000)
1955 | ((src_pixel >> 8) & 0x0000ff00);
1956 } else {
1957 return src_pixel;
1958 }
1959 } else { // GL_RGBA
1960 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
1961 return (src_pixel << 8) | ((src_pixel >> 24) & 0xff);
1962 } else {
1963 return ((src_pixel << 16) & 0xff0000)
1964 | ((src_pixel >> 16) & 0xff)
1965 | (src_pixel & 0xff00ff00);
1966 }
1967 }
1968}
1969
1970QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format)
1971{
1972 return qt_gl_convertToGLFormatHelper(src_pixel, texture_format);
1973}
1974
1975static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format)
1976{
1977 Q_ASSERT(dst.depth() == 32);
1978 Q_ASSERT(img.depth() == 32);
1979
1980 if (dst.size() != img.size()) {
1981 int target_width = dst.width();
1982 int target_height = dst.height();
1983 qreal sx = target_width / qreal(img.width());
1984 qreal sy = target_height / qreal(img.height());
1985
1986 quint32 *dest = (quint32 *) dst.scanLine(0); // NB! avoid detach here
1987 uchar *srcPixels = (uchar *) img.scanLine(img.height() - 1);
1988 int sbpl = img.bytesPerLine();
1989 int dbpl = dst.bytesPerLine();
1990
1991 int ix = int(0x00010000 / sx);
1992 int iy = int(0x00010000 / sy);
1993
1994 quint32 basex = int(0.5 * ix);
1995 quint32 srcy = int(0.5 * iy);
1996
1997 // scale, swizzle and mirror in one loop
1998 while (target_height--) {
1999 const uint *src = (const quint32 *) (srcPixels - (srcy >> 16) * sbpl);
2000 int srcx = basex;
2001 for (int x=0; x<target_width; ++x) {
2002 dest[x] = qt_gl_convertToGLFormatHelper(src[srcx >> 16], texture_format);
2003 srcx += ix;
2004 }
2005 dest = (quint32 *)(((uchar *) dest) + dbpl);
2006 srcy += iy;
2007 }
2008 } else {
2009 const int width = img.width();
2010 const int height = img.height();
2011 const uint *p = (const uint*) img.scanLine(img.height() - 1);
2012 uint *q = (uint*) dst.scanLine(0);
2013
2014 if (texture_format == GL_BGRA) {
2015 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
2016 // mirror + swizzle
2017 for (int i=0; i < height; ++i) {
2018 const uint *end = p + width;
2019 while (p < end) {
2020 *q = ((*p << 24) & 0xff000000)
2021 | ((*p >> 24) & 0x000000ff)
2022 | ((*p << 8) & 0x00ff0000)
2023 | ((*p >> 8) & 0x0000ff00);
2024 p++;
2025 q++;
2026 }
2027 p -= 2 * width;
2028 }
2029 } else {
2030 const uint bytesPerLine = img.bytesPerLine();
2031 for (int i=0; i < height; ++i) {
2032 memcpy(q, p, bytesPerLine);
2033 q += width;
2034 p -= width;
2035 }
2036 }
2037 } else {
2038 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
2039 for (int i=0; i < height; ++i) {
2040 const uint *end = p + width;
2041 while (p < end) {
2042 *q = (*p << 8) | ((*p >> 24) & 0xff);
2043 p++;
2044 q++;
2045 }
2046 p -= 2 * width;
2047 }
2048 } else {
2049 for (int i=0; i < height; ++i) {
2050 const uint *end = p + width;
2051 while (p < end) {
2052 *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
2053 p++;
2054 q++;
2055 }
2056 p -= 2 * width;
2057 }
2058 }
2059 }
2060 }
2061}
2062
2063QImage QGLContextPrivate::convertToGLFormat(const QImage &image, bool force_premul,
2064 GLenum texture_format)
2065{
2066 QImage::Format target_format = image.format();
2067 if (force_premul || image.format() != QImage::Format_ARGB32)
2068 target_format = QImage::Format_ARGB32_Premultiplied;
2069
2070 QImage result(image.width(), image.height(), target_format);
2071 convertToGLFormatHelper(result, image.convertToFormat(target_format), texture_format);
2072 return result;
2073}
2074
2075/*! \internal */
2076QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format,
2077 QGLContext::BindOptions options)
2078{
2079 const qint64 key = image.cacheKey();
2080 QGLTexture *texture = textureCacheLookup(key, target);
2081 if (texture) {
2082 glBindTexture(target, texture->id);
2083 return texture;
2084 }
2085
2086 if (!texture)
2087 texture = bindTexture(image, target, format, key, options);
2088 // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
2089 Q_ASSERT(texture);
2090
2091 // Enable the cleanup hooks for this image so that the texture cache entry is removed when the
2092 // image gets deleted:
2093 QImagePixmapCleanupHooks::enableCleanupHooks(image);
2094
2095 return texture;
2096}
2097
2098// #define QGL_BIND_TEXTURE_DEBUG
2099
2100// map from Qt's ARGB endianness-dependent format to GL's big-endian RGBA layout
2101static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type)
2102{
2103 const int width = img.width();
2104 const int height = img.height();
2105
2106 if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV
2107 || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian))
2108 {
2109 for (int i = 0; i < height; ++i) {
2110 uint *p = (uint *) img.scanLine(i);
2111 for (int x = 0; x < width; ++x)
2112 p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
2113 }
2114 } else {
2115 for (int i = 0; i < height; ++i) {
2116 uint *p = (uint *) img.scanLine(i);
2117 for (int x = 0; x < width; ++x)
2118 p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff);
2119 }
2120 }
2121}
2122
2123QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat,
2124 const qint64 key, QGLContext::BindOptions options)
2125{
2126 Q_Q(QGLContext);
2127
2128#ifdef QGL_BIND_TEXTURE_DEBUG
2129 printf("QGLContextPrivate::bindTexture(), imageSize=(%d,%d), internalFormat =0x%x, options=%x\n",
2130 image.width(), image.height(), internalFormat, int(options));
2131 QTime time;
2132 time.start();
2133#endif
2134
2135#ifndef QT_NO_DEBUG
2136 // Reset the gl error stack...git
2137 while (glGetError() != GL_NO_ERROR) ;
2138#endif
2139
2140 // Scale the pixmap if needed. GL textures needs to have the
2141 // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL
2142 // 2.0 or use the GL_TEXTURE_RECTANGLE texture target
2143 int tx_w = qt_next_power_of_two(image.width());
2144 int tx_h = qt_next_power_of_two(image.height());
2145
2146 QImage img = image;
2147
2148 if (!(QGLExtensions::glExtensions() & QGLExtensions::NPOTTextures)
2149 && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0)
2150 && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height())))
2151 {
2152 img = img.scaled(tx_w, tx_h);
2153#ifdef QGL_BIND_TEXTURE_DEBUG
2154 printf(" - upscaled to %dx%d (%d ms)\n", tx_w, tx_h, time.elapsed());
2155
2156#endif
2157 }
2158
2159 GLuint filtering = options & QGLContext::LinearFilteringBindOption ? GL_LINEAR : GL_NEAREST;
2160
2161 GLuint tx_id;
2162 glGenTextures(1, &tx_id);
2163 glBindTexture(target, tx_id);
2164 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, filtering);
2165
2166#if defined(QT_OPENGL_ES_2)
2167 bool genMipmap = false;
2168#endif
2169 if (glFormat.directRendering()
2170 && (QGLExtensions::glExtensions() & QGLExtensions::GenerateMipmap)
2171 && target == GL_TEXTURE_2D
2172 && (options & QGLContext::MipmapBindOption))
2173 {
2174#ifdef QGL_BIND_TEXTURE_DEBUG
2175 printf(" - generating mipmaps (%d ms)\n", time.elapsed());
2176#endif
2177#if !defined(QT_OPENGL_ES_2)
2178 glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
2179#ifndef QT_OPENGL_ES
2180 glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
2181#else
2182 glTexParameterf(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
2183#endif
2184#else
2185 glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
2186 genMipmap = true;
2187#endif
2188 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, options & QGLContext::LinearFilteringBindOption
2189 ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST);
2190 } else {
2191 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, filtering);
2192 }
2193
2194 QImage::Format target_format = img.format();
2195 bool premul = options & QGLContext::PremultipliedAlphaBindOption;
2196 GLenum externalFormat;
2197 GLuint pixel_type;
2198 if (QGLExtensions::glExtensions() & QGLExtensions::BGRATextureFormat) {
2199 externalFormat = GL_BGRA;
2200 if (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2)
2201 pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
2202 else
2203 pixel_type = GL_UNSIGNED_BYTE;
2204 } else {
2205 externalFormat = GL_RGBA;
2206 pixel_type = GL_UNSIGNED_BYTE;
2207 }
2208
2209 switch (target_format) {
2210 case QImage::Format_ARGB32:
2211 if (premul) {
2212 img = img.convertToFormat(target_format = QImage::Format_ARGB32_Premultiplied);
2213#ifdef QGL_BIND_TEXTURE_DEBUG
2214 printf(" - converting ARGB32 -> ARGB32_Premultiplied (%d ms) \n", time.elapsed());
2215#endif
2216 }
2217 break;
2218 case QImage::Format_ARGB32_Premultiplied:
2219 if (!premul) {
2220 img = img.convertToFormat(target_format = QImage::Format_ARGB32);
2221#ifdef QGL_BIND_TEXTURE_DEBUG
2222 printf(" - converting ARGB32_Premultiplied -> ARGB32 (%d ms)\n", time.elapsed());
2223#endif
2224 }
2225 break;
2226 case QImage::Format_RGB16:
2227 pixel_type = GL_UNSIGNED_SHORT_5_6_5;
2228 externalFormat = GL_RGB;
2229 internalFormat = GL_RGB;
2230 break;
2231 case QImage::Format_RGB32:
2232 break;
2233 default:
2234 if (img.hasAlphaChannel()) {
2235 img = img.convertToFormat(premul
2236 ? QImage::Format_ARGB32_Premultiplied
2237 : QImage::Format_ARGB32);
2238#ifdef QGL_BIND_TEXTURE_DEBUG
2239 printf(" - converting to 32-bit alpha format (%d ms)\n", time.elapsed());
2240#endif
2241 } else {
2242 img = img.convertToFormat(QImage::Format_RGB32);
2243#ifdef QGL_BIND_TEXTURE_DEBUG
2244 printf(" - converting to 32-bit (%d ms)\n", time.elapsed());
2245#endif
2246 }
2247 }
2248
2249 if (options & QGLContext::InvertedYBindOption) {
2250#ifdef QGL_BIND_TEXTURE_DEBUG
2251 printf(" - flipping bits over y (%d ms)\n", time.elapsed());
2252#endif
2253 if (img.isDetached()) {
2254 int ipl = img.bytesPerLine() / 4;
2255 int h = img.height();
2256 for (int y=0; y<h/2; ++y) {
2257 int *a = (int *) img.scanLine(y);
2258 int *b = (int *) img.scanLine(h - y - 1);
2259 for (int x=0; x<ipl; ++x)
2260 qSwap(a[x], b[x]);
2261 }
2262 } else {
2263 // Create a new image and copy across. If we use the
2264 // above in-place code then a full copy of the image is
2265 // made before the lines are swapped, which processes the
2266 // data twice. This version should only do it once.
2267 img = img.mirrored();
2268 }
2269 }
2270
2271 if (externalFormat == GL_RGBA) {
2272#ifdef QGL_BIND_TEXTURE_DEBUG
2273 printf(" - doing byte swapping (%d ms)\n", time.elapsed());
2274#endif
2275 // The only case where we end up with a depth different from
2276 // 32 in the switch above is for the RGB16 case, where we set
2277 // the format to GL_RGB
2278 Q_ASSERT(img.depth() == 32);
2279 qgl_byteSwapImage(img, pixel_type);
2280 }
2281#ifdef QT_OPENGL_ES
2282 // OpenGL/ES requires that the internal and external formats be
2283 // identical.
2284 internalFormat = externalFormat;
2285#endif
2286#ifdef QGL_BIND_TEXTURE_DEBUG
2287 printf(" - uploading, image.format=%d, externalFormat=0x%x, internalFormat=0x%x, pixel_type=0x%x\n",
2288 img.format(), externalFormat, internalFormat, pixel_type);
2289#endif
2290
2291 const QImage &constRef = img; // to avoid detach in bits()...
2292 glTexImage2D(target, 0, internalFormat, img.width(), img.height(), 0, externalFormat,
2293 pixel_type, constRef.bits());
2294#if defined(QT_OPENGL_ES_2)
2295 if (genMipmap)
2296 glGenerateMipmap(target);
2297#endif
2298#ifndef QT_NO_DEBUG
2299 GLenum error = glGetError();
2300 if (error != GL_NO_ERROR) {
2301 qWarning(" - texture upload failed, error code 0x%x\n", error);
2302 }
2303#endif
2304
2305#ifdef QGL_BIND_TEXTURE_DEBUG
2306 static int totalUploadTime = 0;
2307 totalUploadTime += time.elapsed();
2308 printf(" - upload done in (%d ms) time=%d\n", time.elapsed(), totalUploadTime);
2309#endif
2310
2311
2312 // this assumes the size of a texture is always smaller than the max cache size
2313 int cost = img.width()*img.height()*4/1024;
2314 QGLTexture *texture = new QGLTexture(q, tx_id, target, options);
2315 QGLTextureCache::instance()->insert(q, key, texture, cost);
2316
2317 return texture;
2318}
2319
2320QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target)
2321{
2322 Q_Q(QGLContext);
2323 QGLTexture *texture = QGLTextureCache::instance()->getTexture(key);
2324 if (texture && texture->target == target
2325 && (texture->context == q || QGLContext::areSharing(q, texture->context)))
2326 {
2327 return texture;
2328 }
2329 return 0;
2330}
2331
2332
2333/*! \internal */
2334QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, QGLContext::BindOptions options)
2335{
2336 Q_Q(QGLContext);
2337 QPixmapData *pd = pixmap.pixmapData();
2338#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
2339 if (target == GL_TEXTURE_2D && pd->classId() == QPixmapData::OpenGLClass) {
2340 const QGLPixmapData *data = static_cast<const QGLPixmapData *>(pd);
2341
2342 if (data->isValidContext(q)) {
2343 data->bind();
2344 return data->texture();
2345 }
2346 }
2347#else
2348 Q_UNUSED(pd);
2349 Q_UNUSED(q);
2350#endif
2351
2352 const qint64 key = pixmap.cacheKey();
2353 QGLTexture *texture = textureCacheLookup(key, target);
2354 if (texture) {
2355 glBindTexture(target, texture->id);
2356 return texture;
2357 }
2358
2359#if defined(Q_WS_X11)
2360 // Try to use texture_from_pixmap
2361 const QX11Info *xinfo = qt_x11Info(paintDevice);
2362 if (pd->classId() == QPixmapData::X11Class && pd->pixelType() == QPixmapData::PixmapType
2363 && xinfo && xinfo->screen() == pixmap.x11Info().screen())
2364 {
2365 texture = bindTextureFromNativePixmap(pd, key, options);
2366 if (texture) {
2367 texture->options |= QGLContext::MemoryManagedBindOption;
2368 texture->boundPixmap = pd;
2369 boundPixmaps.insert(pd, QPixmap(pixmap));
2370 }
2371 }
2372#endif
2373
2374 if (!texture)
2375 texture = bindTexture(pixmap.toImage(), target, format, key, options);
2376 // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
2377 Q_ASSERT(texture);
2378
2379 if (texture->id > 0)
2380 QImagePixmapCleanupHooks::enableCleanupHooks(pixmap);
2381
2382 return texture;
2383}
2384
2385/*! \internal */
2386int QGLContextPrivate::maxTextureSize()
2387{
2388 if (max_texture_size != -1)
2389 return max_texture_size;
2390
2391 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
2392
2393#if defined(QT_OPENGL_ES)
2394 return max_texture_size;
2395#else
2396 GLenum proxy = GL_PROXY_TEXTURE_2D;
2397
2398 GLint size;
2399 GLint next = 64;
2400 glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
2401 glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size);
2402 if (size == 0) {
2403 return max_texture_size;
2404 }
2405 do {
2406 size = next;
2407 next = size * 2;
2408
2409 if (next > max_texture_size)
2410 break;
2411 glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
2412 glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next);
2413 } while (next > size);
2414
2415 max_texture_size = size;
2416 return max_texture_size;
2417#endif
2418}
2419
2420/*!
2421 Generates and binds a 2D GL texture to the current context, based
2422 on \a image. The generated texture id is returned and can be used in
2423 later \c glBindTexture() calls.
2424
2425 \overload
2426*/
2427GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
2428{
2429 if (image.isNull())
2430 return 0;
2431
2432 Q_D(QGLContext);
2433 QGLTexture *texture = d->bindTexture(image, target, format, DefaultBindOption);
2434 return texture->id;
2435}
2436
2437/*!
2438 \since 4.6
2439
2440 Generates and binds a 2D GL texture to the current context, based
2441 on \a image. The generated texture id is returned and can be used
2442 in later \c glBindTexture() calls.
2443
2444 The \a target parameter specifies the texture target. The default
2445 target is \c GL_TEXTURE_2D.
2446
2447 The \a format parameter sets the internal format for the
2448 texture. The default format is \c GL_RGBA.
2449
2450 The binding \a options are a set of options used to decide how to
2451 bind the texture to the context.
2452
2453 The texture that is generated is cached, so multiple calls to
2454 bindTexture() with the same QImage will return the same texture
2455 id.
2456
2457 Note that we assume default values for the glPixelStore() and
2458 glPixelTransfer() parameters.
2459
2460 \sa deleteTexture()
2461*/
2462GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options)
2463{
2464 if (image.isNull())
2465 return 0;
2466
2467 Q_D(QGLContext);
2468 QGLTexture *texture = d->bindTexture(image, target, format, false, options);
2469 return texture->id;
2470}
2471
2472#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
2473/*! \internal */
2474GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
2475{
2476 if (image.isNull())
2477 return 0;
2478
2479 Q_D(QGLContext);
2480 QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, DefaultBindOption);
2481 return texture->id;
2482}
2483
2484/*! \internal */
2485GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format,
2486 BindOptions options)
2487{
2488 if (image.isNull())
2489 return 0;
2490
2491 Q_D(QGLContext);
2492 QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, options);
2493 return texture->id;
2494}
2495#endif
2496
2497/*! \overload
2498
2499 Generates and binds a 2D GL texture based on \a pixmap.
2500*/
2501GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
2502{
2503 if (pixmap.isNull())
2504 return 0;
2505
2506 Q_D(QGLContext);
2507 QGLTexture *texture = d->bindTexture(pixmap, target, format, DefaultBindOption);
2508 return texture->id;
2509}
2510
2511/*!
2512 \overload
2513 \since 4.6
2514
2515 Generates and binds a 2D GL texture to the current context, based
2516 on \a pixmap.
2517*/
2518GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, BindOptions options)
2519{
2520 if (pixmap.isNull())
2521 return 0;
2522
2523 Q_D(QGLContext);
2524 QGLTexture *texture = d->bindTexture(pixmap, target, format, options);
2525 return texture->id;
2526}
2527
2528#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
2529/*! \internal */
2530GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format)
2531{
2532 if (pixmap.isNull())
2533 return 0;
2534
2535 Q_D(QGLContext);
2536 QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), DefaultBindOption);
2537 return texture->id;
2538}
2539/*! \internal */
2540GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format,
2541 BindOptions options)
2542{
2543 if (pixmap.isNull())
2544 return 0;
2545
2546 Q_D(QGLContext);
2547 QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), options);
2548 return texture->id;
2549}
2550#endif
2551
2552/*!
2553 Removes the texture identified by \a id from the texture cache,
2554 and calls glDeleteTextures() to delete the texture from the
2555 context.
2556
2557 \sa bindTexture()
2558*/
2559void QGLContext::deleteTexture(GLuint id)
2560{
2561 Q_D(QGLContext);
2562
2563 if (QGLTextureCache::instance()->remove(this, id))
2564 return;
2565
2566 // check the DDS cache if the texture wasn't found in the pixmap/image
2567 // cache
2568 QGLDDSCache *dds_cache = &(d->group->m_dds_cache);
2569 QList<QString> ddsKeys = dds_cache->keys();
2570 for (int i = 0; i < ddsKeys.size(); ++i) {
2571 GLuint texture = dds_cache->value(ddsKeys.at(i));
2572 if (id == texture) {
2573 dds_cache->remove(ddsKeys.at(i));
2574 break;
2575 }
2576 }
2577
2578 // Finally, actually delete the texture ID
2579 glDeleteTextures(1, &id);
2580}
2581
2582#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
2583/*! \internal */
2584void QGLContext::deleteTexture(QMacCompatGLuint id)
2585{
2586 return deleteTexture(GLuint(id));
2587}
2588#endif
2589
2590void qt_add_rect_to_array(const QRectF &r, q_vertexType *array)
2591{
2592 qreal left = r.left();
2593 qreal right = r.right();
2594 qreal top = r.top();
2595 qreal bottom = r.bottom();
2596
2597 array[0] = f2vt(left);
2598 array[1] = f2vt(top);
2599 array[2] = f2vt(right);
2600 array[3] = f2vt(top);
2601 array[4] = f2vt(right);
2602 array[5] = f2vt(bottom);
2603 array[6] = f2vt(left);
2604 array[7] = f2vt(bottom);
2605}
2606
2607void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array)
2608{
2609 array[0] = f2vt(x1);
2610 array[1] = f2vt(y1);
2611 array[2] = f2vt(x2);
2612 array[3] = f2vt(y1);
2613 array[4] = f2vt(x2);
2614 array[5] = f2vt(y2);
2615 array[6] = f2vt(x1);
2616 array[7] = f2vt(y2);
2617}
2618
2619#if !defined(QT_OPENGL_ES_2)
2620
2621static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint textureHeight, GLenum textureTarget)
2622{
2623 q_vertexType tx = f2vt(1);
2624 q_vertexType ty = f2vt(1);
2625
2626#ifdef QT_OPENGL_ES
2627 Q_UNUSED(textureWidth);
2628 Q_UNUSED(textureHeight);
2629 Q_UNUSED(textureTarget);
2630#else
2631 if (textureTarget != GL_TEXTURE_2D) {
2632 if (textureWidth == -1 || textureHeight == -1) {
2633 glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_WIDTH, &textureWidth);
2634 glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_HEIGHT, &textureHeight);
2635 }
2636
2637 tx = f2vt(textureWidth);
2638 ty = f2vt(textureHeight);
2639 }
2640#endif
2641
2642 q_vertexType texCoordArray[4*2] = {
2643 0, ty, tx, ty, tx, 0, 0, 0
2644 };
2645
2646 q_vertexType vertexArray[4*2];
2647 qt_add_rect_to_array(target, vertexArray);
2648
2649 glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
2650 glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray);
2651
2652 glEnableClientState(GL_VERTEX_ARRAY);
2653 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2654 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
2655
2656 glDisableClientState(GL_VERTEX_ARRAY);
2657 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
2658}
2659
2660#endif // !QT_OPENGL_ES_2
2661
2662/*!
2663 \since 4.4
2664
2665 Draws the given texture, \a textureId, to the given target rectangle,
2666 \a target, in OpenGL model space. The \a textureTarget should be a 2D
2667 texture target.
2668
2669 \note This function is not supported under OpenGL/ES 2.0.
2670*/
2671void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
2672{
2673#ifndef QT_OPENGL_ES_2
2674#ifdef QT_OPENGL_ES
2675 if (textureTarget != GL_TEXTURE_2D) {
2676 qWarning("QGLContext::drawTexture(): texture target must be GL_TEXTURE_2D on OpenGL ES");
2677 return;
2678 }
2679#else
2680 const bool wasEnabled = glIsEnabled(GL_TEXTURE_2D);
2681 GLint oldTexture;
2682 glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexture);
2683#endif
2684
2685 glEnable(textureTarget);
2686 glBindTexture(textureTarget, textureId);
2687
2688 qDrawTextureRect(target, -1, -1, textureTarget);
2689
2690#ifdef QT_OPENGL_ES
2691 glDisable(textureTarget);
2692#else
2693 if (!wasEnabled)
2694 glDisable(textureTarget);
2695 glBindTexture(textureTarget, oldTexture);
2696#endif
2697#else
2698 Q_UNUSED(target);
2699 Q_UNUSED(textureId);
2700 Q_UNUSED(textureTarget);
2701 qWarning("drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) not supported with OpenGL ES/2.0");
2702#endif
2703}
2704
2705#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
2706/*! \internal */
2707void QGLContext::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
2708{
2709 drawTexture(target, GLuint(textureId), GLenum(textureTarget));
2710}
2711#endif
2712
2713/*!
2714 \since 4.4
2715
2716 Draws the given texture at the given \a point in OpenGL model
2717 space. The \a textureTarget should be a 2D texture target.
2718
2719 \note This function is not supported under OpenGL/ES.
2720*/
2721void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
2722{
2723 // this would be ok on OpenGL ES 2.0, but currently we don't have a define for that
2724#ifdef QT_OPENGL_ES
2725 Q_UNUSED(point);
2726 Q_UNUSED(textureId);
2727 Q_UNUSED(textureTarget);
2728 qWarning("drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget) not supported with OpenGL ES, use rect version instead");
2729#else
2730 const bool wasEnabled = glIsEnabled(GL_TEXTURE_2D);
2731 GLint oldTexture;
2732 glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexture);
2733
2734 glEnable(textureTarget);
2735 glBindTexture(textureTarget, textureId);
2736
2737 GLint textureWidth;
2738 GLint textureHeight;
2739
2740 glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_WIDTH, &textureWidth);
2741 glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_HEIGHT, &textureHeight);
2742
2743 qDrawTextureRect(QRectF(point, QSizeF(textureWidth, textureHeight)), textureWidth, textureHeight, textureTarget);
2744
2745 if (!wasEnabled)
2746 glDisable(textureTarget);
2747 glBindTexture(textureTarget, oldTexture);
2748#endif
2749}
2750
2751#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
2752/*! \internal */
2753void QGLContext::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
2754{
2755 drawTexture(point, GLuint(textureId), GLenum(textureTarget));
2756}
2757#endif
2758
2759
2760/*!
2761 This function sets the limit for the texture cache to \a size,
2762 expressed in kilobytes.
2763
2764 By default, the cache limit is approximately 64 MB.
2765
2766 \sa textureCacheLimit()
2767*/
2768void QGLContext::setTextureCacheLimit(int size)
2769{
2770 QGLTextureCache::instance()->setMaxCost(size);
2771}
2772
2773/*!
2774 Returns the current texture cache limit in kilobytes.
2775
2776 \sa setTextureCacheLimit()
2777*/
2778int QGLContext::textureCacheLimit()
2779{
2780 return QGLTextureCache::instance()->maxCost();
2781}
2782
2783
2784/*!
2785 \fn QGLFormat QGLContext::format() const
2786
2787 Returns the frame buffer format that was obtained (this may be a
2788 subset of what was requested).
2789
2790 \sa requestedFormat()
2791*/
2792
2793/*!
2794 \fn QGLFormat QGLContext::requestedFormat() const
2795
2796 Returns the frame buffer format that was originally requested in
2797 the constructor or setFormat().
2798
2799 \sa format()
2800*/
2801
2802/*!
2803 Sets a \a format for this context. The context is \link reset()
2804 reset\endlink.
2805
2806 Call create() to create a new GL context that tries to match the
2807 new format.
2808
2809 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 7
2810
2811 \sa format(), reset(), create()
2812*/
2813
2814void QGLContext::setFormat(const QGLFormat &format)
2815{
2816 Q_D(QGLContext);
2817 reset();
2818 d->glFormat = d->reqFormat = format;
2819}
2820
2821/*!
2822 \internal
2823*/
2824void QGLContext::setDevice(QPaintDevice *pDev)
2825{
2826 Q_D(QGLContext);
2827 if (isValid())
2828 reset();
2829 d->paintDevice = pDev;
2830 if (d->paintDevice && (d->paintDevice->devType() != QInternal::Widget
2831 && d->paintDevice->devType() != QInternal::Pixmap
2832 && d->paintDevice->devType() != QInternal::Pbuffer)) {
2833 qWarning("QGLContext: Unsupported paint device type");
2834 }
2835}
2836
2837/*!
2838 \fn bool QGLContext::isValid() const
2839
2840 Returns true if a GL rendering context has been successfully
2841 created; otherwise returns false.
2842*/
2843
2844/*!
2845 \fn void QGLContext::setValid(bool valid)
2846 \internal
2847
2848 Forces the GL rendering context to be valid.
2849*/
2850
2851/*!
2852 \fn bool QGLContext::isSharing() const
2853
2854 Returns true if this context is sharing its GL context with
2855 another QGLContext, otherwise false is returned. Note that context
2856 sharing might not be supported between contexts with different
2857 formats.
2858*/
2859
2860/*!
2861 Returns true if \a context1 and \a context2 are sharing their
2862 GL resources such as textures, shader programs, etc;
2863 otherwise returns false.
2864
2865 \since 4.6
2866*/
2867bool QGLContext::areSharing(const QGLContext *context1, const QGLContext *context2)
2868{
2869 if (!context1 || !context2)
2870 return false;
2871 return context1->d_ptr->group == context2->d_ptr->group;
2872}
2873
2874/*!
2875 \fn bool QGLContext::deviceIsPixmap() const
2876
2877 Returns true if the paint device of this context is a pixmap;
2878 otherwise returns false.
2879*/
2880
2881/*!
2882 \fn bool QGLContext::windowCreated() const
2883
2884 Returns true if a window has been created for this context;
2885 otherwise returns false.
2886
2887 \sa setWindowCreated()
2888*/
2889
2890/*!
2891 \fn void QGLContext::setWindowCreated(bool on)
2892
2893 If \a on is true the context has had a window created for it. If
2894 \a on is false no window has been created for the context.
2895
2896 \sa windowCreated()
2897*/
2898
2899/*!
2900 \fn uint QGLContext::colorIndex(const QColor& c) const
2901
2902 \internal
2903
2904 Returns a colormap index for the color c, in ColorIndex mode. Used
2905 by qglColor() and qglClearColor().
2906*/
2907
2908
2909/*!
2910 \fn bool QGLContext::initialized() const
2911
2912 Returns true if this context has been initialized, i.e. if
2913 QGLWidget::initializeGL() has been performed on it; otherwise
2914 returns false.
2915
2916 \sa setInitialized()
2917*/
2918
2919/*!
2920 \fn void QGLContext::setInitialized(bool on)
2921
2922 If \a on is true the context has been initialized, i.e.
2923 QGLContext::setInitialized() has been called on it. If \a on is
2924 false the context has not been initialized.
2925
2926 \sa initialized()
2927*/
2928
2929/*!
2930 \fn const QGLContext* QGLContext::currentContext()
2931
2932 Returns the current context, i.e. the context to which any OpenGL
2933 commands will currently be directed. Returns 0 if no context is
2934 current.
2935
2936 \sa makeCurrent()
2937*/
2938
2939/*!
2940 \fn QColor QGLContext::overlayTransparentColor() const
2941
2942 If this context is a valid context in an overlay plane, returns
2943 the plane's transparent color. Otherwise returns an \link
2944 QColor::isValid() invalid \endlink color.
2945
2946 The returned color's \link QColor::pixel() pixel \endlink value is
2947 the index of the transparent color in the colormap of the overlay
2948 plane. (Naturally, the color's RGB values are meaningless.)
2949
2950 The returned QColor object will generally work as expected only
2951 when passed as the argument to QGLWidget::qglColor() or
2952 QGLWidget::qglClearColor(). Under certain circumstances it can
2953 also be used to draw transparent graphics with a QPainter. See the
2954 examples/opengl/overlay_x11 example for details.
2955*/
2956
2957
2958/*!
2959 Creates the GL context. Returns true if it was successful in
2960 creating a valid GL rendering context on the paint device
2961 specified in the constructor; otherwise returns false (i.e. the
2962 context is invalid).
2963
2964 After successful creation, format() returns the set of features of
2965 the created GL rendering context.
2966
2967 If \a shareContext points to a valid QGLContext, this method will
2968 try to establish OpenGL display list and texture object sharing
2969 between this context and the \a shareContext. Note that this may
2970 fail if the two contexts have different \l {format()} {formats}.
2971 Use isSharing() to see if sharing is in effect.
2972
2973 \warning Implementation note: initialization of C++ class
2974 members usually takes place in the class constructor. QGLContext
2975 is an exception because it must be simple to customize. The
2976 virtual functions chooseContext() (and chooseVisual() for X11) can
2977 be reimplemented in a subclass to select a particular context. The
2978 problem is that virtual functions are not properly called during
2979 construction (even though this is correct C++) because C++
2980 constructs class hierarchies from the bottom up. For this reason
2981 we need a create() function.
2982
2983 \sa chooseContext(), format(), isValid()
2984*/
2985
2986bool QGLContext::create(const QGLContext* shareContext)
2987{
2988 Q_D(QGLContext);
2989 if (!d->paintDevice)
2990 return false;
2991 reset();
2992 d->valid = chooseContext(shareContext);
2993 if (d->valid && d->paintDevice->devType() == QInternal::Widget) {
2994 QWidgetPrivate *wd = qt_widget_private(static_cast<QWidget *>(d->paintDevice));
2995 wd->usesDoubleBufferedGLContext = d->glFormat.doubleBuffer();
2996 }
2997 if (d->sharing) // ok, we managed to share
2998 QGLContextGroup::addShare(this, shareContext);
2999 return d->valid;
3000}
3001
3002bool QGLContext::isValid() const
3003{
3004 Q_D(const QGLContext);
3005 return d->valid;
3006}
3007
3008void QGLContext::setValid(bool valid)
3009{
3010 Q_D(QGLContext);
3011 d->valid = valid;
3012}
3013
3014bool QGLContext::isSharing() const
3015{
3016 Q_D(const QGLContext);
3017 return d->group->isSharing();
3018}
3019
3020QGLFormat QGLContext::format() const
3021{
3022 Q_D(const QGLContext);
3023 return d->glFormat;
3024}
3025
3026QGLFormat QGLContext::requestedFormat() const
3027{
3028 Q_D(const QGLContext);
3029 return d->reqFormat;
3030}
3031
3032 QPaintDevice* QGLContext::device() const
3033{
3034 Q_D(const QGLContext);
3035 return d->paintDevice;
3036}
3037
3038bool QGLContext::deviceIsPixmap() const
3039{
3040 Q_D(const QGLContext);
3041 return d->paintDevice->devType() == QInternal::Pixmap;
3042}
3043
3044
3045bool QGLContext::windowCreated() const
3046{
3047 Q_D(const QGLContext);
3048 return d->crWin;
3049}
3050
3051
3052void QGLContext::setWindowCreated(bool on)
3053{
3054 Q_D(QGLContext);
3055 d->crWin = on;
3056}
3057
3058bool QGLContext::initialized() const
3059{
3060 Q_D(const QGLContext);
3061 return d->initDone;
3062}
3063
3064void QGLContext::setInitialized(bool on)
3065{
3066 Q_D(QGLContext);
3067 d->initDone = on;
3068}
3069
3070const QGLContext* QGLContext::currentContext()
3071{
3072 QGLThreadContext *threadContext = qgl_context_storage.localData();
3073 if (threadContext)
3074 return threadContext->context;
3075 return 0;
3076}
3077
3078void QGLContextPrivate::setCurrentContext(QGLContext *context)
3079{
3080 QGLThreadContext *threadContext = qgl_context_storage.localData();
3081 if (!threadContext) {
3082 if (!QThread::currentThread()) {
3083 // We don't have a current QThread, so just set the static.
3084 QGLContext::currentCtx = context;
3085 return;
3086 }
3087 threadContext = new QGLThreadContext;
3088 qgl_context_storage.setLocalData(threadContext);
3089 }
3090 threadContext->context = context;
3091 QGLContext::currentCtx = context; // XXX: backwards-compat, not thread-safe
3092}
3093
3094/*!
3095 \fn bool QGLContext::chooseContext(const QGLContext* shareContext = 0)
3096
3097 This semi-internal function is called by create(). It creates a
3098 system-dependent OpenGL handle that matches the format() of \a
3099 shareContext as closely as possible, returning true if successful
3100 or false if a suitable handle could not be found.
3101
3102 On Windows, it calls the virtual function choosePixelFormat(),
3103 which finds a matching pixel format identifier. On X11, it calls
3104 the virtual function chooseVisual() which finds an appropriate X
3105 visual. On other platforms it may work differently.
3106*/
3107
3108/*! \fn int QGLContext::choosePixelFormat(void* dummyPfd, HDC pdc)
3109
3110 \bold{Win32 only:} This virtual function chooses a pixel format
3111 that matches the OpenGL \link setFormat() format\endlink.
3112 Reimplement this function in a subclass if you need a custom
3113 context.
3114
3115 \warning The \a dummyPfd pointer and \a pdc are used as a \c
3116 PIXELFORMATDESCRIPTOR*. We use \c void to avoid using
3117 Windows-specific types in our header files.
3118
3119 \sa chooseContext()
3120*/
3121
3122/*! \fn void *QGLContext::chooseVisual()
3123
3124 \bold{X11 only:} This virtual function tries to find a visual that
3125 matches the format, reducing the demands if the original request
3126 cannot be met.
3127
3128 The algorithm for reducing the demands of the format is quite
3129 simple-minded, so override this method in your subclass if your
3130 application has spcific requirements on visual selection.
3131
3132 \sa chooseContext()
3133*/
3134
3135/*! \fn void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth)
3136 \internal
3137
3138 \bold{X11 only:} This virtual function chooses a visual that matches
3139 the OpenGL \link format() format\endlink. Reimplement this function
3140 in a subclass if you need a custom visual.
3141
3142 \sa chooseContext()
3143*/
3144
3145/*!
3146 \fn void QGLContext::reset()
3147
3148 Resets the context and makes it invalid.
3149
3150 \sa create(), isValid()
3151*/
3152
3153
3154/*!
3155 \fn void QGLContext::makeCurrent()
3156
3157 Makes this context the current OpenGL rendering context. All GL
3158 functions you call operate on this context until another context
3159 is made current.
3160
3161 In some very rare cases the underlying call may fail. If this
3162 occurs an error message is output to stderr.
3163*/
3164
3165
3166/*!
3167 \fn void QGLContext::swapBuffers() const
3168
3169 Swaps the screen contents with an off-screen buffer. Only works if
3170 the context is in double buffer mode.
3171
3172 \sa QGLFormat::setDoubleBuffer()
3173*/
3174
3175
3176/*!
3177 \fn void QGLContext::doneCurrent()
3178
3179 Makes no GL context the current context. Normally, you do not need
3180 to call this function; QGLContext calls it as necessary.
3181*/
3182
3183
3184/*!
3185 \fn QPaintDevice* QGLContext::device() const
3186
3187 Returns the paint device set for this context.
3188
3189 \sa QGLContext::QGLContext()
3190*/
3191
3192/*!
3193 \obsolete
3194 \fn void QGLContext::generateFontDisplayLists(const QFont& font, int listBase)
3195
3196 Generates a set of 256 display lists for the 256 first characters
3197 in the font \a font. The first list will start at index \a listBase.
3198
3199 \sa QGLWidget::renderText()
3200*/
3201
3202
3203/*****************************************************************************
3204 QGLWidget implementation
3205 *****************************************************************************/
3206
3207
3208/*!
3209 \class QGLWidget
3210 \brief The QGLWidget class is a widget for rendering OpenGL graphics.
3211
3212 \ingroup painting-3D
3213
3214
3215 QGLWidget provides functionality for displaying OpenGL graphics
3216 integrated into a Qt application. It is very simple to use. You
3217 inherit from it and use the subclass like any other QWidget,
3218 except that you have the choice between using QPainter and
3219 standard OpenGL rendering commands.
3220
3221 QGLWidget provides three convenient virtual functions that you can
3222 reimplement in your subclass to perform the typical OpenGL tasks:
3223
3224 \list
3225 \i paintGL() - Renders the OpenGL scene. Gets called whenever the widget
3226 needs to be updated.
3227 \i resizeGL() - Sets up the OpenGL viewport, projection, etc. Gets
3228 called whenever the widget has been resized (and also when it
3229 is shown for the first time because all newly created widgets get a
3230 resize event automatically).
3231 \i initializeGL() - Sets up the OpenGL rendering context, defines display
3232 lists, etc. Gets called once before the first time resizeGL() or
3233 paintGL() is called.
3234 \endlist
3235
3236 Here is a rough outline of how a QGLWidget subclass might look:
3237
3238 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 8
3239
3240 If you need to trigger a repaint from places other than paintGL()
3241 (a typical example is when using \link QTimer timers\endlink to
3242 animate scenes), you should call the widget's updateGL() function.
3243
3244 Your widget's OpenGL rendering context is made current when
3245 paintGL(), resizeGL(), or initializeGL() is called. If you need to
3246 call the standard OpenGL API functions from other places (e.g. in
3247 your widget's constructor or in your own paint functions), you
3248 must call makeCurrent() first.
3249
3250 QGLWidget provides functions for requesting a new display \link
3251 QGLFormat format\endlink and you can also create widgets with
3252 customized rendering \link QGLContext contexts\endlink.
3253
3254 You can also share OpenGL display lists between QGLWidget objects (see
3255 the documentation of the QGLWidget constructors for details).
3256
3257 Note that under Windows, the QGLContext belonging to a QGLWidget
3258 has to be recreated when the QGLWidget is reparented. This is
3259 necessary due to limitations on the Windows platform. This will
3260 most likely cause problems for users that have subclassed and
3261 installed their own QGLContext on a QGLWidget. It is possible to
3262 work around this issue by putting the QGLWidget inside a dummy
3263 widget and then reparenting the dummy widget, instead of the
3264 QGLWidget. This will side-step the issue altogether, and is what
3265 we recommend for users that need this kind of functionality.
3266
3267 On Mac OS X, when Qt is built with Cocoa support, a QGLWidget
3268 can't have any sibling widgets placed ontop of itself. This is due
3269 to limitations in the Cocoa API and is not supported by Apple.
3270
3271 \section1 Overlays
3272
3273 The QGLWidget creates a GL overlay context in addition to the
3274 normal context if overlays are supported by the underlying system.
3275
3276 If you want to use overlays, you specify it in the \link QGLFormat
3277 format\endlink. (Note: Overlay must be requested in the format
3278 passed to the QGLWidget constructor.) Your GL widget should also
3279 implement some or all of these virtual methods:
3280
3281 \list
3282 \i paintOverlayGL()
3283 \i resizeOverlayGL()
3284 \i initializeOverlayGL()
3285 \endlist
3286
3287 These methods work in the same way as the normal paintGL() etc.
3288 functions, except that they will be called when the overlay
3289 context is made current. You can explicitly make the overlay
3290 context current by using makeOverlayCurrent(), and you can access
3291 the overlay context directly (e.g. to ask for its transparent
3292 color) by calling overlayContext().
3293
3294 On X servers in which the default visual is in an overlay plane,
3295 non-GL Qt windows can also be used for overlays.
3296
3297 \section1 Painting Techniques
3298
3299 As described above, subclass QGLWidget to render pure 3D content in the
3300 following way:
3301
3302 \list
3303 \o Reimplement the QGLWidget::initializeGL() and QGLWidget::resizeGL() to
3304 set up the OpenGL state and provide a perspective transformation.
3305 \o Reimplement QGLWidget::paintGL() to paint the 3D scene, calling only
3306 OpenGL functions to draw on the widget.
3307 \endlist
3308
3309 It is also possible to draw 2D graphics onto a QGLWidget subclass, it is necessary
3310 to reimplement QGLWidget::paintEvent() and do the following:
3311
3312 \list
3313 \o Construct a QPainter object.
3314 \o Initialize it for use on the widget with the QPainter::begin() function.
3315 \o Draw primitives using QPainter's member functions.
3316 \o Call QPainter::end() to finish painting.
3317 \endlist
3318
3319 Overpainting 2D content on top of 3D content takes a little more effort.
3320 One approach to doing this is shown in the
3321 \l{Overpainting Example}{Overpainting} example.
3322
3323 \e{OpenGL is a trademark of Silicon Graphics, Inc. in the United States and other
3324 countries.}
3325
3326 \sa QGLPixelBuffer, {Hello GL Example}, {2D Painting Example}, {Overpainting Example},
3327 {Grabber Example}
3328*/
3329
3330/*!
3331 Constructs an OpenGL widget with a \a parent widget.
3332
3333 The \link QGLFormat::defaultFormat() default format\endlink is
3334 used. The widget will be \link isValid() invalid\endlink if the
3335 system has no \link QGLFormat::hasOpenGL() OpenGL support\endlink.
3336
3337 The \a parent and widget flag, \a f, arguments are passed
3338 to the QWidget constructor.
3339
3340 If \a shareWidget is a valid QGLWidget, this widget will share
3341 OpenGL display lists and texture objects with \a shareWidget. But
3342 if \a shareWidget and this widget have different \l {format()}
3343 {formats}, sharing might not be possible. You can check whether
3344 sharing is in effect by calling isSharing().
3345
3346 The initialization of OpenGL rendering state, etc. should be done
3347 by overriding the initializeGL() function, rather than in the
3348 constructor of your QGLWidget subclass.
3349
3350 \sa QGLFormat::defaultFormat(), {Textures Example}
3351*/
3352
3353QGLWidget::QGLWidget(QWidget *parent, const QGLWidget* shareWidget, Qt::WindowFlags f)
3354 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
3355{
3356 Q_D(QGLWidget);
3357 setAttribute(Qt::WA_PaintOnScreen);
3358 setAttribute(Qt::WA_NoSystemBackground);
3359 setAutoFillBackground(true); // for compatibility
3360 d->init(new QGLContext(QGLFormat::defaultFormat(), this), shareWidget);
3361}
3362
3363
3364/*!
3365 Constructs an OpenGL widget with parent \a parent.
3366
3367 The \a format argument specifies the desired \link QGLFormat
3368 rendering options \endlink. If the underlying OpenGL/Window system
3369 cannot satisfy all the features requested in \a format, the
3370 nearest subset of features will be used. After creation, the
3371 format() method will return the actual format obtained.
3372
3373 The widget will be \link isValid() invalid\endlink if the system
3374 has no \link QGLFormat::hasOpenGL() OpenGL support\endlink.
3375
3376 The \a parent and widget flag, \a f, arguments are passed
3377 to the QWidget constructor.
3378
3379 If \a shareWidget is a valid QGLWidget, this widget will share
3380 OpenGL display lists and texture objects with \a shareWidget. But
3381 if \a shareWidget and this widget have different \l {format()}
3382 {formats}, sharing might not be possible. You can check whether
3383 sharing is in effect by calling isSharing().
3384
3385 The initialization of OpenGL rendering state, etc. should be done
3386 by overriding the initializeGL() function, rather than in the
3387 constructor of your QGLWidget subclass.
3388
3389 \sa QGLFormat::defaultFormat(), isValid()
3390*/
3391
3392QGLWidget::QGLWidget(const QGLFormat &format, QWidget *parent, const QGLWidget* shareWidget,
3393 Qt::WindowFlags f)
3394 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
3395{
3396 Q_D(QGLWidget);
3397 setAttribute(Qt::WA_PaintOnScreen);
3398 setAttribute(Qt::WA_NoSystemBackground);
3399 setAutoFillBackground(true); // for compatibility
3400 d->init(new QGLContext(format, this), shareWidget);
3401}
3402
3403/*!
3404 Constructs an OpenGL widget with parent \a parent.
3405
3406 The \a context argument is a pointer to the QGLContext that
3407 you wish to be bound to this widget. This allows you to pass in
3408 your own QGLContext sub-classes.
3409
3410 The widget will be \link isValid() invalid\endlink if the system
3411 has no \link QGLFormat::hasOpenGL() OpenGL support\endlink.
3412
3413 The \a parent and widget flag, \a f, arguments are passed
3414 to the QWidget constructor.
3415
3416 If \a shareWidget is a valid QGLWidget, this widget will share
3417 OpenGL display lists and texture objects with \a shareWidget. But
3418 if \a shareWidget and this widget have different \l {format()}
3419 {formats}, sharing might not be possible. You can check whether
3420 sharing is in effect by calling isSharing().
3421
3422 The initialization of OpenGL rendering state, etc. should be done
3423 by overriding the initializeGL() function, rather than in the
3424 constructor of your QGLWidget subclass.
3425
3426 \sa QGLFormat::defaultFormat(), isValid()
3427*/
3428QGLWidget::QGLWidget(QGLContext *context, QWidget *parent, const QGLWidget *shareWidget,
3429 Qt::WindowFlags f)
3430 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
3431{
3432 Q_D(QGLWidget);
3433 setAttribute(Qt::WA_PaintOnScreen);
3434 setAttribute(Qt::WA_NoSystemBackground);
3435 setAutoFillBackground(true); // for compatibility
3436 d->init(context, shareWidget);
3437}
3438
3439/*!
3440 Destroys the widget.
3441*/
3442
3443QGLWidget::~QGLWidget()
3444{
3445 Q_D(QGLWidget);
3446#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT)
3447 bool doRelease = (glcx && glcx->windowCreated());
3448#endif
3449 delete d->glcx;
3450#if defined(Q_WGL)
3451 delete d->olcx;
3452#endif
3453#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT)
3454 if (doRelease)
3455 glXReleaseBuffersMESA(x11Display(), winId());
3456#endif
3457 d->cleanupColormaps();
3458
3459#ifdef Q_WS_MAC
3460 QWidget *current = parentWidget();
3461 while (current) {
3462 qt_widget_private(current)->glWidgets.removeAll(QWidgetPrivate::GlWidgetInfo(this));
3463 if (current->isWindow())
3464 break;
3465 current = current->parentWidget();
3466 };
3467#endif
3468}
3469
3470/*!
3471 \fn QGLFormat QGLWidget::format() const
3472
3473 Returns the format of the contained GL rendering context.
3474*/
3475
3476/*!
3477 \fn bool QGLWidget::doubleBuffer() const
3478
3479 Returns true if the contained GL rendering context has double
3480 buffering; otherwise returns false.
3481
3482 \sa QGLFormat::doubleBuffer()
3483*/
3484
3485/*!
3486 \fn void QGLWidget::setAutoBufferSwap(bool on)
3487
3488 If \a on is true automatic GL buffer swapping is switched on;
3489 otherwise it is switched off.
3490
3491 If \a on is true and the widget is using a double-buffered format,
3492 the background and foreground GL buffers will automatically be
3493 swapped after each paintGL() call.
3494
3495 The buffer auto-swapping is on by default.
3496
3497 \sa autoBufferSwap(), doubleBuffer(), swapBuffers()
3498*/
3499
3500/*!
3501 \fn bool QGLWidget::autoBufferSwap() const
3502
3503 Returns true if the widget is doing automatic GL buffer swapping;
3504 otherwise returns false.
3505
3506 \sa setAutoBufferSwap()
3507*/
3508
3509/*!
3510 \fn void *QGLContext::getProcAddress(const QString &proc) const
3511
3512 Returns a function pointer to the GL extension function passed in
3513 \a proc. 0 is returned if a pointer to the function could not be
3514 obtained.
3515*/
3516
3517/*!
3518 \fn bool QGLWidget::isValid() const
3519
3520 Returns true if the widget has a valid GL rendering context;
3521 otherwise returns false. A widget will be invalid if the system
3522 has no \link QGLFormat::hasOpenGL() OpenGL support\endlink.
3523*/
3524
3525bool QGLWidget::isValid() const
3526{
3527 Q_D(const QGLWidget);
3528 return d->glcx && d->glcx->isValid();
3529}
3530
3531/*!
3532 \fn bool QGLWidget::isSharing() const
3533
3534 Returns true if this widget's GL context is shared with another GL
3535 context, otherwise false is returned. Context sharing might not be
3536 possible if the widgets use different formats.
3537
3538 \sa format()
3539*/
3540
3541bool QGLWidget::isSharing() const
3542{
3543 Q_D(const QGLWidget);
3544 return d->glcx->isSharing();
3545}
3546
3547/*!
3548 \fn void QGLWidget::makeCurrent()
3549
3550 Makes this widget the current widget for OpenGL operations, i.e.
3551 makes the widget's rendering context the current OpenGL rendering
3552 context.
3553*/
3554
3555void QGLWidget::makeCurrent()
3556{
3557 Q_D(QGLWidget);
3558 d->glcx->makeCurrent();
3559}
3560
3561/*!
3562 \fn void QGLWidget::doneCurrent()
3563
3564 Makes no GL context the current context. Normally, you do not need
3565 to call this function; QGLContext calls it as necessary. However,
3566 it may be useful in multithreaded environments.
3567*/
3568
3569void QGLWidget::doneCurrent()
3570{
3571 Q_D(QGLWidget);
3572 d->glcx->doneCurrent();
3573}
3574
3575/*!
3576 \fn void QGLWidget::swapBuffers()
3577
3578 Swaps the screen contents with an off-screen buffer. This only
3579 works if the widget's format specifies double buffer mode.
3580
3581 Normally, there is no need to explicitly call this function
3582 because it is done automatically after each widget repaint, i.e.
3583 each time after paintGL() has been executed.
3584
3585 \sa doubleBuffer(), setAutoBufferSwap(), QGLFormat::setDoubleBuffer()
3586*/
3587
3588void QGLWidget::swapBuffers()
3589{
3590 Q_D(QGLWidget);
3591 d->glcx->swapBuffers();
3592}
3593
3594
3595/*!
3596 \fn const QGLContext* QGLWidget::overlayContext() const
3597
3598 Returns the overlay context of this widget, or 0 if this widget
3599 has no overlay.
3600
3601 \sa context()
3602*/
3603
3604
3605
3606/*!
3607 \fn void QGLWidget::makeOverlayCurrent()
3608
3609 Makes the overlay context of this widget current. Use this if you
3610 need to issue OpenGL commands to the overlay context outside of
3611 initializeOverlayGL(), resizeOverlayGL(), and paintOverlayGL().
3612
3613 Does nothing if this widget has no overlay.
3614
3615 \sa makeCurrent()
3616*/
3617
3618
3619/*!
3620 \obsolete
3621
3622 Sets a new format for this widget.
3623
3624 If the underlying OpenGL/Window system cannot satisfy all the
3625 features requested in \a format, the nearest subset of features will
3626 be used. After creation, the format() method will return the actual
3627 rendering context format obtained.
3628
3629 The widget will be assigned a new QGLContext, and the initializeGL()
3630 function will be executed for this new context before the first
3631 resizeGL() or paintGL().
3632
3633 This method will try to keep display list and texture object sharing
3634 in effect with other QGLWidget objects, but changing the format might make
3635 sharing impossible. Use isSharing() to see if sharing is still in
3636 effect.
3637
3638 \sa format(), isSharing(), isValid()
3639*/
3640
3641void QGLWidget::setFormat(const QGLFormat &format)
3642{
3643 setContext(new QGLContext(format,this));
3644}
3645
3646
3647
3648
3649/*!
3650 \fn const QGLContext *QGLWidget::context() const
3651
3652 Returns the context of this widget.
3653
3654 It is possible that the context is not valid (see isValid()), for
3655 example, if the underlying hardware does not support the format
3656 attributes that were requested.
3657*/
3658
3659/*
3660 \fn void QGLWidget::setContext(QGLContext *context,
3661 const QGLContext* shareContext,
3662 bool deleteOldContext)
3663 \obsolete
3664
3665 Sets a new context for this widget. The QGLContext \a context must
3666 be created using \e new. QGLWidget will delete \a context when
3667 another context is set or when the widget is destroyed.
3668
3669 If \a context is invalid, QGLContext::create() is performed on
3670 it. The initializeGL() function will then be executed for the new
3671 context before the first resizeGL() or paintGL().
3672
3673 If \a context is invalid, this method will try to keep display list
3674 and texture object sharing in effect, or (if \a shareContext points
3675 to a valid context) start display list and texture object sharing
3676 with that context, but sharing might be impossible if the two
3677 contexts have different \l {format()} {formats}. Use isSharing() to
3678 see whether sharing is in effect.
3679
3680 If \a deleteOldContext is true (the default), the existing context
3681 will be deleted. You may use false here if you have kept a pointer
3682 to the old context (as returned by context()), and want to restore
3683 that context later.
3684
3685 \sa context(), isSharing()
3686*/
3687
3688
3689
3690/*!
3691 \fn void QGLWidget::updateGL()
3692
3693 Updates the widget by calling glDraw().
3694*/
3695
3696void QGLWidget::updateGL()
3697{
3698 if (updatesEnabled())
3699 glDraw();
3700}
3701
3702
3703/*!
3704 \fn void QGLWidget::updateOverlayGL()
3705
3706 Updates the widget's overlay (if any). Will cause the virtual
3707 function paintOverlayGL() to be executed.
3708
3709 The widget's rendering context will become the current context and
3710 initializeGL() will be called if it hasn't already been called.
3711*/
3712
3713
3714/*!
3715 This virtual function is called once before the first call to
3716 paintGL() or resizeGL(), and then once whenever the widget has
3717 been assigned a new QGLContext. Reimplement it in a subclass.
3718
3719 This function should set up any required OpenGL context rendering
3720 flags, defining display lists, etc.
3721
3722 There is no need to call makeCurrent() because this has already
3723 been done when this function is called.
3724*/
3725
3726void QGLWidget::initializeGL()
3727{
3728}
3729
3730
3731/*!
3732 This virtual function is called whenever the widget needs to be
3733 painted. Reimplement it in a subclass.
3734
3735 There is no need to call makeCurrent() because this has already
3736 been done when this function is called.
3737*/
3738
3739void QGLWidget::paintGL()
3740{
3741}
3742
3743
3744/*!
3745 \fn void QGLWidget::resizeGL(int width , int height)
3746
3747 This virtual function is called whenever the widget has been
3748 resized. The new size is passed in \a width and \a height.
3749 Reimplement it in a subclass.
3750
3751 There is no need to call makeCurrent() because this has already
3752 been done when this function is called.
3753*/
3754
3755void QGLWidget::resizeGL(int, int)
3756{
3757}
3758
3759
3760
3761/*!
3762 This virtual function is used in the same manner as initializeGL()
3763 except that it operates on the widget's overlay context instead of
3764 the widget's main context. This means that initializeOverlayGL()
3765 is called once before the first call to paintOverlayGL() or
3766 resizeOverlayGL(). Reimplement it in a subclass.
3767
3768 This function should set up any required OpenGL context rendering
3769 flags, defining display lists, etc. for the overlay context.
3770
3771 There is no need to call makeOverlayCurrent() because this has
3772 already been done when this function is called.
3773*/
3774
3775void QGLWidget::initializeOverlayGL()
3776{
3777}
3778
3779
3780/*!
3781 This virtual function is used in the same manner as paintGL()
3782 except that it operates on the widget's overlay context instead of
3783 the widget's main context. This means that paintOverlayGL() is
3784 called whenever the widget's overlay needs to be painted.
3785 Reimplement it in a subclass.
3786
3787 There is no need to call makeOverlayCurrent() because this has
3788 already been done when this function is called.
3789*/
3790
3791void QGLWidget::paintOverlayGL()
3792{
3793}
3794
3795
3796/*!
3797 \fn void QGLWidget::resizeOverlayGL(int width , int height)
3798
3799 This virtual function is used in the same manner as paintGL()
3800 except that it operates on the widget's overlay context instead of
3801 the widget's main context. This means that resizeOverlayGL() is
3802 called whenever the widget has been resized. The new size is
3803 passed in \a width and \a height. Reimplement it in a subclass.
3804
3805 There is no need to call makeOverlayCurrent() because this has
3806 already been done when this function is called.
3807*/
3808
3809void QGLWidget::resizeOverlayGL(int, int)
3810{
3811}
3812
3813/*! \fn bool QGLWidget::event(QEvent *e)
3814 \reimp
3815*/
3816#if !defined(Q_OS_WINCE) && !defined(Q_WS_QWS)
3817bool QGLWidget::event(QEvent *e)
3818{
3819 Q_D(QGLWidget);
3820
3821 if (e->type() == QEvent::Paint) {
3822 QPoint offset;
3823 QPaintDevice *redirectedDevice = d->redirected(&offset);
3824 if (redirectedDevice && redirectedDevice->devType() == QInternal::Pixmap) {
3825 d->restoreRedirected();
3826 QPixmap pixmap = renderPixmap();
3827 d->setRedirected(redirectedDevice, offset);
3828 QPainter p(redirectedDevice);
3829 p.drawPixmap(-offset, pixmap);
3830 return true;
3831 }
3832 }
3833
3834#if defined(Q_WS_X11)
3835 // prevents X errors on some systems, where we get a flush to a
3836 // hidden widget
3837 if (e->type() == QEvent::Hide) {
3838 makeCurrent();
3839 glFinish();
3840 doneCurrent();
3841 } else if (e->type() == QEvent::ParentChange) {
3842 // if we've reparented a window that has the current context
3843 // bound, we need to rebind that context to the new window id
3844 if (d->glcx == QGLContext::currentContext())
3845 makeCurrent();
3846
3847 if (d->glcx->d_func()->screen != d->xinfo.screen() || testAttribute(Qt::WA_TranslucentBackground)) {
3848 setContext(new QGLContext(d->glcx->requestedFormat(), this));
3849 // ### recreating the overlay isn't supported atm
3850 }
3851 }
3852
3853#if defined(QT_OPENGL_ES)
3854 // A re-parent is likely to destroy the X11 window and re-create it. It is important
3855 // that we free the EGL surface _before_ the winID changes - otherwise we can leak.
3856 if (e->type() == QEvent::ParentAboutToChange)
3857 d->glcx->d_func()->destroyEglSurfaceForDevice();
3858
3859 if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) {
3860 // The window may have been re-created during re-parent or state change - if so, the EGL
3861 // surface will need to be re-created.
3862 d->recreateEglSurface(false);
3863 }
3864#endif
3865#elif defined(Q_WS_WIN)
3866 if (e->type() == QEvent::ParentChange) {
3867 QGLContext *newContext = new QGLContext(d->glcx->requestedFormat(), this);
3868 setContext(newContext, d->glcx);
3869
3870 // the overlay needs to be recreated as well
3871 delete d->olcx;
3872 if (isValid() && context()->format().hasOverlay()) {
3873 d->olcx = new QGLContext(QGLFormat::defaultOverlayFormat(), this);
3874 if (!d->olcx->create(isSharing() ? d->glcx : 0)) {
3875 delete d->olcx;
3876 d->olcx = 0;
3877 d->glcx->d_func()->glFormat.setOverlay(false);
3878 }
3879 } else {
3880 d->olcx = 0;
3881 }
3882 } else if (e->type() == QEvent::Show) {
3883 if (!format().rgba())
3884 d->updateColormap();
3885 }
3886#elif defined(Q_WS_MAC)
3887 if (e->type() == QEvent::MacGLWindowChange
3888#if 0 //(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
3889 && ((QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 && isWindow())
3890 || QSysInfo::MacintoshVersion <= QSysInfo::MV_10_4)
3891#endif
3892 ) {
3893 if (d->needWindowChange) {
3894 d->needWindowChange = false;
3895 d->glcx->updatePaintDevice();
3896 update();
3897 }
3898 return true;
3899# if defined(QT_MAC_USE_COCOA)
3900 } else if (e->type() == QEvent::MacGLClearDrawable) {
3901 d->glcx->d_ptr->clearDrawable();
3902# endif
3903 }
3904#endif
3905
3906 return QWidget::event(e);
3907}
3908#endif
3909
3910/*!
3911 \fn void QGLWidget::paintEvent(QPaintEvent *event)
3912
3913 Handles paint events passed in the \a event parameter. Will cause
3914 the virtual paintGL() function to be called.
3915
3916 The widget's rendering context will become the current context and
3917 initializeGL() will be called if it hasn't already been called.
3918*/
3919
3920void QGLWidget::paintEvent(QPaintEvent *)
3921{
3922 if (updatesEnabled()) {
3923 glDraw();
3924 updateOverlayGL();
3925 }
3926}
3927
3928
3929/*!
3930 \fn void QGLWidget::resizeEvent(QResizeEvent *event)
3931
3932 Handles resize events that are passed in the \a event parameter.
3933 Calls the virtual function resizeGL().
3934*/
3935
3936
3937/*!
3938 \fn void QGLWidget::setMouseTracking(bool enable)
3939
3940 If \a enable is true then mouse tracking is enabled; otherwise it
3941 is disabled.
3942*/
3943
3944
3945/*!
3946 Renders the current scene on a pixmap and returns the pixmap.
3947
3948 You can use this method on both visible and invisible QGLWidget objects.
3949
3950 This method will create a pixmap and a temporary QGLContext to
3951 render on the pixmap. It will then call initializeGL(),
3952 resizeGL(), and paintGL() on this context. Finally, the widget's
3953 original GL context is restored.
3954
3955 The size of the pixmap will be \a w pixels wide and \a h pixels
3956 high unless one of these parameters is 0 (the default), in which
3957 case the pixmap will have the same size as the widget.
3958
3959 If \a useContext is true, this method will try to be more
3960 efficient by using the existing GL context to render the pixmap.
3961 The default is false. Only use true if you understand the risks.
3962 Note that under Windows a temporary context has to be created
3963 and usage of the \e useContext parameter is not supported.
3964
3965 Overlays are not rendered onto the pixmap.
3966
3967 If the GL rendering context and the desktop have different bit
3968 depths, the result will most likely look surprising.
3969
3970 Note that the creation of display lists, modifications of the view
3971 frustum etc. should be done from within initializeGL(). If this is
3972 not done, the temporary QGLContext will not be initialized
3973 properly, and the rendered pixmap may be incomplete/corrupted.
3974*/
3975
3976QPixmap QGLWidget::renderPixmap(int w, int h, bool useContext)
3977{
3978 Q_D(QGLWidget);
3979 QSize sz = size();
3980 if ((w > 0) && (h > 0))
3981 sz = QSize(w, h);
3982
3983#if defined(Q_WS_X11)
3984 extern int qt_x11_preferred_pixmap_depth;
3985 int old_depth = qt_x11_preferred_pixmap_depth;
3986 qt_x11_preferred_pixmap_depth = x11Info().depth();
3987
3988 QPixmapData *data = new QX11PixmapData(QPixmapData::PixmapType);
3989 data->resize(sz.width(), sz.height());
3990 QPixmap pm(data);
3991 qt_x11_preferred_pixmap_depth = old_depth;
3992 QX11Info xinfo = x11Info();
3993
3994 // make sure we use a pixmap with the same depth/visual as the widget
3995 if (xinfo.visual() != QX11Info::appVisual()) {
3996 QX11InfoData* xd = pm.x11Info().getX11Data(true);
3997 xd->depth = xinfo.depth();
3998 xd->visual = static_cast<Visual *>(xinfo.visual());
3999 const_cast<QX11Info &>(pm.x11Info()).setX11Data(xd);
4000 }
4001
4002#else
4003 QPixmap pm(sz);
4004#endif
4005
4006 d->glcx->doneCurrent();
4007
4008 bool success = true;
4009
4010 if (useContext && isValid() && d->renderCxPm(&pm))
4011 return pm;
4012
4013 QGLFormat fmt = d->glcx->requestedFormat();
4014 fmt.setDirectRendering(false); // Direct is unlikely to work
4015 fmt.setDoubleBuffer(false); // We don't need dbl buf
4016#ifdef Q_WS_MAC // crash prevention on the Mac - it's unlikely to work anyway
4017 fmt.setSampleBuffers(false);
4018#endif
4019
4020 QGLContext* ocx = d->glcx;
4021 ocx->doneCurrent();
4022 d->glcx = new QGLContext(fmt, &pm);
4023 d->glcx->create();
4024
4025 if (d->glcx->isValid())
4026 updateGL();
4027 else
4028 success = false;
4029
4030 delete d->glcx;
4031 d->glcx = ocx;
4032
4033 ocx->makeCurrent();
4034
4035 if (success) {
4036#if defined(Q_WS_X11)
4037 if (xinfo.visual() != QX11Info::appVisual()) {
4038 QImage image = pm.toImage();
4039 QPixmap p = QPixmap::fromImage(image);
4040 return p;
4041 }
4042#endif
4043 return pm;
4044 }
4045 return QPixmap();
4046}
4047
4048/*!
4049 Returns an image of the frame buffer. If \a withAlpha is true the
4050 alpha channel is included.
4051
4052 Depending on your hardware, you can explicitly select which color
4053 buffer to grab with a glReadBuffer() call before calling this
4054 function.
4055*/
4056QImage QGLWidget::grabFrameBuffer(bool withAlpha)
4057{
4058 makeCurrent();
4059 QImage res;
4060 int w = width();
4061 int h = height();
4062 if (format().rgba()) {
4063 res = qt_gl_read_framebuffer(QSize(w, h), format().alpha(), withAlpha);
4064 } else {
4065#if defined (Q_WS_WIN) && !defined(QT_OPENGL_ES)
4066 res = QImage(w, h, QImage::Format_Indexed8);
4067 glReadPixels(0, 0, w, h, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, res.bits());
4068 const QVector<QColor> pal = QColormap::instance().colormap();
4069 if (pal.size()) {
4070 res.setColorCount(pal.size());
4071 for (int i = 0; i < pal.size(); i++)
4072 res.setColor(i, pal.at(i).rgb());
4073 }
4074 res = res.mirrored();
4075#endif
4076 }
4077
4078 return res;
4079}
4080
4081
4082
4083/*!
4084 Initializes OpenGL for this widget's context. Calls the virtual
4085 function initializeGL().
4086*/
4087
4088void QGLWidget::glInit()
4089{
4090 Q_D(QGLWidget);
4091 if (!isValid())
4092 return;
4093 makeCurrent();
4094 initializeGL();
4095 d->glcx->setInitialized(true);
4096}
4097
4098
4099/*!
4100 Executes the virtual function paintGL().
4101
4102 The widget's rendering context will become the current context and
4103 initializeGL() will be called if it hasn't already been called.
4104*/
4105
4106void QGLWidget::glDraw()
4107{
4108 Q_D(QGLWidget);
4109 if (!isValid())
4110 return;
4111 makeCurrent();
4112#ifndef QT_OPENGL_ES
4113 if (d->glcx->deviceIsPixmap())
4114 glDrawBuffer(GL_FRONT);
4115#endif
4116 if (!d->glcx->initialized()) {
4117 glInit();
4118 resizeGL(d->glcx->device()->width(), d->glcx->device()->height()); // New context needs this "resize"
4119 }
4120 paintGL();
4121 if (doubleBuffer()) {
4122 if (d->autoSwap)
4123 swapBuffers();
4124 } else {
4125 glFlush();
4126 }
4127}
4128
4129/*!
4130 Convenience function for specifying a drawing color to OpenGL.
4131 Calls glColor4 (in RGBA mode) or glIndex (in color-index mode)
4132 with the color \a c. Applies to this widgets GL context.
4133
4134 \note This function is not supported on OpenGL/ES 2.0 systems.
4135
4136 \sa qglClearColor(), QGLContext::currentContext(), QColor
4137*/
4138
4139void QGLWidget::qglColor(const QColor& c) const
4140{
4141#if !defined(QT_OPENGL_ES_2)
4142#ifdef QT_OPENGL_ES
4143 glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF());
4144#else
4145 Q_D(const QGLWidget);
4146 const QGLContext *ctx = QGLContext::currentContext();
4147 if (ctx) {
4148 if (ctx->format().rgba())
4149 glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF());
4150 else if (!d->cmap.isEmpty()) { // QGLColormap in use?
4151 int i = d->cmap.find(c.rgb());
4152 if (i < 0)
4153 i = d->cmap.findNearest(c.rgb());
4154 glIndexi(i);
4155 } else
4156 glIndexi(ctx->colorIndex(c));
4157 }
4158#endif //QT_OPENGL_ES
4159#else
4160 Q_UNUSED(c);
4161#endif //QT_OPENGL_ES_2
4162}
4163
4164/*!
4165 Convenience function for specifying the clearing color to OpenGL.
4166 Calls glClearColor (in RGBA mode) or glClearIndex (in color-index
4167 mode) with the color \a c. Applies to this widgets GL context.
4168
4169 \sa qglColor(), QGLContext::currentContext(), QColor
4170*/
4171
4172void QGLWidget::qglClearColor(const QColor& c) const
4173{
4174#ifdef QT_OPENGL_ES
4175 glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
4176#else
4177 Q_D(const QGLWidget);
4178 const QGLContext *ctx = QGLContext::currentContext();
4179 if (ctx) {
4180 if (ctx->format().rgba())
4181 glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
4182 else if (!d->cmap.isEmpty()) { // QGLColormap in use?
4183 int i = d->cmap.find(c.rgb());
4184 if (i < 0)
4185 i = d->cmap.findNearest(c.rgb());
4186 glClearIndex(i);
4187 } else
4188 glClearIndex(ctx->colorIndex(c));
4189 }
4190#endif
4191}
4192
4193
4194/*!
4195 Converts the image \a img into the unnamed format expected by
4196 OpenGL functions such as glTexImage2D(). The returned image is not
4197 usable as a QImage, but QImage::width(), QImage::height() and
4198 QImage::bits() may be used with OpenGL. The GL format used is
4199 \c GL_RGBA.
4200
4201 \omit ###
4202
4203 \l opengl/texture example
4204 The following few lines are from the texture example. Most of the
4205 code is irrelevant, so we just quote the relevant bits:
4206
4207 \quotefromfile opengl/texture/gltexobj.cpp
4208 \skipto tex1
4209 \printline tex1
4210 \printline gllogo.bmp
4211
4212 We create \e tex1 (and another variable) for OpenGL, and load a real
4213 image into \e buf.
4214
4215 \skipto convertToGLFormat
4216 \printline convertToGLFormat
4217
4218 A few lines later, we convert \e buf into OpenGL format and store it
4219 in \e tex1.
4220
4221 \skipto glTexImage2D
4222 \printline glTexImage2D
4223 \printline tex1.bits
4224
4225 Note the dimension restrictions for texture images as described in
4226 the glTexImage2D() documentation. The width must be 2^m + 2*border
4227 and the height 2^n + 2*border where m and n are integers and
4228 border is either 0 or 1.
4229
4230 Another function in the same example uses \e tex1 with OpenGL.
4231
4232 \endomit
4233*/
4234
4235QImage QGLWidget::convertToGLFormat(const QImage& img)
4236{
4237 QImage res(img.size(), QImage::Format_ARGB32);
4238 convertToGLFormatHelper(res, img.convertToFormat(QImage::Format_ARGB32), GL_RGBA);
4239 return res;
4240}
4241
4242
4243/*!
4244 \fn QGLColormap & QGLWidget::colormap() const
4245
4246 Returns the colormap for this widget.
4247
4248 Usually it is only top-level widgets that can have different
4249 colormaps installed. Asking for the colormap of a child widget
4250 will return the colormap for the child's top-level widget.
4251
4252 If no colormap has been set for this widget, the QGLColormap
4253 returned will be empty.
4254
4255 \sa setColormap(), QGLColormap::isEmpty()
4256*/
4257
4258/*!
4259 \fn void QGLWidget::setColormap(const QGLColormap & cmap)
4260
4261 Set the colormap for this widget to \a cmap. Usually it is only
4262 top-level widgets that can have colormaps installed.
4263
4264 \sa colormap()
4265*/
4266
4267
4268/*!
4269 \obsolete
4270
4271 Returns the value of the first display list that is generated for
4272 the characters in the given \a font. \a listBase indicates the base
4273 value used when generating the display lists for the font. The
4274 default value is 2000.
4275
4276 \note This function is not supported on OpenGL/ES systems.
4277*/
4278int QGLWidget::fontDisplayListBase(const QFont & font, int listBase)
4279{
4280#ifndef QT_OPENGL_ES
4281 Q_D(QGLWidget);
4282 int base;
4283
4284 if (!d->glcx) { // this can't happen unless we run out of mem
4285 return 0;
4286 }
4287
4288 // always regenerate font disp. lists for pixmaps - hw accelerated
4289 // contexts can't handle this otherwise
4290 bool regenerate = d->glcx->deviceIsPixmap();
4291#ifndef QT_NO_FONTCONFIG
4292 // font color needs to be part of the font cache key when using
4293 // antialiased fonts since one set of glyphs needs to be generated
4294 // for each font color
4295 QString color_key;
4296 if (font.styleStrategy() != QFont::NoAntialias) {
4297 GLfloat color[4];
4298 glGetFloatv(GL_CURRENT_COLOR, color);
4299 color_key.sprintf("%f_%f_%f",color[0], color[1], color[2]);
4300 }
4301 QString key = font.key() + color_key + QString::number((int) regenerate);
4302#else
4303 QString key = font.key() + QString::number((int) regenerate);
4304#endif
4305 if (!regenerate && (d->displayListCache.find(key) != d->displayListCache.end())) {
4306 base = d->displayListCache[key];
4307 } else {
4308 int maxBase = listBase - 256;
4309 QMap<QString,int>::ConstIterator it;
4310 for (it = d->displayListCache.constBegin(); it != d->displayListCache.constEnd(); ++it) {
4311 if (maxBase < it.value()) {
4312 maxBase = it.value();
4313 }
4314 }
4315 maxBase += 256;
4316 d->glcx->generateFontDisplayLists(font, maxBase);
4317 d->displayListCache[key] = maxBase;
4318 base = maxBase;
4319 }
4320 return base;
4321#else // QT_OPENGL_ES
4322 Q_UNUSED(font);
4323 Q_UNUSED(listBase);
4324 return 0;
4325#endif
4326}
4327
4328#ifndef QT_OPENGL_ES
4329
4330static void qt_save_gl_state()
4331{
4332 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
4333 glPushAttrib(GL_ALL_ATTRIB_BITS);
4334 glMatrixMode(GL_TEXTURE);
4335 glPushMatrix();
4336 glLoadIdentity();
4337 glMatrixMode(GL_PROJECTION);
4338 glPushMatrix();
4339 glMatrixMode(GL_MODELVIEW);
4340 glPushMatrix();
4341
4342 glShadeModel(GL_FLAT);
4343 glDisable(GL_CULL_FACE);
4344 glDisable(GL_LIGHTING);
4345 glDisable(GL_STENCIL_TEST);
4346 glDisable(GL_DEPTH_TEST);
4347 glEnable(GL_BLEND);
4348 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
4349}
4350
4351static void qt_restore_gl_state()
4352{
4353 glMatrixMode(GL_TEXTURE);
4354 glPopMatrix();
4355 glMatrixMode(GL_PROJECTION);
4356 glPopMatrix();
4357 glMatrixMode(GL_MODELVIEW);
4358 glPopMatrix();
4359 glPopAttrib();
4360 glPopClientAttrib();
4361}
4362
4363static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str,
4364 const QFont &font)
4365{
4366 GLfloat color[4];
4367 glGetFloatv(GL_CURRENT_COLOR, &color[0]);
4368
4369 QColor col;
4370 col.setRgbF(color[0], color[1], color[2],color[3]);
4371 QPen old_pen = p->pen();
4372 QFont old_font = p->font();
4373
4374 p->setPen(col);
4375 p->setFont(font);
4376 p->drawText(x, y, str);
4377
4378 p->setPen(old_pen);
4379 p->setFont(old_font);
4380}
4381
4382#endif // !QT_OPENGL_ES
4383
4384/*!
4385 Renders the string \a str into the GL context of this widget.
4386
4387 \a x and \a y are specified in window coordinates, with the origin
4388 in the upper left-hand corner of the window. If \a font is not
4389 specified, the currently set application font will be used to
4390 render the string. To change the color of the rendered text you can
4391 use the glColor() call (or the qglColor() convenience function),
4392 just before the renderText() call.
4393
4394 The \a listBase parameter is obsolete and will be removed in a
4395 future version of Qt.
4396
4397 \note This function clears the stencil buffer.
4398
4399 \note This function is not supported on OpenGL/ES systems.
4400
4401 \note This function temporarily disables depth-testing when the
4402 text is drawn.
4403
4404 \note This function can only be used inside a
4405 QPainter::beginNativePainting()/QPainter::endNativePainting() block
4406 if the default OpenGL paint engine is QPaintEngine::OpenGL. To make
4407 QPaintEngine::OpenGL the default GL engine, call
4408 QGL::setPreferredPaintEngine(QPaintEngine::OpenGL) before the
4409 QApplication constructor.
4410
4411 \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead.
4412*/
4413
4414void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, int)
4415{
4416#ifndef QT_OPENGL_ES
4417 Q_D(QGLWidget);
4418 if (str.isEmpty() || !isValid())
4419 return;
4420
4421 GLint view[4];
4422 bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST);
4423 if (!use_scissor_testing)
4424 glGetIntegerv(GL_VIEWPORT, &view[0]);
4425 int width = d->glcx->device()->width();
4426 int height = d->glcx->device()->height();
4427 bool auto_swap = autoBufferSwap();
4428
4429 QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine();
4430
4431 QPaintEngine *engine = paintEngine();
4432 if (engine && (oldEngineType == QPaintEngine::OpenGL2) && engine->isActive()) {
4433 qWarning("QGLWidget::renderText(): Calling renderText() while a GL 2 paint engine is"
4434 " active on the same device is not allowed.");
4435 return;
4436 }
4437
4438 // this changes what paintEngine() returns
4439 qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL);
4440 engine = paintEngine();
4441 QPainter *p;
4442 bool reuse_painter = false;
4443 if (engine->isActive()) {
4444 reuse_painter = true;
4445 p = engine->painter();
4446 qt_save_gl_state();
4447
4448 glDisable(GL_DEPTH_TEST);
4449 glViewport(0, 0, width, height);
4450 glMatrixMode(GL_PROJECTION);
4451 glLoadIdentity();
4452 glOrtho(0, width, height, 0, 0, 1);
4453 glMatrixMode(GL_MODELVIEW);
4454
4455 glLoadIdentity();
4456 } else {
4457 setAutoBufferSwap(false);
4458 // disable glClear() as a result of QPainter::begin()
4459 d->disable_clear_on_painter_begin = true;
4460 p = new QPainter(this);
4461 }
4462
4463 QRect viewport(view[0], view[1], view[2], view[3]);
4464 if (!use_scissor_testing && viewport != rect()) {
4465 // if the user hasn't set a scissor box, we set one that
4466 // covers the current viewport
4467 glScissor(view[0], view[1], view[2], view[3]);
4468 glEnable(GL_SCISSOR_TEST);
4469 } else if (use_scissor_testing) {
4470 // use the scissor box set by the user
4471 glEnable(GL_SCISSOR_TEST);
4472 }
4473
4474 qt_gl_draw_text(p, x, y, str, font);
4475
4476 if (reuse_painter) {
4477 qt_restore_gl_state();
4478 } else {
4479 p->end();
4480 delete p;
4481 setAutoBufferSwap(auto_swap);
4482 d->disable_clear_on_painter_begin = false;
4483 }
4484 qgl_engine_selector()->setPreferredPaintEngine(oldEngineType);
4485#else // QT_OPENGL_ES
4486 Q_UNUSED(x);
4487 Q_UNUSED(y);
4488 Q_UNUSED(str);
4489 Q_UNUSED(font);
4490 qWarning("QGLWidget::renderText is not supported under OpenGL/ES");
4491#endif
4492}
4493
4494/*! \overload
4495
4496 \a x, \a y and \a z are specified in scene or object coordinates
4497 relative to the currently set projection and model matrices. This
4498 can be useful if you want to annotate models with text labels and
4499 have the labels move with the model as it is rotated etc.
4500
4501 \note This function is not supported on OpenGL/ES systems.
4502
4503 \note If depth testing is enabled before this function is called,
4504 then the drawn text will be depth-tested against the models that
4505 have already been drawn in the scene. Use \c{glDisable(GL_DEPTH_TEST)}
4506 before calling this function to annotate the models without
4507 depth-testing the text.
4508
4509 \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead.
4510*/
4511void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int)
4512{
4513#ifndef QT_OPENGL_ES
4514 Q_D(QGLWidget);
4515 if (str.isEmpty() || !isValid())
4516 return;
4517
4518 bool auto_swap = autoBufferSwap();
4519
4520 int width = d->glcx->device()->width();
4521 int height = d->glcx->device()->height();
4522 GLdouble model[4][4], proj[4][4];
4523 GLint view[4];
4524 glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
4525 glGetDoublev(GL_PROJECTION_MATRIX, &proj[0][0]);
4526 glGetIntegerv(GL_VIEWPORT, &view[0]);
4527 GLdouble win_x = 0, win_y = 0, win_z = 0;
4528 qgluProject(x, y, z, &model[0][0], &proj[0][0], &view[0],
4529 &win_x, &win_y, &win_z);
4530 win_y = height - win_y; // y is inverted
4531
4532 QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine();
4533 QPaintEngine *engine = paintEngine();
4534
4535 if (engine && (oldEngineType == QPaintEngine::OpenGL2) && engine->isActive()) {
4536 qWarning("QGLWidget::renderText(): Calling renderText() while a GL 2 paint engine is"
4537 " active on the same device is not allowed.");
4538 return;
4539 }
4540
4541 // this changes what paintEngine() returns
4542 qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL);
4543 engine = paintEngine();
4544 QPainter *p;
4545 bool reuse_painter = false;
4546 bool use_depth_testing = glIsEnabled(GL_DEPTH_TEST);
4547 bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST);
4548
4549 if (engine->isActive()) {
4550 reuse_painter = true;
4551 p = engine->painter();
4552 qt_save_gl_state();
4553 } else {
4554 setAutoBufferSwap(false);
4555 // disable glClear() as a result of QPainter::begin()
4556 d->disable_clear_on_painter_begin = true;
4557 p = new QPainter(this);
4558 }
4559
4560 QRect viewport(view[0], view[1], view[2], view[3]);
4561 if (!use_scissor_testing && viewport != rect()) {
4562 glScissor(view[0], view[1], view[2], view[3]);
4563 glEnable(GL_SCISSOR_TEST);
4564 } else if (use_scissor_testing) {
4565 glEnable(GL_SCISSOR_TEST);
4566 }
4567 glMatrixMode(GL_PROJECTION);
4568 glLoadIdentity();
4569 glViewport(0, 0, width, height);
4570 glOrtho(0, width, height, 0, 0, 1);
4571 glMatrixMode(GL_MODELVIEW);
4572 glLoadIdentity();
4573 glAlphaFunc(GL_GREATER, 0.0);
4574 glEnable(GL_ALPHA_TEST);
4575 if (use_depth_testing)
4576 glEnable(GL_DEPTH_TEST);
4577 glTranslated(0, 0, -win_z);
4578 qt_gl_draw_text(p, qRound(win_x), qRound(win_y), str, font);
4579
4580 if (reuse_painter) {
4581 qt_restore_gl_state();
4582 } else {
4583 p->end();
4584 delete p;
4585 setAutoBufferSwap(auto_swap);
4586 d->disable_clear_on_painter_begin = false;
4587 }
4588 qgl_engine_selector()->setPreferredPaintEngine(oldEngineType);
4589#else // QT_OPENGL_ES
4590 Q_UNUSED(x);
4591 Q_UNUSED(y);
4592 Q_UNUSED(z);
4593 Q_UNUSED(str);
4594 Q_UNUSED(font);
4595 qWarning("QGLWidget::renderText is not supported under OpenGL/ES");
4596#endif
4597}
4598
4599QGLFormat QGLWidget::format() const
4600{
4601 Q_D(const QGLWidget);
4602 return d->glcx->format();
4603}
4604
4605const QGLContext *QGLWidget::context() const
4606{
4607 Q_D(const QGLWidget);
4608 return d->glcx;
4609}
4610
4611bool QGLWidget::doubleBuffer() const
4612{
4613 Q_D(const QGLWidget);
4614 return d->glcx->d_ptr->glFormat.testOption(QGL::DoubleBuffer);
4615}
4616
4617void QGLWidget::setAutoBufferSwap(bool on)
4618{
4619 Q_D(QGLWidget);
4620 d->autoSwap = on;
4621}
4622
4623bool QGLWidget::autoBufferSwap() const
4624{
4625 Q_D(const QGLWidget);
4626 return d->autoSwap;
4627}
4628
4629/*!
4630 Calls QGLContext:::bindTexture(\a image, \a target, \a format) on the currently
4631 set context.
4632
4633 \sa deleteTexture()
4634*/
4635GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format)
4636{
4637 if (image.isNull())
4638 return 0;
4639
4640 Q_D(QGLWidget);
4641 return d->glcx->bindTexture(image, target, format, QGLContext::DefaultBindOption);
4642}
4643
4644/*!
4645 \overload
4646 \since 4.6
4647
4648 The binding \a options are a set of options used to decide how to
4649 bind the texture to the context.
4650 */
4651GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options)
4652{
4653 if (image.isNull())
4654 return 0;
4655
4656 Q_D(QGLWidget);
4657 return d->glcx->bindTexture(image, target, format, options);
4658}
4659
4660
4661#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
4662/*! \internal */
4663GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
4664{
4665 if (image.isNull())
4666 return 0;
4667
4668 Q_D(QGLWidget);
4669 return d->glcx->bindTexture(image, GLenum(target), GLint(format), QGLContext::DefaultBindOption);
4670}
4671
4672GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format,
4673 QGLContext::BindOptions options)
4674{
4675 if (image.isNull())
4676 return 0;
4677
4678 Q_D(QGLWidget);
4679 return d->glcx->bindTexture(image, GLenum(target), GLint(format), options);
4680}
4681#endif
4682
4683/*!
4684 Calls QGLContext:::bindTexture(\a pixmap, \a target, \a format) on the currently
4685 set context.
4686
4687 \sa deleteTexture()
4688*/
4689GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
4690{
4691 if (pixmap.isNull())
4692 return 0;
4693
4694 Q_D(QGLWidget);
4695 return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption);
4696}
4697
4698/*!
4699 \overload
4700 \since 4.6
4701
4702 Generates and binds a 2D GL texture to the current context, based
4703 on \a pixmap. The generated texture id is returned and can be used in
4704
4705 The binding \a options are a set of options used to decide how to
4706 bind the texture to the context.
4707 */
4708GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
4709 QGLContext::BindOptions options)
4710{
4711 Q_D(QGLWidget);
4712 return d->glcx->bindTexture(pixmap, target, format, options);
4713}
4714
4715#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
4716/*! \internal */
4717GLuint QGLWidget::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format)
4718{
4719 Q_D(QGLWidget);
4720 return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption);
4721}
4722
4723GLuint QGLWidget::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format,
4724 QGLContext::BindOptions options)
4725{
4726 Q_D(QGLWidget);
4727 return d->glcx->bindTexture(pixmap, target, format, options);
4728}
4729#endif
4730
4731
4732/*! \overload
4733
4734 Calls QGLContext::bindTexture(\a fileName) on the currently set context.
4735
4736 \sa deleteTexture()
4737*/
4738GLuint QGLWidget::bindTexture(const QString &fileName)
4739{
4740 Q_D(QGLWidget);
4741 return d->glcx->bindTexture(fileName);
4742}
4743
4744/*!
4745 Calls QGLContext::deleteTexture(\a id) on the currently set
4746 context.
4747
4748 \sa bindTexture()
4749*/
4750void QGLWidget::deleteTexture(GLuint id)
4751{
4752 Q_D(QGLWidget);
4753 d->glcx->deleteTexture(id);
4754}
4755
4756#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
4757/*! \internal */
4758void QGLWidget::deleteTexture(QMacCompatGLuint id)
4759{
4760 Q_D(QGLWidget);
4761 d->glcx->deleteTexture(GLuint(id));
4762}
4763#endif
4764
4765/*!
4766 \since 4.4
4767
4768 Draws the given texture, \a textureId to the given target rectangle,
4769 \a target, in OpenGL model space. The \a textureTarget should be a 2D
4770 texture target.
4771
4772 Equivalent to the corresponding QGLContext::drawTexture().
4773*/
4774void QGLWidget::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
4775{
4776 Q_D(QGLWidget);
4777 d->glcx->drawTexture(target, textureId, textureTarget);
4778}
4779
4780#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
4781/*! \internal */
4782void QGLWidget::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
4783{
4784 Q_D(QGLWidget);
4785 d->glcx->drawTexture(target, GLint(textureId), GLenum(textureTarget));
4786}
4787#endif
4788
4789/*!
4790 \since 4.4
4791
4792 Draws the given texture, \a textureId, at the given \a point in OpenGL
4793 model space. The \a textureTarget should be a 2D texture target.
4794
4795 Equivalent to the corresponding QGLContext::drawTexture().
4796*/
4797void QGLWidget::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
4798{
4799 Q_D(QGLWidget);
4800 d->glcx->drawTexture(point, textureId, textureTarget);
4801}
4802
4803#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
4804/*! \internal */
4805void QGLWidget::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
4806{
4807 Q_D(QGLWidget);
4808 d->glcx->drawTexture(point, GLuint(textureId), GLenum(textureTarget));
4809}
4810#endif
4811
4812#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
4813Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_2_engine)
4814#endif
4815
4816#ifndef QT_OPENGL_ES_2
4817Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_engine)
4818#endif
4819
4820Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine()
4821{
4822#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL)
4823 return qt_gl_engine();
4824#elif defined(QT_OPENGL_ES_2)
4825 return qt_gl_2_engine();
4826#else
4827 if (qt_gl_preferGL2Engine())
4828 return qt_gl_2_engine();
4829 else
4830 return qt_gl_engine();
4831#endif
4832}
4833
4834/*!
4835 \internal
4836
4837 Returns the GL widget's paint engine. This is normally a
4838 QOpenGLPaintEngine.
4839*/
4840QPaintEngine *QGLWidget::paintEngine() const
4841{
4842 return qt_qgl_paint_engine();
4843}
4844
4845#ifdef QT3_SUPPORT
4846/*!
4847 \overload
4848 \obsolete
4849 */
4850QGLWidget::QGLWidget(QWidget *parent, const char *name,
4851 const QGLWidget* shareWidget, Qt::WindowFlags f)
4852 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
4853{
4854 Q_D(QGLWidget);
4855 if (name)
4856 setObjectName(QString::fromAscii(name));
4857 setAttribute(Qt::WA_PaintOnScreen);
4858 setAttribute(Qt::WA_NoSystemBackground);
4859 setAutoFillBackground(true); // for compatibility
4860 d->init(new QGLContext(QGLFormat::defaultFormat(), this), shareWidget);
4861}
4862
4863/*!
4864 \overload
4865 \obsolete
4866 */
4867QGLWidget::QGLWidget(const QGLFormat &format, QWidget *parent,
4868 const char *name, const QGLWidget* shareWidget,
4869 Qt::WindowFlags f)
4870 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
4871{
4872 Q_D(QGLWidget);
4873 if (name)
4874 setObjectName(QString::fromAscii(name));
4875 setAttribute(Qt::WA_PaintOnScreen);
4876 setAttribute(Qt::WA_NoSystemBackground);
4877 setAutoFillBackground(true); // for compatibility
4878 d->init(new QGLContext(format, this), shareWidget);
4879}
4880
4881/*!
4882 \overload
4883 \obsolete
4884 */
4885QGLWidget::QGLWidget(QGLContext *context, QWidget *parent,
4886 const char *name, const QGLWidget *shareWidget, Qt::WindowFlags f)
4887 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
4888{
4889 Q_D(QGLWidget);
4890 if (name)
4891 setObjectName(QString::fromAscii(name));
4892 setAttribute(Qt::WA_PaintOnScreen);
4893 setAttribute(Qt::WA_NoSystemBackground);
4894 setAutoFillBackground(true); // for compatibility
4895 d->init(context, shareWidget);
4896}
4897
4898#endif // QT3_SUPPORT
4899
4900/*
4901 Returns the GL extensions for the current context.
4902*/
4903QGLExtensions::Extensions QGLExtensions::currentContextExtensions()
4904{
4905 QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
4906 Extensions glExtensions;
4907
4908 if (extensions.match("GL_ARB_texture_rectangle"))
4909 glExtensions |= TextureRectangle;
4910 if (extensions.match("GL_ARB_multisample"))
4911 glExtensions |= SampleBuffers;
4912 if (extensions.match("GL_SGIS_generate_mipmap"))
4913 glExtensions |= GenerateMipmap;
4914 if (extensions.match("GL_ARB_texture_compression"))
4915 glExtensions |= TextureCompression;
4916 if (extensions.match("GL_EXT_texture_compression_s3tc"))
4917 glExtensions |= DDSTextureCompression;
4918 if (extensions.match("GL_OES_compressed_ETC1_RGB8_texture"))
4919 glExtensions |= ETC1TextureCompression;
4920 if (extensions.match("GL_IMG_texture_compression_pvrtc"))
4921 glExtensions |= PVRTCTextureCompression;
4922 if (extensions.match("GL_ARB_fragment_program"))
4923 glExtensions |= FragmentProgram;
4924 if (extensions.match("GL_ARB_fragment_shader"))
4925 glExtensions |= FragmentShader;
4926 if (extensions.match("GL_ARB_texture_mirrored_repeat"))
4927 glExtensions |= MirroredRepeat;
4928 if (extensions.match("GL_EXT_framebuffer_object"))
4929 glExtensions |= FramebufferObject;
4930 if (extensions.match("GL_EXT_stencil_two_side"))
4931 glExtensions |= StencilTwoSide;
4932 if (extensions.match("GL_EXT_stencil_wrap"))
4933 glExtensions |= StencilWrap;
4934 if (extensions.match("GL_EXT_packed_depth_stencil"))
4935 glExtensions |= PackedDepthStencil;
4936 if (extensions.match("GL_NV_float_buffer"))
4937 glExtensions |= NVFloatBuffer;
4938 if (extensions.match("GL_ARB_pixel_buffer_object"))
4939 glExtensions |= PixelBufferObject;
4940#if defined(QT_OPENGL_ES_2)
4941 glExtensions |= FramebufferObject;
4942 glExtensions |= GenerateMipmap;
4943 glExtensions |= FragmentShader;
4944#endif
4945#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL)
4946 if (extensions.match("GL_OES_framebuffer_object"))
4947 glExtensions |= FramebufferObject;
4948#endif
4949#if defined(QT_OPENGL_ES)
4950 if (extensions.match("GL_OES_packed_depth_stencil"))
4951 glExtensions |= PackedDepthStencil;
4952#endif
4953 if (extensions.match("GL_ARB_framebuffer_object")) {
4954 // ARB_framebuffer_object also includes EXT_framebuffer_blit.
4955 glExtensions |= FramebufferObject;
4956 glExtensions |= FramebufferBlit;
4957 }
4958
4959 if (extensions.match("GL_EXT_framebuffer_blit"))
4960 glExtensions |= FramebufferBlit;
4961
4962 if (extensions.match("GL_ARB_texture_non_power_of_two"))
4963 glExtensions |= NPOTTextures;
4964
4965 if (extensions.match("GL_EXT_bgra"))
4966 glExtensions |= BGRATextureFormat;
4967
4968 return glExtensions;
4969}
4970
4971/*
4972 Returns the GL extensions for the current QGLContext. If there is no
4973 current QGLContext, a default context will be created and the extensions
4974 for that context will be returned instead.
4975*/
4976QGLExtensions::Extensions QGLExtensions::glExtensions()
4977{
4978 QGLTemporaryContext *tmpContext = 0;
4979 static bool cachedDefault = false;
4980 static Extensions defaultExtensions = 0;
4981 QGLContext *currentCtx = const_cast<QGLContext *>(QGLContext::currentContext());
4982
4983 if (currentCtx && currentCtx->d_func()->extension_flags_cached)
4984 return currentCtx->d_func()->extension_flags;
4985
4986 if (!currentCtx) {
4987 if (cachedDefault) {
4988 return defaultExtensions;
4989 } else {
4990 tmpContext = new QGLTemporaryContext;
4991 cachedDefault = true;
4992 }
4993 }
4994
4995 Extensions extensionFlags = currentContextExtensions();
4996 if (currentCtx) {
4997 currentCtx->d_func()->extension_flags_cached = true;
4998 currentCtx->d_func()->extension_flags = extensionFlags;
4999 } else {
5000 defaultExtensions = extensionFlags;
5001 }
5002
5003 if (tmpContext)
5004 delete tmpContext;
5005
5006 return extensionFlags;
5007}
5008
5009/*
5010 This is the shared initialization for all platforms. Called from QGLWidgetPrivate::init()
5011*/
5012void QGLWidgetPrivate::initContext(QGLContext *context, const QGLWidget* shareWidget)
5013{
5014 Q_Q(QGLWidget);
5015
5016 glDevice.setWidget(q);
5017
5018 glcx = 0;
5019 autoSwap = true;
5020
5021 if (context && !context->device())
5022 context->setDevice(q);
5023 q->setContext(context, shareWidget ? shareWidget->context() : 0);
5024
5025 if (!glcx)
5026 glcx = new QGLContext(QGLFormat::defaultFormat(), q);
5027}
5028
5029#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
5030Q_GLOBAL_STATIC(QString, qt_gl_lib_name)
5031
5032Q_OPENGL_EXPORT void qt_set_gl_library_name(const QString& name)
5033{
5034 qt_gl_lib_name()->operator=(name);
5035}
5036
5037Q_OPENGL_EXPORT const QString qt_gl_library_name()
5038{
5039 if (qt_gl_lib_name()->isNull()) {
5040#if defined(Q_WS_X11) || defined(Q_WS_QWS)
5041 return QLatin1String("GL");
5042#else // Q_WS_MAC
5043 return QLatin1String("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib");
5044#endif
5045 }
5046 return *qt_gl_lib_name();
5047}
5048#endif
5049
5050void QGLContextGroup::addShare(const QGLContext *context, const QGLContext *share) {
5051 Q_ASSERT(context && share);
5052 if (context->d_ptr->group == share->d_ptr->group)
5053 return;
5054
5055 // Make sure 'context' is not already shared with another group of contexts.
5056 Q_ASSERT(context->d_ptr->group->m_refs == 1);
5057
5058 // Free 'context' group resources and make it use the same resources as 'share'.
5059 QGLContextGroup *group = share->d_ptr->group;
5060 delete context->d_ptr->group;
5061 context->d_ptr->group = group;
5062 group->m_refs.ref();
5063
5064 // Maintain a list of all the contexts in each group of sharing contexts.
5065 // The list is empty if the "share" context wasn't sharing already.
5066 if (group->m_shares.isEmpty())
5067 group->m_shares.append(share);
5068 group->m_shares.append(context);
5069}
5070
5071void QGLContextGroup::removeShare(const QGLContext *context) {
5072 // Remove the context from the group.
5073 QGLContextGroup *group = context->d_ptr->group;
5074 if (group->m_shares.isEmpty())
5075 return;
5076 group->m_shares.removeAll(context);
5077
5078 // Update context group representative.
5079 Q_ASSERT(group->m_shares.size() != 0);
5080 if (group->m_context == context)
5081 group->m_context = group->m_shares[0];
5082
5083 // If there is only one context left, then make the list empty.
5084 if (group->m_shares.size() == 1)
5085 group->m_shares.clear();
5086}
5087
5088QGLContextResource::QGLContextResource(FreeFunc f)
5089 : free(f), active(0)
5090{
5091}
5092
5093QGLContextResource::~QGLContextResource()
5094{
5095#ifndef QT_NO_DEBUG
5096 if (active != 0) {
5097 qWarning("QtOpenGL: Resources are still available at program shutdown.\n"
5098 " This is possibly caused by a leaked QGLWidget, \n"
5099 " QGLFramebufferObject or QGLPixelBuffer.");
5100 }
5101#endif
5102}
5103
5104void QGLContextResource::insert(const QGLContext *key, void *value)
5105{
5106 QGLContextGroup *group = QGLContextPrivate::contextGroup(key);
5107 Q_ASSERT(!group->m_resources.contains(this));
5108 group->m_resources.insert(this, value);
5109 active.ref();
5110}
5111
5112void *QGLContextResource::value(const QGLContext *key)
5113{
5114 QGLContextGroup *group = QGLContextPrivate::contextGroup(key);
5115 return group->m_resources.value(this, 0);
5116}
5117
5118void QGLContextResource::cleanup(const QGLContext *ctx, void *value)
5119{
5120 QGLShareContextScope scope(ctx);
5121 free(value);
5122 active.deref();
5123}
5124
5125void QGLContextGroup::cleanupResources(const QGLContext *ctx)
5126{
5127 // If there are still shares, then no cleanup to be done yet.
5128 if (m_shares.size() > 1)
5129 return;
5130
5131 // Iterate over all resources and free each in turn.
5132 QHash<QGLContextResource *, void *>::ConstIterator it;
5133 for (it = m_resources.begin(); it != m_resources.end(); ++it)
5134 it.key()->cleanup(ctx, it.value());
5135}
5136
5137QGLSharedResourceGuard::~QGLSharedResourceGuard()
5138{
5139 if (m_group)
5140 m_group->removeGuard(this);
5141}
5142
5143void QGLSharedResourceGuard::setContext(const QGLContext *context)
5144{
5145 if (m_group)
5146 m_group->removeGuard(this);
5147 if (context) {
5148 m_group = QGLContextPrivate::contextGroup(context);
5149 m_group->addGuard(this);
5150 } else {
5151 m_group = 0;
5152 }
5153}
5154
5155QSize QGLTexture::bindCompressedTexture
5156 (const QString& fileName, const char *format)
5157{
5158 QFile file(fileName);
5159 if (!file.open(QIODevice::ReadOnly))
5160 return QSize();
5161 QByteArray contents = file.readAll();
5162 file.close();
5163 return bindCompressedTexture
5164 (contents.constData(), contents.size(), format);
5165}
5166
5167// PVR header format for container files that store textures compressed
5168// with the ETC1, PVRTC2, and PVRTC4 encodings. Format information from the
5169// PowerVR SDK at http://www.imgtec.com/powervr/insider/powervr-sdk.asp
5170// "PVRTexTool Reference Manual, version 1.11f".
5171struct PvrHeader
5172{
5173 quint32 headerSize;
5174 quint32 height;
5175 quint32 width;
5176 quint32 mipMapCount;
5177 quint32 flags;
5178 quint32 dataSize;
5179 quint32 bitsPerPixel;
5180 quint32 redMask;
5181 quint32 greenMask;
5182 quint32 blueMask;
5183 quint32 alphaMask;
5184 quint32 magic;
5185 quint32 surfaceCount;
5186};
5187
5188#define PVR_MAGIC 0x21525650 // "PVR!" in little-endian
5189
5190#define PVR_FORMAT_MASK 0x000000FF
5191#define PVR_FORMAT_PVRTC2 0x00000018
5192#define PVR_FORMAT_PVRTC4 0x00000019
5193#define PVR_FORMAT_ETC1 0x00000036
5194
5195#define PVR_HAS_MIPMAPS 0x00000100
5196#define PVR_TWIDDLED 0x00000200
5197#define PVR_NORMAL_MAP 0x00000400
5198#define PVR_BORDER_ADDED 0x00000800
5199#define PVR_CUBE_MAP 0x00001000
5200#define PVR_FALSE_COLOR_MIPMAPS 0x00002000
5201#define PVR_VOLUME_TEXTURE 0x00004000
5202#define PVR_ALPHA_IN_TEXTURE 0x00008000
5203#define PVR_VERTICAL_FLIP 0x00010000
5204
5205#ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
5206#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
5207#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
5208#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
5209#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
5210#endif
5211
5212#ifndef GL_ETC1_RGB8_OES
5213#define GL_ETC1_RGB8_OES 0x8D64
5214#endif
5215
5216bool QGLTexture::canBindCompressedTexture
5217 (const char *buf, int len, const char *format, bool *hasAlpha)
5218{
5219 if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) {
5220 // Compressed texture loading only supported on little-endian
5221 // systems such as x86 and ARM at the moment.
5222 return false;
5223 }
5224 if (!format) {
5225 // Auto-detect the format from the header.
5226 if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) {
5227 *hasAlpha = true;
5228 return true;
5229 } else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) {
5230 const PvrHeader *pvrHeader =
5231 reinterpret_cast<const PvrHeader *>(buf);
5232 *hasAlpha = (pvrHeader->alphaMask != 0);
5233 return true;
5234 }
5235 } else {
5236 // Validate the format against the header.
5237 if (!qstricmp(format, "DDS")) {
5238 if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) {
5239 *hasAlpha = true;
5240 return true;
5241 }
5242 } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) {
5243 if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) {
5244 const PvrHeader *pvrHeader =
5245 reinterpret_cast<const PvrHeader *>(buf);
5246 *hasAlpha = (pvrHeader->alphaMask != 0);
5247 return true;
5248 }
5249 }
5250 }
5251 return false;
5252}
5253
5254#define ctx QGLContext::currentContext()
5255
5256QSize QGLTexture::bindCompressedTexture
5257 (const char *buf, int len, const char *format)
5258{
5259 if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) {
5260 // Compressed texture loading only supported on little-endian
5261 // systems such as x86 and ARM at the moment.
5262 return QSize();
5263 }
5264#if !defined(QT_OPENGL_ES)
5265 if (!glCompressedTexImage2D) {
5266 if (!(QGLExtensions::glExtensions() & QGLExtensions::TextureCompression)) {
5267 qWarning("QGLContext::bindTexture(): The GL implementation does "
5268 "not support texture compression extensions.");
5269 return QSize();
5270 }
5271 glCompressedTexImage2D = (_glCompressedTexImage2DARB) ctx->getProcAddress(QLatin1String("glCompressedTexImage2DARB"));
5272 if (!glCompressedTexImage2D) {
5273 qWarning("QGLContext::bindTexture(): could not resolve "
5274 "glCompressedTexImage2DARB.");
5275 return QSize();
5276 }
5277 }
5278#endif
5279 if (!format) {
5280 // Auto-detect the format from the header.
5281 if (len >= 4 && !qstrncmp(buf, "DDS ", 4))
5282 return bindCompressedTextureDDS(buf, len);
5283 else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4))
5284 return bindCompressedTexturePVR(buf, len);
5285 } else {
5286 // Validate the format against the header.
5287 if (!qstricmp(format, "DDS")) {
5288 if (len >= 4 && !qstrncmp(buf, "DDS ", 4))
5289 return bindCompressedTextureDDS(buf, len);
5290 } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) {
5291 if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4))
5292 return bindCompressedTexturePVR(buf, len);
5293 }
5294 }
5295 return QSize();
5296}
5297
5298QSize QGLTexture::bindCompressedTextureDDS(const char *buf, int len)
5299{
5300 // We only support 2D texture loading at present.
5301 if (target != GL_TEXTURE_2D)
5302 return QSize();
5303
5304 // Bail out if the necessary extension is not present.
5305 if (!(QGLExtensions::glExtensions() & QGLExtensions::DDSTextureCompression)) {
5306 qWarning("QGLContext::bindTexture(): DDS texture compression is not supported.");
5307 return QSize();
5308 }
5309
5310 const DDSFormat *ddsHeader = reinterpret_cast<const DDSFormat *>(buf + 4);
5311 if (!ddsHeader->dwLinearSize) {
5312 qWarning("QGLContext::bindTexture(): DDS image size is not valid.");
5313 return QSize();
5314 }
5315
5316 int blockSize = 16;
5317 GLenum format;
5318
5319 switch(ddsHeader->ddsPixelFormat.dwFourCC) {
5320 case FOURCC_DXT1:
5321 format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
5322 blockSize = 8;
5323 break;
5324 case FOURCC_DXT3:
5325 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
5326 break;
5327 case FOURCC_DXT5:
5328 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
5329 break;
5330 default:
5331 qWarning("QGLContext::bindTexture(): DDS image format not supported.");
5332 return QSize();
5333 }
5334
5335 const GLubyte *pixels =
5336 reinterpret_cast<const GLubyte *>(buf + ddsHeader->dwSize + 4);
5337
5338 glGenTextures(1, &id);
5339 glBindTexture(GL_TEXTURE_2D, id);
5340 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5341 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5342
5343 int size;
5344 int offset = 0;
5345 int available = len - int(ddsHeader->dwSize + 4);
5346 int w = ddsHeader->dwWidth;
5347 int h = ddsHeader->dwHeight;
5348
5349 // load mip-maps
5350 for(int i = 0; i < (int) ddsHeader->dwMipMapCount; ++i) {
5351 if (w == 0) w = 1;
5352 if (h == 0) h = 1;
5353
5354 size = ((w+3)/4) * ((h+3)/4) * blockSize;
5355 if (size > available)
5356 break;
5357 glCompressedTexImage2D(GL_TEXTURE_2D, i, format, w, h, 0,
5358 size, pixels + offset);
5359 offset += size;
5360 available -= size;
5361
5362 // half size for each mip-map level
5363 w = w/2;
5364 h = h/2;
5365 }
5366
5367 // DDS images are not inverted.
5368 options &= ~QGLContext::InvertedYBindOption;
5369
5370 return QSize(ddsHeader->dwWidth, ddsHeader->dwHeight);
5371}
5372
5373QSize QGLTexture::bindCompressedTexturePVR(const char *buf, int len)
5374{
5375 // We only support 2D texture loading at present. Cube maps later.
5376 if (target != GL_TEXTURE_2D)
5377 return QSize();
5378
5379 // Determine which texture format we will be loading.
5380 const PvrHeader *pvrHeader = reinterpret_cast<const PvrHeader *>(buf);
5381 GLenum textureFormat;
5382 quint32 minWidth, minHeight;
5383 switch (pvrHeader->flags & PVR_FORMAT_MASK) {
5384 case PVR_FORMAT_PVRTC2:
5385 if (pvrHeader->alphaMask)
5386 textureFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
5387 else
5388 textureFormat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
5389 minWidth = 16;
5390 minHeight = 8;
5391 break;
5392
5393 case PVR_FORMAT_PVRTC4:
5394 if (pvrHeader->alphaMask)
5395 textureFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
5396 else
5397 textureFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
5398 minWidth = 8;
5399 minHeight = 8;
5400 break;
5401
5402 case PVR_FORMAT_ETC1:
5403 textureFormat = GL_ETC1_RGB8_OES;
5404 minWidth = 4;
5405 minHeight = 4;
5406 break;
5407
5408 default:
5409 qWarning("QGLContext::bindTexture(): PVR image format 0x%x not supported.", int(pvrHeader->flags & PVR_FORMAT_MASK));
5410 return QSize();
5411 }
5412
5413 // Bail out if the necessary extension is not present.
5414 if (textureFormat == GL_ETC1_RGB8_OES) {
5415 if (!(QGLExtensions::glExtensions() &
5416 QGLExtensions::ETC1TextureCompression)) {
5417 qWarning("QGLContext::bindTexture(): ETC1 texture compression is not supported.");
5418 return QSize();
5419 }
5420 } else {
5421 if (!(QGLExtensions::glExtensions() &
5422 QGLExtensions::PVRTCTextureCompression)) {
5423 qWarning("QGLContext::bindTexture(): PVRTC texture compression is not supported.");
5424 return QSize();
5425 }
5426 }
5427
5428 // Boundary check on the buffer size.
5429 quint32 bufferSize = pvrHeader->headerSize + pvrHeader->dataSize;
5430 if (bufferSize > quint32(len)) {
5431 qWarning("QGLContext::bindTexture(): PVR image size is not valid.");
5432 return QSize();
5433 }
5434
5435 // Create the texture.
5436 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
5437 glGenTextures(1, &id);
5438 glBindTexture(GL_TEXTURE_2D, id);
5439 if (pvrHeader->mipMapCount) {
5440 if ((options & QGLContext::LinearFilteringBindOption) != 0) {
5441 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5442 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
5443 } else {
5444 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5445 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
5446 }
5447 } else if ((options & QGLContext::LinearFilteringBindOption) != 0) {
5448 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5449 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5450 } else {
5451 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5452 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5453 }
5454
5455 // Load the compressed mipmap levels.
5456 const GLubyte *buffer =
5457 reinterpret_cast<const GLubyte *>(buf + pvrHeader->headerSize);
5458 bufferSize = pvrHeader->dataSize;
5459 quint32 level = 0;
5460 quint32 width = pvrHeader->width;
5461 quint32 height = pvrHeader->height;
5462 while (bufferSize > 0 && level <= pvrHeader->mipMapCount) {
5463 quint32 size =
5464 (qMax(width, minWidth) * qMax(height, minHeight) *
5465 pvrHeader->bitsPerPixel) / 8;
5466 if (size > bufferSize)
5467 break;
5468 glCompressedTexImage2D(GL_TEXTURE_2D, GLint(level), textureFormat,
5469 GLsizei(width), GLsizei(height), 0,
5470 GLsizei(size), buffer);
5471 width /= 2;
5472 height /= 2;
5473 buffer += size;
5474 ++level;
5475 }
5476
5477 // Restore the default pixel alignment for later texture uploads.
5478 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
5479
5480 // Set the invert flag for the texture. The "vertical flip"
5481 // flag in PVR is the opposite sense to our sense of inversion.
5482 if ((pvrHeader->flags & PVR_VERTICAL_FLIP) != 0)
5483 options &= ~QGLContext::InvertedYBindOption;
5484 else
5485 options |= QGLContext::InvertedYBindOption;
5486
5487 return QSize(pvrHeader->width, pvrHeader->height);
5488}
5489
5490#undef ctx
5491
5492QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.