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