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

Last change on this file since 147 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 121.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtOpenGL module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
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 <stdlib.h> // malloc
63
64#include "qpixmap.h"
65#include "qimage.h"
66#include "qgl_p.h"
67
68#if defined(QT_OPENGL_ES_2)
69#include "gl2paintengineex/qpaintengineex_opengl2_p.h"
70#else
71#include <private/qpaintengine_opengl_p.h>
72#endif
73
74#include <private/qimage_p.h>
75#include <private/qpixmapdata_p.h>
76#include <private/qpixmapdata_gl_p.h>
77#include "qcolormap.h"
78#include "qcache.h"
79#include "qfile.h"
80#include "qlibrary.h"
81
82
83QT_BEGIN_NAMESPACE
84
85#ifdef QT_OPENGL_ES_1_CL
86#include "qgl_cl_p.h"
87#endif
88
89
90#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
91QGLExtensionFuncs QGLContextPrivate::qt_extensionFuncs;
92#endif
93
94QThreadStorage<QGLThreadContext *> qgl_context_storage;
95
96Q_GLOBAL_STATIC(QGLFormat, qgl_default_format)
97
98class QGLDefaultOverlayFormat: public QGLFormat
99{
100public:
101 inline QGLDefaultOverlayFormat()
102 {
103 setOption(QGL::FormatOption(0xffff << 16)); // turn off all options
104 setOption(QGL::DirectRendering);
105 setPlane(1);
106 }
107};
108Q_GLOBAL_STATIC(QGLDefaultOverlayFormat, defaultOverlayFormatInstance)
109
110QGLExtensions::Extensions QGLExtensions::glExtensions = 0;
111bool QGLExtensions::nvidiaFboNeedsFinish = false;
112
113#ifndef APIENTRY
114# define APIENTRY
115#endif
116typedef void (APIENTRY *pfn_glCompressedTexImage2DARB) (GLenum, GLint, GLenum, GLsizei,
117 GLsizei, GLint, GLsizei, const GLvoid *);
118static pfn_glCompressedTexImage2DARB qt_glCompressedTexImage2DARB = 0;
119
120
121#ifndef APIENTRY
122#define APIENTRY
123#endif
124
125Q_GLOBAL_STATIC(QGLSignalProxy, theSignalProxy)
126QGLSignalProxy *QGLSignalProxy::instance()
127{
128 return theSignalProxy();
129}
130
131/*!
132 \namespace QGL
133
134 \brief The QGL namespace specifies miscellaneous identifiers used
135 in the Qt OpenGL module.
136
137 \ingroup multimedia
138*/
139
140/*!
141 \enum QGL::FormatOption
142
143 This enum specifies the format options that can be used to configure an OpenGL
144 context. These are set using QGLFormat::setOption().
145
146 \value DoubleBuffer Specifies the use of double buffering.
147 \value DepthBuffer Enables the use of a depth buffer.
148 \value Rgba Specifies that the context should use RGBA as its pixel format.
149 \value AlphaChannel Enables the use of an alpha channel.
150 \value AccumBuffer Enables the use of an accumulation buffer.
151 \value StencilBuffer Enables the use of a stencil buffer.
152 \value StereoBuffers Enables the use of a stereo buffers for use with visualization hardware.
153 \value DirectRendering Specifies that the context is used for direct rendering to a display.
154 \value HasOverlay Enables the use of an overlay.
155 \value SampleBuffers Enables the use of sample buffers.
156 \value SingleBuffer Specifies the use of a single buffer, as opposed to double buffers.
157 \value NoDepthBuffer Disables the use of a depth buffer.
158 \value ColorIndex Specifies that the context should use a color index as its pixel format.
159 \value NoAlphaChannel Disables the use of an alpha channel.
160 \value NoAccumBuffer Disables the use of an accumulation buffer.
161 \value NoStencilBuffer Disables the use of a stencil buffer.
162 \value NoStereoBuffers Disables the use of stereo buffers.
163 \value IndirectRendering Specifies that the context is used for indirect rendering to a buffer.
164 \value NoOverlay Disables the use of an overlay.
165 \value NoSampleBuffers Disables the use of sample buffers.
166
167 \sa {Sample Buffers Example}
168*/
169
170/*****************************************************************************
171 QGLFormat implementation
172 *****************************************************************************/
173
174
175/*!
176 \class QGLFormat
177 \brief The QGLFormat class specifies the display format of an OpenGL
178 rendering context.
179
180 \ingroup multimedia
181
182 A display format has several characteristics:
183 \list
184 \i \link setDoubleBuffer() Double or single buffering.\endlink
185 \i \link setDepth() Depth buffer.\endlink
186 \i \link setRgba() RGBA or color index mode.\endlink
187 \i \link setAlpha() Alpha channel.\endlink
188 \i \link setAccum() Accumulation buffer.\endlink
189 \i \link setStencil() Stencil buffer.\endlink
190 \i \link setStereo() Stereo buffers.\endlink
191 \i \link setDirectRendering() Direct rendering.\endlink
192 \i \link setOverlay() Presence of an overlay.\endlink
193 \i \link setPlane() The plane of an overlay format.\endlink
194 \i \link setSampleBuffers() Multisample buffers.\endlink
195 \endlist
196
197 You can also specify preferred bit depths for the depth buffer,
198 alpha buffer, accumulation buffer and the stencil buffer with the
199 functions: setDepthBufferSize(), setAlphaBufferSize(),
200 setAccumBufferSize() and setStencilBufferSize().
201
202 Note that even if you specify that you prefer a 32 bit depth
203 buffer (e.g. with setDepthBufferSize(32)), the format that is
204 chosen may not have a 32 bit depth buffer, even if there is a
205 format available with a 32 bit depth buffer. The main reason for
206 this is how the system dependant picking algorithms work on the
207 different platforms, and some format options may have higher
208 precedence than others.
209
210 You create and tell a QGLFormat object what rendering options you
211 want from an OpenGL rendering context.
212
213 OpenGL drivers or accelerated hardware may or may not support
214 advanced features such as alpha channel or stereographic viewing.
215 If you request some features that the driver/hardware does not
216 provide when you create a QGLWidget, you will get a rendering
217 context with the nearest subset of features.
218
219 There are different ways to define the display characteristics of
220 a rendering context. One is to create a QGLFormat and make it the
221 default for the entire application:
222 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 0
223
224 Or you can specify the desired format when creating an object of
225 your QGLWidget subclass:
226 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 1
227
228 After the widget has been created, you can find out which of the
229 requested features the system was able to provide:
230 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 2
231
232 \legalese
233 OpenGL is a trademark of Silicon Graphics, Inc. in the
234 United States and other countries.
235 \endlegalese
236
237 \sa QGLContext, QGLWidget
238*/
239
240static inline void transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4])
241{
242#define M(row,col) m[col*4+row]
243 out[0] =
244 M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
245 out[1] =
246 M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
247 out[2] =
248 M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
249 out[3] =
250 M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
251#undef M
252}
253
254static inline GLint qgluProject(GLdouble objx, GLdouble objy, GLdouble objz,
255 const GLdouble model[16], const GLdouble proj[16],
256 const GLint viewport[4],
257 GLdouble * winx, GLdouble * winy, GLdouble * winz)
258{
259 GLdouble in[4], out[4];
260
261 in[0] = objx;
262 in[1] = objy;
263 in[2] = objz;
264 in[3] = 1.0;
265 transform_point(out, model, in);
266 transform_point(in, proj, out);
267
268 if (in[3] == 0.0)
269 return GL_FALSE;
270
271 in[0] /= in[3];
272 in[1] /= in[3];
273 in[2] /= in[3];
274
275 *winx = viewport[0] + (1 + in[0]) * viewport[2] / 2;
276 *winy = viewport[1] + (1 + in[1]) * viewport[3] / 2;
277
278 *winz = (1 + in[2]) / 2;
279 return GL_TRUE;
280}
281
282/*!
283 Constructs a QGLFormat object with the factory default settings:
284 \list
285 \i \link setDoubleBuffer() Double buffer:\endlink Enabled.
286 \i \link setDepth() Depth buffer:\endlink Enabled.
287 \i \link setRgba() RGBA:\endlink Enabled (i.e., color index disabled).
288 \i \link setAlpha() Alpha channel:\endlink Disabled.
289 \i \link setAccum() Accumulator buffer:\endlink Disabled.
290 \i \link setStencil() Stencil buffer:\endlink Disabled.
291 \i \link setStereo() Stereo:\endlink Disabled.
292 \i \link setDirectRendering() Direct rendering:\endlink Enabled.
293 \i \link setOverlay() Overlay:\endlink Disabled.
294 \i \link setPlane() Plane:\endlink 0 (i.e., normal plane).
295 \i \link setSampleBuffers() Multisample buffers:\endlink Disabled.
296 \endlist
297*/
298
299QGLFormat::QGLFormat()
300{
301 d = new QGLFormatPrivate;
302}
303
304
305/*!
306 Creates a QGLFormat object that is a copy of the current \link
307 defaultFormat() application default format\endlink.
308
309 If \a options is not 0, this copy is modified by these format
310 options. The \a options parameter should be \c FormatOption values
311 OR'ed together.
312
313 This constructor makes it easy to specify a certain desired format
314 in classes derived from QGLWidget, for example:
315 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 3
316
317 Note that there are \c FormatOption values to turn format settings
318 both on and off, e.g. \c DepthBuffer and \c NoDepthBuffer,
319 \c DirectRendering and \c IndirectRendering, etc.
320
321 The \a plane parameter defaults to 0 and is the plane which this
322 format should be associated with. Not all OpenGL implementations
323 supports overlay/underlay rendering planes.
324
325 \sa defaultFormat(), setOption()
326*/
327
328QGLFormat::QGLFormat(QGL::FormatOptions options, int plane)
329{
330 d = new QGLFormatPrivate;
331 QGL::FormatOptions newOpts = options;
332 d->opts = defaultFormat().d->opts;
333 d->opts |= (newOpts & 0xffff);
334 d->opts &= ~(newOpts >> 16);
335 d->pln = plane;
336}
337
338/*!
339 Constructs a copy of \a other.
340*/
341
342QGLFormat::QGLFormat(const QGLFormat &other)
343{
344 d = new QGLFormatPrivate;
345 *d = *other.d;
346}
347
348/*!
349 Assigns \a other to this object.
350*/
351
352QGLFormat &QGLFormat::operator=(const QGLFormat &other)
353{
354 *d = *other.d;
355 return *this;
356}
357
358/*!
359 Destroys the QGLFormat.
360*/
361QGLFormat::~QGLFormat()
362{
363 delete d;
364}
365
366/*!
367 \fn bool QGLFormat::doubleBuffer() const
368
369 Returns true if double buffering is enabled; otherwise returns
370 false. Double buffering is enabled by default.
371
372 \sa setDoubleBuffer()
373*/
374
375/*!
376 If \a enable is true sets double buffering; otherwise sets single
377 buffering.
378
379 Double buffering is enabled by default.
380
381 Double buffering is a technique where graphics are rendered on an
382 off-screen buffer and not directly to the screen. When the drawing
383 has been completed, the program calls a swapBuffers() function to
384 exchange the screen contents with the buffer. The result is
385 flicker-free drawing and often better performance.
386
387 \sa doubleBuffer(), QGLContext::swapBuffers(),
388 QGLWidget::swapBuffers()
389*/
390
391void QGLFormat::setDoubleBuffer(bool enable)
392{
393 setOption(enable ? QGL::DoubleBuffer : QGL::SingleBuffer);
394}
395
396
397/*!
398 \fn bool QGLFormat::depth() const
399
400 Returns true if the depth buffer is enabled; otherwise returns
401 false. The depth buffer is enabled by default.
402
403 \sa setDepth(), setDepthBufferSize()
404*/
405
406/*!
407 If \a enable is true enables the depth buffer; otherwise disables
408 the depth buffer.
409
410 The depth buffer is enabled by default.
411
412 The purpose of a depth buffer (or Z-buffering) is to remove hidden
413 surfaces. Pixels are assigned Z values based on the distance to
414 the viewer. A pixel with a high Z value is closer to the viewer
415 than a pixel with a low Z value. This information is used to
416 decide whether to draw a pixel or not.
417
418 \sa depth(), setDepthBufferSize()
419*/
420
421void QGLFormat::setDepth(bool enable)
422{
423 setOption(enable ? QGL::DepthBuffer : QGL::NoDepthBuffer);
424}
425
426
427/*!
428 \fn bool QGLFormat::rgba() const
429
430 Returns true if RGBA color mode is set. Returns false if color
431 index mode is set. The default color mode is RGBA.
432
433 \sa setRgba()
434*/
435
436/*!
437 If \a enable is true sets RGBA mode. If \a enable is false sets
438 color index mode.
439
440 The default color mode is RGBA.
441
442 RGBA is the preferred mode for most OpenGL applications. In RGBA
443 color mode you specify colors as red + green + blue + alpha
444 quadruplets.
445
446 In color index mode you specify an index into a color lookup
447 table.
448
449 \sa rgba()
450*/
451
452void QGLFormat::setRgba(bool enable)
453{
454 setOption(enable ? QGL::Rgba : QGL::ColorIndex);
455}
456
457
458/*!
459 \fn bool QGLFormat::alpha() const
460
461 Returns true if the alpha buffer in the framebuffer is enabled;
462 otherwise returns false. The alpha buffer is disabled by default.
463
464 \sa setAlpha(), setAlphaBufferSize()
465*/
466
467/*!
468 If \a enable is true enables the alpha buffer; otherwise disables
469 the alpha buffer.
470
471 The alpha buffer is disabled by default.
472
473 The alpha buffer is typically used for implementing transparency
474 or translucency. The A in RGBA specifies the transparency of a
475 pixel.
476
477 \sa alpha(), setAlphaBufferSize()
478*/
479
480void QGLFormat::setAlpha(bool enable)
481{
482 setOption(enable ? QGL::AlphaChannel : QGL::NoAlphaChannel);
483}
484
485
486/*!
487 \fn bool QGLFormat::accum() const
488
489 Returns true if the accumulation buffer is enabled; otherwise
490 returns false. The accumulation buffer is disabled by default.
491
492 \sa setAccum(), setAccumBufferSize()
493*/
494
495/*!
496 If \a enable is true enables the accumulation buffer; otherwise
497 disables the accumulation buffer.
498
499 The accumulation buffer is disabled by default.
500
501 The accumulation buffer is used to create blur effects and
502 multiple exposures.
503
504 \sa accum(), setAccumBufferSize()
505*/
506
507void QGLFormat::setAccum(bool enable)
508{
509 setOption(enable ? QGL::AccumBuffer : QGL::NoAccumBuffer);
510}
511
512
513/*!
514 \fn bool QGLFormat::stencil() const
515
516 Returns true if the stencil buffer is enabled; otherwise returns
517 false. The stencil buffer is disabled by default.
518
519 \sa setStencil(), setStencilBufferSize()
520*/
521
522/*!
523 If \a enable is true enables the stencil buffer; otherwise
524 disables the stencil buffer.
525
526 The stencil buffer is disabled by default.
527
528 The stencil buffer masks certain parts of the drawing area so that
529 masked parts are not drawn on.
530
531 \sa stencil(), setStencilBufferSize()
532*/
533
534void QGLFormat::setStencil(bool enable)
535{
536 setOption(enable ? QGL::StencilBuffer: QGL::NoStencilBuffer);
537}
538
539
540/*!
541 \fn bool QGLFormat::stereo() const
542
543 Returns true if stereo buffering is enabled; otherwise returns
544 false. Stereo buffering is disabled by default.
545
546 \sa setStereo()
547*/
548
549/*!
550 If \a enable is true enables stereo buffering; otherwise disables
551 stereo buffering.
552
553 Stereo buffering is disabled by default.
554
555 Stereo buffering provides extra color buffers to generate left-eye
556 and right-eye images.
557
558 \sa stereo()
559*/
560
561void QGLFormat::setStereo(bool enable)
562{
563 setOption(enable ? QGL::StereoBuffers : QGL::NoStereoBuffers);
564}
565
566
567/*!
568 \fn bool QGLFormat::directRendering() const
569
570 Returns true if direct rendering is enabled; otherwise returns
571 false.
572
573 Direct rendering is enabled by default.
574
575 \sa setDirectRendering()
576*/
577
578/*!
579 If \a enable is true enables direct rendering; otherwise disables
580 direct rendering.
581
582 Direct rendering is enabled by default.
583
584 Enabling this option will make OpenGL bypass the underlying window
585 system and render directly from hardware to the screen, if this is
586 supported by the system.
587
588 \sa directRendering()
589*/
590
591void QGLFormat::setDirectRendering(bool enable)
592{
593 setOption(enable ? QGL::DirectRendering : QGL::IndirectRendering);
594}
595
596/*!
597 \fn bool QGLFormat::sampleBuffers() const
598
599 Returns true if multisample buffer support is enabled; otherwise
600 returns false.
601
602 The multisample buffer is disabled by default.
603
604 \sa setSampleBuffers()
605*/
606
607/*!
608 If \a enable is true, a GL context with multisample buffer support
609 is picked; otherwise ignored.
610
611 \sa sampleBuffers(), setSamples(), samples()
612*/
613void QGLFormat::setSampleBuffers(bool enable)
614{
615 setOption(enable ? QGL::SampleBuffers : QGL::NoSampleBuffers);
616}
617
618/*!
619 Returns the number of samples per pixel when multisampling is
620 enabled. By default, the highest number of samples that is
621 available is used.
622
623 \sa setSampleBuffers(), sampleBuffers(), setSamples()
624*/
625int QGLFormat::samples() const
626{
627 return d->numSamples;
628}
629
630/*!
631 Set the preferred number of samples per pixel when multisampling
632 is enabled to \a numSamples. By default, the highest number of
633 samples available is used.
634
635 \sa setSampleBuffers(), sampleBuffers(), samples()
636*/
637void QGLFormat::setSamples(int numSamples)
638{
639 if (numSamples < 0) {
640 qWarning("QGLFormat::setSamples: Cannot have negative number of samples per pixel %d", numSamples);
641 return;
642 }
643 d->numSamples = numSamples;
644}
645
646/*!
647 \since 4.2
648
649 Set the preferred swap interval. This can be used to sync the GL
650 drawing into a system window to the vertical refresh of the screen.
651 Setting an \a interval value of 0 will turn the vertical refresh syncing
652 off, any value higher than 0 will turn the vertical syncing on.
653
654 Under Windows and under X11, where the \c{WGL_EXT_swap_control}
655 and \c{GLX_SGI_video_sync} extensions are used, the \a interval
656 parameter can be used to set the minimum number of video frames
657 that are displayed before a buffer swap will occur. In effect,
658 setting the \a interval to 10, means there will be 10 vertical
659 retraces between every buffer swap.
660
661 Under Windows the \c{WGL_EXT_swap_control} extension has to be present,
662 and under X11 the \c{GLX_SGI_video_sync} extension has to be present.
663*/
664void QGLFormat::setSwapInterval(int interval)
665{
666 d->swapInterval = interval;
667}
668
669/*!
670 \since 4.2
671
672 Returns the currently set swap interval. -1 is returned if setting
673 the swap interval isn't supported in the system GL implementation.
674*/
675int QGLFormat::swapInterval() const
676{
677 return d->swapInterval;
678}
679
680/*!
681 \fn bool QGLFormat::hasOverlay() const
682
683 Returns true if overlay plane is enabled; otherwise returns false.
684
685 Overlay is disabled by default.
686
687 \sa setOverlay()
688*/
689
690/*!
691 If \a enable is true enables an overlay plane; otherwise disables
692 the overlay plane.
693
694 Enabling the overlay plane will cause QGLWidget to create an
695 additional context in an overlay plane. See the QGLWidget
696 documentation for further information.
697
698 \sa hasOverlay()
699*/
700
701void QGLFormat::setOverlay(bool enable)
702{
703 setOption(enable ? QGL::HasOverlay : QGL::NoOverlay);
704}
705
706/*!
707 Returns the plane of this format. The default for normal formats
708 is 0, which means the normal plane. The default for overlay
709 formats is 1, which is the first overlay plane.
710
711 \sa setPlane()
712*/
713int QGLFormat::plane() const
714{
715 return d->pln;
716}
717
718/*!
719 Sets the requested plane to \a plane. 0 is the normal plane, 1 is
720 the first overlay plane, 2 is the second overlay plane, etc.; -1,
721 -2, etc. are underlay planes.
722
723 Note that in contrast to other format specifications, the plane
724 specifications will be matched exactly. This means that if you
725 specify a plane that the underlying OpenGL system cannot provide,
726 an \link QGLWidget::isValid() invalid\endlink QGLWidget will be
727 created.
728
729 \sa plane()
730*/
731void QGLFormat::setPlane(int plane)
732{
733 d->pln = plane;
734}
735
736/*!
737 Sets the format option to \a opt.
738
739 \sa testOption()
740*/
741
742void QGLFormat::setOption(QGL::FormatOptions opt)
743{
744 if (opt & 0xffff)
745 d->opts |= opt;
746 else
747 d->opts &= ~(opt >> 16);
748}
749
750
751
752/*!
753 Returns true if format option \a opt is set; otherwise returns false.
754
755 \sa setOption()
756*/
757
758bool QGLFormat::testOption(QGL::FormatOptions opt) const
759{
760 if (opt & 0xffff)
761 return (d->opts & opt) != 0;
762 else
763 return (d->opts & (opt >> 16)) == 0;
764}
765
766/*!
767 Set the minimum depth buffer size to \a size.
768
769 \sa depthBufferSize(), setDepth(), depth()
770*/
771void QGLFormat::setDepthBufferSize(int size)
772{
773 if (size < 0) {
774 qWarning("QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size %d", size);
775 return;
776 }
777 d->depthSize = size;
778}
779
780/*!
781 Returns the depth buffer size.
782
783 \sa depth(), setDepth(), setDepthBufferSize()
784*/
785int QGLFormat::depthBufferSize() const
786{
787 return d->depthSize;
788}
789
790/*!
791 \since 4.2
792
793 Set the preferred red buffer size to \a size.
794
795 \sa setGreenBufferSize(), setBlueBufferSize(), setAlphaBufferSize()
796*/
797void QGLFormat::setRedBufferSize(int size)
798{
799 if (size < 0) {
800 qWarning("QGLFormat::setRedBufferSize: Cannot set negative red buffer size %d", size);
801 return;
802 }
803 d->redSize = size;
804}
805
806/*!
807 \since 4.2
808
809 Returns the red buffer size.
810
811 \sa setRedBufferSize()
812*/
813int QGLFormat::redBufferSize() const
814{
815 return d->redSize;
816}
817
818/*!
819 \since 4.2
820
821 Set the preferred green buffer size to \a size.
822
823 \sa setRedBufferSize(), setBlueBufferSize(), setAlphaBufferSize()
824*/
825void QGLFormat::setGreenBufferSize(int size)
826{
827 if (size < 0) {
828 qWarning("QGLFormat::setGreenBufferSize: Cannot set negative green buffer size %d", size);
829 return;
830 }
831 d->greenSize = size;
832}
833
834/*!
835 \since 4.2
836
837 Returns the green buffer size.
838
839 \sa setGreenBufferSize()
840*/
841int QGLFormat::greenBufferSize() const
842{
843 return d->greenSize;
844}
845
846/*!
847 \since 4.2
848
849 Set the preferred blue buffer size to \a size.
850
851 \sa setRedBufferSize(), setGreenBufferSize(), setAlphaBufferSize()
852*/
853void QGLFormat::setBlueBufferSize(int size)
854{
855 if (size < 0) {
856 qWarning("QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size %d", size);
857 return;
858 }
859 d->blueSize = size;
860}
861
862/*!
863 \since 4.2
864
865 Returns the blue buffer size.
866
867 \sa setBlueBufferSize()
868*/
869int QGLFormat::blueBufferSize() const
870{
871 return d->blueSize;
872}
873
874/*!
875 Set the preferred alpha buffer size to \a size.
876 This function implicitly enables the alpha channel.
877
878 \sa setRedBufferSize(), setGreenBufferSize(), alphaBufferSize()
879*/
880void QGLFormat::setAlphaBufferSize(int size)
881{
882 if (size < 0) {
883 qWarning("QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size %d", size);
884 return;
885 }
886 d->alphaSize = size;
887 setOption(QGL::AlphaChannel);
888}
889
890/*!
891 Returns the alpha buffer size.
892
893 \sa alpha(), setAlpha(), setAlphaBufferSize()
894*/
895int QGLFormat::alphaBufferSize() const
896{
897 return d->alphaSize;
898}
899
900/*!
901 Set the preferred accumulation buffer size, where \a size is the
902 bit depth for each RGBA component.
903
904 \sa accum(), setAccum(), accumBufferSize()
905*/
906void QGLFormat::setAccumBufferSize(int size)
907{
908 if (size < 0) {
909 qWarning("QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size %d", size);
910 return;
911 }
912 d->accumSize = size;
913}
914
915/*!
916 Returns the accumulation buffer size.
917
918 \sa setAccumBufferSize(), accum(), setAccum()
919*/
920int QGLFormat::accumBufferSize() const
921{
922 return d->accumSize;
923}
924
925/*!
926 Set the preferred stencil buffer size to \a size.
927
928 \sa stencilBufferSize(), setStencil(), stencil()
929*/
930void QGLFormat::setStencilBufferSize(int size)
931{
932 if (size < 0) {
933 qWarning("QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size %d", size);
934 return;
935 }
936 d->stencilSize = size;
937}
938
939/*!
940 Returns the stencil buffer size.
941
942 \sa stencil(), setStencil(), setStencilBufferSize()
943*/
944int QGLFormat::stencilBufferSize() const
945{
946 return d->stencilSize;
947}
948
949/*!
950 \fn bool QGLFormat::hasOpenGL()
951
952 Returns true if the window system has any OpenGL support;
953 otherwise returns false.
954
955 \warning This function must not be called until the QApplication
956 object has been created.
957*/
958
959
960
961/*!
962 \fn bool QGLFormat::hasOpenGLOverlays()
963
964 Returns true if the window system supports OpenGL overlays;
965 otherwise returns false.
966
967 \warning This function must not be called until the QApplication
968 object has been created.
969*/
970
971QGLFormat::OpenGLVersionFlags Q_AUTOTEST_EXPORT qOpenGLVersionFlagsFromString(const QString &versionString)
972{
973 QGLFormat::OpenGLVersionFlags versionFlags = QGLFormat::OpenGL_Version_None;
974
975 if (versionString.startsWith(QLatin1String("OpenGL ES"))) {
976 QStringList parts = versionString.split(QLatin1Char(' '));
977 if (parts.size() >= 3) {
978 if (parts[2].startsWith(QLatin1String("1."))) {
979 if (parts[1].endsWith(QLatin1String("-CM"))) {
980 versionFlags |= QGLFormat::OpenGL_ES_Common_Version_1_0 |
981 QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
982 if (parts[2].startsWith(QLatin1String("1.1")))
983 versionFlags |= QGLFormat::OpenGL_ES_Common_Version_1_1 |
984 QGLFormat::OpenGL_ES_CommonLite_Version_1_1;
985 }
986 else {
987 // Not -CM, must be CL, CommonLite
988 versionFlags |= QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
989 if (parts[2].startsWith(QLatin1String("1.1")))
990 versionFlags |= QGLFormat::OpenGL_ES_CommonLite_Version_1_1;
991 }
992 }
993 else {
994 // OpenGL ES version 2.0 or higher
995 versionFlags |= QGLFormat::OpenGL_ES_Version_2_0;
996 }
997 }
998 else {
999 // if < 3 parts to the name, it is an unrecognised OpenGL ES
1000 qWarning("Unrecognised OpenGL ES version");
1001 }
1002 }
1003 else {
1004 // not ES, regular OpenGL, the version numbers are first in the string
1005 if (versionString.startsWith(QLatin1String("1."))) {
1006 switch (versionString[2].toAscii()) {
1007 case '5':
1008 versionFlags |= QGLFormat::OpenGL_Version_1_5;
1009 case '4':
1010 versionFlags |= QGLFormat::OpenGL_Version_1_4;
1011 case '3':
1012 versionFlags |= QGLFormat::OpenGL_Version_1_3;
1013 case '2':
1014 versionFlags |= QGLFormat::OpenGL_Version_1_2;
1015 case '1':
1016 versionFlags |= QGLFormat::OpenGL_Version_1_1;
1017 default:
1018 break;
1019 }
1020 }
1021 else if (versionString.startsWith(QLatin1String("2."))) {
1022 versionFlags |= QGLFormat::OpenGL_Version_1_1 |
1023 QGLFormat::OpenGL_Version_1_2 |
1024 QGLFormat::OpenGL_Version_1_3 |
1025 QGLFormat::OpenGL_Version_1_4 |
1026 QGLFormat::OpenGL_Version_1_5 |
1027 QGLFormat::OpenGL_Version_2_0;
1028 QString minorVersion = versionString.section(QLatin1Char(' '), 0, 0).section(QLatin1Char('.'), 1, 1);
1029 if (minorVersion == QChar(QLatin1Char('1')))
1030 versionFlags |= QGLFormat::OpenGL_Version_2_1;
1031 }
1032 else if (versionString.startsWith(QLatin1String("3."))) {
1033 versionFlags |= QGLFormat::OpenGL_Version_1_1 |
1034 QGLFormat::OpenGL_Version_1_2 |
1035 QGLFormat::OpenGL_Version_1_3 |
1036 QGLFormat::OpenGL_Version_1_4 |
1037 QGLFormat::OpenGL_Version_1_5 |
1038 QGLFormat::OpenGL_Version_2_0 |
1039 QGLFormat::OpenGL_Version_2_1 |
1040 QGLFormat::OpenGL_Version_3_0;
1041 }
1042 else
1043 qWarning("Unrecognised OpenGL version");
1044 }
1045 return versionFlags;
1046}
1047
1048/*!
1049 \enum QGLFormat::OpenGLVersionFlag
1050 \since 4.2
1051
1052 This enum describes the various OpenGL versions that are
1053 recognized by Qt. Use the QGLFormat::openGLVersionFlags() function
1054 to identify which versions that are supported at runtime.
1055
1056 \value OpenGL_Version_None If no OpenGL is present or if no OpenGL context is current.
1057
1058 \value OpenGL_Version_1_1 OpenGL version 1.1 or higher is present.
1059
1060 \value OpenGL_Version_1_2 OpenGL version 1.2 or higher is present.
1061
1062 \value OpenGL_Version_1_3 OpenGL version 1.3 or higher is present.
1063
1064 \value OpenGL_Version_1_4 OpenGL version 1.4 or higher is present.
1065
1066 \value OpenGL_Version_1_5 OpenGL version 1.5 or higher is present.
1067
1068 \value OpenGL_Version_2_0 OpenGL version 2.0 or higher is present.
1069 Note that version 2.0 supports all the functionality of version 1.5.
1070
1071 \value OpenGL_Version_2_1 OpenGL version 2.1 or higher is present.
1072
1073 \value OpenGL_Version_3_0 OpenGL version 3.0 or higher is present.
1074
1075 \value OpenGL_ES_CommonLite_Version_1_0 OpenGL ES version 1.0 Common Lite or higher is present.
1076
1077 \value OpenGL_ES_Common_Version_1_0 OpenGL ES version 1.0 Common or higher is present.
1078 The Common profile supports all the features of Common Lite.
1079
1080 \value OpenGL_ES_CommonLite_Version_1_1 OpenGL ES version 1.1 Common Lite or higher is present.
1081
1082 \value OpenGL_ES_Common_Version_1_1 OpenGL ES version 1.1 Common or higher is present.
1083 The Common profile supports all the features of Common Lite.
1084
1085 \value OpenGL_ES_Version_2_0 OpenGL ES version 2.0 or higher is present.
1086 Note that OpenGL ES version 2.0 does not support all the features of OpenGL ES 1.x.
1087 So if OpenGL_ES_Version_2_0 is returned, none of the ES 1.x flags are returned.
1088
1089 See also \l{http://www.opengl.org} for more information about the different
1090 revisions of OpenGL.
1091
1092 \sa openGLVersionFlags()
1093*/
1094
1095/*!
1096 \since 4.2
1097
1098 Identifies, at runtime, which OpenGL versions that are supported
1099 by the current platform.
1100
1101 Note that if OpenGL version 1.5 is supported, its predecessors
1102 (i.e., version 1.4 and lower) are also supported. To identify the
1103 support of a particular feature, like multi texturing, test for
1104 the version in which the feature was first introduced (i.e.,
1105 version 1.3 in the case of multi texturing) to adapt to the largest
1106 possible group of runtime platforms.
1107
1108 This function needs a valid current OpenGL context to work;
1109 otherwise it will return OpenGL_Version_None.
1110
1111 \sa hasOpenGL(), hasOpenGLOverlays()
1112*/
1113QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags()
1114{
1115 static bool cachedDefault = false;
1116 static OpenGLVersionFlags defaultVersionFlags = OpenGL_Version_None;
1117 QGLContext *currentCtx = const_cast<QGLContext *>(QGLContext::currentContext());
1118 QGLWidget *dummy = 0;
1119
1120 if (currentCtx && currentCtx->d_func()->version_flags_cached)
1121 return currentCtx->d_func()->version_flags;
1122
1123 if (!currentCtx) {
1124 if (cachedDefault) {
1125 return defaultVersionFlags;
1126 } else {
1127 cachedDefault = true;
1128 if (!hasOpenGL())
1129 return defaultVersionFlags;
1130 dummy = new QGLWidget;
1131 dummy->makeCurrent(); // glGetString() needs a current context
1132 }
1133 }
1134
1135 QString versionString(QLatin1String(reinterpret_cast<const char*>(glGetString(GL_VERSION))));
1136 OpenGLVersionFlags versionFlags = qOpenGLVersionFlagsFromString(versionString);
1137 if (currentCtx) {
1138 currentCtx->d_func()->version_flags_cached = true;
1139 currentCtx->d_func()->version_flags = versionFlags;
1140 }
1141 if (dummy) {
1142 defaultVersionFlags = versionFlags;
1143 delete dummy;
1144 }
1145
1146 return versionFlags;
1147}
1148
1149
1150/*!
1151 Returns the default QGLFormat for the application. All QGLWidgets
1152 that are created use this format unless another format is
1153 specified, e.g. when they are constructed.
1154
1155 If no special default format has been set using
1156 setDefaultFormat(), the default format is the same as that created
1157 with QGLFormat().
1158
1159 \sa setDefaultFormat()
1160*/
1161
1162QGLFormat QGLFormat::defaultFormat()
1163{
1164 return *qgl_default_format();
1165}
1166
1167/*!
1168 Sets a new default QGLFormat for the application to \a f. For
1169 example, to set single buffering as the default instead of double
1170 buffering, your main() might contain code like this:
1171 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 4
1172
1173 \sa defaultFormat()
1174*/
1175
1176void QGLFormat::setDefaultFormat(const QGLFormat &f)
1177{
1178 *qgl_default_format() = f;
1179}
1180
1181
1182/*!
1183 Returns the default QGLFormat for overlay contexts.
1184
1185 The factory default overlay format is:
1186 \list
1187 \i \link setDoubleBuffer() Double buffer:\endlink Disabled.
1188 \i \link setDepth() Depth buffer:\endlink Disabled.
1189 \i \link setRgba() RGBA:\endlink Disabled (i.e., color index enabled).
1190 \i \link setAlpha() Alpha channel:\endlink Disabled.
1191 \i \link setAccum() Accumulator buffer:\endlink Disabled.
1192 \i \link setStencil() Stencil buffer:\endlink Disabled.
1193 \i \link setStereo() Stereo:\endlink Disabled.
1194 \i \link setDirectRendering() Direct rendering:\endlink Enabled.
1195 \i \link setOverlay() Overlay:\endlink Disabled.
1196 \i \link setPlane() Plane:\endlink 1 (i.e., first overlay plane).
1197 \endlist
1198
1199 \sa setDefaultFormat()
1200*/
1201
1202QGLFormat QGLFormat::defaultOverlayFormat()
1203{
1204 return *defaultOverlayFormatInstance();
1205}
1206
1207/*!
1208 Sets a new default QGLFormat for overlay contexts to \a f. This
1209 format is used whenever a QGLWidget is created with a format that
1210 hasOverlay() enabled.
1211
1212 For example, to get a double buffered overlay context (if
1213 available), use code like this:
1214
1215 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 5
1216
1217 As usual, you can find out after widget creation whether the
1218 underlying OpenGL system was able to provide the requested
1219 specification:
1220
1221 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 6
1222
1223 \sa defaultOverlayFormat()
1224*/
1225
1226void QGLFormat::setDefaultOverlayFormat(const QGLFormat &f)
1227{
1228 QGLFormat *defaultFormat = defaultOverlayFormatInstance();
1229 *defaultFormat = f;
1230 // Make sure the user doesn't request that the overlays themselves
1231 // have overlays, since it is unlikely that the system supports
1232 // infinitely many planes...
1233 defaultFormat->setOverlay(false);
1234}
1235
1236
1237/*!
1238 Returns true if all the options of the two QGLFormats are equal;
1239 otherwise returns false.
1240*/
1241
1242bool operator==(const QGLFormat& a, const QGLFormat& b)
1243{
1244 return (int) a.d->opts == (int) b.d->opts && a.d->pln == b.d->pln && a.d->alphaSize == b.d->alphaSize
1245 && a.d->accumSize == b.d->accumSize && a.d->stencilSize == b.d->stencilSize
1246 && a.d->depthSize == b.d->depthSize;
1247}
1248
1249
1250/*!
1251 Returns false if all the options of the two QGLFormats are equal;
1252 otherwise returns true.
1253*/
1254
1255bool operator!=(const QGLFormat& a, const QGLFormat& b)
1256{
1257 return !(a == b);
1258}
1259
1260/*****************************************************************************
1261 QGLContext implementation
1262 *****************************************************************************/
1263void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
1264{
1265 Q_Q(QGLContext);
1266 glFormat = reqFormat = format;
1267 valid = false;
1268 q->setDevice(dev);
1269#if defined(Q_WS_X11)
1270 pbuf = 0;
1271 gpm = 0;
1272 vi = 0;
1273 screen = QX11Info::appScreen();
1274#endif
1275#if defined(Q_WS_WIN)
1276 dc = 0;
1277 win = 0;
1278 pixelFormatId = 0;
1279 cmap = 0;
1280 hbitmap = 0;
1281 hbitmap_hdc = 0;
1282#endif
1283#if defined(Q_WS_MAC)
1284# ifndef QT_MAC_USE_COCOA
1285 update = false;
1286# endif
1287 vi = 0;
1288#endif
1289#if defined(QT_OPENGL_ES)
1290 eglContext = 0;
1291#endif
1292 pbo = 0;
1293 crWin = false;
1294 initDone = false;
1295 sharing = false;
1296 clear_on_painter_begin = true;
1297 max_texture_size = -1;
1298 version_flags_cached = false;
1299 version_flags = QGLFormat::OpenGL_Version_None;
1300}
1301
1302QGLContext* QGLContext::currentCtx = 0;
1303
1304/*
1305 Read back the contents of the currently bound framebuffer, used in
1306 QGLWidget::grabFrameBuffer(), QGLPixelbuffer::toImage() and
1307 QGLFramebufferObject::toImage()
1308*/
1309
1310QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha)
1311{
1312 QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32);
1313 int w = size.width();
1314 int h = size.height();
1315 glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
1316 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
1317 // OpenGL gives RGBA; Qt wants ARGB
1318 uint *p = (uint*)img.bits();
1319 uint *end = p + w*h;
1320 if (alpha_format && include_alpha) {
1321 while (p < end) {
1322 uint a = *p << 24;
1323 *p = (*p >> 8) | a;
1324 p++;
1325 }
1326 } else {
1327 // This is an old legacy fix for PowerPC based Macs, which
1328 // we shouldn't remove
1329 while (p < end) {
1330 *p = 0xFF000000 | (*p>>8);
1331 ++p;
1332 }
1333 }
1334 } else {
1335 // OpenGL gives ABGR (i.e. RGBA backwards); Qt wants ARGB
1336 img = img.rgbSwapped();
1337 }
1338 return img.mirrored();
1339}
1340
1341// returns the highest number closest to v, which is a power of 2
1342// NB! assumes 32 bit ints
1343int qt_next_power_of_two(int v)
1344{
1345 v--;
1346 v |= v >> 1;
1347 v |= v >> 2;
1348 v |= v >> 4;
1349 v |= v >> 8;
1350 v |= v >> 16;
1351 ++v;
1352 return v;
1353}
1354
1355class QGLTexture {
1356public:
1357 QGLTexture(const QGLContext *ctx, GLuint tx_id, GLenum tx_target, bool _clean = false)
1358 : context(ctx), id(tx_id), target(tx_target), clean(_clean) {}
1359 ~QGLTexture() {
1360 if (clean) {
1361 QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext());
1362 QGLContext *ctx = const_cast<QGLContext *>(context);
1363 bool switch_context = current && current != ctx && !qgl_share_reg()->checkSharing(current, ctx);
1364 if (switch_context)
1365 ctx->makeCurrent();
1366 glDeleteTextures(1, &id);
1367 if (switch_context)
1368 current->makeCurrent();
1369 }
1370 }
1371
1372 const QGLContext *context;
1373 GLuint id;
1374 GLenum target;
1375 bool clean;
1376};
1377
1378typedef QCache<qint64, QGLTexture> QGLTextureCache;
1379static int qt_tex_cache_limit = 64*1024; // cache ~64 MB worth of textures - this is not accurate though
1380static QGLTextureCache *qt_tex_cache = 0;
1381
1382typedef void (*_qt_pixmap_cleanup_hook_64)(qint64);
1383typedef void (*_qt_image_cleanup_hook_64)(qint64);
1384
1385extern Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64;
1386extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64;
1387
1388// DDS format structure
1389struct DDSFormat {
1390 quint32 dwSize;
1391 quint32 dwFlags;
1392 quint32 dwHeight;
1393 quint32 dwWidth;
1394 quint32 dwLinearSize;
1395 quint32 dummy1;
1396 quint32 dwMipMapCount;
1397 quint32 dummy2[11];
1398 struct {
1399 quint32 dummy3[2];
1400 quint32 dwFourCC;
1401 quint32 dummy4[5];
1402 } ddsPixelFormat;
1403};
1404
1405// compressed texture pixel formats
1406#define FOURCC_DXT1 0x31545844
1407#define FOURCC_DXT2 0x32545844
1408#define FOURCC_DXT3 0x33545844
1409#define FOURCC_DXT4 0x34545844
1410#define FOURCC_DXT5 0x35545844
1411
1412#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
1413#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
1414#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
1415#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
1416#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
1417#endif
1418
1419#ifndef GL_GENERATE_MIPMAP_SGIS
1420#define GL_GENERATE_MIPMAP_SGIS 0x8191
1421#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
1422#endif
1423
1424Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg);
1425Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
1426{
1427 return _qgl_share_reg();
1428}
1429
1430/*!
1431 \class QGLContext
1432 \brief The QGLContext class encapsulates an OpenGL rendering context.
1433
1434 \ingroup multimedia
1435
1436 An OpenGL rendering context is a complete set of OpenGL state
1437 variables. The rendering context's \l {QGL::FormatOption} {format}
1438 is set in the constructor, but it can also be set later with
1439 setFormat(). The format options that are actually set are returned
1440 by format(); the options you asked for are returned by
1441 requestedFormat(). Note that after a QGLContext object has been
1442 constructed, the actual OpenGL context must be created by
1443 explicitly calling the \link create() create()\endlink
1444 function. The makeCurrent() function makes this context the
1445 current rendering context. You can make \e no context current
1446 using doneCurrent(). The reset() function will reset the context
1447 and make it invalid.
1448
1449 You can examine properties of the context with, e.g. isValid(),
1450 isSharing(), initialized(), windowCreated() and
1451 overlayTransparentColor().
1452
1453 If you're using double buffering you can swap the screen contents
1454 with the off-screen buffer using swapBuffers().
1455
1456 Please note that QGLContext is not thread safe.
1457*/
1458
1459
1460/*!
1461 \obsolete
1462
1463 Constructs an OpenGL context for the given paint \a device, which
1464 can be a widget or a pixmap. The \a format specifies several
1465 display options for the context.
1466
1467 If the underlying OpenGL/Window system cannot satisfy all the
1468 features requested in \a format, the nearest subset of features
1469 will be used. After creation, the format() method will return the
1470 actual format obtained.
1471
1472 Note that after a QGLContext object has been constructed, \l
1473 create() must be called explicitly to create the actual OpenGL
1474 context. The context will be \l {isValid()}{invalid} if it was not
1475 possible to obtain a GL context at all.
1476*/
1477
1478QGLContext::QGLContext(const QGLFormat &format, QPaintDevice *device)
1479{
1480 d_ptr = new QGLContextPrivate(this);
1481 Q_D(QGLContext);
1482 d->init(device, format);
1483}
1484
1485/*!
1486 Constructs an OpenGL context with the given \a format which
1487 specifies several display options for the context.
1488
1489 If the underlying OpenGL/Window system cannot satisfy all the
1490 features requested in \a format, the nearest subset of features
1491 will be used. After creation, the format() method will return the
1492 actual format obtained.
1493
1494 Note that after a QGLContext object has been constructed, \l
1495 create() must be called explicitly to create the actual OpenGL
1496 context. The context will be \l {isValid()}{invalid} if it was not
1497 possible to obtain a GL context at all.
1498
1499 \sa format(), isValid()
1500*/
1501QGLContext::QGLContext(const QGLFormat &format)
1502{
1503 d_ptr = new QGLContextPrivate(this);
1504 Q_D(QGLContext);
1505 d->init(0, format);
1506}
1507
1508/*!
1509 Destroys the OpenGL context and frees its resources.
1510*/
1511
1512QGLContext::~QGLContext()
1513{
1514 Q_D(QGLContext);
1515 // remove any textures cached in this context
1516 if (qt_tex_cache) {
1517 QList<qint64> keys = qt_tex_cache->keys();
1518 for (int i = 0; i < keys.size(); ++i) {
1519 const qint64 &key = keys.at(i);
1520 if (qt_tex_cache->object(key)->context == this)
1521 qt_tex_cache->remove(key);
1522 }
1523 // ### thread safety
1524 if (qt_tex_cache->size() == 0) {
1525 qt_pixmap_cleanup_hook_64 = 0;
1526 qt_image_cleanup_hook_64 = 0;
1527 delete qt_tex_cache;
1528 qt_tex_cache = 0;
1529 }
1530 }
1531
1532 QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
1533 reset();
1534 delete d;
1535}
1536
1537void QGLContextPrivate::cleanup()
1538{
1539 Q_Q(QGLContext);
1540 if (pbo) {
1541 QGLContext *ctx = q;
1542 glDeleteBuffersARB(1, &pbo);
1543 pbo = 0;
1544 }
1545}
1546
1547typedef QHash<QString, GLuint> QGLDDSCache;
1548Q_GLOBAL_STATIC(QGLDDSCache, qgl_dds_cache)
1549
1550/*!
1551 \overload
1552
1553 Reads the DirectDrawSurface (DDS) compressed file \a fileName and
1554 generates a 2D GL texture from it.
1555
1556 Only the DXT1, DXT3 and DXT5 DDS formats are supported.
1557
1558 Note that this will only work if the implementation supports the
1559 \c GL_ARB_texture_compression and \c GL_EXT_texture_compression_s3tc
1560 extensions.
1561
1562 \sa deleteTexture()
1563*/
1564
1565GLuint QGLContext::bindTexture(const QString &fileName)
1566{
1567 if (!qt_glCompressedTexImage2DARB) {
1568 qWarning("QGLContext::bindTexture(): The GL implementation does not support texture"
1569 "compression extensions.");
1570 return 0;
1571 }
1572
1573 QGLDDSCache::const_iterator it = qgl_dds_cache()->constFind(fileName);
1574 if (it != qgl_dds_cache()->constEnd()) {
1575 glBindTexture(GL_TEXTURE_2D, it.value());
1576 return it.value();
1577 }
1578
1579 QFile f(fileName);
1580 f.open(QIODevice::ReadOnly);
1581
1582 char tag[4];
1583 f.read(&tag[0], 4);
1584 if (strncmp(tag,"DDS ", 4) != 0) {
1585 qWarning("QGLContext::bindTexture(): not a DDS image file.");
1586 return 0;
1587 }
1588
1589 DDSFormat ddsHeader;
1590 f.read((char *) &ddsHeader, sizeof(DDSFormat));
1591
1592 if (!ddsHeader.dwLinearSize) {
1593 qWarning("QGLContext::bindTexture() DDS image size is not valid.");
1594 return 0;
1595 }
1596
1597 int factor = 4;
1598 int bufferSize = 0;
1599 int blockSize = 16;
1600 GLenum format;
1601
1602 switch(ddsHeader.ddsPixelFormat.dwFourCC) {
1603 case FOURCC_DXT1:
1604 format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
1605 factor = 2;
1606 blockSize = 8;
1607 break;
1608 case FOURCC_DXT3:
1609 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
1610 break;
1611 case FOURCC_DXT5:
1612 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
1613 break;
1614 default:
1615 qWarning("QGLContext::bindTexture() DDS image format not supported.");
1616 return 0;
1617 }
1618
1619 if (ddsHeader.dwMipMapCount > 1)
1620 bufferSize = ddsHeader.dwLinearSize * factor;
1621 else
1622 bufferSize = ddsHeader.dwLinearSize;
1623
1624 GLubyte *pixels = (GLubyte *) malloc(bufferSize*sizeof(GLubyte));
1625 f.seek(ddsHeader.dwSize + 4);
1626 f.read((char *) pixels, bufferSize);
1627 f.close();
1628
1629 GLuint tx_id;
1630 glGenTextures(1, &tx_id);
1631 glBindTexture(GL_TEXTURE_2D, tx_id);
1632 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1633 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1634
1635 int size;
1636 int offset = 0;
1637 int w = ddsHeader.dwWidth;
1638 int h = ddsHeader.dwHeight;
1639
1640 // load mip-maps
1641 for(int i = 0; i < (int) ddsHeader.dwMipMapCount; ++i) {
1642 if (w == 0) w = 1;
1643 if (h == 0) h = 1;
1644
1645 size = ((w+3)/4) * ((h+3)/4) * blockSize;
1646 qt_glCompressedTexImage2DARB(GL_TEXTURE_2D, i, format, w, h, 0,
1647 size, pixels + offset);
1648 offset += size;
1649
1650 // half size for each mip-map level
1651 w = w/2;
1652 h = h/2;
1653 }
1654
1655 free(pixels);
1656
1657 qgl_dds_cache()->insert(fileName, tx_id);
1658 return tx_id;
1659}
1660
1661/*
1662 a hook that removes textures from the cache when a pixmap/image
1663 is deref'ed
1664*/
1665static void qt_gl_clean_cache(qint64 cacheKey)
1666{
1667 // ### remove when the GL texture cache becomes thread-safe
1668 if (qApp->thread() != QThread::currentThread())
1669 return;
1670 if (qt_tex_cache) {
1671 QGLTexture *texture = qt_tex_cache->object(cacheKey);
1672 if (texture && texture->clean)
1673 qt_tex_cache->remove(cacheKey);
1674 }
1675}
1676
1677static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format)
1678{
1679 Q_ASSERT(dst.size() == img.size());
1680 Q_ASSERT(dst.depth() == 32);
1681 Q_ASSERT(img.depth() == 32);
1682
1683 const int width = img.width();
1684 const int height = img.height();
1685 const uint *p = (const uint*) img.scanLine(img.height() - 1);
1686 uint *q = (uint*) dst.scanLine(0);
1687
1688 if (texture_format == GL_BGRA) {
1689 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
1690 // mirror + swizzle
1691 for (int i=0; i < height; ++i) {
1692 const uint *end = p + width;
1693 while (p < end) {
1694 *q = ((*p << 24) & 0xff000000)
1695 | ((*p >> 24) & 0x000000ff)
1696 | ((*p << 8) & 0x00ff0000)
1697 | ((*p >> 8) & 0x0000ff00);
1698 p++;
1699 q++;
1700 }
1701 p -= 2 * width;
1702 }
1703 } else {
1704 const uint bytesPerLine = img.bytesPerLine();
1705 for (int i=0; i < height; ++i) {
1706 memcpy(q, p, bytesPerLine);
1707 q += width;
1708 p -= width;
1709 }
1710 }
1711 } else {
1712 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
1713 for (int i=0; i < height; ++i) {
1714 const uint *end = p + width;
1715 while (p < end) {
1716 *q = (*p << 8) | ((*p >> 24) & 0xFF);
1717 p++;
1718 q++;
1719 }
1720 p -= 2 * width;
1721 }
1722 } else {
1723 for (int i=0; i < height; ++i) {
1724 const uint *end = p + width;
1725 while (p < end) {
1726 *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
1727 p++;
1728 q++;
1729 }
1730 p -= 2 * width;
1731 }
1732 }
1733 }
1734}
1735
1736QImage QGLContextPrivate::convertToGLFormat(const QImage &image, bool force_premul,
1737 GLenum texture_format)
1738{
1739 QImage::Format target_format = image.format();
1740 if (force_premul || image.format() != QImage::Format_ARGB32)
1741 target_format = QImage::Format_ARGB32_Premultiplied;
1742
1743 QImage result(image.width(), image.height(), target_format);
1744 convertToGLFormatHelper(result, image.convertToFormat(target_format), texture_format);
1745 return result;
1746}
1747
1748GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format,
1749 const qint64 key, bool clean)
1750{
1751 Q_Q(QGLContext);
1752
1753 QGLContext *ctx = q;
1754
1755 bool use_pbo = false;
1756 if (QGLExtensions::glExtensions & QGLExtensions::PixelBufferObject) {
1757
1758 use_pbo = qt_resolve_buffer_extensions(ctx);
1759 if (use_pbo && pbo == 0)
1760 glGenBuffersARB(1, &pbo);
1761 }
1762
1763 // the GL_BGRA format is only present in GL version >= 1.2
1764 GLenum texture_format = (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2)
1765 ? GL_BGRA : GL_RGBA;
1766 if (!qt_tex_cache) {
1767 qt_tex_cache = new QGLTextureCache(qt_tex_cache_limit);
1768 qt_pixmap_cleanup_hook_64 = qt_gl_clean_cache;
1769 qt_image_cleanup_hook_64 = qt_gl_clean_cache;
1770 }
1771
1772 // Scale the pixmap if needed. GL textures needs to have the
1773 // dimensions 2^n+2(border) x 2^m+2(border).
1774 int tx_w = qt_next_power_of_two(image.width());
1775 int tx_h = qt_next_power_of_two(image.height());
1776
1777 // Note: the clean param is only true when a texture is bound
1778 // from the QOpenGLPaintEngine - in that case we have to force
1779 // a premultiplied texture format
1780 QImage img = image;
1781 if (( !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) &&
1782 !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0) )
1783 && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height())))
1784 {
1785 img = image.scaled(tx_w, tx_h);
1786 }
1787
1788 GLuint tx_id;
1789 glGenTextures(1, &tx_id);
1790 glBindTexture(target, tx_id);
1791 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1792 if (glFormat.directRendering()
1793 && QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap
1794 && target == GL_TEXTURE_2D && !clean)
1795 {
1796 glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
1797#ifndef QT_OPENGL_ES
1798 glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
1799#else
1800 glTexParameterf(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
1801#endif
1802 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
1803
1804 // Mipmap generation causes huge slowdown with PBO's for some reason
1805 use_pbo = false;
1806 } else {
1807 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1808 }
1809
1810 uchar *ptr = 0;
1811 if (use_pbo) {
1812 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
1813 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, img.width() * img.height() * 4, 0, GL_STREAM_DRAW_ARB);
1814 ptr = reinterpret_cast<uchar *>(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB));
1815 }
1816
1817 if (ptr) {
1818 QImage::Format target_format = img.format();
1819 if (clean || img.format() != QImage::Format_ARGB32)
1820 target_format = QImage::Format_ARGB32_Premultiplied;
1821
1822 QImage buffer(ptr, img.width(), img.height(), target_format);
1823 convertToGLFormatHelper(buffer, img.convertToFormat(target_format), texture_format);
1824 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
1825 glTexImage2D(target, 0, format, img.width(), img.height(), 0, texture_format, GL_UNSIGNED_BYTE, 0);
1826 } else {
1827 QImage tx = convertToGLFormat(img, clean, texture_format);
1828 glTexImage2D(target, 0, format, tx.width(), tx.height(), 0, texture_format,
1829 GL_UNSIGNED_BYTE, tx.bits());
1830 }
1831
1832 if (use_pbo)
1833 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
1834
1835 // this assumes the size of a texture is always smaller than the max cache size
1836 int cost = img.width()*img.height()*4/1024;
1837 if (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost()) {
1838 // the cache is full - make an attempt to remove something
1839 const QList<qint64> keys = qt_tex_cache->keys();
1840 int i = 0;
1841 while (i < qt_tex_cache->count()
1842 && (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost())) {
1843 QGLTexture *tex = qt_tex_cache->object(keys.at(i));
1844 if (tex->context == q)
1845 qt_tex_cache->remove(keys.at(i));
1846 ++i;
1847 }
1848 }
1849 qt_tex_cache->insert(key, new QGLTexture(q, tx_id, target, clean), cost);
1850 return tx_id;
1851}
1852
1853bool QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target, GLuint *id)
1854{
1855 Q_Q(QGLContext);
1856 if (qt_tex_cache) {
1857 QGLTexture *texture = qt_tex_cache->object(key);
1858 if (texture && texture->target == target
1859 && (texture->context == q || qgl_share_reg()->checkSharing(q, texture->context)))
1860 {
1861 *id = texture->id;
1862 return true;
1863 }
1864 }
1865 return false;
1866}
1867
1868/*! \internal */
1869GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, bool clean)
1870{
1871 const qint64 key = image.cacheKey();
1872 GLuint id;
1873 if (textureCacheLookup(key, target, &id)) {
1874 glBindTexture(target, id);
1875 return id;
1876 }
1877 GLuint cached = bindTexture(image, target, format, key, clean);
1878 const_cast<QImage &>(image).data_ptr()->is_cached = (cached > 0);
1879 return cached;
1880}
1881
1882/*! \internal */
1883GLuint QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean)
1884{
1885#if !defined(QT_OPENGL_ES_2)
1886 if (target == qt_gl_preferredTextureTarget() && pixmap.pixmapData()->classId() == QPixmapData::OpenGLClass) {
1887 const QGLPixmapData *data = static_cast<const QGLPixmapData *>(pixmap.pixmapData());
1888
1889 if (data->isValidContext(QGLContext::currentContext()))
1890 return data->bind();
1891 }
1892#endif
1893
1894 const qint64 key = pixmap.cacheKey();
1895 GLuint id;
1896 if (textureCacheLookup(key, target, &id)) {
1897 glBindTexture(target, id);
1898 return id;
1899 }
1900 GLuint cached = bindTexture(pixmap.toImage(), target, format, key, clean);
1901 const_cast<QPixmap &>(pixmap).data_ptr()->is_cached = (cached > 0);
1902 return cached;
1903}
1904
1905/*! \internal */
1906int QGLContextPrivate::maxTextureSize()
1907{
1908 if (max_texture_size != -1)
1909 return max_texture_size;
1910
1911 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
1912
1913#if defined(QT_OPENGL_ES)
1914 return max_texture_size;
1915#else
1916 GLenum proxy = GL_PROXY_TEXTURE_2D;
1917
1918 GLint size;
1919 GLint next = 64;
1920 glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
1921 glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size);
1922 if (size == 0) {
1923 return max_texture_size;
1924 }
1925 do {
1926 size = next;
1927 next = size * 2;
1928
1929 if (next > max_texture_size)
1930 break;
1931 glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
1932 glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next);
1933 } while (next > size);
1934
1935 max_texture_size = size;
1936 return max_texture_size;
1937#endif
1938}
1939
1940/*!
1941 Generates and binds a 2D GL texture to the current context, based
1942 on \a image. The generated texture id is returned and can be used
1943 in later \c glBindTexture() calls.
1944
1945 The \a target parameter specifies the texture target. The default
1946 target is \c GL_TEXTURE_2D.
1947
1948 The \a format parameter sets the internal format for the
1949 texture. The default format is \c GL_RGBA8.
1950
1951 If the GL implementation supports the \c GL_SGIS_generate_mipmap
1952 extension, mipmaps will be automatically generated for the
1953 texture. Mipmap generation is only supported for the \c
1954 GL_TEXTURE_2D target.
1955
1956 The texture that is generated is cached, so multiple calls to
1957 bindTexture() with the same QImage will return the same texture
1958 id.
1959
1960 Note that we assume default values for the glPixelStore() and
1961 glPixelTransfer() parameters.
1962
1963 \sa deleteTexture()
1964*/
1965GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
1966{
1967 Q_D(QGLContext);
1968 return d->bindTexture(image, target, format, false);
1969}
1970
1971#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
1972/*! \internal */
1973GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
1974{
1975 Q_D(QGLContext);
1976 return d->bindTexture(image, GLenum(target), GLint(format), false);
1977}
1978#endif
1979
1980/*! \overload
1981
1982 Generates and binds a 2D GL texture based on \a pixmap.
1983*/
1984GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
1985{
1986 Q_D(QGLContext);
1987 return d->bindTexture(pixmap, target, format, false);
1988}
1989
1990#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
1991/*! \internal */
1992GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format)
1993{
1994 Q_D(QGLContext);
1995 return d->bindTexture(pixmap, GLenum(target), GLint(format), false);
1996}
1997#endif
1998
1999/*!
2000 Removes the texture identified by \a id from the texture cache,
2001 and calls glDeleteTextures() to delete the texture from the
2002 context.
2003
2004 \sa bindTexture()
2005*/
2006void QGLContext::deleteTexture(GLuint id)
2007{
2008 if (qt_tex_cache) {
2009 QList<qint64> keys = qt_tex_cache->keys();
2010 for (int i = 0; i < keys.size(); ++i) {
2011 QGLTexture *tex = qt_tex_cache->object(keys.at(i));
2012 if (tex->id == id && tex->context == this) {
2013 tex->clean = true; // forces a glDeleteTextures() call
2014 qt_tex_cache->remove(keys.at(i));
2015 return;
2016 }
2017 }
2018 }
2019
2020 // check the DDS cache if the texture wasn't found in the pixmap/image
2021 // cache
2022 QList<QString> ddsKeys = qgl_dds_cache()->keys();
2023 for (int i = 0; i < ddsKeys.size(); ++i) {
2024 GLuint texture = qgl_dds_cache()->value(ddsKeys.at(i));
2025 if (id == texture) {
2026 glDeleteTextures(1, &texture);
2027 qgl_dds_cache()->remove(ddsKeys.at(i));
2028 return;
2029 }
2030 }
2031}
2032
2033#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
2034/*! \internal */
2035void QGLContext::deleteTexture(QMacCompatGLuint id)
2036{
2037 return deleteTexture(GLuint(id));
2038}
2039#endif
2040
2041// qpaintengine_opengl.cpp
2042#if !defined(QT_OPENGL_ES_2)
2043extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array);
2044#else
2045void qt_add_rect_to_array(const QRectF &r, q_vertexType *array) {};
2046#endif
2047
2048static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint textureHeight, GLenum textureTarget)
2049{
2050 q_vertexType tx = f2vt(1);
2051 q_vertexType ty = f2vt(1);
2052
2053#ifdef QT_OPENGL_ES
2054 Q_UNUSED(textureWidth);
2055 Q_UNUSED(textureHeight);
2056 Q_UNUSED(textureTarget);
2057#else
2058 if (textureTarget != GL_TEXTURE_2D) {
2059 if (textureWidth == -1 || textureHeight == -1) {
2060 glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_WIDTH, &textureWidth);
2061 glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_HEIGHT, &textureHeight);
2062 }
2063
2064 tx = f2vt(textureWidth);
2065 ty = f2vt(textureHeight);
2066 }
2067#endif
2068
2069 q_vertexType texCoordArray[4*2] = {
2070 0, ty, tx, ty, tx, 0, 0, 0
2071 };
2072
2073 q_vertexType vertexArray[4*2];
2074 qt_add_rect_to_array(target, vertexArray);
2075
2076#if !defined(QT_OPENGL_ES_2)
2077 glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
2078 glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray);
2079
2080 glEnableClientState(GL_VERTEX_ARRAY);
2081 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2082 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
2083
2084 glDisableClientState(GL_VERTEX_ARRAY);
2085 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
2086#endif
2087}
2088
2089/*!
2090 \since 4.4
2091
2092 Draws the given texture, \a textureId, to the given target rectangle,
2093 \a target, in OpenGL model space. The \a textureTarget should be a 2D
2094 texture target.
2095
2096 Equivalent to the corresponding QGLContext::drawTexture().
2097*/
2098void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
2099{
2100#ifdef QT_OPENGL_ES
2101 if (textureTarget != GL_TEXTURE_2D) {
2102 qWarning("QGLContext::drawTexture(): texture target must be GL_TEXTURE_2D on OpenGL ES");
2103 return;
2104 }
2105#else
2106 const bool wasEnabled = glIsEnabled(GL_TEXTURE_2D);
2107 GLint oldTexture;
2108 glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexture);
2109#endif
2110
2111 glEnable(textureTarget);
2112 glBindTexture(textureTarget, textureId);
2113
2114 qDrawTextureRect(target, -1, -1, textureTarget);
2115
2116#ifdef QT_OPENGL_ES
2117 glDisable(textureTarget);
2118#else
2119 if (!wasEnabled)
2120 glDisable(textureTarget);
2121 glBindTexture(textureTarget, oldTexture);
2122#endif
2123}
2124
2125#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
2126/*! \internal */
2127void QGLContext::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
2128{
2129 drawTexture(target, GLuint(textureId), GLenum(textureTarget));
2130}
2131#endif
2132
2133/*!
2134 \since 4.4
2135
2136 Draws the given texture at the given \a point in OpenGL model
2137 space. The \a textureTarget should be a 2D texture target.
2138
2139 Equivalent to the corresponding QGLContext::drawTexture().
2140*/
2141void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
2142{
2143 // this would be ok on OpenGL ES 2.0, but currently we don't have a define for that
2144#ifdef QT_OPENGL_ES
2145 Q_UNUSED(point);
2146 Q_UNUSED(textureId);
2147 Q_UNUSED(textureTarget);
2148 qWarning("drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget) not supported with OpenGL ES, use rect version instead");
2149#else
2150 const bool wasEnabled = glIsEnabled(GL_TEXTURE_2D);
2151 GLint oldTexture;
2152 glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexture);
2153
2154 glEnable(textureTarget);
2155 glBindTexture(textureTarget, textureId);
2156
2157 GLint textureWidth;
2158 GLint textureHeight;
2159
2160 glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_WIDTH, &textureWidth);
2161 glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_HEIGHT, &textureHeight);
2162
2163 qDrawTextureRect(QRectF(point, QSizeF(textureWidth, textureHeight)), textureWidth, textureHeight, textureTarget);
2164
2165 if (!wasEnabled)
2166 glDisable(textureTarget);
2167 glBindTexture(textureTarget, oldTexture);
2168#endif
2169}
2170
2171#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
2172/*! \internal */
2173void QGLContext::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
2174{
2175 drawTexture(point, GLuint(textureId), GLenum(textureTarget));
2176}
2177#endif
2178
2179
2180/*!
2181 This function sets the limit for the texture cache to \a size,
2182 expressed in kilobytes.
2183
2184 By default, the cache limit is approximately 64 MB.
2185
2186 \sa textureCacheLimit()
2187*/
2188void QGLContext::setTextureCacheLimit(int size)
2189{
2190 qt_tex_cache_limit = size;
2191 if (qt_tex_cache)
2192 qt_tex_cache->setMaxCost(qt_tex_cache_limit);
2193}
2194
2195/*!
2196 Returns the current texture cache limit in kilobytes.
2197
2198 \sa setTextureCacheLimit()
2199*/
2200int QGLContext::textureCacheLimit()
2201{
2202 return qt_tex_cache_limit;
2203}
2204
2205
2206/*!
2207 \fn QGLFormat QGLContext::format() const
2208
2209 Returns the frame buffer format that was obtained (this may be a
2210 subset of what was requested).
2211
2212 \sa requestedFormat()
2213*/
2214
2215/*!
2216 \fn QGLFormat QGLContext::requestedFormat() const
2217
2218 Returns the frame buffer format that was originally requested in
2219 the constructor or setFormat().
2220
2221 \sa format()
2222*/
2223
2224/*!
2225 Sets a \a format for this context. The context is \link reset()
2226 reset\endlink.
2227
2228 Call create() to create a new GL context that tries to match the
2229 new format.
2230
2231 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 7
2232
2233 \sa format(), reset(), create()
2234*/
2235
2236void QGLContext::setFormat(const QGLFormat &format)
2237{
2238 Q_D(QGLContext);
2239 reset();
2240 d->glFormat = d->reqFormat = format;
2241}
2242
2243/*!
2244 \internal
2245*/
2246void QGLContext::setDevice(QPaintDevice *pDev)
2247{
2248 Q_D(QGLContext);
2249 if (isValid())
2250 reset();
2251 d->paintDevice = pDev;
2252 if (d->paintDevice && (d->paintDevice->devType() != QInternal::Widget
2253 && d->paintDevice->devType() != QInternal::Pixmap
2254 && d->paintDevice->devType() != QInternal::Pbuffer)) {
2255 qWarning("QGLContext: Unsupported paint device type");
2256 }
2257}
2258
2259/*!
2260 \fn bool QGLContext::isValid() const
2261
2262 Returns true if a GL rendering context has been successfully
2263 created; otherwise returns false.
2264*/
2265
2266/*!
2267 \fn void QGLContext::setValid(bool valid)
2268 \internal
2269
2270 Forces the GL rendering context to be valid.
2271*/
2272
2273/*!
2274 \fn bool QGLContext::isSharing() const
2275
2276 Returns true if this context is sharing its GL context with
2277 another QGLContext, otherwise false is returned. Note that context
2278 sharing might not be supported between contexts with different
2279 formats.
2280*/
2281
2282/*!
2283 \fn bool QGLContext::deviceIsPixmap() const
2284
2285 Returns true if the paint device of this context is a pixmap;
2286 otherwise returns false.
2287*/
2288
2289/*!
2290 \fn bool QGLContext::windowCreated() const
2291
2292 Returns true if a window has been created for this context;
2293 otherwise returns false.
2294
2295 \sa setWindowCreated()
2296*/
2297
2298/*!
2299 \fn void QGLContext::setWindowCreated(bool on)
2300
2301 If \a on is true the context has had a window created for it. If
2302 \a on is false no window has been created for the context.
2303
2304 \sa windowCreated()
2305*/
2306
2307/*!
2308 \fn uint QGLContext::colorIndex(const QColor& c) const
2309
2310 \internal
2311
2312 Returns a colormap index for the color c, in ColorIndex mode. Used
2313 by qglColor() and qglClearColor().
2314*/
2315
2316
2317/*!
2318 \fn bool QGLContext::initialized() const
2319
2320 Returns true if this context has been initialized, i.e. if
2321 QGLWidget::initializeGL() has been performed on it; otherwise
2322 returns false.
2323
2324 \sa setInitialized()
2325*/
2326
2327/*!
2328 \fn void QGLContext::setInitialized(bool on)
2329
2330 If \a on is true the context has been initialized, i.e.
2331 QGLContext::setInitialized() has been called on it. If \a on is
2332 false the context has not been initialized.
2333
2334 \sa initialized()
2335*/
2336
2337/*!
2338 \fn const QGLContext* QGLContext::currentContext()
2339
2340 Returns the current context, i.e. the context to which any OpenGL
2341 commands will currently be directed. Returns 0 if no context is
2342 current.
2343
2344 \sa makeCurrent()
2345*/
2346
2347/*!
2348 \fn QColor QGLContext::overlayTransparentColor() const
2349
2350 If this context is a valid context in an overlay plane, returns
2351 the plane's transparent color. Otherwise returns an \link
2352 QColor::isValid() invalid \endlink color.
2353
2354 The returned color's \link QColor::pixel() pixel \endlink value is
2355 the index of the transparent color in the colormap of the overlay
2356 plane. (Naturally, the color's RGB values are meaningless.)
2357
2358 The returned QColor object will generally work as expected only
2359 when passed as the argument to QGLWidget::qglColor() or
2360 QGLWidget::qglClearColor(). Under certain circumstances it can
2361 also be used to draw transparent graphics with a QPainter. See the
2362 examples/opengl/overlay_x11 example for details.
2363*/
2364
2365
2366/*!
2367 Creates the GL context. Returns true if it was successful in
2368 creating a valid GL rendering context on the paint device
2369 specified in the constructor; otherwise returns false (i.e. the
2370 context is invalid).
2371
2372 After successful creation, format() returns the set of features of
2373 the created GL rendering context.
2374
2375 If \a shareContext points to a valid QGLContext, this method will
2376 try to establish OpenGL display list and texture object sharing
2377 between this context and the \a shareContext. Note that this may
2378 fail if the two contexts have different \l {format()} {formats}.
2379 Use isSharing() to see if sharing is in effect.
2380
2381 \warning Implementation note: initialization of C++ class
2382 members usually takes place in the class constructor. QGLContext
2383 is an exception because it must be simple to customize. The
2384 virtual functions chooseContext() (and chooseVisual() for X11) can
2385 be reimplemented in a subclass to select a particular context. The
2386 problem is that virtual functions are not properly called during
2387 construction (even though this is correct C++) because C++
2388 constructs class hierarchies from the bottom up. For this reason
2389 we need a create() function.
2390
2391 \sa chooseContext(), format(), isValid()
2392*/
2393
2394bool QGLContext::create(const QGLContext* shareContext)
2395{
2396 Q_D(QGLContext);
2397 if (!d->paintDevice)
2398 return false;
2399 reset();
2400 d->valid = chooseContext(shareContext);
2401 if (d->sharing) // ok, we managed to share
2402 qgl_share_reg()->addShare(this, shareContext);
2403 return d->valid;
2404}
2405
2406bool QGLContext::isValid() const
2407{
2408 Q_D(const QGLContext);
2409 return d->valid;
2410}
2411
2412void QGLContext::setValid(bool valid)
2413{
2414 Q_D(QGLContext);
2415 d->valid = valid;
2416}
2417
2418bool QGLContext::isSharing() const
2419{
2420 Q_D(const QGLContext);
2421 return d->sharing;
2422}
2423
2424QGLFormat QGLContext::format() const
2425{
2426 Q_D(const QGLContext);
2427 return d->glFormat;
2428}
2429
2430QGLFormat QGLContext::requestedFormat() const
2431{
2432 Q_D(const QGLContext);
2433 return d->reqFormat;
2434}
2435
2436 QPaintDevice* QGLContext::device() const
2437{
2438 Q_D(const QGLContext);
2439 return d->paintDevice;
2440}
2441
2442bool QGLContext::deviceIsPixmap() const
2443{
2444 Q_D(const QGLContext);
2445 return d->paintDevice->devType() == QInternal::Pixmap;
2446}
2447
2448
2449bool QGLContext::windowCreated() const
2450{
2451 Q_D(const QGLContext);
2452 return d->crWin;
2453}
2454
2455
2456void QGLContext::setWindowCreated(bool on)
2457{
2458 Q_D(QGLContext);
2459 d->crWin = on;
2460}
2461
2462bool QGLContext::initialized() const
2463{
2464 Q_D(const QGLContext);
2465 return d->initDone;
2466}
2467
2468void QGLContext::setInitialized(bool on)
2469{
2470 Q_D(QGLContext);
2471 d->initDone = on;
2472}
2473
2474const QGLContext* QGLContext::currentContext()
2475{
2476 if (qgl_context_storage.hasLocalData())
2477 return qgl_context_storage.localData()->context;
2478 return 0;
2479}
2480
2481/*!
2482 \fn bool QGLContext::chooseContext(const QGLContext* shareContext = 0)
2483
2484 This semi-internal function is called by create(). It creates a
2485 system-dependent OpenGL handle that matches the format() of \a
2486 shareContext as closely as possible, returning true if successful
2487 or false if a suitable handle could not be found.
2488
2489 On Windows, it calls the virtual function choosePixelFormat(),
2490 which finds a matching pixel format identifier. On X11, it calls
2491 the virtual function chooseVisual() which finds an appropriate X
2492 visual. On other platforms it may work differently.
2493*/
2494
2495
2496/*!
2497 \fn void QGLContext::reset()
2498
2499 Resets the context and makes it invalid.
2500
2501 \sa create(), isValid()
2502*/
2503
2504
2505/*!
2506 \fn void QGLContext::makeCurrent()
2507
2508 Makes this context the current OpenGL rendering context. All GL
2509 functions you call operate on this context until another context
2510 is made current.
2511
2512 In some very rare cases the underlying call may fail. If this
2513 occurs an error message is output to stderr.
2514*/
2515
2516
2517/*!
2518 \fn void QGLContext::swapBuffers() const
2519
2520 Swaps the screen contents with an off-screen buffer. Only works if
2521 the context is in double buffer mode.
2522
2523 \sa QGLFormat::setDoubleBuffer()
2524*/
2525
2526
2527/*!
2528 \fn void QGLContext::doneCurrent()
2529
2530 Makes no GL context the current context. Normally, you do not need
2531 to call this function; QGLContext calls it as necessary.
2532*/
2533
2534
2535/*!
2536 \fn QPaintDevice* QGLContext::device() const
2537
2538 Returns the paint device set for this context.
2539
2540 \sa QGLContext::QGLContext()
2541*/
2542
2543/*!
2544 \obsolete
2545 \fn void QGLContext::generateFontDisplayLists(const QFont& font, int listBase)
2546
2547 Generates a set of 256 display lists for the 256 first characters
2548 in the font \a font. The first list will start at index \a listBase.
2549
2550 \sa QGLWidget::renderText()
2551*/
2552
2553
2554/*****************************************************************************
2555 QGLWidget implementation
2556 *****************************************************************************/
2557
2558
2559/*!
2560 \class QGLWidget
2561 \brief The QGLWidget class is a widget for rendering OpenGL graphics.
2562
2563 \ingroup multimedia
2564 \mainclass
2565
2566 QGLWidget provides functionality for displaying OpenGL graphics
2567 integrated into a Qt application. It is very simple to use. You
2568 inherit from it and use the subclass like any other QWidget,
2569 except that you have the choice between using QPainter and
2570 standard OpenGL rendering commands.
2571
2572 QGLWidget provides three convenient virtual functions that you can
2573 reimplement in your subclass to perform the typical OpenGL tasks:
2574
2575 \list
2576 \i paintGL() - Renders the OpenGL scene. Gets called whenever the widget
2577 needs to be updated.
2578 \i resizeGL() - Sets up the OpenGL viewport, projection, etc. Gets
2579 called whenever the the widget has been resized (and also when it
2580 is shown for the first time because all newly created widgets get a
2581 resize event automatically).
2582 \i initializeGL() - Sets up the OpenGL rendering context, defines display
2583 lists, etc. Gets called once before the first time resizeGL() or
2584 paintGL() is called.
2585 \endlist
2586
2587 Here is a rough outline of how a QGLWidget subclass might look:
2588
2589 \snippet doc/src/snippets/code/src_opengl_qgl.cpp 8
2590
2591 If you need to trigger a repaint from places other than paintGL()
2592 (a typical example is when using \link QTimer timers\endlink to
2593 animate scenes), you should call the widget's updateGL() function.
2594
2595 Your widget's OpenGL rendering context is made current when
2596 paintGL(), resizeGL(), or initializeGL() is called. If you need to
2597 call the standard OpenGL API functions from other places (e.g. in
2598 your widget's constructor or in your own paint functions), you
2599 must call makeCurrent() first.
2600
2601 QGLWidget provides functions for requesting a new display \link
2602 QGLFormat format\endlink and you can also create widgets with
2603 customized rendering \link QGLContext contexts\endlink.
2604
2605 You can also share OpenGL display lists between QGLWidgets (see
2606 the documentation of the QGLWidget constructors for details).
2607
2608 Note that under Windows, the QGLContext belonging to a QGLWidget
2609 has to be recreated when the QGLWidget is reparented. This is
2610 necessary due to limitations on the Windows platform. This will
2611 most likely cause problems for users that have subclassed and
2612 installed their own QGLContext on a QGLWidget. It is possible to
2613 work around this issue by putting the QGLWidget inside a dummy
2614 widget and then reparenting the dummy widget, instead of the
2615 QGLWidget. This will side-step the issue altogether, and is what
2616 we recommend for users that need this kind of functionality.
2617
2618 On Mac OS X, when Qt is built with Cocoa support, a QGLWidget
2619 can't have any sibling widgets placed ontop of itself. This is due
2620 to limitations in the Cocoa API and is not supported by Apple.
2621
2622 \section1 Overlays
2623
2624 The QGLWidget creates a GL overlay context in addition to the
2625 normal context if overlays are supported by the underlying system.
2626
2627 If you want to use overlays, you specify it in the \link QGLFormat
2628 format\endlink. (Note: Overlay must be requested in the format
2629 passed to the QGLWidget constructor.) Your GL widget should also
2630 implement some or all of these virtual methods:
2631
2632 \list
2633 \i paintOverlayGL()
2634 \i resizeOverlayGL()
2635 \i initializeOverlayGL()
2636 \endlist
2637
2638 These methods work in the same way as the normal paintGL() etc.
2639 functions, except that they will be called when the overlay
2640 context is made current. You can explicitly make the overlay
2641 context current by using makeOverlayCurrent(), and you can access
2642 the overlay context directly (e.g. to ask for its transparent
2643 color) by calling overlayContext().
2644
2645 On X servers in which the default visual is in an overlay plane,
2646 non-GL Qt windows can also be used for overlays.
2647
2648 \section1 Painting Techniques
2649
2650 As described above, subclass QGLWidget to render pure 3D content in the
2651 following way:
2652
2653 \list
2654 \o Reimplement the QGLWidget::initializeGL() and QGLWidget::resizeGL() to
2655 set up the OpenGL state and provide a perspective transformation.
2656 \o Reimplement QGLWidget::paintGL() to paint the 3D scene, calling only
2657 OpenGL functions to draw on the widget.
2658 \endlist
2659
2660 It is also possible to draw 2D graphics onto a QGLWidget subclass, it is necessary
2661 to reimplement QGLWidget::paintEvent() and do the following:
2662
2663 \list
2664 \o Construct a QPainter object.
2665 \o Initialize it for use on the widget with the QPainter::begin() function.
2666 \o Draw primitives using QPainter's member functions.
2667 \o Call QPainter::end() to finish painting.
2668 \endlist
2669
2670 Overpainting 2D content on top of 3D content takes a little more effort.
2671 One approach to doing this is shown in the
2672 \l{Overpainting Example}{Overpainting} example.
2673
2674 \e{OpenGL is a trademark of Silicon Graphics, Inc. in the United States and other
2675 countries.}
2676
2677 \sa QGLPixelBuffer, {Hello GL Example}, {2D Painting Example}, {Overpainting Example},
2678 {Grabber Example}
2679*/
2680
2681/*!
2682 Constructs an OpenGL widget with a \a parent widget.
2683
2684 The \link QGLFormat::defaultFormat() default format\endlink is
2685 used. The widget will be \link isValid() invalid\endlink if the
2686 system has no \link QGLFormat::hasOpenGL() OpenGL support\endlink.
2687
2688 The \a parent and widget flag, \a f, arguments are passed
2689 to the QWidget constructor.
2690
2691 If \a shareWidget is a valid QGLWidget, this widget will share
2692 OpenGL display lists and texture objects with \a shareWidget. But
2693 if \a shareWidget and this widget have different \l {format()}
2694 {formats}, sharing might not be possible. You can check whether
2695 sharing is in effect by calling isSharing().
2696
2697 The initialization of OpenGL rendering state, etc. should be done
2698 by overriding the initializeGL() function, rather than in the
2699 constructor of your QGLWidget subclass.
2700
2701 \sa QGLFormat::defaultFormat(), {Textures Example}
2702*/
2703
2704QGLWidget::QGLWidget(QWidget *parent, const QGLWidget* shareWidget, Qt::WindowFlags f)
2705 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
2706{
2707 Q_D(QGLWidget);
2708 setAttribute(Qt::WA_PaintOnScreen);
2709 setAttribute(Qt::WA_NoSystemBackground);
2710 setAutoFillBackground(true); // for compatibility
2711 d->init(new QGLContext(QGLFormat::defaultFormat(), this), shareWidget);
2712}
2713
2714
2715/*!
2716 Constructs an OpenGL widget with parent \a parent.
2717
2718 The \a format argument specifies the desired \link QGLFormat
2719 rendering options \endlink. If the underlying OpenGL/Window system
2720 cannot satisfy all the features requested in \a format, the
2721 nearest subset of features will be used. After creation, the
2722 format() method will return the actual format obtained.
2723
2724 The widget will be \link isValid() invalid\endlink if the system
2725 has no \link QGLFormat::hasOpenGL() OpenGL support\endlink.
2726
2727 The \a parent and widget flag, \a f, arguments are passed
2728 to the QWidget constructor.
2729
2730 If \a shareWidget is a valid QGLWidget, this widget will share
2731 OpenGL display lists and texture objects with \a shareWidget. But
2732 if \a shareWidget and this widget have different \l {format()}
2733 {formats}, sharing might not be possible. You can check whether
2734 sharing is in effect by calling isSharing().
2735
2736 The initialization of OpenGL rendering state, etc. should be done
2737 by overriding the initializeGL() function, rather than in the
2738 constructor of your QGLWidget subclass.
2739
2740 \sa QGLFormat::defaultFormat(), isValid()
2741*/
2742
2743QGLWidget::QGLWidget(const QGLFormat &format, QWidget *parent, const QGLWidget* shareWidget,
2744 Qt::WindowFlags f)
2745 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
2746{
2747 Q_D(QGLWidget);
2748 setAttribute(Qt::WA_PaintOnScreen);
2749 setAttribute(Qt::WA_NoSystemBackground);
2750 setAutoFillBackground(true); // for compatibility
2751 d->init(new QGLContext(format, this), shareWidget);
2752}
2753
2754/*!
2755 Constructs an OpenGL widget with parent \a parent.
2756
2757 The \a context argument is a pointer to the QGLContext that
2758 you wish to be bound to this widget. This allows you to pass in
2759 your own QGLContext sub-classes.
2760
2761 The widget will be \link isValid() invalid\endlink if the system
2762 has no \link QGLFormat::hasOpenGL() OpenGL support\endlink.
2763
2764 The \a parent and widget flag, \a f, arguments are passed
2765 to the QWidget constructor.
2766
2767 If \a shareWidget is a valid QGLWidget, this widget will share
2768 OpenGL display lists and texture objects with \a shareWidget. But
2769 if \a shareWidget and this widget have different \l {format()}
2770 {formats}, sharing might not be possible. You can check whether
2771 sharing is in effect by calling isSharing().
2772
2773 The initialization of OpenGL rendering state, etc. should be done
2774 by overriding the initializeGL() function, rather than in the
2775 constructor of your QGLWidget subclass.
2776
2777 \sa QGLFormat::defaultFormat(), isValid()
2778*/
2779QGLWidget::QGLWidget(QGLContext *context, QWidget *parent, const QGLWidget *shareWidget,
2780 Qt::WindowFlags f)
2781 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
2782{
2783 Q_D(QGLWidget);
2784 setAttribute(Qt::WA_PaintOnScreen);
2785 setAttribute(Qt::WA_NoSystemBackground);
2786 setAutoFillBackground(true); // for compatibility
2787 d->init(context, shareWidget);
2788}
2789
2790/*!
2791 Destroys the widget.
2792*/
2793
2794QGLWidget::~QGLWidget()
2795{
2796 Q_D(QGLWidget);
2797#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT)
2798 bool doRelease = (glcx && glcx->windowCreated());
2799#endif
2800 delete d->glcx;
2801#if defined(Q_WGL)
2802 delete d->olcx;
2803#endif
2804#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT)
2805 if (doRelease)
2806 glXReleaseBuffersMESA(x11Display(), winId());
2807#endif
2808 d->cleanupColormaps();
2809
2810#ifdef Q_WS_MAC
2811 QWidget *current = parentWidget();
2812 while (current) {
2813 qt_widget_private(current)->glWidgets.removeAll(QWidgetPrivate::GlWidgetInfo(this));
2814 if (current->isWindow())
2815 break;
2816 current = current->parentWidget();
2817 };
2818#endif
2819}
2820
2821/*!
2822 \fn QGLFormat QGLWidget::format() const
2823
2824 Returns the format of the contained GL rendering context.
2825*/
2826
2827/*!
2828 \fn bool QGLWidget::doubleBuffer() const
2829
2830 Returns true if the contained GL rendering context has double
2831 buffering; otherwise returns false.
2832
2833 \sa QGLFormat::doubleBuffer()
2834*/
2835
2836/*!
2837 \fn void QGLWidget::setAutoBufferSwap(bool on)
2838
2839 If \a on is true automatic GL buffer swapping is switched on;
2840 otherwise it is switched off.
2841
2842 If \a on is true and the widget is using a double-buffered format,
2843 the background and foreground GL buffers will automatically be
2844 swapped after each paintGL() call.
2845
2846 The buffer auto-swapping is on by default.
2847
2848 \sa autoBufferSwap(), doubleBuffer(), swapBuffers()
2849*/
2850
2851/*!
2852 \fn bool QGLWidget::autoBufferSwap() const
2853
2854 Returns true if the widget is doing automatic GL buffer swapping;
2855 otherwise returns false.
2856
2857 \sa setAutoBufferSwap()
2858*/
2859
2860/*!
2861 \fn void *QGLContext::getProcAddress(const QString &proc) const
2862
2863 Returns a function pointer to the GL extension function passed in
2864 \a proc. 0 is returned if a pointer to the function could not be
2865 obtained.
2866*/
2867
2868/*!
2869 \fn bool QGLWidget::isValid() const
2870
2871 Returns true if the widget has a valid GL rendering context;
2872 otherwise returns false. A widget will be invalid if the system
2873 has no \link QGLFormat::hasOpenGL() OpenGL support\endlink.
2874*/
2875
2876bool QGLWidget::isValid() const
2877{
2878 Q_D(const QGLWidget);
2879 return d->glcx && d->glcx->isValid();
2880}
2881
2882/*!
2883 \fn bool QGLWidget::isSharing() const
2884
2885 Returns true if this widget's GL context is shared with another GL
2886 context, otherwise false is returned. Context sharing might not be
2887 possible if the QGLWidgets use different formats.
2888
2889 \sa format()
2890*/
2891
2892bool QGLWidget::isSharing() const
2893{
2894 Q_D(const QGLWidget);
2895 return d->glcx->isSharing();
2896}
2897
2898/*!
2899 \fn void QGLWidget::makeCurrent()
2900
2901 Makes this widget the current widget for OpenGL operations, i.e.
2902 makes the widget's rendering context the current OpenGL rendering
2903 context.
2904*/
2905
2906void QGLWidget::makeCurrent()
2907{
2908 Q_D(QGLWidget);
2909 d->glcx->makeCurrent();
2910}
2911
2912/*!
2913 \fn void QGLWidget::doneCurrent()
2914
2915 Makes no GL context the current context. Normally, you do not need
2916 to call this function; QGLContext calls it as necessary. However,
2917 it may be useful in multithreaded environments.
2918*/
2919
2920void QGLWidget::doneCurrent()
2921{
2922 Q_D(QGLWidget);
2923 d->glcx->doneCurrent();
2924}
2925
2926/*!
2927 \fn void QGLWidget::swapBuffers()
2928
2929 Swaps the screen contents with an off-screen buffer. This only
2930 works if the widget's format specifies double buffer mode.
2931
2932 Normally, there is no need to explicitly call this function
2933 because it is done automatically after each widget repaint, i.e.
2934 each time after paintGL() has been executed.
2935
2936 \sa doubleBuffer(), setAutoBufferSwap(), QGLFormat::setDoubleBuffer()
2937*/
2938
2939void QGLWidget::swapBuffers()
2940{
2941 Q_D(QGLWidget);
2942 d->glcx->swapBuffers();
2943}
2944
2945
2946/*!
2947 \fn const QGLContext* QGLWidget::overlayContext() const
2948
2949 Returns the overlay context of this widget, or 0 if this widget
2950 has no overlay.
2951
2952 \sa context()
2953*/
2954
2955
2956
2957/*!
2958 \fn void QGLWidget::makeOverlayCurrent()
2959
2960 Makes the overlay context of this widget current. Use this if you
2961 need to issue OpenGL commands to the overlay context outside of
2962 initializeOverlayGL(), resizeOverlayGL(), and paintOverlayGL().
2963
2964 Does nothing if this widget has no overlay.
2965
2966 \sa makeCurrent()
2967*/
2968
2969
2970/*!
2971 \obsolete
2972
2973 Sets a new format for this widget.
2974
2975 If the underlying OpenGL/Window system cannot satisfy all the
2976 features requested in \a format, the nearest subset of features will
2977 be used. After creation, the format() method will return the actual
2978 rendering context format obtained.
2979
2980 The widget will be assigned a new QGLContext, and the initializeGL()
2981 function will be executed for this new context before the first
2982 resizeGL() or paintGL().
2983
2984 This method will try to keep display list and texture object sharing
2985 in effect with other QGLWidgets, but changing the format might make
2986 sharing impossible. Use isSharing() to see if sharing is still in
2987 effect.
2988
2989 \sa format(), isSharing(), isValid()
2990*/
2991
2992void QGLWidget::setFormat(const QGLFormat &format)
2993{
2994 setContext(new QGLContext(format,this));
2995}
2996
2997
2998
2999
3000/*!
3001 \fn const QGLContext *QGLWidget::context() const
3002
3003 Returns the context of this widget.
3004
3005 It is possible that the context is not valid (see isValid()), for
3006 example, if the underlying hardware does not support the format
3007 attributes that were requested.
3008*/
3009
3010/*
3011 \obsolete
3012
3013 \fn void QGLWidget::setContext(QGLContext *context,
3014 const QGLContext* shareContext,
3015 bool deleteOldContext)
3016
3017 Sets a new context for this widget. The QGLContext \a context must
3018 be created using \e new. QGLWidget will delete \a context when
3019 another context is set or when the widget is destroyed.
3020
3021 If \a context is invalid, QGLContext::create() is performed on
3022 it. The initializeGL() function will then be executed for the new
3023 context before the first resizeGL() or paintGL().
3024
3025 If \a context is invalid, this method will try to keep display list
3026 and texture object sharing in effect, or (if \a shareContext points
3027 to a valid context) start display list and texture object sharing
3028 with that context, but sharing might be impossible if the two
3029 contexts have different \l {format()} {formats}. Use isSharing() to
3030 see whether sharing is in effect.
3031
3032 If \a deleteOldContext is true (the default), the existing context
3033 will be deleted. You may use false here if you have kept a pointer
3034 to the old context (as returned by context()), and want to restore
3035 that context later.
3036
3037 \sa context(), isSharing()
3038*/
3039
3040
3041
3042/*!
3043 \fn void QGLWidget::updateGL()
3044
3045 Updates the widget by calling glDraw().
3046*/
3047
3048void QGLWidget::updateGL()
3049{
3050 if (updatesEnabled())
3051 glDraw();
3052}
3053
3054
3055/*!
3056 \fn void QGLWidget::updateOverlayGL()
3057
3058 Updates the widget's overlay (if any). Will cause the virtual
3059 function paintOverlayGL() to be executed.
3060
3061 The widget's rendering context will become the current context and
3062 initializeGL() will be called if it hasn't already been called.
3063*/
3064
3065
3066/*!
3067 This virtual function is called once before the first call to
3068 paintGL() or resizeGL(), and then once whenever the widget has
3069 been assigned a new QGLContext. Reimplement it in a subclass.
3070
3071 This function should set up any required OpenGL context rendering
3072 flags, defining display lists, etc.
3073
3074 There is no need to call makeCurrent() because this has already
3075 been done when this function is called.
3076*/
3077
3078void QGLWidget::initializeGL()
3079{
3080}
3081
3082
3083/*!
3084 This virtual function is called whenever the widget needs to be
3085 painted. Reimplement it in a subclass.
3086
3087 There is no need to call makeCurrent() because this has already
3088 been done when this function is called.
3089*/
3090
3091void QGLWidget::paintGL()
3092{
3093}
3094
3095
3096/*!
3097 \fn void QGLWidget::resizeGL(int width , int height)
3098
3099 This virtual function is called whenever the widget has been
3100 resized. The new size is passed in \a width and \a height.
3101 Reimplement it in a subclass.
3102
3103 There is no need to call makeCurrent() because this has already
3104 been done when this function is called.
3105*/
3106
3107void QGLWidget::resizeGL(int, int)
3108{
3109}
3110
3111
3112
3113/*!
3114 This virtual function is used in the same manner as initializeGL()
3115 except that it operates on the widget's overlay context instead of
3116 the widget's main context. This means that initializeOverlayGL()
3117 is called once before the first call to paintOverlayGL() or
3118 resizeOverlayGL(). Reimplement it in a subclass.
3119
3120 This function should set up any required OpenGL context rendering
3121 flags, defining display lists, etc. for the overlay context.
3122
3123 There is no need to call makeOverlayCurrent() because this has
3124 already been done when this function is called.
3125*/
3126
3127void QGLWidget::initializeOverlayGL()
3128{
3129}
3130
3131
3132/*!
3133 This virtual function is used in the same manner as paintGL()
3134 except that it operates on the widget's overlay context instead of
3135 the widget's main context. This means that paintOverlayGL() is
3136 called whenever the widget's overlay needs to be painted.
3137 Reimplement it in a subclass.
3138
3139 There is no need to call makeOverlayCurrent() because this has
3140 already been done when this function is called.
3141*/
3142
3143void QGLWidget::paintOverlayGL()
3144{
3145}
3146
3147
3148/*!
3149 \fn void QGLWidget::resizeOverlayGL(int width , int height)
3150
3151 This virtual function is used in the same manner as paintGL()
3152 except that it operates on the widget's overlay context instead of
3153 the widget's main context. This means that resizeOverlayGL() is
3154 called whenever the widget has been resized. The new size is
3155 passed in \a width and \a height. Reimplement it in a subclass.
3156
3157 There is no need to call makeOverlayCurrent() because this has
3158 already been done when this function is called.
3159*/
3160
3161void QGLWidget::resizeOverlayGL(int, int)
3162{
3163}
3164
3165
3166#if !defined(Q_OS_WINCE) && !defined(Q_WS_QWS)
3167/*! \reimp */
3168bool QGLWidget::event(QEvent *e)
3169{
3170 Q_D(QGLWidget);
3171
3172 if (e->type() == QEvent::Paint) {
3173 QPoint offset;
3174 QPaintDevice *redirectedDevice = d->redirected(&offset);
3175 if (redirectedDevice && redirectedDevice->devType() == QInternal::Pixmap) {
3176 d->restoreRedirected();
3177 QPixmap pixmap = renderPixmap();
3178 d->setRedirected(redirectedDevice, offset);
3179 QPainter p(redirectedDevice);
3180 p.drawPixmap(-offset, pixmap);
3181 return true;
3182 }
3183 }
3184
3185#if defined(Q_WS_X11)
3186 // prevents X errors on some systems, where we get a flush to a
3187 // hidden widget
3188 if (e->type() == QEvent::Hide) {
3189 makeCurrent();
3190 glFinish();
3191 doneCurrent();
3192 } else if (e->type() == QEvent::ParentChange) {
3193 if (d->glcx->d_func()->screen != d->xinfo.screen()) {
3194 setContext(new QGLContext(d->glcx->requestedFormat(), this));
3195 // ### recreating the overlay isn't supported atm
3196 }
3197#if defined(QT_OPENGL_ES)
3198 // The window may have been re-created during re-parent - if so, the EGL
3199 // surface will need to be re-created.
3200 d->recreateEglSurface(false);
3201#endif
3202 }
3203#elif defined(Q_WS_WIN)
3204 if (e->type() == QEvent::ParentChange) {
3205 QGLContext *newContext = new QGLContext(d->glcx->requestedFormat(), this);
3206 qgl_share_reg()->replaceShare(d->glcx, newContext);
3207 setContext(newContext);
3208 // the overlay needs to be recreated as well
3209 delete d->olcx;
3210 if (isValid() && context()->format().hasOverlay()) {
3211 d->olcx = new QGLContext(QGLFormat::defaultOverlayFormat(), this);
3212 if (!d->olcx->create(isSharing() ? d->glcx : 0)) {
3213 delete d->olcx;
3214 d->olcx = 0;
3215 d->glcx->d_func()->glFormat.setOverlay(false);
3216 }
3217 } else {
3218 d->olcx = 0;
3219 }
3220 } else if (e->type() == QEvent::Show) {
3221 if (!format().rgba())
3222 d->updateColormap();
3223 }
3224#elif defined(Q_WS_MAC)
3225 if (e->type() == QEvent::MacGLWindowChange
3226#if 0 //(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
3227 && ((QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 && isWindow())
3228 || QSysInfo::MacintoshVersion <= QSysInfo::MV_10_4)
3229#endif
3230 ) {
3231 if (d->needWindowChange) {
3232 d->needWindowChange = false;
3233 d->glcx->updatePaintDevice();
3234 update();
3235 }
3236 return true;
3237# if defined(QT_MAC_USE_COCOA)
3238 } else if (e->type() == QEvent::MacGLClearDrawable) {
3239 d->glcx->d_ptr->clearDrawable();
3240# endif
3241 }
3242#endif
3243
3244 return QWidget::event(e);
3245}
3246#endif
3247
3248/*!
3249 \fn void QGLWidget::paintEvent(QPaintEvent *event)
3250
3251 Handles paint events passed in the \a event parameter. Will cause
3252 the virtual paintGL() function to be called.
3253
3254 The widget's rendering context will become the current context and
3255 initializeGL() will be called if it hasn't already been called.
3256*/
3257
3258void QGLWidget::paintEvent(QPaintEvent *)
3259{
3260 if (updatesEnabled()) {
3261 glDraw();
3262 updateOverlayGL();
3263 }
3264}
3265
3266
3267/*!
3268 \fn void QGLWidget::resizeEvent(QResizeEvent *event)
3269
3270 Handles resize events that are passed in the \a event parameter.
3271 Calls the virtual function resizeGL().
3272*/
3273
3274
3275/*!
3276 \fn void QGLWidget::setMouseTracking(bool enable)
3277
3278 If \a enable is true then mouse tracking is enabled; otherwise it
3279 is disabled.
3280*/
3281
3282
3283/*!
3284 Renders the current scene on a pixmap and returns the pixmap.
3285
3286 You can use this method on both visible and invisible QGLWidgets.
3287
3288 This method will create a pixmap and a temporary QGLContext to
3289 render on the pixmap. It will then call initializeGL(),
3290 resizeGL(), and paintGL() on this context. Finally, the widget's
3291 original GL context is restored.
3292
3293 The size of the pixmap will be \a w pixels wide and \a h pixels
3294 high unless one of these parameters is 0 (the default), in which
3295 case the pixmap will have the same size as the widget.
3296
3297 If \a useContext is true, this method will try to be more
3298 efficient by using the existing GL context to render the pixmap.
3299 The default is false. Only use true if you understand the risks.
3300 Note that under Windows a temporary context has to be created
3301 and usage of the \e useContext parameter is not supported.
3302
3303 Overlays are not rendered onto the pixmap.
3304
3305 If the GL rendering context and the desktop have different bit
3306 depths, the result will most likely look surprising.
3307
3308 Note that the creation of display lists, modifications of the view
3309 frustum etc. should be done from within initializeGL(). If this is
3310 not done, the temporary QGLContext will not be initialized
3311 properly, and the rendered pixmap may be incomplete/corrupted.
3312*/
3313
3314QPixmap QGLWidget::renderPixmap(int w, int h, bool useContext)
3315{
3316 Q_D(QGLWidget);
3317 QSize sz = size();
3318 if ((w > 0) && (h > 0))
3319 sz = QSize(w, h);
3320
3321#if defined(Q_WS_X11)
3322 extern int qt_x11_preferred_pixmap_depth;
3323 int old_depth = qt_x11_preferred_pixmap_depth;
3324 qt_x11_preferred_pixmap_depth = x11Info().depth();
3325
3326 QPixmapData *data = new QX11PixmapData(QPixmapData::PixmapType);
3327 data->resize(sz.width(), sz.height());
3328 QPixmap pm(data);
3329 qt_x11_preferred_pixmap_depth = old_depth;
3330 QX11Info xinfo = x11Info();
3331
3332 // make sure we use a pixmap with the same depth/visual as the widget
3333 if (xinfo.visual() != QX11Info::appVisual()) {
3334 QX11InfoData* xd = pm.x11Info().getX11Data(true);
3335 xd->depth = xinfo.depth();
3336 xd->visual = static_cast<Visual *>(xinfo.visual());
3337 const_cast<QX11Info &>(pm.x11Info()).setX11Data(xd);
3338 }
3339
3340#else
3341 QPixmap pm(sz);
3342#endif
3343
3344 d->glcx->doneCurrent();
3345
3346 bool success = true;
3347
3348 if (useContext && isValid() && d->renderCxPm(&pm))
3349 return pm;
3350
3351 QGLFormat fmt = d->glcx->requestedFormat();
3352 fmt.setDirectRendering(false); // Direct is unlikely to work
3353 fmt.setDoubleBuffer(false); // We don't need dbl buf
3354#ifdef Q_WS_MAC // crash prevention on the Mac - it's unlikely to work anyway
3355 fmt.setSampleBuffers(false);
3356#endif
3357
3358 QGLContext* ocx = d->glcx;
3359 ocx->doneCurrent();
3360 d->glcx = new QGLContext(fmt, &pm);
3361 d->glcx->create();
3362
3363 if (d->glcx->isValid())
3364 updateGL();
3365 else
3366 success = false;
3367
3368 delete d->glcx;
3369 d->glcx = ocx;
3370
3371 ocx->makeCurrent();
3372
3373 if (success) {
3374#if defined(Q_WS_X11)
3375 if (xinfo.visual() != QX11Info::appVisual()) {
3376 QImage image = pm.toImage();
3377 QPixmap p = QPixmap::fromImage(image);
3378 return p;
3379 }
3380#endif
3381 return pm;
3382 }
3383 return QPixmap();
3384}
3385
3386/*!
3387 Returns an image of the frame buffer. If \a withAlpha is true the
3388 alpha channel is included.
3389
3390 Depending on your hardware, you can explicitly select which color
3391 buffer to grab with a glReadBuffer() call before calling this
3392 function.
3393*/
3394QImage QGLWidget::grabFrameBuffer(bool withAlpha)
3395{
3396 makeCurrent();
3397 QImage res;
3398 int w = width();
3399 int h = height();
3400 if (format().rgba()) {
3401 res = qt_gl_read_framebuffer(QSize(w, h), format().alpha(), withAlpha);
3402 } else {
3403#if defined (Q_WS_WIN) && !defined(QT_OPENGL_ES)
3404 res = QImage(w, h, QImage::Format_Indexed8);
3405 glReadPixels(0, 0, w, h, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, res.bits());
3406 const QVector<QColor> pal = QColormap::instance().colormap();
3407 if (pal.size()) {
3408 res.setNumColors(pal.size());
3409 for (int i = 0; i < pal.size(); i++)
3410 res.setColor(i, pal.at(i).rgb());
3411 }
3412 res = res.mirrored();
3413#endif
3414 }
3415
3416 return res;
3417}
3418
3419
3420
3421/*!
3422 Initializes OpenGL for this widget's context. Calls the virtual
3423 function initializeGL().
3424*/
3425
3426void QGLWidget::glInit()
3427{
3428 Q_D(QGLWidget);
3429 if (!isValid())
3430 return;
3431 makeCurrent();
3432 initializeGL();
3433 d->glcx->setInitialized(true);
3434}
3435
3436
3437/*!
3438 Executes the virtual function paintGL().
3439
3440 The widget's rendering context will become the current context and
3441 initializeGL() will be called if it hasn't already been called.
3442*/
3443
3444void QGLWidget::glDraw()
3445{
3446 Q_D(QGLWidget);
3447 if (!isValid())
3448 return;
3449 makeCurrent();
3450#ifndef QT_OPENGL_ES
3451 if (d->glcx->deviceIsPixmap())
3452 glDrawBuffer(GL_FRONT);
3453#endif
3454 if (!d->glcx->initialized()) {
3455 glInit();
3456 resizeGL(d->glcx->device()->width(), d->glcx->device()->height()); // New context needs this "resize"
3457 }
3458 paintGL();
3459 if (doubleBuffer()) {
3460 if (d->autoSwap)
3461 swapBuffers();
3462 } else {
3463 glFlush();
3464 }
3465}
3466
3467/*!
3468 Convenience function for specifying a drawing color to OpenGL.
3469 Calls glColor4 (in RGBA mode) or glIndex (in color-index mode)
3470 with the color \a c. Applies to this widgets GL context.
3471
3472 \sa qglClearColor(), QGLContext::currentContext(), QColor
3473*/
3474
3475void QGLWidget::qglColor(const QColor& c) const
3476{
3477#if !defined(QT_OPENGL_ES_2)
3478#ifdef QT_OPENGL_ES
3479 glColor4f(c.red()/255.0, c.green()/255.0, c.blue()/255.0, c.alpha()/255.0);
3480#else
3481 Q_D(const QGLWidget);
3482 const QGLContext *ctx = QGLContext::currentContext();
3483 if (ctx) {
3484 if (ctx->format().rgba())
3485 glColor4ub(c.red(), c.green(), c.blue(), c.alpha());
3486 else if (!d->cmap.isEmpty()) { // QGLColormap in use?
3487 int i = d->cmap.find(c.rgb());
3488 if (i < 0)
3489 i = d->cmap.findNearest(c.rgb());
3490 glIndexi(i);
3491 } else
3492 glIndexi(ctx->colorIndex(c));
3493 }
3494#endif //QT_OPENGL_ES
3495#endif //QT_OPENGL_ES_2
3496}
3497
3498/*!
3499 Convenience function for specifying the clearing color to OpenGL.
3500 Calls glClearColor (in RGBA mode) or glClearIndex (in color-index
3501 mode) with the color \a c. Applies to this widgets GL context.
3502
3503 \sa qglColor(), QGLContext::currentContext(), QColor
3504*/
3505
3506void QGLWidget::qglClearColor(const QColor& c) const
3507{
3508#ifdef QT_OPENGL_ES
3509 glClearColor((GLfloat)c.red() / 255.0, (GLfloat)c.green() / 255.0,
3510 (GLfloat)c.blue() / 255.0, (GLfloat) c.alpha() / 255.0);
3511#else
3512 Q_D(const QGLWidget);
3513 const QGLContext *ctx = QGLContext::currentContext();
3514 if (ctx) {
3515 if (ctx->format().rgba())
3516 glClearColor((GLfloat)c.red() / 255.0, (GLfloat)c.green() / 255.0,
3517 (GLfloat)c.blue() / 255.0, (GLfloat) c.alpha() / 255.0);
3518 else if (!d->cmap.isEmpty()) { // QGLColormap in use?
3519 int i = d->cmap.find(c.rgb());
3520 if (i < 0)
3521 i = d->cmap.findNearest(c.rgb());
3522 glClearIndex(i);
3523 } else
3524 glClearIndex(ctx->colorIndex(c));
3525 }
3526#endif
3527}
3528
3529
3530/*!
3531 Converts the image \a img into the unnamed format expected by
3532 OpenGL functions such as glTexImage2D(). The returned image is not
3533 usable as a QImage, but QImage::width(), QImage::height() and
3534 QImage::bits() may be used with OpenGL. The GL format used is
3535 \c GL_RGBA.
3536
3537 \omit ###
3538
3539 \l opengl/texture example
3540 The following few lines are from the texture example. Most of the
3541 code is irrelevant, so we just quote the relevant bits:
3542
3543 \quotefromfile opengl/texture/gltexobj.cpp
3544 \skipto tex1
3545 \printline tex1
3546 \printline gllogo.bmp
3547
3548 We create \e tex1 (and another variable) for OpenGL, and load a real
3549 image into \e buf.
3550
3551 \skipto convertToGLFormat
3552 \printline convertToGLFormat
3553
3554 A few lines later, we convert \e buf into OpenGL format and store it
3555 in \e tex1.
3556
3557 \skipto glTexImage2D
3558 \printline glTexImage2D
3559 \printline tex1.bits
3560
3561 Note the dimension restrictions for texture images as described in
3562 the glTexImage2D() documentation. The width must be 2^m + 2*border
3563 and the height 2^n + 2*border where m and n are integers and
3564 border is either 0 or 1.
3565
3566 Another function in the same example uses \e tex1 with OpenGL.
3567
3568 \endomit
3569*/
3570
3571QImage QGLWidget::convertToGLFormat(const QImage& img)
3572{
3573 QImage res(img.size(), QImage::Format_ARGB32);
3574 convertToGLFormatHelper(res, img.convertToFormat(QImage::Format_ARGB32), GL_RGBA);
3575 return res;
3576}
3577
3578
3579/*!
3580 \fn QGLColormap & QGLWidget::colormap() const
3581
3582 Returns the colormap for this widget.
3583
3584 Usually it is only top-level widgets that can have different
3585 colormaps installed. Asking for the colormap of a child widget
3586 will return the colormap for the child's top-level widget.
3587
3588 If no colormap has been set for this widget, the QColormap
3589 returned will be empty.
3590
3591 \sa setColormap()
3592*/
3593
3594/*!
3595 \fn void QGLWidget::setColormap(const QGLColormap & cmap)
3596
3597 Set the colormap for this widget to \a cmap. Usually it is only
3598 top-level widgets that can have colormaps installed.
3599
3600 \sa colormap()
3601*/
3602
3603
3604/*!
3605 \obsolete
3606
3607 Returns the value of the first display list that is generated for
3608 the characters in the given \a font. \a listBase indicates the base
3609 value used when generating the display lists for the font. The
3610 default value is 2000.
3611*/
3612int QGLWidget::fontDisplayListBase(const QFont & font, int listBase)
3613{
3614 Q_D(QGLWidget);
3615 int base;
3616
3617 if (!d->glcx) { // this can't happen unless we run out of mem
3618 return 0;
3619 }
3620
3621 // always regenerate font disp. lists for pixmaps - hw accelerated
3622 // contexts can't handle this otherwise
3623 bool regenerate = d->glcx->deviceIsPixmap();
3624#ifndef QT_NO_FONTCONFIG
3625 // font color needs to be part of the font cache key when using
3626 // antialiased fonts since one set of glyphs needs to be generated
3627 // for each font color
3628 QString color_key;
3629 if (font.styleStrategy() != QFont::NoAntialias) {
3630 GLfloat color[4];
3631#ifndef QT_OPENGL_ES
3632 glGetFloatv(GL_CURRENT_COLOR, color);
3633#endif
3634 color_key.sprintf("%f_%f_%f",color[0], color[1], color[2]);
3635 }
3636 QString key = font.key() + color_key + QString::number((int) regenerate);
3637#else
3638 QString key = font.key() + QString::number((int) regenerate);
3639#endif
3640 if (!regenerate && (d->displayListCache.find(key) != d->displayListCache.end())) {
3641 base = d->displayListCache[key];
3642 } else {
3643 int maxBase = listBase - 256;
3644 QMap<QString,int>::ConstIterator it;
3645 for (it = d->displayListCache.constBegin(); it != d->displayListCache.constEnd(); ++it) {
3646 if (maxBase < it.value()) {
3647 maxBase = it.value();
3648 }
3649 }
3650 maxBase += 256;
3651 d->glcx->generateFontDisplayLists(font, maxBase);
3652 d->displayListCache[key] = maxBase;
3653 base = maxBase;
3654 }
3655 return base;
3656}
3657
3658static void qt_save_gl_state()
3659{
3660#ifndef QT_OPENGL_ES
3661 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
3662 glPushAttrib(GL_ALL_ATTRIB_BITS);
3663#endif
3664#if !defined(QT_OPENGL_ES_2)
3665 glMatrixMode(GL_TEXTURE);
3666 glPushMatrix();
3667 glLoadIdentity();
3668 glMatrixMode(GL_PROJECTION);
3669 glPushMatrix();
3670 glMatrixMode(GL_MODELVIEW);
3671 glPushMatrix();
3672
3673 glShadeModel(GL_FLAT);
3674 glDisable(GL_CULL_FACE);
3675 glDisable(GL_LIGHTING);
3676 glDisable(GL_STENCIL_TEST);
3677 glEnable(GL_BLEND);
3678 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
3679#endif // !defined(QT_OPENGL_ES_2)
3680}
3681
3682static void qt_restore_gl_state()
3683{
3684#if !defined(QT_OPENGL_ES_2)
3685 glMatrixMode(GL_TEXTURE);
3686 glPopMatrix();
3687 glMatrixMode(GL_PROJECTION);
3688 glPopMatrix();
3689 glMatrixMode(GL_MODELVIEW);
3690 glPopMatrix();
3691#endif // !defined(QT_OPENGL_ES_2)
3692#ifndef QT_OPENGL_ES
3693 glPopAttrib();
3694 glPopClientAttrib();
3695#endif
3696}
3697
3698static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str,
3699 const QFont &font)
3700{
3701 GLfloat color[4];
3702#ifndef QT_OPENGL_ES
3703 glGetFloatv(GL_CURRENT_COLOR, &color[0]);
3704#endif
3705
3706 QColor col;
3707 col.setRgbF(color[0], color[1], color[2],color[3]);
3708 QPen old_pen = p->pen();
3709 QFont old_font = p->font();
3710
3711 p->setPen(col);
3712 p->setFont(font);
3713 p->drawText(x, y, str);
3714
3715 p->setPen(old_pen);
3716 p->setFont(old_font);
3717}
3718
3719/*!
3720 Renders the string \a str into the GL context of this widget.
3721
3722 \a x and \a y are specified in window coordinates, with the origin
3723 in the upper left-hand corner of the window. If \a font is not
3724 specified, the currently set application font will be used to
3725 render the string. To change the color of the rendered text you can
3726 use the glColor() call (or the qglColor() convenience function),
3727 just before the renderText() call.
3728
3729 The \a listBase parameter is obsolete and will be removed in a
3730 future version of Qt.
3731
3732 \note This function clears the stencil buffer.
3733*/
3734
3735void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, int)
3736{
3737 Q_D(QGLWidget);
3738 if (str.isEmpty() || !isValid())
3739 return;
3740
3741 GLint view[4];
3742#ifndef QT_OPENGL_ES
3743 bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST);
3744 if (!use_scissor_testing)
3745 glGetIntegerv(GL_VIEWPORT, &view[0]);
3746#else
3747 bool use_scissor_testing = false;
3748#endif
3749 int width = d->glcx->device()->width();
3750 int height = d->glcx->device()->height();
3751 bool auto_swap = autoBufferSwap();
3752
3753 QPaintEngine *engine = paintEngine();
3754 QPainter *p;
3755 bool reuse_painter = false;
3756 if (engine->isActive()) {
3757 reuse_painter = true;
3758 p = engine->painter();
3759 qt_save_gl_state();
3760
3761#if !defined(QT_OPENGL_ES_2)
3762 glDisable(GL_DEPTH_TEST);
3763 glViewport(0, 0, width, height);
3764 glMatrixMode(GL_PROJECTION);
3765 glLoadIdentity();
3766#ifndef QT_OPENGL_ES
3767 glOrtho(0, width, height, 0, 0, 1);
3768#else
3769 glOrthof(0, width, height, 0, 0, 1);
3770#endif
3771 glMatrixMode(GL_MODELVIEW);
3772
3773 glLoadIdentity();
3774#endif // !defined(QT_OPENGL_ES_2)
3775 } else {
3776 setAutoBufferSwap(false);
3777 // disable glClear() as a result of QPainter::begin()
3778 d->glcx->d_func()->clear_on_painter_begin = false;
3779 p = new QPainter(this);
3780 }
3781
3782 QRect viewport(view[0], view[1], view[2], view[3]);
3783 if (!use_scissor_testing && viewport != rect()) {
3784 // if the user hasn't set a scissor box, we set one that
3785 // covers the current viewport
3786 glScissor(view[0], view[1], view[2], view[3]);
3787 glEnable(GL_SCISSOR_TEST);
3788 } else if (use_scissor_testing) {
3789 // use the scissor box set by the user
3790 glEnable(GL_SCISSOR_TEST);
3791 }
3792
3793 qt_gl_draw_text(p, x, y, str, font);
3794
3795 if (reuse_painter) {
3796 qt_restore_gl_state();
3797 } else {
3798 p->end();
3799 delete p;
3800 setAutoBufferSwap(auto_swap);
3801 d->glcx->d_func()->clear_on_painter_begin = true;
3802 }
3803}
3804
3805/*! \overload
3806
3807 \a x, \a y and \a z are specified in scene or object coordinates
3808 relative to the currently set projection and model matrices. This
3809 can be useful if you want to annotate models with text labels and
3810 have the labels move with the model as it is rotated etc.
3811*/
3812void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int)
3813{
3814 Q_D(QGLWidget);
3815 if (str.isEmpty() || !isValid())
3816 return;
3817
3818 bool auto_swap = autoBufferSwap();
3819
3820 int width = d->glcx->device()->width();
3821 int height = d->glcx->device()->height();
3822 GLdouble model[4][4], proj[4][4];
3823 GLint view[4];
3824#ifndef QT_OPENGL_ES
3825 glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
3826 glGetDoublev(GL_PROJECTION_MATRIX, &proj[0][0]);
3827 glGetIntegerv(GL_VIEWPORT, &view[0]);
3828#endif
3829 GLdouble win_x = 0, win_y = 0, win_z = 0;
3830 qgluProject(x, y, z, &model[0][0], &proj[0][0], &view[0],
3831 &win_x, &win_y, &win_z);
3832 win_y = height - win_y; // y is inverted
3833
3834 QPaintEngine *engine = paintEngine();
3835 QPainter *p;
3836 bool reuse_painter = false;
3837#ifndef QT_OPENGL_ES
3838 bool use_depth_testing = glIsEnabled(GL_DEPTH_TEST);
3839 bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST);
3840#else
3841 bool use_depth_testing = false;
3842 bool use_scissor_testing = false;
3843#endif
3844
3845 if (engine->isActive()) {
3846 reuse_painter = true;
3847 p = engine->painter();
3848 qt_save_gl_state();
3849 } else {
3850 setAutoBufferSwap(false);
3851 // disable glClear() as a result of QPainter::begin()
3852 d->glcx->d_func()->clear_on_painter_begin = false;
3853 p = new QPainter(this);
3854 }
3855
3856 QRect viewport(view[0], view[1], view[2], view[3]);
3857 if (!use_scissor_testing && viewport != rect()) {
3858 glScissor(view[0], view[1], view[2], view[3]);
3859 glEnable(GL_SCISSOR_TEST);
3860 } else if (use_scissor_testing) {
3861 glEnable(GL_SCISSOR_TEST);
3862 }
3863#if !defined(QT_OPENGL_ES_2)
3864 glMatrixMode(GL_PROJECTION);
3865 glLoadIdentity();
3866 glViewport(0, 0, width, height);
3867#ifndef QT_OPENGL_ES
3868 glOrtho(0, width, height, 0, 0, 1);
3869#else
3870 glOrthof(0, width, height, 0, 0, 1);
3871#endif
3872 glMatrixMode(GL_MODELVIEW);
3873 glLoadIdentity();
3874 glAlphaFunc(GL_GREATER, 0.0);
3875 glEnable(GL_ALPHA_TEST);
3876 if (use_depth_testing)
3877 glEnable(GL_DEPTH_TEST);
3878#ifndef QT_OPENGL_ES
3879 glTranslated(0, 0, -win_z);
3880#else
3881 glTranslatef(0, 0, -win_z);
3882#endif
3883#endif // !defined(QT_OPENGL_ES_2)
3884 qt_gl_draw_text(p, qRound(win_x), qRound(win_y), str, font);
3885
3886 if (reuse_painter) {
3887 qt_restore_gl_state();
3888 } else {
3889 p->end();
3890 delete p;
3891 setAutoBufferSwap(auto_swap);
3892 d->glcx->d_func()->clear_on_painter_begin = true;
3893 }
3894}
3895
3896QGLFormat QGLWidget::format() const
3897{
3898 Q_D(const QGLWidget);
3899 return d->glcx->format();
3900}
3901
3902const QGLContext *QGLWidget::context() const
3903{
3904 Q_D(const QGLWidget);
3905 return d->glcx;
3906}
3907
3908bool QGLWidget::doubleBuffer() const
3909{
3910 Q_D(const QGLWidget);
3911 return d->glcx->d_ptr->glFormat.testOption(QGL::DoubleBuffer);
3912}
3913
3914void QGLWidget::setAutoBufferSwap(bool on)
3915{
3916 Q_D(QGLWidget);
3917 d->autoSwap = on;
3918}
3919
3920bool QGLWidget::autoBufferSwap() const
3921{
3922 Q_D(const QGLWidget);
3923 return d->autoSwap;
3924}
3925
3926/*!
3927 Calls QGLContext:::bindTexture(\a image, \a target, \a format) on the currently
3928 set context.
3929
3930 \sa deleteTexture()
3931*/
3932GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format)
3933{
3934 Q_D(QGLWidget);
3935 return d->glcx->bindTexture(image, target, format);
3936}
3937
3938#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
3939/*! \internal */
3940GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
3941{
3942 Q_D(QGLWidget);
3943 return d->glcx->bindTexture(image, GLenum(target), GLint(format));
3944}
3945#endif
3946
3947/*!
3948 Calls QGLContext:::bindTexture(\a pixmap, \a target, \a format) on the currently
3949 set context.
3950
3951 \sa deleteTexture()
3952*/
3953GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
3954{
3955 Q_D(QGLWidget);
3956 return d->glcx->bindTexture(pixmap, target, format);
3957}
3958
3959#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
3960/*! \internal */
3961GLuint QGLWidget::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format)
3962{
3963 Q_D(QGLWidget);
3964 return d->glcx->bindTexture(pixmap, target, format);
3965}
3966#endif
3967
3968
3969/*! \overload
3970
3971 Calls QGLContext::bindTexture(\a fileName) on the currently set context.
3972
3973 \sa deleteTexture()
3974*/
3975GLuint QGLWidget::bindTexture(const QString &fileName)
3976{
3977 Q_D(QGLWidget);
3978 return d->glcx->bindTexture(fileName);
3979}
3980
3981/*!
3982 Calls QGLContext::deleteTexture(\a id) on the currently set
3983 context.
3984
3985 \sa bindTexture()
3986*/
3987void QGLWidget::deleteTexture(GLuint id)
3988{
3989 Q_D(QGLWidget);
3990 d->glcx->deleteTexture(id);
3991}
3992
3993#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
3994/*! \internal */
3995void QGLWidget::deleteTexture(QMacCompatGLuint id)
3996{
3997 Q_D(QGLWidget);
3998 d->glcx->deleteTexture(GLuint(id));
3999}
4000#endif
4001
4002/*!
4003 \since 4.4
4004
4005 Draws the given texture, \a textureId to the given target rectangle,
4006 \a target, in OpenGL model space. The \a textureTarget should be a 2D
4007 texture target.
4008
4009 Equivalent to the corresponding QGLContext::drawTexture().
4010*/
4011void QGLWidget::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
4012{
4013 Q_D(QGLWidget);
4014 d->glcx->drawTexture(target, textureId, textureTarget);
4015}
4016
4017#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
4018/*! \internal */
4019void QGLWidget::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
4020{
4021 Q_D(QGLWidget);
4022 d->glcx->drawTexture(target, GLint(textureId), GLenum(textureTarget));
4023}
4024#endif
4025
4026/*!
4027 \since 4.4
4028
4029 Draws the given texture, \a textureId, at the given \a point in OpenGL
4030 model space. The \a textureTarget should be a 2D texture target.
4031
4032 Equivalent to the corresponding QGLContext::drawTexture().
4033*/
4034void QGLWidget::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
4035{
4036 Q_D(QGLWidget);
4037 d->glcx->drawTexture(point, textureId, textureTarget);
4038}
4039
4040#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
4041/*! \internal */
4042void QGLWidget::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
4043{
4044 Q_D(QGLWidget);
4045 d->glcx->drawTexture(point, GLuint(textureId), GLenum(textureTarget));
4046}
4047#endif
4048
4049#if defined(QT_OPENGL_ES_2)
4050Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_engine)
4051#else
4052Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_engine)
4053#endif
4054
4055#ifdef Q_WS_QWS
4056Q_OPENGL_EXPORT QOpenGLPaintEngine* qt_qgl_paint_engine()
4057{
4058#if !defined(QT_OPENGL_ES_2)
4059 return qt_gl_engine();
4060#else
4061 return 0; // XXX
4062#endif
4063}
4064#endif
4065
4066/*!
4067 \internal
4068
4069 Returns the GL widget's paint engine. This is normally a
4070 QOpenGLPaintEngine.
4071*/
4072QPaintEngine *QGLWidget::paintEngine() const
4073{
4074 return qt_gl_engine();
4075}
4076
4077#ifdef QT3_SUPPORT
4078/*!
4079 \overload
4080 \obsolete
4081 */
4082QGLWidget::QGLWidget(QWidget *parent, const char *name,
4083 const QGLWidget* shareWidget, Qt::WindowFlags f)
4084 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
4085{
4086 Q_D(QGLWidget);
4087 if (name)
4088 setObjectName(QString::fromAscii(name));
4089 setAttribute(Qt::WA_PaintOnScreen);
4090 setAttribute(Qt::WA_NoSystemBackground);
4091 setAutoFillBackground(true); // for compatibility
4092 d->init(new QGLContext(QGLFormat::defaultFormat(), this), shareWidget);
4093}
4094
4095/*!
4096 \overload
4097 \obsolete
4098 */
4099QGLWidget::QGLWidget(const QGLFormat &format, QWidget *parent,
4100 const char *name, const QGLWidget* shareWidget,
4101 Qt::WindowFlags f)
4102 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
4103{
4104 Q_D(QGLWidget);
4105 if (name)
4106 setObjectName(QString::fromAscii(name));
4107 setAttribute(Qt::WA_PaintOnScreen);
4108 setAttribute(Qt::WA_NoSystemBackground);
4109 setAutoFillBackground(true); // for compatibility
4110 d->init(new QGLContext(format, this), shareWidget);
4111}
4112
4113/*!
4114 \overload
4115 \obsolete
4116 */
4117QGLWidget::QGLWidget(QGLContext *context, QWidget *parent,
4118 const char *name, const QGLWidget *shareWidget, Qt::WindowFlags f)
4119 : QWidget(*(new QGLWidgetPrivate), parent, f | Qt::MSWindowsOwnDC)
4120{
4121 Q_D(QGLWidget);
4122 if (name)
4123 setObjectName(QString::fromAscii(name));
4124 setAttribute(Qt::WA_PaintOnScreen);
4125 setAttribute(Qt::WA_NoSystemBackground);
4126 setAutoFillBackground(true); // for compatibility
4127 d->init(context, shareWidget);
4128}
4129
4130#endif // QT3_SUPPORT
4131
4132void QGLExtensions::init_extensions()
4133{
4134 QString extensions = QLatin1String(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
4135 if (extensions.contains(QLatin1String("texture_rectangle")))
4136 glExtensions |= TextureRectangle;
4137 if (extensions.contains(QLatin1String("multisample")))
4138 glExtensions |= SampleBuffers;
4139 if (extensions.contains(QLatin1String("generate_mipmap")))
4140 glExtensions |= GenerateMipmap;
4141 if (extensions.contains(QLatin1String("texture_compression_s3tc")))
4142 glExtensions |= TextureCompression;
4143 if (extensions.contains(QLatin1String("ARB_fragment_program")))
4144 glExtensions |= FragmentProgram;
4145 if (extensions.contains(QLatin1String("mirrored_repeat")))
4146 glExtensions |= MirroredRepeat;
4147 if (extensions.contains(QLatin1String("EXT_framebuffer_object")))
4148 glExtensions |= FramebufferObject;
4149 if (extensions.contains(QLatin1String("EXT_stencil_two_side")))
4150 glExtensions |= StencilTwoSide;
4151 if (extensions.contains(QLatin1String("EXT_stencil_wrap")))
4152 glExtensions |= StencilWrap;
4153 if (extensions.contains(QLatin1String("EXT_packed_depth_stencil")))
4154 glExtensions |= PackedDepthStencil;
4155 if (extensions.contains(QLatin1String("GL_NV_float_buffer")))
4156 glExtensions |= NVFloatBuffer;
4157 if (extensions.contains(QLatin1String("ARB_pixel_buffer_object")))
4158 glExtensions |= PixelBufferObject;
4159#if defined(QT_OPENGL_ES_2)
4160 glExtensions |= FramebufferObject;
4161 glExtensions |= GenerateMipmap;
4162#endif
4163
4164 QGLContext cx(QGLFormat::defaultFormat());
4165 if (glExtensions & TextureCompression) {
4166 qt_glCompressedTexImage2DARB = (pfn_glCompressedTexImage2DARB) cx.getProcAddress(QLatin1String("glCompressedTexImage2DARB"));
4167 }
4168}
4169
4170/*
4171 This is the shared initialization for all platforms. Called from QGLWidgetPrivate::init()
4172*/
4173void QGLWidgetPrivate::initContext(QGLContext *context, const QGLWidget* shareWidget)
4174{
4175 Q_Q(QGLWidget);
4176
4177 QGLExtensions::init();
4178 glcx = 0;
4179 autoSwap = true;
4180
4181 if (context && !context->device())
4182 context->setDevice(q);
4183 q->setContext(context, shareWidget ? shareWidget->context() : 0);
4184
4185 if (!glcx)
4186 glcx = new QGLContext(QGLFormat::defaultFormat(), q);
4187
4188 q->setAttribute(Qt::WA_NoSystemBackground);
4189}
4190
4191#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
4192Q_GLOBAL_STATIC(QString, qt_gl_lib_name);
4193
4194Q_OPENGL_EXPORT void qt_set_gl_library_name(const QString& name)
4195{
4196 qt_gl_lib_name()->operator=(name);
4197}
4198
4199Q_OPENGL_EXPORT const QString qt_gl_library_name()
4200{
4201 if (qt_gl_lib_name()->isNull()) {
4202#if defined(Q_WS_X11) || defined(Q_WS_QWS)
4203 return QString(QLatin1String("GL"));
4204#else // Q_WS_MAC
4205 return QLatin1String("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib");
4206#endif
4207 }
4208 return *qt_gl_lib_name();
4209}
4210#endif
4211
4212QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.