diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2011-07-10 15:24:15 -0500 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2011-07-10 15:24:15 -0500 |
commit | bd0f3345a938b35ce6a12f6150373b0955b8dd12 (patch) | |
tree | 7a520322212d48ebcb9fbe1087e7fca28b76185c /src/opengl | |
download | qt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.tar.gz qt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.zip |
Add Qt3 development HEAD version
Diffstat (limited to 'src/opengl')
-rw-r--r-- | src/opengl/qgl.cpp | 2367 | ||||
-rw-r--r-- | src/opengl/qgl.h | 541 | ||||
-rw-r--r-- | src/opengl/qgl_x11.cpp | 1406 | ||||
-rw-r--r-- | src/opengl/qgl_x11_p.h | 197 | ||||
-rw-r--r-- | src/opengl/qglcolormap.cpp | 292 | ||||
-rw-r--r-- | src/opengl/qglcolormap.h | 99 | ||||
-rw-r--r-- | src/opengl/qt_opengl.pri | 18 |
7 files changed, 4920 insertions, 0 deletions
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp new file mode 100644 index 0000000..c2a35ea --- /dev/null +++ b/src/opengl/qgl.cpp @@ -0,0 +1,2367 @@ +/**************************************************************************** +** +** Implementation of OpenGL classes for Qt +** +** Created : 970112 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the opengl module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qgl.h" +#include "qpixmap.h" +#include "qpaintdevicemetrics.h" +#include "qimage.h" +#include "qcleanuphandler.h" +#include "qptrdict.h" + +static QGLFormat* qgl_default_format = 0; +static QGLFormat* qgl_default_overlay_format = 0; + +#if defined(Q_WS_X11) +#include "private/qt_x11_p.h" +#define INT32 dummy_INT32 +#define INT8 dummy_INT8 +#include <GL/glx.h> +#undef INT32 +#undef INT8 +#include "qgl_x11_p.h" +#endif + +static QCleanupHandler<QGLFormat> qgl_cleanup_format; + + +/*! + \class QGL qgl.h + \brief The QGL class is a namespace for miscellaneous identifiers + in the Qt OpenGL module. +\if defined(commercial) + It is part of the <a href="commercialeditions.html">Qt Enterprise Edition</a>. +\endif + + \module OpenGL + \ingroup graphics + \ingroup images + + + Normally you can ignore this class. QGLWidget and the other + OpenGL<sup>*</sup> module classes inherit it, so when you make your + own QGLWidget subclass you can use the identifiers in the QGL + namespace without qualification. + + However, you may occasionally find yourself in situations where you + need to refer to these identifiers from outside the QGL namespace's + scope, e.g. in static functions. In such cases, simply write e.g. \c + QGL::DoubleBuffer instead of just \c DoubleBuffer. + + <sup>*</sup> OpenGL is a trademark of Silicon Graphics, Inc. in the + United States and other countries. + +*/ + + +/***************************************************************************** + QGLFormat implementation + *****************************************************************************/ + + +/*! + \class QGLFormat qgl.h + \brief The QGLFormat class specifies the display format of an OpenGL + rendering context. +\if defined(commercial) + It is part of the <a href="commercialeditions.html">Qt Enterprise Edition</a>. +\endif + + \ingroup graphics + \ingroup images + \module OpenGL + + A display format has several characteristics: + \list + \i \link setDoubleBuffer() Double or single buffering.\endlink + \i \link setDepth() Depth buffer.\endlink + \i \link setRgba() RGBA or color index mode.\endlink + \i \link setAlpha() Alpha channel.\endlink + \i \link setAccum() Accumulation buffer.\endlink + \i \link setStencil() Stencil buffer.\endlink + \i \link setStereo() Stereo buffers.\endlink + \i \link setDirectRendering() Direct rendering.\endlink + \i \link setOverlay() Presence of an overlay.\endlink + \i \link setPlane() The plane of an overlay format.\endlink + \endlist + + You create and tell a QGLFormat object what rendering options you + want from an OpenGL<sup>*</sup> rendering context. + + OpenGL drivers or accelerated hardware may or may not support + advanced features such as alpha channel or stereographic viewing. + If you request some features that the driver/hardware does not + provide when you create a QGLWidget, you will get a rendering + context with the nearest subset of features. + + There are different ways to define the display characteristics of + a rendering context. One is to create a QGLFormat and make it the + default for the entire application: + \code + QGLFormat f; + f.setAlpha( TRUE ); + f.setStereo( TRUE ); + QGLFormat::setDefaultFormat( f ); + \endcode + + Or you can specify the desired format when creating an object of + your QGLWidget subclass: + \code + QGLFormat f; + f.setDoubleBuffer( FALSE ); // single buffer + f.setDirectRendering( FALSE ); // software rendering + MyGLWidget* myWidget = new MyGLWidget( f, ... ); + \endcode + + After the widget has been created, you can find out which of the + requested features the system was able to provide: + \code + QGLFormat f; + f.setOverlay( TRUE ); + f.setStereo( TRUE ); + MyGLWidget* myWidget = new MyGLWidget( f, ... ); + if ( !w->format().stereo() ) { + // ok, goggles off + if ( !w->format().hasOverlay() ) { + qFatal( "Cool hardware required" ); + } + } + \endcode + + <sup>*</sup> OpenGL is a trademark of Silicon Graphics, Inc. in the + United States and other countries. + + \sa QGLContext, QGLWidget +*/ + + +/*! + Constructs a QGLFormat object with the factory default settings: + \list + \i \link setDoubleBuffer() Double buffer:\endlink Enabled. + \i \link setDepth() Depth buffer:\endlink Enabled. + \i \link setRgba() RGBA:\endlink Enabled (i.e., color index disabled). + \i \link setAlpha() Alpha channel:\endlink Disabled. + \i \link setAccum() Accumulator buffer:\endlink Disabled. + \i \link setStencil() Stencil buffer:\endlink Disabled. + \i \link setStereo() Stereo:\endlink Disabled. + \i \link setDirectRendering() Direct rendering:\endlink Enabled. + \i \link setOverlay() Overlay:\endlink Disabled. + \i \link setPlane() Plane:\endlink 0 (i.e., normal plane). + \endlist +*/ + +QGLFormat::QGLFormat() +{ + opts = DoubleBuffer | DepthBuffer | Rgba | DirectRendering; + pln = 0; +} + + +/*! + Creates a QGLFormat object that is a copy of the current \link + defaultFormat() application default format\endlink. + + If \a options is not 0, this copy is modified by these format + options. The \a options parameter should be \c FormatOption values + OR'ed together. + + This constructor makes it easy to specify a certain desired format + in classes derived from QGLWidget, for example: + \code + // The rendering in MyGLWidget depends on using + // stencil buffer and alpha channel + MyGLWidget::MyGLWidget( QWidget* parent, const char* name ) + : QGLWidget( QGLFormat( StencilBuffer | AlphaChannel ), parent, name ) + { + if ( !format().stencil() ) + qWarning( "Could not get stencil buffer; results will be suboptimal" ); + if ( !format().alphaChannel() ) + qWarning( "Could not get alpha channel; results will be suboptimal" ); + ... + } + \endcode + + Note that there are \c FormatOption values to turn format settings + both on and off, e.g. \c DepthBuffer and \c NoDepthBuffer, + \c DirectRendering and \c IndirectRendering, etc. + + The \a plane parameter defaults to 0 and is the plane which this + format should be associated with. Not all OpenGL implmentations + supports overlay/underlay rendering planes. + + \sa defaultFormat(), setOption() +*/ + +QGLFormat::QGLFormat( int options, int plane ) +{ + uint newOpts = options; + opts = defaultFormat().opts; + opts |= ( newOpts & 0xffff ); + opts &= ~( newOpts >> 16 ); + pln = plane; +} + + +/*! + \fn bool QGLFormat::doubleBuffer() const + + Returns TRUE if double buffering is enabled; otherwise returns + FALSE. Double buffering is enabled by default. + + \sa setDoubleBuffer() +*/ + +/*! + If \a enable is TRUE sets double buffering; otherwise sets single + buffering. + + Double buffering is enabled by default. + + Double buffering is a technique where graphics are rendered on an + off-screen buffer and not directly to the screen. When the drawing + has been completed, the program calls a swapBuffers() function to + exchange the screen contents with the buffer. The result is + flicker-free drawing and often better performance. + + \sa doubleBuffer(), QGLContext::swapBuffers(), + QGLWidget::swapBuffers() +*/ + +void QGLFormat::setDoubleBuffer( bool enable ) +{ + setOption( enable ? DoubleBuffer : SingleBuffer ); +} + + +/*! + \fn bool QGLFormat::depth() const + + Returns TRUE if the depth buffer is enabled; otherwise returns + FALSE. The depth buffer is enabled by default. + + \sa setDepth() +*/ + +/*! + If \a enable is TRUE enables the depth buffer; otherwise disables + the depth buffer. + + The depth buffer is enabled by default. + + The purpose of a depth buffer (or Z-buffering) is to remove hidden + surfaces. Pixels are assigned Z values based on the distance to + the viewer. A pixel with a high Z value is closer to the viewer + than a pixel with a low Z value. This information is used to + decide whether to draw a pixel or not. + + \sa depth() +*/ + +void QGLFormat::setDepth( bool enable ) +{ + setOption( enable ? DepthBuffer : NoDepthBuffer ); +} + + +/*! + \fn bool QGLFormat::rgba() const + + Returns TRUE if RGBA color mode is set. Returns FALSE if color + index mode is set. The default color mode is RGBA. + + \sa setRgba() +*/ + +/*! + If \a enable is TRUE sets RGBA mode. If \a enable is FALSE sets + color index mode. + + The default color mode is RGBA. + + RGBA is the preferred mode for most OpenGL applications. In RGBA + color mode you specify colors as red + green + blue + alpha + quadruplets. + + In color index mode you specify an index into a color lookup + table. + + \sa rgba() +*/ + +void QGLFormat::setRgba( bool enable ) +{ + setOption( enable ? Rgba : ColorIndex ); +} + + +/*! + \fn bool QGLFormat::alpha() const + + Returns TRUE if the alpha channel of the framebuffer is enabled; + otherwise returns FALSE. The alpha channel is disabled by default. + + \sa setAlpha() +*/ + +/*! + If \a enable is TRUE enables the alpha channel; otherwise disables + the alpha channel. + + The alpha buffer is disabled by default. + + The alpha channel is typically used for implementing transparency + or translucency. The A in RGBA specifies the transparency of a + pixel. + + \sa alpha() +*/ + +void QGLFormat::setAlpha( bool enable ) +{ + setOption( enable ? AlphaChannel : NoAlphaChannel ); +} + + +/*! + \fn bool QGLFormat::accum() const + + Returns TRUE if the accumulation buffer is enabled; otherwise + returns FALSE. The accumulation buffer is disabled by default. + + \sa setAccum() +*/ + +/*! + If \a enable is TRUE enables the accumulation buffer; otherwise + disables the accumulation buffer. + + The accumulation buffer is disabled by default. + + The accumulation buffer is used to create blur effects and + multiple exposures. + + \sa accum() +*/ + +void QGLFormat::setAccum( bool enable ) +{ + setOption( enable ? AccumBuffer : NoAccumBuffer ); +} + + +/*! + \fn bool QGLFormat::stencil() const + + Returns TRUE if the stencil buffer is enabled; otherwise returns + FALSE. The stencil buffer is disabled by default. + + \sa setStencil() +*/ + +/*! + If \a enable is TRUE enables the stencil buffer; otherwise + disables the stencil buffer. + + The stencil buffer is disabled by default. + + The stencil buffer masks certain parts of the drawing area so that + masked parts are not drawn on. + + \sa stencil() +*/ + +void QGLFormat::setStencil( bool enable ) +{ + setOption( enable ? StencilBuffer: NoStencilBuffer ); +} + + +/*! + \fn bool QGLFormat::stereo() const + + Returns TRUE if stereo buffering is enabled; otherwise returns + FALSE. Stereo buffering is disabled by default. + + \sa setStereo() +*/ + +/*! + If \a enable is TRUE enables stereo buffering; otherwise disables + stereo buffering. + + Stereo buffering is disabled by default. + + Stereo buffering provides extra color buffers to generate left-eye + and right-eye images. + + \sa stereo() +*/ + +void QGLFormat::setStereo( bool enable ) +{ + setOption( enable ? StereoBuffers : NoStereoBuffers ); +} + + +/*! + \fn bool QGLFormat::directRendering() const + + Returns TRUE if direct rendering is enabled; otherwise returns + FALSE. + + Direct rendering is enabled by default. + + \sa setDirectRendering() +*/ + +/*! + If \a enable is TRUE enables direct rendering; otherwise disables + direct rendering. + + Direct rendering is enabled by default. + + Enabling this option will make OpenGL bypass the underlying window + system and render directly from hardware to the screen, if this is + supported by the system. + + \sa directRendering() +*/ + +void QGLFormat::setDirectRendering( bool enable ) +{ + setOption( enable ? DirectRendering : IndirectRendering ); +} + + +/*! + \fn bool QGLFormat::hasOverlay() const + + Returns TRUE if overlay plane is enabled; otherwise returns FALSE. + + Overlay is disabled by default. + + \sa setOverlay() +*/ + +/*! + If \a enable is TRUE enables an overlay plane; otherwise disables + the overlay plane. + + Enabling the overlay plane will cause QGLWidget to create an + additional context in an overlay plane. See the QGLWidget + documentation for further information. + + \sa hasOverlay() +*/ + +void QGLFormat::setOverlay( bool enable ) +{ + setOption( enable ? HasOverlay : NoOverlay ); +} + +/*! + Returns the plane of this format. The default for normal formats + is 0, which means the normal plane. The default for overlay + formats is 1, which is the first overlay plane. + + \sa setPlane() +*/ +int QGLFormat::plane() const +{ + return pln; +} + +/*! + Sets the requested plane to \a plane. 0 is the normal plane, 1 is + the first overlay plane, 2 is the second overlay plane, etc.; -1, + -2, etc. are underlay planes. + + Note that in contrast to other format specifications, the plane + specifications will be matched exactly. This means that if you + specify a plane that the underlying OpenGL system cannot provide, + an \link QGLWidget::isValid() invalid\endlink QGLWidget will be + created. + + \sa plane() +*/ +void QGLFormat::setPlane( int plane ) +{ + pln = plane; +} + +/*! + Sets the format option to \a opt. + + \sa testOption() +*/ + +void QGLFormat::setOption( FormatOption opt ) +{ + if ( opt & 0xffff ) + opts |= opt; + else + opts &= ~( opt >> 16 ); +} + + + +/*! + Returns TRUE if format option \a opt is set; otherwise returns FALSE. + + \sa setOption() +*/ + +bool QGLFormat::testOption( FormatOption opt ) const +{ + if ( opt & 0xffff ) + return ( opts & opt ) != 0; + else + return ( opts & ( opt >> 16 ) ) == 0; +} + + + +/*! + \fn bool QGLFormat::hasOpenGL() + + Returns TRUE if the window system has any OpenGL support; + otherwise returns FALSE. + + \warning This function must not be called until the QApplication + object has been created. +*/ + + + +/*! + \fn bool QGLFormat::hasOpenGLOverlays() + + Returns TRUE if the window system supports OpenGL overlays; + otherwise returns FALSE. + + \warning This function must not be called until the QApplication + object has been created. +*/ + +/*! + Returns the default QGLFormat for the application. All QGLWidgets + that are created use this format unless another format is + specified, e.g. when they are constructed. + + If no special default format has been set using + setDefaultFormat(), the default format is the same as that created + with QGLFormat(). + + \sa setDefaultFormat() +*/ + +QGLFormat QGLFormat::defaultFormat() +{ + if ( !qgl_default_format ) { + qgl_default_format = new QGLFormat; + qgl_cleanup_format.add( &qgl_default_format ); + } + return *qgl_default_format; +} + +/*! + Sets a new default QGLFormat for the application to \a f. For + example, to set single buffering as the default instead of double + buffering, your main() might contain code like this: + \code + QApplication a(argc, argv); + QGLFormat f; + f.setDoubleBuffer( FALSE ); + QGLFormat::setDefaultFormat( f ); + \endcode + + \sa defaultFormat() +*/ + +void QGLFormat::setDefaultFormat( const QGLFormat &f ) +{ + if ( !qgl_default_format ) { + qgl_default_format = new QGLFormat; + qgl_cleanup_format.add( &qgl_default_format ); + } + *qgl_default_format = f; +} + + +/*! + Returns the default QGLFormat for overlay contexts. + + The factory default overlay format is: + \list + \i \link setDoubleBuffer() Double buffer:\endlink Disabled. + \i \link setDepth() Depth buffer:\endlink Disabled. + \i \link setRgba() RGBA:\endlink Disabled (i.e., color index enabled). + \i \link setAlpha() Alpha channel:\endlink Disabled. + \i \link setAccum() Accumulator buffer:\endlink Disabled. + \i \link setStencil() Stencil buffer:\endlink Disabled. + \i \link setStereo() Stereo:\endlink Disabled. + \i \link setDirectRendering() Direct rendering:\endlink Enabled. + \i \link setOverlay() Overlay:\endlink Disabled. + \i \link setPlane() Plane:\endlink 1 (i.e., first overlay plane). + \endlist + + \sa setDefaultFormat() +*/ + +QGLFormat QGLFormat::defaultOverlayFormat() +{ + if ( !qgl_default_overlay_format ) { + qgl_default_overlay_format = new QGLFormat; + qgl_default_overlay_format->opts = DirectRendering; + qgl_default_overlay_format->pln = 1; + qgl_cleanup_format.add( &qgl_default_overlay_format ); + } + return *qgl_default_overlay_format; +} + +/*! + Sets a new default QGLFormat for overlay contexts to \a f. This + format is used whenever a QGLWidget is created with a format that + hasOverlay() enabled. + + For example, to get a double buffered overlay context (if + available), use code like this: + + \code + QGLFormat f = QGLFormat::defaultOverlayFormat(); + f.setDoubleBuffer( TRUE ); + QGLFormat::setDefaultOverlayFormat( f ); + \endcode + + As usual, you can find out after widget creation whether the + underlying OpenGL system was able to provide the requested + specification: + + \code + // ...continued from above + MyGLWidget* myWidget = new MyGLWidget( QGLFormat( QGL::HasOverlay ), ... ); + if ( myWidget->format().hasOverlay() ) { + // Yes, we got an overlay, let's check _its_ format: + QGLContext* olContext = myWidget->overlayContext(); + if ( olContext->format().doubleBuffer() ) + ; // yes, we got a double buffered overlay + else + ; // no, only single buffered overlays are available + } + \endcode + + \sa defaultOverlayFormat() +*/ + +void QGLFormat::setDefaultOverlayFormat( const QGLFormat &f ) +{ + if ( !qgl_default_overlay_format ) { + qgl_default_overlay_format = new QGLFormat; + qgl_cleanup_format.add( &qgl_default_overlay_format ); + } + *qgl_default_overlay_format = f; + // Make sure the user doesn't request that the overlays themselves + // have overlays, since it is unlikely that the system supports + // infinitely many planes... + qgl_default_overlay_format->setOverlay( FALSE ); +} + + +/*! + Returns TRUE if all the options of the two QGLFormats are equal; + otherwise returns FALSE. +*/ + +bool operator==( const QGLFormat& a, const QGLFormat& b ) +{ + return (a.opts == b.opts) && (a.pln == b.pln); +} + + +/*! + Returns FALSE if all the options of the two QGLFormats are equal; + otherwise returns TRUE. +*/ + +bool operator!=( const QGLFormat& a, const QGLFormat& b ) +{ + return !( a == b ); +} + + + +/***************************************************************************** + QGLContext implementation + *****************************************************************************/ + +QGLContext* QGLContext::currentCtx = 0; + +/*! + \class QGLContext qgl.h + \brief The QGLContext class encapsulates an OpenGL rendering context. +\if defined(commercial) + It is part of the <a href="commercialeditions.html">Qt Enterprise Edition</a>. +\endif + + \ingroup graphics + \ingroup images + \module OpenGL + + An OpenGL<sup>*</sup> rendering context is a complete set of + OpenGL state variables. + + The context's \link QGL::FormatOption format\endlink is set in the + constructor or later with setFormat(). The format options that are + actually set are returned by format(); the options you asked for + are returned by requestedFormat(). Note that after a QGLContext + object has been constructed, the actual OpenGL context must be + created by explicitly calling the \link create() create()\endlink + function. The makeCurrent() function makes this context the + current rendering context. You can make \e no context current + using doneCurrent(). The reset() function will reset the context + and make it invalid. + + You can examine properties of the context with, e.g. isValid(), + isSharing(), initialized(), windowCreated() and + overlayTransparentColor(). + + If you're using double buffering you can swap the screen contents + with the off-screen buffer using swapBuffers(). + + Please note that QGLContext is not thread safe. + + <sup>*</sup> OpenGL is a trademark of Silicon Graphics, Inc. in the + United States and other countries. + +*/ + + +/*! + Constructs an OpenGL context for the paint device \a device, which + can be a widget or a pixmap. The \a format specifies several + display options for the context. + + If the underlying OpenGL/Window system cannot satisfy all the + features requested in \a format, the nearest subset of features + will be used. After creation, the format() method will return the + actual format obtained. + + Note that after a QGLContext object has been constructed, \link + create() create()\endlink must be called explicitly to create + the actual OpenGL context. The context will be \link isValid() + invalid\endlink if it was not possible to obtain a GL context at + all. + + \sa format(), isValid() +*/ + +QGLContext::QGLContext( const QGLFormat &format, QPaintDevice *device ) + : glFormat(format), reqFormat(format) +{ + init( device ); +} + +/*! + \overload + \internal +*/ +QGLContext::QGLContext( const QGLFormat &format ) + : glFormat( format ), reqFormat(format) +{ + init(); +} + +/*! + Destroys the OpenGL context and frees its resources. +*/ + +QGLContext::~QGLContext() +{ + reset(); + if ( d ) + delete d; +} + + +/*! + \fn QGLFormat QGLContext::format() const + + Returns the frame buffer format that was obtained (this may be a + subset of what was requested). + + \sa requestedFormat() +*/ + +/*! + \fn QGLFormat QGLContext::requestedFormat() const + + Returns the frame buffer format that was originally requested in + the constructor or setFormat(). + + \sa format() +*/ + +/*! + Sets a \a format for this context. The context is \link reset() + reset\endlink. + + Call create() to create a new GL context that tries to match the + new format. + + \code + QGLContext *cx; + // ... + QGLFormat f; + f.setStereo( TRUE ); + cx->setFormat( f ); + if ( !cx->create() ) + exit(); // no OpenGL support, or cannot render on the specified paintdevice + if ( !cx->format().stereo() ) + exit(); // could not create stereo context + \endcode + + \sa format(), reset(), create() +*/ + +void QGLContext::setFormat( const QGLFormat &format ) +{ + reset(); + glFormat = reqFormat = format; +} + +/*! + \internal +*/ +void QGLContext::setDevice( QPaintDevice *pDev ) +{ + if ( isValid() ) + reset(); + d->paintDevice = pDev; + if ( d->paintDevice && (d->paintDevice->devType() != QInternal::Widget + && d->paintDevice->devType() != QInternal::Pixmap) ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QGLContext: Unsupported paint device type" ); +#endif + } +} + +void QGLContext::init( QPaintDevice *dev ) +{ + d = new Private; + d->valid = FALSE; +#if defined(Q_WS_X11) + qt_resolve_gl_symbols(); + gpm = 0; +#endif + setDevice( dev ); +#if defined(Q_WS_WIN) + dc = 0; + win = 0; + pixelFormatId = 0; + cmap = 0; +#endif +#if defined(Q_WS_MAC) + d->oldR = QRect(1, 1, 1, 1); +#endif + d->crWin = FALSE; + d->initDone = FALSE; + d->sharing = FALSE; +} + +/*! + \fn bool QGLContext::isValid() const + + Returns TRUE if a GL rendering context has been successfully + created; otherwise returns FALSE. +*/ + +/*! + \fn void QGLContext::setValid( bool valid ) + \internal + + Forces the GL rendering context to be valid. +*/ + +/*! + \fn bool QGLContext::isSharing() const + + Returns TRUE if display list sharing with another context was + requested in the create() call and the GL system was able to + fulfill this request; otherwise returns FALSE. Note that display + list sharing might not be supported between contexts with + different formats. +*/ + +/*! + \fn bool QGLContext::deviceIsPixmap() const + + Returns TRUE if the paint device of this context is a pixmap; + otherwise returns FALSE. +*/ + +/*! + \fn bool QGLContext::windowCreated() const + + Returns TRUE if a window has been created for this context; + otherwise returns FALSE. + + \sa setWindowCreated() +*/ + +/*! + \fn void QGLContext::setWindowCreated( bool on ) + + If \a on is TRUE the context has had a window created for it. If + \a on is FALSE no window has been created for the context. + + \sa windowCreated() +*/ + +/*! + \fn uint QGLContext::colorIndex( const QColor& c ) const + + \internal + + Returns a colormap index for the color c, in ColorIndex mode. Used + by qglColor() and qglClearColor(). +*/ + + +/*! + \fn bool QGLContext::initialized() const + + Returns TRUE if this context has been initialized, i.e. if + QGLWidget::initializeGL() has been performed on it; otherwise + returns FALSE. + + \sa setInitialized() +*/ + +/*! + \fn void QGLContext::setInitialized( bool on ) + + If \a on is TRUE the context has been initialized, i.e. + QGLContext::setInitialized() has been called on it. If \a on is + FALSE the context has not been initialized. + + \sa initialized() +*/ + +/*! + \fn const QGLContext* QGLContext::currentContext() + + Returns the current context, i.e. the context to which any OpenGL + commands will currently be directed. Returns 0 if no context is + current. + + \sa makeCurrent() +*/ + +/*! + \fn QColor QGLContext::overlayTransparentColor() const + + If this context is a valid context in an overlay plane, returns + the plane's transparent color. Otherwise returns an \link + QColor::isValid() invalid \endlink color. + + The returned color's \link QColor::pixel() pixel \endlink value is + the index of the transparent color in the colormap of the overlay + plane. (Naturally, the color's RGB values are meaningless.) + + The returned QColor object will generally work as expected only + when passed as the argument to QGLWidget::qglColor() or + QGLWidget::qglClearColor(). Under certain circumstances it can + also be used to draw transparent graphics with a QPainter. See the + examples/opengl/overlay_x11 example for details. +*/ + + +/*! + Creates the GL context. Returns TRUE if it was successful in + creating a valid GL rendering context on the paint device + specified in the constructor; otherwise returns FALSE (i.e. the + context is invalid). + + After successful creation, format() returns the set of features of + the created GL rendering context. + + If \a shareContext points to a valid QGLContext, this method will + try to establish OpenGL display list sharing between this context + and the \a shareContext. Note that this may fail if the two + contexts have different formats. Use isSharing() to see if sharing + succeeded. + + \warning Implementation note: initialization of C++ class + members usually takes place in the class constructor. QGLContext + is an exception because it must be simple to customize. The + virtual functions chooseContext() (and chooseVisual() for X11) can + be reimplemented in a subclass to select a particular context. The + problem is that virtual functions are not properly called during + construction (even though this is correct C++) because C++ + constructs class hierarchies from the bottom up. For this reason + we need a create() function. + + \sa chooseContext(), format(), isValid() +*/ + +bool QGLContext::create( const QGLContext* shareContext ) +{ + reset(); + d->valid = chooseContext( shareContext ); + return d->valid; +} + + + +/*! + \fn bool QGLContext::chooseContext( const QGLContext* shareContext = 0 ) + + This semi-internal function is called by create(). It creates a + system-dependent OpenGL handle that matches the format() of \a + shareContext as closely as possible. + + On Windows, it calls the virtual function choosePixelFormat(), + which finds a matching pixel format identifier. On X11, it calls + the virtual function chooseVisual() which finds an appropriate X + visual. On other platforms it may work differently. +*/ + + +/*! + \fn void QGLContext::reset() + + Resets the context and makes it invalid. + + \sa create(), isValid() +*/ + + +/*! + \fn void QGLContext::makeCurrent() + + Makes this context the current OpenGL rendering context. All GL + functions you call operate on this context until another context + is made current. + + In some very rare cases the underlying call may fail. If this + occurs an error message is output to stderr. +*/ + + +/*! + \fn void QGLContext::swapBuffers() const + + Swaps the screen contents with an off-screen buffer. Only works if + the context is in double buffer mode. + + \sa QGLFormat::setDoubleBuffer() +*/ + + +/*! + \fn void QGLContext::doneCurrent() + + Makes no GL context the current context. Normally, you do not need + to call this function; QGLContext calls it as necessary. +*/ + + +/*! + \fn QPaintDevice* QGLContext::device() const + + Returns the paint device set for this context. + + \sa QGLContext::QGLContext() +*/ + +/*! + \fn void QGLContext::generateFontDisplayLists( const QFont& font, int listBase ) + + Generates a set of 256 display lists for the 256 first characters + in the font \a font. The first list will start at index \a listBase. + + \sa QGLWidget::renderText() +*/ + + +/***************************************************************************** + QGLWidget implementation + *****************************************************************************/ + + +/*! + \class QGLWidget qgl.h + \brief The QGLWidget class is a widget for rendering OpenGL graphics. +\if defined(commercial) + It is part of the <a href="commercialeditions.html">Qt Enterprise Edition</a>. +\endif + + \ingroup graphics + \ingroup images + \mainclass + \module OpenGL + + QGLWidget provides functionality for displaying OpenGL<sup>*</sup> + graphics integrated into a Qt application. It is very simple to + use. You inherit from it and use the subclass like any other + QWidget, except that instead of drawing the widget's contents + using QPainter etc. you use the standard OpenGL rendering + commands. + + QGLWidget provides three convenient virtual functions that you can + reimplement in your subclass to perform the typical OpenGL tasks: + + \list + \i paintGL() - Renders the OpenGL scene. Gets called whenever the widget + needs to be updated. + \i resizeGL() - Sets up the OpenGL viewport, projection, etc. Gets + called whenever the the widget has been resized (and also when it + is shown for the first time because all newly created widgets get a + resize event automatically). + \i initializeGL() - Sets up the OpenGL rendering context, defines display + lists, etc. Gets called once before the first time resizeGL() or + paintGL() is called. + \endlist + + Here is a rough outline of how a QGLWidget subclass might look: + + \code + class MyGLDrawer : public QGLWidget + { + Q_OBJECT // must include this if you use Qt signals/slots + + public: + MyGLDrawer( QWidget *parent, const char *name ) + : QGLWidget(parent, name) {} + + protected: + + void initializeGL() + { + // Set up the rendering context, define display lists etc.: + ... + glClearColor( 0.0, 0.0, 0.0, 0.0 ); + glEnable(GL_DEPTH_TEST); + ... + } + + void resizeGL( int w, int h ) + { + // setup viewport, projection etc.: + glViewport( 0, 0, (GLint)w, (GLint)h ); + ... + glFrustum( ... ); + ... + } + + void paintGL() + { + // draw the scene: + ... + glRotatef( ... ); + glMaterialfv( ... ); + glBegin( GL_QUADS ); + glVertex3f( ... ); + glVertex3f( ... ); + ... + glEnd(); + ... + } + + }; + \endcode + + If you need to trigger a repaint from places other than paintGL() + (a typical example is when using \link QTimer timers\endlink to + animate scenes), you should call the widget's updateGL() function. + + Your widget's OpenGL rendering context is made current when + paintGL(), resizeGL(), or initializeGL() is called. If you need to + call the standard OpenGL API functions from other places (e.g. in + your widget's constructor or in your own paint functions), you + must call makeCurrent() first. + + QGLWidget provides functions for requesting a new display \link + QGLFormat format\endlink and you can also create widgets with + customized rendering \link QGLContext contexts\endlink. + + You can also share OpenGL display lists between QGLWidgets (see + the documentation of the QGLWidget constructors for details). + + \section1 Overlays + + The QGLWidget creates a GL overlay context in addition to the + normal context if overlays are supported by the underlying system. + + If you want to use overlays, you specify it in the \link QGLFormat + format\endlink. (Note: Overlay must be requested in the format + passed to the QGLWidget constructor.) Your GL widget should also + implement some or all of these virtual methods: + + \list + \i paintOverlayGL() + \i resizeOverlayGL() + \i initializeOverlayGL() + \endlist + + These methods work in the same way as the normal paintGL() etc. + functions, except that they will be called when the overlay + context is made current. You can explicitly make the overlay + context current by using makeOverlayCurrent(), and you can access + the overlay context directly (e.g. to ask for its transparent + color) by calling overlayContext(). + + On X servers in which the default visual is in an overlay plane, + non-GL Qt windows can also be used for overlays. See the + examples/opengl/overlay_x11 example program for details. + + <sup>*</sup> OpenGL is a trademark of Silicon Graphics, Inc. in the + United States and other countries. +*/ + +// ### BCI - fix in 4.0 + +// the display list cache can't be global because display lists are +// tied to the GL contexts for each individual widget + +class QGLWidgetPrivate +{ +public: + QMap<QString, int> displayListCache; +}; + +static QPtrDict<QGLWidgetPrivate> * qgl_d_ptr = 0; +static QSingleCleanupHandler< QPtrDict<QGLWidgetPrivate> > qgl_cleanup_d_ptr; + +static QGLWidgetPrivate * qgl_d( const QGLWidget * w ) +{ + if ( !qgl_d_ptr ) { + qgl_d_ptr = new QPtrDict<QGLWidgetPrivate>; + qgl_cleanup_d_ptr.set( &qgl_d_ptr ); + qgl_d_ptr->setAutoDelete( TRUE ); + } + QGLWidgetPrivate * ret = qgl_d_ptr->find( (void *) w ); + if ( !ret ) { + ret = new QGLWidgetPrivate; + qgl_d_ptr->replace( (void *) w, ret ); + } + return ret; +} + +void qgl_delete_d( const QGLWidget * w ) +{ + if ( qgl_d_ptr ) + qgl_d_ptr->remove( (void *) w ); +} + +/*! + Constructs an OpenGL widget with a \a parent widget and a \a name. + + The \link QGLFormat::defaultFormat() default format\endlink is + used. The widget will be \link isValid() invalid\endlink if the + system has no \link QGLFormat::hasOpenGL() OpenGL support\endlink. + + The \a parent, \a name and widget flag, \a f, arguments are passed + to the QWidget constructor. + + If the \a shareWidget parameter points to a valid QGLWidget, this + widget will share OpenGL display lists with \a shareWidget. If + this widget and \a shareWidget have different \link format() + formats\endlink, display list sharing may fail. You can check + whether display list sharing succeeded by calling isSharing(). + + The initialization of OpenGL rendering state, etc. should be done + by overriding the initializeGL() function, rather than in the + constructor of your QGLWidget subclass. + + \sa QGLFormat::defaultFormat() +*/ + +QGLWidget::QGLWidget( QWidget *parent, const char *name, + const QGLWidget* shareWidget, WFlags f ) + : QWidget( parent, name, f | Qt::WWinOwnDC | Qt::WNoAutoErase ) +{ + init( new QGLContext(QGLFormat::defaultFormat(), this), shareWidget ); +} + + +/*! + Constructs an OpenGL widget with parent \a parent, called \a name. + + The \a format argument specifies the desired \link QGLFormat + rendering options \endlink. If the underlying OpenGL/Window system + cannot satisfy all the features requested in \a format, the + nearest subset of features will be used. After creation, the + format() method will return the actual format obtained. + + The widget will be \link isValid() invalid\endlink if the system + has no \link QGLFormat::hasOpenGL() OpenGL support\endlink. + + The \a parent, \a name and widget flag, \a f, arguments are passed + to the QWidget constructor. + + If the \a shareWidget parameter points to a valid QGLWidget, this + widget will share OpenGL display lists with \a shareWidget. If + this widget and \a shareWidget have different \link format() + formats\endlink, display list sharing may fail. You can check + whether display list sharing succeeded by calling isSharing(). + + The initialization of OpenGL rendering state, etc. should be done + by overriding the initializeGL() function, rather than in the + constructor of your QGLWidget subclass. + + \sa QGLFormat::defaultFormat(), isValid() +*/ + +QGLWidget::QGLWidget( const QGLFormat &format, QWidget *parent, + const char *name, const QGLWidget* shareWidget, + WFlags f ) + : QWidget( parent, name, f | Qt::WWinOwnDC | Qt::WNoAutoErase ) +{ + init( new QGLContext(format, this), shareWidget ); +} + +/*! + Constructs an OpenGL widget with parent \a parent, called \a name. + + The \a context argument is a pointer to the QGLContext that + you wish to be bound to this widget. This allows you to pass in + your own QGLContext sub-classes. + + The widget will be \link isValid() invalid\endlink if the system + has no \link QGLFormat::hasOpenGL() OpenGL support\endlink. + + The \a parent, \a name and widget flag, \a f, arguments are passed + to the QWidget constructor. + + If the \a shareWidget parameter points to a valid QGLWidget, this + widget will share OpenGL display lists with \a shareWidget. If + this widget and \a shareWidget have different \link format() + formats\endlink, display list sharing may fail. You can check + whether display list sharing succeeded by calling isSharing(). + + The initialization of OpenGL rendering state, etc. should be done + by overriding the initializeGL() function, rather than in the + constructor of your QGLWidget subclass. + + \sa QGLFormat::defaultFormat(), isValid() +*/ +QGLWidget::QGLWidget( QGLContext *context, QWidget *parent, + const char *name, const QGLWidget *shareWidget, WFlags f ) + : QWidget( parent, name, f | Qt::WWinOwnDC | Qt::WNoAutoErase ) +{ + init( context, shareWidget ); +} + +/*! + Destroys the widget. +*/ + +QGLWidget::~QGLWidget() +{ +#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT) + bool doRelease = ( glcx && glcx->windowCreated() ); +#endif + qgl_delete_d( this ); + delete glcx; +#if defined(Q_WGL) + delete olcx; +#endif +#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT) + if ( doRelease ) + glXReleaseBuffersMESA( x11Display(), winId() ); +#endif +#if defined(Q_WS_MAC) + if(gl_pix) { + delete gl_pix; + gl_pix = NULL; + } +#endif + cleanupColormaps(); +} + + + + + +/*! + \fn QGLFormat QGLWidget::format() const + + Returns the format of the contained GL rendering context. +*/ + +/*! + \fn bool QGLWidget::doubleBuffer() const + + Returns TRUE if the contained GL rendering context has double + buffering; otherwise returns FALSE. + + \sa QGLFormat::doubleBuffer() +*/ + +/*! + \fn void QGLWidget::setAutoBufferSwap( bool on ) + + If \a on is TRUE automatic GL buffer swapping is switched on; + otherwise it is switched off. + + If \a on is TRUE and the widget is using a double-buffered format, + the background and foreground GL buffers will automatically be + swapped after each paintGL() call. + + The buffer auto-swapping is on by default. + + \sa autoBufferSwap(), doubleBuffer(), swapBuffers() +*/ + +/*! + \fn bool QGLWidget::autoBufferSwap() const + + Returns TRUE if the widget is doing automatic GL buffer swapping; + otherwise returns FALSE. + + \sa setAutoBufferSwap() +*/ + +/*! + \fn bool QGLWidget::isValid() const + + Returns TRUE if the widget has a valid GL rendering context; + otherwise returns FALSE. A widget will be invalid if the system + has no \link QGLFormat::hasOpenGL() OpenGL support\endlink. +*/ + +bool QGLWidget::isValid() const +{ + return glcx->isValid(); +} + +/*! + \fn bool QGLWidget::isSharing() const + + Returns TRUE if display list sharing with another QGLWidget was + requested in the constructor, and the GL system was able to + provide it; otherwise returns FALSE. The GL system may fail to + provide display list sharing if the two QGLWidgets use different + formats. + + \sa format() +*/ + +bool QGLWidget::isSharing() const +{ + return glcx->isSharing(); +} + +/*! + \fn void QGLWidget::makeCurrent() + + Makes this widget the current widget for OpenGL operations, i.e. + makes the widget's rendering context the current OpenGL rendering + context. +*/ + +void QGLWidget::makeCurrent() +{ +#if defined( Q_WS_MAC ) + macInternalDoubleBuffer(); //make sure the correct context is used +#endif + glcx->makeCurrent(); +} + +/*! + \fn void QGLWidget::doneCurrent() + + Makes no GL context the current context. Normally, you do not need + to call this function; QGLContext calls it as necessary. However, + it may be useful in multithreaded environments. +*/ + +void QGLWidget::doneCurrent() +{ + glcx->doneCurrent(); +} + +/*! + \fn void QGLWidget::swapBuffers() + + Swaps the screen contents with an off-screen buffer. This only + works if the widget's format specifies double buffer mode. + + Normally, there is no need to explicitly call this function + because it is done automatically after each widget repaint, i.e. + each time after paintGL() has been executed. + + \sa doubleBuffer(), setAutoBufferSwap(), QGLFormat::setDoubleBuffer() +*/ + +void QGLWidget::swapBuffers() +{ + glcx->swapBuffers(); +#if defined(Q_WS_MAC) + if(macInternalDoubleBuffer() && gl_pix) + bitBlt(this, 0, 0, gl_pix); +#endif +} + + +/*! + \fn const QGLContext* QGLWidget::overlayContext() const + + Returns the overlay context of this widget, or 0 if this widget + has no overlay. + + \sa context() +*/ + + + +/*! + \fn void QGLWidget::makeOverlayCurrent() + + Makes the overlay context of this widget current. Use this if you + need to issue OpenGL commands to the overlay context outside of + initializeOverlayGL(), resizeOverlayGL(), and paintOverlayGL(). + + Does nothing if this widget has no overlay. + + \sa makeCurrent() +*/ + + +/* + \obsolete + + Sets a new format for this widget. + + If the underlying OpenGL/Window system cannot satisfy all the + features requested in \a format, the nearest subset of features will + be used. After creation, the format() method will return the actual + rendering context format obtained. + + The widget will be assigned a new QGLContext, and the initializeGL() + function will be executed for this new context before the first + resizeGL() or paintGL(). + + This method will try to keep any existing display list sharing with + other QGLWidgets, but it may fail. Use isSharing() to test. + + \sa format(), isSharing(), isValid() +*/ + +void QGLWidget::setFormat( const QGLFormat &format ) +{ + setContext( new QGLContext(format,this) ); +} + + + + +/*! + \fn const QGLContext *QGLWidget::context() const + + Returns the context of this widget. + + It is possible that the context is not valid (see isValid()), for + example, if the underlying hardware does not support the format + attributes that were requested. +*/ + +/* + \obsolete + + \fn void QGLWidget::setContext( QGLContext *context, + const QGLContext* shareContext, + bool deleteOldContext ) + + Sets a new context for this widget. The QGLContext \a context must + be created using \e new. QGLWidget will delete \a context when + another context is set or when the widget is destroyed. + + If \a context is invalid, QGLContext::create() is performed on + it. The initializeGL() function will then be executed for the new + context before the first resizeGL() or paintGL(). + + If \a context is invalid, this method will try to keep any existing + display list sharing with other QGLWidgets this widget currently + has, or (if \a shareContext points to a valid context) start display + list sharing with that context, but it may fail. Use isSharing() to + test. + + If \a deleteOldContext is TRUE (the default), the existing context + will be deleted. You may use FALSE here if you have kept a pointer + to the old context (as returned by context()), and want to restore + that context later. + + \sa context(), isSharing() +*/ + + + +/*! + \fn void QGLWidget::updateGL() + + Updates the widget by calling glDraw(). +*/ + +void QGLWidget::updateGL() +{ + glDraw(); +} + + +/*! + \fn void QGLWidget::updateOverlayGL() + + Updates the widget's overlay (if any). Will cause the virtual + function paintOverlayGL() to be executed. + + The widget's rendering context will become the current context and + initializeGL() will be called if it hasn't already been called. +*/ + + +/*! + This virtual function is called once before the first call to + paintGL() or resizeGL(), and then once whenever the widget has + been assigned a new QGLContext. Reimplement it in a subclass. + + This function should set up any required OpenGL context rendering + flags, defining display lists, etc. + + There is no need to call makeCurrent() because this has already + been done when this function is called. +*/ + +void QGLWidget::initializeGL() +{ +} + + +/*! + This virtual function is called whenever the widget needs to be + painted. Reimplement it in a subclass. + + There is no need to call makeCurrent() because this has already + been done when this function is called. +*/ + +void QGLWidget::paintGL() +{ +} + + +/*! + \fn void QGLWidget::resizeGL( int width , int height ) + + This virtual function is called whenever the widget has been + resized. The new size is passed in \a width and \a height. + Reimplement it in a subclass. + + There is no need to call makeCurrent() because this has already + been done when this function is called. +*/ + +void QGLWidget::resizeGL( int, int ) +{ +} + + + +/*! + This virtual function is used in the same manner as initializeGL() + except that it operates on the widget's overlay context instead of + the widget's main context. This means that initializeOverlayGL() + is called once before the first call to paintOverlayGL() or + resizeOverlayGL(). Reimplement it in a subclass. + + This function should set up any required OpenGL context rendering + flags, defining display lists, etc. for the overlay context. + + There is no need to call makeOverlayCurrent() because this has + already been done when this function is called. +*/ + +void QGLWidget::initializeOverlayGL() +{ +} + + +/*! + This virtual function is used in the same manner as paintGL() + except that it operates on the widget's overlay context instead of + the widget's main context. This means that paintOverlayGL() is + called whenever the widget's overlay needs to be painted. + Reimplement it in a subclass. + + There is no need to call makeOverlayCurrent() because this has + already been done when this function is called. +*/ + +void QGLWidget::paintOverlayGL() +{ +} + + +/*! + \fn void QGLWidget::resizeOverlayGL( int width , int height ) + + This virtual function is used in the same manner as paintGL() + except that it operates on the widget's overlay context instead of + the widget's main context. This means that resizeOverlayGL() is + called whenever the widget has been resized. The new size is + passed in \a width and \a height. Reimplement it in a subclass. + + There is no need to call makeOverlayCurrent() because this has + already been done when this function is called. +*/ + +void QGLWidget::resizeOverlayGL( int, int ) +{ +} + + + + +/*! + Handles paint events. Will cause the virtual paintGL() function to + be called. + + The widget's rendering context will become the current context and + initializeGL() will be called if it hasn't already been called. +*/ + +void QGLWidget::paintEvent( QPaintEvent * ) +{ + glDraw(); + updateOverlayGL(); +} + + +/*! + \fn void QGLWidget::resizeEvent( QResizeEvent * ) + + Handles resize events. Calls the virtual function resizeGL(). +*/ + + +/*! + \fn void QGLWidget::setMouseTracking( bool enable ) + + \reimp +*/ + + +/*! + Renders the current scene on a pixmap and returns the pixmap. + + You can use this method on both visible and invisible QGLWidgets. + + This method will create a pixmap and a temporary QGLContext to + render on the pixmap. It will then call initializeGL(), + resizeGL(), and paintGL() on this context. Finally, the widget's + original GL context is restored. + + The size of the pixmap will be \a w pixels wide and \a h pixels + high unless one of these parameters is 0 (the default), in which + case the pixmap will have the same size as the widget. + + If \a useContext is TRUE, this method will try to be more + efficient by using the existing GL context to render the pixmap. + The default is FALSE. Only use TRUE if you understand the risks. + + Overlays are not rendered onto the pixmap. + + If the GL rendering context and the desktop have different bit + depths, the result will most likely look surprising. + + Note that the creation of display lists, modifications of the view + frustum etc. should be done from within initializeGL(). If this is + not done, the temporary QGLContext will not be initialized + properly, and the rendered pixmap may be incomplete/corrupted. +*/ + +QPixmap QGLWidget::renderPixmap( int w, int h, bool useContext ) +{ + QSize sz = size(); + if ( (w > 0) && (h > 0) ) + sz = QSize( w, h ); + +#if defined(Q_WS_X11) + QPixmap pm( sz.width(), sz.height(), x11Depth() ); + bool needConversion = x11Visual() != QPaintDevice::x11AppVisual(); + + // make sure the pixmap uses the same visual as the widget itself + if ( needConversion ) { + QPaintDeviceX11Data* xd = pm.getX11Data( TRUE ); + xd->x_depth = x11Depth(); + xd->x_visual = (Visual *) x11Visual(); + pm.setX11Data( xd ); + } +#else + QPixmap pm; + pm.resize( sz ); +#endif + + glcx->doneCurrent(); + + bool success = TRUE; + + if ( useContext && isValid() && renderCxPm( &pm ) ) + return pm; + + QGLFormat fmt = glcx->requestedFormat(); + fmt.setDirectRendering( FALSE ); // Direct is unlikely to work + fmt.setDoubleBuffer( FALSE ); // We don't need dbl buf + + QGLContext* ocx = glcx; + bool wasCurrent = (QGLContext::currentContext() == ocx ); + ocx->doneCurrent(); + glcx = new QGLContext( fmt, &pm ); + glcx->create(); + + if ( glcx->isValid() ) + updateGL(); + else + success = FALSE; + + delete glcx; + glcx = ocx; + + if ( wasCurrent ) + ocx->makeCurrent(); + + if ( success ) { +#if defined(Q_WS_X11) + if ( needConversion ) { + QImage image = pm.convertToImage(); + QPixmap p; + p = image; + return p; + } +#endif + return pm; + } else + return QPixmap(); +} + + + +/*! + Returns an image of the frame buffer. If \a withAlpha is TRUE the + alpha channel is included. + + Depending on your hardware, you can explicitly select which color + buffer to grab with a glReadBuffer() call before calling this + function. +*/ +QImage QGLWidget::grabFrameBuffer( bool withAlpha ) +{ +#if defined( Q_WS_MAC ) + if(dblbuf == macInternalDoubleBuffer(FALSE) && gl_pix) //why not optimize? + return ((QPixmap*)gl_pix)->convertToImage(); +#endif + makeCurrent(); + QImage res; + int w = width(); + int h = height(); + if ( format().rgba() ) { + res = QImage( w, h, 32 ); + glReadPixels( 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, res.bits() ); + if ( QImage::systemByteOrder() == QImage::BigEndian ) { + // OpenGL gives RGBA; Qt wants ARGB + uint *p = (uint*)res.bits(); + uint *end = p + w*h; + if ( withAlpha && format().alpha() ) { + while ( p < end ) { + uint a = *p << 24; + *p = (*p >> 8) | a; + p++; + } + } + else { + while ( p < end ) + *p++ >>= 8; + } + } + else { + // OpenGL gives ABGR (i.e. RGBA backwards); Qt wants ARGB + res = res.swapRGB(); + } + res.setAlphaBuffer( withAlpha && format().alpha() ); + } + else { +#if defined (Q_WS_WIN) + res = QImage( w, h, 8 ); + glReadPixels( 0, 0, w, h, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, + res.bits() ); + int palSize = 0; + const QRgb* pal = QColor::palette( &palSize ); + if ( pal && palSize ) { + res.setNumColors( palSize ); + for ( int i = 0; i < palSize; i++ ) + res.setColor( i, pal[i] ); + } +#endif + } + + return res.mirror(); +} + + + +/*! + Initializes OpenGL for this widget's context. Calls the virtual + function initializeGL(). +*/ + +void QGLWidget::glInit() +{ + if ( !isValid() ) + return; + makeCurrent(); + initializeGL(); + glcx->setInitialized( TRUE ); +} + + +/*! + Executes the virtual function paintGL(). + + The widget's rendering context will become the current context and + initializeGL() will be called if it hasn't already been called. +*/ + +void QGLWidget::glDraw() +{ + if ( !isValid() ) + return; + makeCurrent(); + if ( glcx->deviceIsPixmap() ) + glDrawBuffer( GL_FRONT ); + if ( !glcx->initialized() ) { + glInit(); + QPaintDeviceMetrics dm( glcx->device() ); + resizeGL( dm.width(), dm.height() ); // New context needs this "resize" + } + paintGL(); + if ( doubleBuffer() ) { + if ( autoSwap ) + swapBuffers(); + } else { + glFlush(); +#if defined( Q_WS_MAC ) + if(dblbuf && gl_pix) + bitBlt(this, 0, 0, gl_pix); +#endif + } +} + + +/*! + Convenience function for specifying a drawing color to OpenGL. + Calls glColor3 (in RGBA mode) or glIndex (in color-index mode) + with the color \a c. Applies to the current GL context. + + \sa qglClearColor(), QGLContext::currentContext(), QColor +*/ + +void QGLWidget::qglColor( const QColor& c ) const +{ + const QGLContext* ctx = QGLContext::currentContext(); + if ( ctx ) { + if ( ctx->format().rgba() ) + glColor3ub( c.red(), c.green(), c.blue() ); + + else if ( ctx->device() == context()->device() + && !cmap.isEmpty() ) { // QGLColormap in use? + int i = cmap.find( c.rgb() ); + if ( i < 0 ) + i = cmap.findNearest( c.rgb() ); + glIndexi( i ); + } else + glIndexi( ctx->colorIndex( c ) ); + } +} + +/*! + Convenience function for specifying the clearing color to OpenGL. + Calls glClearColor (in RGBA mode) or glClearIndex (in color-index + mode) with the color \a c. Applies to the current GL context. + + \sa qglColor(), QGLContext::currentContext(), QColor +*/ + +void QGLWidget::qglClearColor( const QColor& c ) const +{ + const QGLContext* ctx = QGLContext::currentContext(); + if ( ctx ) { + if ( ctx->format().rgba() ) + glClearColor( (GLfloat)c.red() / 255.0, (GLfloat)c.green() / 255.0, + (GLfloat)c.blue() / 255.0, (GLfloat) 0.0 ); + else if ( ctx->device() == context()->device() + && !cmap.isEmpty() ) { // QGLColormap in use? + int i = cmap.find( c.rgb() ); + if ( i < 0 ) + i = cmap.findNearest( c.rgb() ); + glClearIndex( i ); + } else + glClearIndex( ctx->colorIndex( c ) ); + } +} + + +/*! + Converts the image \a img into the unnamed format expected by + OpenGL functions such as glTexImage2D(). The returned image is not + usable as a QImage, but QImage::width(), QImage::height() and + QImage::bits() may be used with OpenGL. The following few lines + are from the texture example. Most of the code is irrelevant, so + we just quote the relevant bits: + + \quotefile opengl/texture/gltexobj.cpp + \skipto tex1 + \printline tex1 + \printline gllogo.bmp + + We create \e tex1 (and another variable) for OpenGL, and load a real + image into \e buf. + + \skipto convertToGLFormat + \printline convertToGLFormat + + A few lines later, we convert \e buf into OpenGL format and store it + in \e tex1. + + \skipto glTexImage2D + \printline glTexImage2D + \printline tex1.bits + + Note the dimension restrictions for texture images as described in + the glTexImage2D() documentation. The width must be 2^m + 2*border + and the height 2^n + 2*border where m and n are integers and + border is either 0 or 1. + + Another function in the same example uses \e tex1 with OpenGL. +*/ + + +QImage QGLWidget::convertToGLFormat( const QImage& img ) +{ + QImage res = img.convertDepth( 32 ); + res = res.mirror(); + + if ( QImage::systemByteOrder() == QImage::BigEndian ) { + // Qt has ARGB; OpenGL wants RGBA + for ( int i=0; i < res.height(); i++ ) { + uint *p = (uint*)res.scanLine( i ); + uint *end = p + res.width(); + while ( p < end ) { + *p = (*p << 8) | ((*p >> 24) & 0xFF); + p++; + } + } + } + else { + // Qt has ARGB; OpenGL wants ABGR (i.e. RGBA backwards) + res = res.swapRGB(); + } + return res; +} + + +/*! + \fn QGLColormap & QGLWidget::colormap() const + + Returns the colormap for this widget. + + Usually it is only top-level widgets that can have different + colormaps installed. Asking for the colormap of a child widget + will return the colormap for the child's top-level widget. + + If no colormap has been set for this widget, the QColormap + returned will be empty. + + \sa setColormap() +*/ + +/*! + \fn void QGLWidget::setColormap( const QGLColormap & cmap ) + + Set the colormap for this widget to \a cmap. Usually it is only + top-level widgets that can have colormaps installed. + + \sa colormap() +*/ + +int QGLWidget::displayListBase( const QFont & fnt, int listBase ) +{ + int base; + + QGLWidgetPrivate * d = qgl_d( this ); + if ( !d || !glcx ) { // this can't happen unless we run out of mem + return 0; + } + + // always regenerate font disp. lists for pixmaps - hw accelerated + // contexts can't handle this otherwise + bool regenerate = glcx->deviceIsPixmap(); + +#if 0 // QT_NO_XFTFREETYPE + // font color needs to be part of the font cache key when using + // antialiased fonts since one set of glyphs needs to be generated + // for each font color + QString color_key; + if (fnt.styleStrategy() != QFont::NoAntialias) { + GLfloat color[4]; + glGetFloatv(GL_CURRENT_COLOR, color); + color_key.sprintf("%f_%f_%f",color[0], color[1], color[2]); + } + QString key = fnt.key() + color_key + QString::number((int) regenerate); +#else + QString key = fnt.key() + QString::number((int) regenerate); +#endif + + if ( !regenerate && (d->displayListCache.find( key ) != d->displayListCache.end()) ) { + base = d->displayListCache[ key ]; + } else { + int maxBase = listBase - 256; + QMapConstIterator<QString,int> it; + for ( it = d->displayListCache.begin(); it != d->displayListCache.end(); ++it ) { + if ( maxBase < it.data() ) { + maxBase = it.data(); + } + } + maxBase += 256; + glcx->generateFontDisplayLists( fnt, maxBase ); + d->displayListCache[ key ] = maxBase; + base = maxBase; + } + return base; +} + +/*! + Renders the string \a str into the GL context of this widget. + + \a x and \a y are specified in window coordinates, with the origin + in the upper left-hand corner of the window. If \a fnt is not + specified, the currently set application font will be used to + render the string. To change the color of the rendered text you can + use the glColor() call (or the qglColor() convenience function), + just before the renderText() call. Note that if you have + GL_LIGHTING enabled, the string will not appear in the color you + want. You should therefore switch lighting off before using + renderText(). + + \a listBase specifies the index of the first display list that is + generated by this function. The default value is 2000. 256 display + lists will be generated, one for each of the first 256 characters + in the font that is used to render the string. If several fonts are + used in the same widget, the display lists for these fonts will + follow the last generated list. You would normally not have to + change this value unless you are using lists in the same range. The + lists are deleted when the widget is destroyed. + + Note: This function only works reliably with ASCII strings. +*/ + +void QGLWidget::renderText( int x, int y, const QString & str, const QFont & fnt, int listBase ) +{ + if (str.isEmpty()) + return; + makeCurrent(); + glPushAttrib( GL_TRANSFORM_BIT | GL_VIEWPORT_BIT | GL_LIST_BIT | GL_CURRENT_BIT ); + glMatrixMode( GL_PROJECTION ); + glPushMatrix(); + glLoadIdentity(); + glOrtho( 0, width(), height(), 0, -1, 1 ); + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glLoadIdentity(); + + glRasterPos2i( 0, 0 ); + glBitmap(0, 0, 0, 0, x, -y, NULL); + glListBase( displayListBase( fnt, listBase ) ); + const char *cstr = str.latin1(); + glCallLists( qstrlen(cstr), GL_UNSIGNED_BYTE, cstr ); + + // restore the matrix stacks and GL state + glPopMatrix(); + glMatrixMode( GL_PROJECTION ); + glPopMatrix(); + glPopAttrib(); +} + +/*! \overload + + \a x, \a y and \a z are specified in scene or object coordinates + relative to the currently set projection and model matrices. This + can be useful if you want to annotate models with text labels and + have the labels move with the model as it is rotated etc. +*/ +void QGLWidget::renderText( double x, double y, double z, const QString & str, const QFont & fnt, + int listBase ) +{ + if (str.isEmpty()) + return; + makeCurrent(); + glRasterPos3d( x, y, z ); + glPushAttrib( GL_LIST_BIT ); + glListBase( displayListBase( fnt, listBase ) ); + const char *cstr = str.latin1(); + glCallLists( qstrlen(cstr), GL_UNSIGNED_BYTE, cstr ); + glPopAttrib(); +} + +/***************************************************************************** + QGL classes overview documentation. + *****************************************************************************/ + +/*! + +\page opengl.html + +\title Qt OpenGL 3D Graphics + +\if defined(commercial) +This module is part of the \link commercialeditions.html Qt Enterprise +Edition\endlink. +\endif + +\section1 Introduction + +OpenGL is a standard API for rendering 3D graphics. + +OpenGL only deals with 3D rendering and provides little or no support +for GUI programming issues. The user interface for an +OpenGL<sup>*</sup> application must be created with another toolkit, +such as Motif on the X platform, Microsoft Foundation Classes (MFC) +under Windows, or Qt on \e both platforms. + +The Qt OpenGL module makes it easy to use OpenGL in Qt applications. +It provides an OpenGL widget class that can be used just like any +other Qt widget, except that it opens an OpenGL display buffer where +you can use the OpenGL API to render the contents. + +The Qt OpenGL module is implemented as a platform-independent Qt/C++ +wrapper around the platform-dependent GLX, WGL, or AGL C APIs. The +functionality provided is very similar to Mark Kilgard's GLUT library, +but with much more non-OpenGL-specific GUI functionality, i.e. the +whole Qt API. + +\section1 Installation + +When you install Qt for X11, the configure script will autodetect if +OpenGL headers and libraries are installed on your system, and if so, +it will include the Qt OpenGL module in the Qt library. (If your +OpenGL headers or libraries are placed in a non-standard directory, +you may need to change the QMAKE_INCDIR_OPENGL and/or +QMAKE_LIBDIR_OPENGL in the config file for your system). Some +configurations require threading to be enabled for OpenGL, so if +OpenGL is not detected, try \c{configure -thread}. + +When you install Qt for Windows, the Qt OpenGL module is always +included. + +The Qt OpenGL module is not licensed for use with the Qt Professional +Edition. Consider upgrading to the Qt Enterprise Edition if you +require OpenGL support. + +Note about using Mesa on X11: Mesa versions earlier than 3.1 would use +the name "MesaGL" and "MesaGLU" for the libraries, instead of "GL" and +"GLU". If you want to use a pre-3.1 version of Mesa, you must change +the Makefiles to use these library names instead. The easiest way to +do this is to edit the QMAKE_LIBS_OPENGL line in the config file you +are using, changing "-lGL -lGLU" to "-lMesaGL -lMesaGLU"; then run +"configure" again. + +\section1 The QGL Classes + +The OpenGL support classes in Qt are: +\list +\i \link QGLWidget QGLWidget\endlink: An easy-to-use Qt + widget for rendering OpenGL scenes. +\i \link QGLContext QGLContext\endlink: Encapsulates an OpenGL rendering context. +\i \link QGLFormat QGLFormat\endlink: Specifies the +display format of a rendering context. +\i \link QGLColormap QGLColormap\endlink: Handles indexed +colormaps in GL-index mode. +\endlist + +Many applications only need the high-level QGLWidget class. The other +QGL classes provide advanced features. X11 users might like to read +the notes on \link opengl-x11-overlays.html overlays\endlink. + +See also the \link opengl-examples.html OpenGL examples\endlink. + +The QGL documentation assumes that you are familiar with OpenGL +programming. If you're new to the subject a good starting point is +\l{http://www.opengl.org/}. + + +<sup>*</sup> OpenGL is a trademark of Silicon Graphics, Inc. in the +United States and other countries. + +*/ + +/*! + \enum QGL::FormatOption + + This enum specifies the format options. + + \value DoubleBuffer + \value DepthBuffer + \value Rgba + \value AlphaChannel + \value AccumBuffer + \value StencilBuffer + \value StereoBuffers + \value DirectRendering + \value HasOverlay + \value SingleBuffer + \value NoDepthBuffer + \value ColorIndex + \value NoAlphaChannel + \value NoAccumBuffer + \value NoStencilBuffer + \value NoStereoBuffers + \value IndirectRendering + \value NoOverlay +*/ diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h new file mode 100644 index 0000000..55fa07e --- /dev/null +++ b/src/opengl/qgl.h @@ -0,0 +1,541 @@ +/**************************************************************************** +** +** Definition of OpenGL classes for Qt +** +** Created : 970112 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the opengl module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QGL_H +#define QGL_H + +#ifndef QT_H +#include "qwidget.h" +#include "qglcolormap.h" +#endif // QT_H + +#if !defined( QT_MODULE_OPENGL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_OPENGL +#else +#define QM_EXPORT_OPENGL Q_EXPORT +#endif + +#ifndef QT_NO_COMPAT +#define QGL_VERSION 450 +#define QGL_VERSION_STR "4.5" +QM_EXPORT_OPENGL inline const char *qGLVersion() { + qObsolete( 0, "qGLVersion", "qVersion" ); + return QGL_VERSION_STR; +} +#endif + +#if defined(Q_WS_WIN) +# include "qt_windows.h" +#endif + +#if defined(Q_WS_MAC) +#if !defined( QMAC_OPENGL_DOUBLEBUFFER ) +/* This macro is different now. If the macro is not defined QGLWidget will + * try to determine when you need double buffering. If set to 0 it will + * never double buffer and *can* be acclerated. If set to 1 (the default) + * it will always double buffer. Unlike before the value of this macro does + * not upset binary compatability either. */ +#if QT_MACOSX_VERSION >= 0x1020 +# define QMAC_OPENGL_DOUBLEBUFFER 0 +#endif +#endif +# include <OpenGL/gl.h> +# include <OpenGL/glu.h> +#else +# include <GL/gl.h> +# include <GL/glu.h> +#endif + +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) +class QGLCmap; +#endif + +class QPixmap; +#if defined(Q_WS_X11) +class QGLOverlayWidget; +#endif + +// Namespace class: +class QM_EXPORT_OPENGL QGL +{ +public: + enum FormatOption { + DoubleBuffer = 0x0001, + DepthBuffer = 0x0002, + Rgba = 0x0004, + AlphaChannel = 0x0008, + AccumBuffer = 0x0010, + StencilBuffer = 0x0020, + StereoBuffers = 0x0040, + DirectRendering = 0x0080, + HasOverlay = 0x0100, + SingleBuffer = DoubleBuffer << 16, + NoDepthBuffer = DepthBuffer << 16, + ColorIndex = Rgba << 16, + NoAlphaChannel = AlphaChannel << 16, + NoAccumBuffer = AccumBuffer << 16, + NoStencilBuffer = StencilBuffer << 16, + NoStereoBuffers = StereoBuffers << 16, + IndirectRendering = DirectRendering << 16, + NoOverlay = HasOverlay << 16 + }; +}; + + + +class QM_EXPORT_OPENGL QGLFormat : public QGL +{ +public: + QGLFormat(); + QGLFormat( int options, int plane = 0 ); + + bool doubleBuffer() const; + void setDoubleBuffer( bool enable ); + bool depth() const; + void setDepth( bool enable ); + bool rgba() const; + void setRgba( bool enable ); + bool alpha() const; + void setAlpha( bool enable ); + bool accum() const; + void setAccum( bool enable ); + bool stencil() const; + void setStencil( bool enable ); + bool stereo() const; + void setStereo( bool enable ); + bool directRendering() const; + void setDirectRendering( bool enable ); + bool hasOverlay() const; + void setOverlay( bool enable ); + + int plane() const; + void setPlane( int plane ); + + void setOption( FormatOption opt ); + bool testOption( FormatOption opt ) const; + + static QGLFormat defaultFormat(); + static void setDefaultFormat( const QGLFormat& f ); + + static QGLFormat defaultOverlayFormat(); + static void setDefaultOverlayFormat( const QGLFormat& f ); + + static bool hasOpenGL(); + static bool hasOpenGLOverlays(); + + friend QM_EXPORT_OPENGL bool operator==( const QGLFormat&, + const QGLFormat& ); + friend QM_EXPORT_OPENGL bool operator!=( const QGLFormat&, + const QGLFormat& ); +private: + uint opts; + int pln; +}; + + +QM_EXPORT_OPENGL bool operator==( const QGLFormat&, const QGLFormat& ); +QM_EXPORT_OPENGL bool operator!=( const QGLFormat&, const QGLFormat& ); + +class QM_EXPORT_OPENGL QGLContext : public QGL +{ +public: + QGLContext( const QGLFormat& format, QPaintDevice* device ); + QGLContext( const QGLFormat& format ); + virtual ~QGLContext(); + + virtual bool create( const QGLContext* shareContext = 0 ); + bool isValid() const; + bool isSharing() const; + virtual void reset(); + + QGLFormat format() const; + QGLFormat requestedFormat() const; + virtual void setFormat( const QGLFormat& format ); + + virtual void makeCurrent(); + virtual void swapBuffers() const; + + QPaintDevice* device() const; + + QColor overlayTransparentColor() const; + + static const QGLContext* currentContext(); + +protected: + virtual bool chooseContext( const QGLContext* shareContext = 0 ); + virtual void doneCurrent(); // ### 4.0: make this public - needed for multithreading stuff + +#if defined(Q_WS_WIN) + virtual int choosePixelFormat( void* pfd, HDC pdc ); +#endif +#if defined(Q_WS_X11) + virtual void* tryVisual( const QGLFormat& f, int bufDepth = 1 ); + virtual void* chooseVisual(); +#endif +#if defined(Q_WS_MAC) + virtual void* chooseMacVisual(GDHandle); +#endif + + bool deviceIsPixmap() const; + bool windowCreated() const; + void setWindowCreated( bool on ); + bool initialized() const; + void setInitialized( bool on ); + void generateFontDisplayLists( const QFont & fnt, int listBase ); + + uint colorIndex( const QColor& c ) const; + void setValid( bool valid ); + void setDevice( QPaintDevice *pDev ); + +protected: +#if defined(Q_WS_WIN) + HGLRC rc; + HDC dc; + WId win; + int pixelFormatId; + QGLCmap* cmap; +#elif defined(Q_WS_X11) || defined(Q_WS_MAC) + void* vi; + void* cx; +#if defined(Q_WS_X11) + Q_UINT32 gpm; +#endif +#endif + QGLFormat glFormat; + QGLFormat reqFormat; + static QGLContext* currentCtx; + +private: + void init( QPaintDevice *dev = 0 ); + class Private { + public: + bool valid; + bool sharing; + bool initDone; + bool crWin; + QPaintDevice* paintDevice; + QColor transpColor; +#ifdef Q_WS_MAC + QRect oldR; +#endif + }; + Private* d; + + friend class QGLWidget; +#ifdef Q_WS_MAC + void fixBufferRect(); +#endif + +private: // Disabled copy constructor and operator= + QGLContext() {} + QGLContext( const QGLContext& ) {} + QGLContext& operator=( const QGLContext& ) { return *this; } +}; + + + + +class QM_EXPORT_OPENGL QGLWidget : public QWidget, public QGL +{ + Q_OBJECT +public: + QGLWidget( QWidget* parent=0, const char* name=0, + const QGLWidget* shareWidget = 0, WFlags f=0 ); + QGLWidget( QGLContext *context, QWidget* parent, const char* name=0, + const QGLWidget* shareWidget = 0, WFlags f=0 ); + QGLWidget( const QGLFormat& format, QWidget* parent=0, const char* name=0, + const QGLWidget* shareWidget = 0, WFlags f=0 ); + ~QGLWidget(); + + void qglColor( const QColor& c ) const; + void qglClearColor( const QColor& c ) const; + + bool isValid() const; + bool isSharing() const; + virtual void makeCurrent(); + void doneCurrent(); + + bool doubleBuffer() const; + virtual void swapBuffers(); + + QGLFormat format() const; +#ifndef Q_QDOC + virtual void setFormat( const QGLFormat& format ); +#endif + + const QGLContext* context() const; +#ifndef Q_QDOC + virtual void setContext( QGLContext* context, + const QGLContext* shareContext = 0, + bool deleteOldContext = TRUE ); +#endif + + virtual QPixmap renderPixmap( int w = 0, int h = 0, + bool useContext = FALSE ); + virtual QImage grabFrameBuffer( bool withAlpha = FALSE ); + + virtual void makeOverlayCurrent(); + const QGLContext* overlayContext() const; + + static QImage convertToGLFormat( const QImage& img ); + + void setMouseTracking( bool enable ); + virtual void reparent( QWidget* parent, WFlags f, const QPoint& p, + bool showIt = FALSE ); + + const QGLColormap & colormap() const; + void setColormap( const QGLColormap & map ); + + void renderText( int x, int y, const QString & str, + const QFont & fnt = QFont(), int listBase = 2000 ); + void renderText( double x, double y, double z, const QString & str, + const QFont & fnt = QFont(), int listBase = 2000 ); +public slots: + virtual void updateGL(); + virtual void updateOverlayGL(); + +protected: + virtual void initializeGL(); + virtual void resizeGL( int w, int h ); + virtual void paintGL(); + + virtual void initializeOverlayGL(); + virtual void resizeOverlayGL( int w, int h ); + virtual void paintOverlayGL(); + + void setAutoBufferSwap( bool on ); + bool autoBufferSwap() const; + + void paintEvent( QPaintEvent* ); + void resizeEvent( QResizeEvent* ); + + virtual void glInit(); + virtual void glDraw(); + +private: + int displayListBase( const QFont & fnt, int listBase ); + void cleanupColormaps(); + void init( QGLContext *context, const QGLWidget* shareWidget ); + bool renderCxPm( QPixmap* pm ); + QGLContext* glcx; + bool autoSwap; + + QGLColormap cmap; + +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) + QGLContext* olcx; +#elif defined(Q_WS_X11) + QGLOverlayWidget* olw; + friend class QGLOverlayWidget; +#endif + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QGLWidget( const QGLWidget& ); + QGLWidget& operator=( const QGLWidget& ); +#endif + +#if defined(Q_WS_MAC) +private: + const QGLContext *slcx; + uint pending_fix : 1, + glcx_dblbuf : 2, + dblbuf : 1, + clp_serial : 15; + QPixmap *gl_pix; + QGLFormat req_format; + + void macInternalRecreateContext( QGLContext *ctx, + const QGLContext* = NULL, + bool update = TRUE ); + bool macInternalDoubleBuffer( bool fix = TRUE ); + virtual void setRegionDirty( bool ); + virtual void macWidgetChangedWindow(); +#endif +private slots: + void macInternalFixBufferRect(); +}; + + +// +// QGLFormat inline functions +// + +inline bool QGLFormat::doubleBuffer() const +{ + return testOption( DoubleBuffer ); +} + +inline bool QGLFormat::depth() const +{ + return testOption( DepthBuffer ); +} + +inline bool QGLFormat::rgba() const +{ + return testOption( Rgba ); +} + +inline bool QGLFormat::alpha() const +{ + return testOption( AlphaChannel ); +} + +inline bool QGLFormat::accum() const +{ + return testOption( AccumBuffer ); +} + +inline bool QGLFormat::stencil() const +{ + return testOption( StencilBuffer ); +} + +inline bool QGLFormat::stereo() const +{ + return testOption( StereoBuffers ); +} + +inline bool QGLFormat::directRendering() const +{ + return testOption( DirectRendering ); +} + +inline bool QGLFormat::hasOverlay() const +{ + return testOption( HasOverlay ); +} + +// +// QGLContext inline functions +// + +inline bool QGLContext::isValid() const +{ + return d->valid; +} + +inline void QGLContext::setValid( bool valid ) +{ + d->valid = valid; +} + +inline bool QGLContext::isSharing() const +{ + return d->sharing; +} + +inline QGLFormat QGLContext::format() const +{ + return glFormat; +} + +inline QGLFormat QGLContext::requestedFormat() const +{ + return reqFormat; +} + +inline QPaintDevice* QGLContext::device() const +{ + return d->paintDevice; +} + +inline bool QGLContext::deviceIsPixmap() const +{ + return d->paintDevice->devType() == QInternal::Pixmap; +} + + +inline bool QGLContext::windowCreated() const +{ + return d->crWin; +} + + +inline void QGLContext::setWindowCreated( bool on ) +{ + d->crWin = on; +} + +inline bool QGLContext::initialized() const +{ + return d->initDone; +} + +inline void QGLContext::setInitialized( bool on ) +{ + d->initDone = on; +} + +inline const QGLContext* QGLContext::currentContext() +{ + return currentCtx; +} + +// +// QGLWidget inline functions +// + +inline QGLFormat QGLWidget::format() const +{ + return glcx->format(); +} + +inline const QGLContext *QGLWidget::context() const +{ + return glcx; +} + +inline bool QGLWidget::doubleBuffer() const +{ + return glcx->format().doubleBuffer(); +} + +inline void QGLWidget::setAutoBufferSwap( bool on ) +{ + autoSwap = on; +} + +inline bool QGLWidget::autoBufferSwap() const +{ + return autoSwap; +} + +#endif diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp new file mode 100644 index 0000000..a8abef8 --- /dev/null +++ b/src/opengl/qgl_x11.cpp @@ -0,0 +1,1406 @@ +/**************************************************************************** +** +** Implementation of OpenGL classes for Qt +** +** Created : 970112 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the opengl module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qgl.h" + +#if defined(Q_WS_X11) + +#include "qmap.h" +#include "qpixmap.h" +#include "qapplication.h" + +#include "qintdict.h" +#include "private/qfontengine_p.h" + +#define INT8 dummy_INT8 +#define INT32 dummy_INT32 +#include <GL/glx.h> +#undef INT8 +#undef INT32 +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xos.h> +#include <X11/Xatom.h> + +// POSIX Large File Support redefines truncate -> truncate64 +#if defined(truncate) +# undef truncate +#endif + +#ifndef QT_DLOPEN_OPENGL +extern "C" { + Status XmuLookupStandardColormap( Display *dpy, int screen, VisualID visualid, + unsigned int depth, Atom property, + Bool replace, Bool retain ); +} +#endif + +#include "qgl_x11_p.h" +#ifdef QT_DLOPEN_OPENGL +#include "qlibrary.h" + +extern "C" { +_glCallLists qt_glCallLists; +_glClearColor qt_glClearColor; +_glClearIndex qt_glClearIndex; +_glColor3ub qt_glColor3ub; +_glDeleteLists qt_glDeleteLists; +_glDrawBuffer qt_glDrawBuffer; +_glFlush qt_glFlush; +_glIndexi qt_glIndexi; +_glListBase qt_glListBase; +_glLoadIdentity qt_glLoadIdentity; +_glMatrixMode qt_glMatrixMode; +_glOrtho qt_glOrtho; +_glPopAttrib qt_glPopAttrib; +_glPopMatrix qt_glPopMatrix; +_glPushAttrib qt_glPushAttrib; +_glPushMatrix qt_glPushMatrix; +_glRasterPos2i qt_glRasterPos2i; +_glRasterPos3d qt_glRasterPos3d; +_glReadPixels qt_glReadPixels; +_glViewport qt_glViewport; +_glPixelStorei qt_glPixelStorei; +_glBitmap qt_glBitmap; +_glDrawPixels qt_glDrawPixels; +_glNewList qt_glNewList; +_glGetFloatv qt_glGetFloatv; +_glGetIntegerv qt_glGetIntegerv; +_glEndList qt_glEndList; + +_glXChooseVisual qt_glXChooseVisual; +_glXCreateContext qt_glXCreateContext; +_glXCreateGLXPixmap qt_glXCreateGLXPixmap; +_glXDestroyContext qt_glXDestroyContext; +_glXDestroyGLXPixmap qt_glXDestroyGLXPixmap; +_glXGetClientString qt_glXGetClientString; +_glXGetConfig qt_glXGetConfig; +_glXIsDirect qt_glXIsDirect; +_glXMakeCurrent qt_glXMakeCurrent; +_glXQueryExtension qt_glXQueryExtension; +_glXQueryExtensionsString qt_glXQueryExtensionsString; +_glXQueryServerString qt_glXQueryServerString; +_glXSwapBuffers qt_glXSwapBuffers; +_glXUseXFont qt_glXUseXFont; +_glXWaitX qt_glXWaitX; +}; + +bool qt_resolve_gl_symbols(bool fatal) +{ + static bool gl_syms_resolved = FALSE; + if (gl_syms_resolved) + return TRUE; + + QLibrary gl("GL.so.1"); + gl.setAutoUnload(FALSE); + + qt_glCallLists = (_glCallLists) gl.resolve("glCallLists"); + + if (!qt_glCallLists) { // if this fails the rest will surely fail + if (fatal) + qFatal("Unable to resolve GL/GLX symbols - please check your GL library installation."); + return FALSE; + } + + qt_glClearColor = (_glClearColor) gl.resolve("glClearColor"); + qt_glClearIndex = (_glClearIndex) gl.resolve("glClearIndex"); + qt_glColor3ub = (_glColor3ub) gl.resolve("glColor3ub"); + qt_glDeleteLists = (_glDeleteLists) gl.resolve("glDeleteLists"); + qt_glDrawBuffer = (_glDrawBuffer) gl.resolve("glDrawBuffer"); + qt_glFlush = (_glFlush) gl.resolve("glFlush"); + qt_glIndexi = (_glIndexi) gl.resolve("glIndexi"); + qt_glListBase = (_glListBase) gl.resolve("glListBase"); + qt_glLoadIdentity = (_glLoadIdentity) gl.resolve("glLoadIdentity"); + qt_glMatrixMode = (_glMatrixMode) gl.resolve("glMatrixMode"); + qt_glOrtho = (_glOrtho) gl.resolve("glOrtho"); + qt_glPopAttrib = (_glPopAttrib) gl.resolve("glPopAttrib"); + qt_glPopMatrix = (_glPopMatrix) gl.resolve("glPopMatrix"); + qt_glPushAttrib = (_glPushAttrib) gl.resolve("glPushAttrib"); + qt_glPushMatrix = (_glPushMatrix) gl.resolve("glPushMatrix"); + qt_glRasterPos2i = (_glRasterPos2i) gl.resolve("glRasterPos2i"); + qt_glRasterPos3d = (_glRasterPos3d) gl.resolve("glRasterPos3d"); + qt_glReadPixels = (_glReadPixels) gl.resolve("glReadPixels"); + qt_glViewport = (_glViewport) gl.resolve("glViewport"); + qt_glPixelStorei = (_glPixelStorei) gl.resolve("glPixelStorei"); + qt_glBitmap = (_glBitmap) gl.resolve("glBitmap"); + qt_glDrawPixels = (_glDrawPixels) gl.resolve("glDrawPixels"); + qt_glNewList = (_glNewList) gl.resolve("glNewList"); + qt_glGetFloatv = (_glGetFloatv) gl.resolve("glGetFloatv"); + qt_glGetIntegerv = (_glGetIntegerv) gl.resolve("glGetIntegerv"); + qt_glEndList = (_glEndList) gl.resolve("glEndList"); + + qt_glXChooseVisual = (_glXChooseVisual) gl.resolve("glXChooseVisual"); + qt_glXCreateContext = (_glXCreateContext) gl.resolve("glXCreateContext"); + qt_glXCreateGLXPixmap = (_glXCreateGLXPixmap) gl.resolve("glXCreateGLXPixmap"); + qt_glXDestroyContext = (_glXDestroyContext) gl.resolve("glXDestroyContext"); + qt_glXDestroyGLXPixmap = (_glXDestroyGLXPixmap) gl.resolve("glXDestroyGLXPixmap"); + qt_glXGetClientString = (_glXGetClientString) gl.resolve("glXGetClientString"); + qt_glXGetConfig = (_glXGetConfig) gl.resolve("glXGetConfig"); + qt_glXIsDirect = (_glXIsDirect) gl.resolve("glXIsDirect"); + qt_glXMakeCurrent = (_glXMakeCurrent) gl.resolve("glXMakeCurrent"); + qt_glXQueryExtension = (_glXQueryExtension) gl.resolve("glXQueryExtension"); + qt_glXQueryExtensionsString = (_glXQueryExtensionsString) gl.resolve("glXQueryExtensionsString"); + qt_glXQueryServerString = (_glXQueryServerString) gl.resolve("glXQueryServerString"); + qt_glXSwapBuffers = (_glXSwapBuffers) gl.resolve("glXSwapBuffers"); + qt_glXUseXFont = (_glXUseXFont) gl.resolve("glXUseXFont"); + qt_glXWaitX = (_glXWaitX) gl.resolve("glXWaitX"); + gl_syms_resolved = TRUE; + return TRUE; +} +#endif // QT_DLOPEN_OPENGL + + +/* + The choose_cmap function is internal and used by QGLWidget::setContext() + and GLX (not Windows). If the application can't find any sharable + colormaps, it must at least create as few colormaps as possible. The + dictionary solution below ensures only one colormap is created per visual. + Colormaps are also deleted when the application terminates. +*/ + +struct CMapEntry { + CMapEntry(); + ~CMapEntry(); + Colormap cmap; + bool alloc; + XStandardColormap scmap; +}; + +CMapEntry::CMapEntry() +{ + cmap = 0; + alloc = FALSE; + scmap.colormap = 0; +} + +CMapEntry::~CMapEntry() +{ + if ( alloc ) + XFreeColormap( QPaintDevice::x11AppDisplay(), cmap ); +} + +static QIntDict<CMapEntry> *cmap_dict = 0; +static bool mesa_gl = FALSE; +static QIntDict< QMap<int, QRgb> > *qglcmap_dict = 0; + +static void cleanup_cmaps() +{ + if (cmap_dict) { + cmap_dict->setAutoDelete(TRUE); + delete cmap_dict; + cmap_dict = 0; + } + if (qglcmap_dict) { + qglcmap_dict->setAutoDelete(TRUE); + delete qglcmap_dict; + qglcmap_dict = 0; + } +} + +static Colormap choose_cmap( Display *dpy, XVisualInfo *vi ) +{ + if ( !cmap_dict ) { + cmap_dict = new QIntDict<CMapEntry>; + const char *v = glXQueryServerString( dpy, vi->screen, GLX_VERSION ); + if ( v ) + mesa_gl = strstr(v,"Mesa") != 0; + qAddPostRoutine( cleanup_cmaps ); + } + + CMapEntry *x = cmap_dict->find( (long) vi->visualid + ( vi->screen * 256 ) ); + if ( x ) // found colormap for visual + return x->cmap; + + x = new CMapEntry(); + + XStandardColormap *c; + int n, i; + + // qDebug( "Choosing cmap for vID %0x", vi->visualid ); + + if ( vi->visualid == + XVisualIDFromVisual( (Visual*)QPaintDevice::x11AppVisual( vi->screen ) ) ) { + // qDebug( "Using x11AppColormap" ); + return QPaintDevice::x11AppColormap( vi->screen ); + } + + if ( mesa_gl ) { // we're using MesaGL + Atom hp_cmaps = XInternAtom( dpy, "_HP_RGB_SMOOTH_MAP_LIST", TRUE ); + if ( hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8 ) { + if ( XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n, + hp_cmaps) ) { + i = 0; + while ( i < n && x->cmap == 0 ) { + if ( c[i].visualid == vi->visual->visualid ) { + x->cmap = c[i].colormap; + x->scmap = c[i]; + //qDebug( "Using HP_RGB scmap" ); + + } + i++; + } + XFree( (char *)c ); + } + } + } +#if !defined(Q_OS_SOLARIS) + if ( !x->cmap ) { +#ifdef QT_DLOPEN_OPENGL + typedef Status (*_XmuLookupStandardColormap)( Display *dpy, int screen, VisualID visualid, unsigned int depth, + Atom property, Bool replace, Bool retain ); + _XmuLookupStandardColormap qt_XmuLookupStandardColormap; + qt_XmuLookupStandardColormap = (_XmuLookupStandardColormap) QLibrary::resolve("Xmu.so.6", "XmuLookupStandardColormap"); + if (!qt_XmuLookupStandardColormap) + qFatal("Unable to resolve Xmu symbols - please check your Xmu library installation."); +#define XmuLookupStandardColormap qt_XmuLookupStandardColormap + +#endif + + if ( XmuLookupStandardColormap(dpy,vi->screen,vi->visualid,vi->depth, + XA_RGB_DEFAULT_MAP,FALSE,TRUE) ) { + if ( XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n, + XA_RGB_DEFAULT_MAP) ) { + i = 0; + while ( i < n && x->cmap == 0 ) { + if ( c[i].visualid == vi->visualid ) { + x->cmap = c[i].colormap; + x->scmap = c[i]; + //qDebug( "Using RGB_DEFAULT scmap" ); + } + i++; + } + XFree( (char *)c ); + } + } + } +#endif + if ( !x->cmap ) { // no shared cmap found + x->cmap = XCreateColormap( dpy, RootWindow(dpy,vi->screen), vi->visual, + AllocNone ); + x->alloc = TRUE; + // qDebug( "Allocating cmap" ); + } + + // associate cmap with visualid + cmap_dict->insert( (long) vi->visualid + ( vi->screen * 256 ), x ); + return x->cmap; +} + +struct TransColor +{ + VisualID vis; + int screen; + long color; +}; + +static QMemArray<TransColor> trans_colors; +static int trans_colors_init = FALSE; + + +static void find_trans_colors() +{ + struct OverlayProp { + long visual; + long type; + long value; + long layer; + }; + + trans_colors_init = TRUE; + + Display* appDisplay = QPaintDevice::x11AppDisplay(); + + int scr; + int lastsize = 0; + for ( scr = 0; scr < ScreenCount( appDisplay ); scr++ ) { + QWidget* rootWin = QApplication::desktop()->screen( scr ); + if ( !rootWin ) + return; // Should not happen + Atom overlayVisualsAtom = XInternAtom( appDisplay, + "SERVER_OVERLAY_VISUALS", True ); + if ( overlayVisualsAtom == None ) + return; // Server has no overlays + + Atom actualType; + int actualFormat; + ulong nItems; + ulong bytesAfter; + OverlayProp* overlayProps = 0; + int res = XGetWindowProperty( appDisplay, rootWin->winId(), + overlayVisualsAtom, 0, 10000, False, + overlayVisualsAtom, &actualType, + &actualFormat, &nItems, &bytesAfter, + (uchar**)&overlayProps ); + + if ( res != Success || actualType != overlayVisualsAtom + || actualFormat != 32 || nItems < 4 || !overlayProps ) + return; // Error reading property + + int numProps = nItems / 4; + trans_colors.resize( lastsize + numProps ); + int j = lastsize; + for ( int i = 0; i < numProps; i++ ) { + if ( overlayProps[i].type == 1 ) { + trans_colors[j].vis = (VisualID)overlayProps[i].visual; + trans_colors[j].screen = scr; + trans_colors[j].color = (int)overlayProps[i].value; + j++; + } + } + XFree( overlayProps ); + lastsize = j; + trans_colors.truncate( lastsize ); + } +} + + +/***************************************************************************** + QGLFormat UNIX/GLX-specific code + *****************************************************************************/ + +bool QGLFormat::hasOpenGL() +{ + if (!qt_resolve_gl_symbols(FALSE)) + return FALSE; + return glXQueryExtension(qt_xdisplay(),0,0) != 0; +} + + +bool QGLFormat::hasOpenGLOverlays() +{ + qt_resolve_gl_symbols(); + if ( !trans_colors_init ) + find_trans_colors(); + return trans_colors.size() > 0; +} + + + +/***************************************************************************** + QGLContext UNIX/GLX-specific code + *****************************************************************************/ + +bool QGLContext::chooseContext( const QGLContext* shareContext ) +{ + Display* disp = d->paintDevice->x11Display(); + vi = chooseVisual(); + if ( !vi ) + return FALSE; + + if ( deviceIsPixmap() && + (((XVisualInfo*)vi)->depth != d->paintDevice->x11Depth() || + ((XVisualInfo*)vi)->screen != d->paintDevice->x11Screen()) ) + { + XFree( vi ); + XVisualInfo appVisInfo; + memset( &appVisInfo, 0, sizeof(XVisualInfo) ); + appVisInfo.visualid = XVisualIDFromVisual( (Visual*)d->paintDevice->x11Visual() ); + appVisInfo.screen = d->paintDevice->x11Screen(); + int nvis; + vi = XGetVisualInfo( disp, VisualIDMask | VisualScreenMask, &appVisInfo, &nvis ); + if ( !vi ) + return FALSE; + + int useGL; + glXGetConfig( disp, (XVisualInfo*)vi, GLX_USE_GL, &useGL ); + if ( !useGL ) + return FALSE; //# Chickening out already... + } + int res; + glXGetConfig( disp, (XVisualInfo*)vi, GLX_LEVEL, &res ); + glFormat.setPlane( res ); + glXGetConfig( disp, (XVisualInfo*)vi, GLX_DOUBLEBUFFER, &res ); + glFormat.setDoubleBuffer( res ); + glXGetConfig( disp, (XVisualInfo*)vi, GLX_DEPTH_SIZE, &res ); + glFormat.setDepth( res ); + glXGetConfig( disp, (XVisualInfo*)vi, GLX_RGBA, &res ); + glFormat.setRgba( res ); + glXGetConfig( disp, (XVisualInfo*)vi, GLX_ALPHA_SIZE, &res ); + glFormat.setAlpha( res ); + glXGetConfig( disp, (XVisualInfo*)vi, GLX_ACCUM_RED_SIZE, &res ); + glFormat.setAccum( res ); + glXGetConfig( disp, (XVisualInfo*)vi, GLX_STENCIL_SIZE, &res ); + glFormat.setStencil( res ); + glXGetConfig( disp, (XVisualInfo*)vi, GLX_STEREO, &res ); + glFormat.setStereo( res ); + + Bool direct = format().directRendering() ? True : False; + + if ( shareContext && + ( !shareContext->isValid() || !shareContext->cx ) ) { +#if defined(QT_CHECK_NULL) + qWarning("QGLContext::chooseContext(): Cannot share with invalid context"); +#endif + shareContext = 0; + } + + // 1. Sharing between rgba and color-index will give wrong colors. + // 2. Contexts cannot be shared btw. direct/non-direct renderers. + // 3. Pixmaps cannot share contexts that are set up for direct rendering. + if ( shareContext && (format().rgba() != shareContext->format().rgba() || + (deviceIsPixmap() && + glXIsDirect( disp, (GLXContext)shareContext->cx )))) + shareContext = 0; + + cx = 0; + if ( shareContext ) { + cx = glXCreateContext( disp, (XVisualInfo *)vi, + (GLXContext)shareContext->cx, direct ); + if ( cx ) + d->sharing = TRUE; + } + if ( !cx ) + cx = glXCreateContext( disp, (XVisualInfo *)vi, None, direct ); + if ( !cx ) + return FALSE; + glFormat.setDirectRendering( glXIsDirect( disp, (GLXContext)cx ) ); + if ( deviceIsPixmap() ) { +#if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT) + gpm = glXCreateGLXPixmapMESA( disp, (XVisualInfo *)vi, + d->paintDevice->handle(), + choose_cmap( disp, (XVisualInfo *)vi ) ); +#else + gpm = (Q_UINT32)glXCreateGLXPixmap( disp, (XVisualInfo *)vi, + d->paintDevice->handle() ); +#endif + if ( !gpm ) + return FALSE; + } + return TRUE; +} + + +/*! + <strong>X11 only</strong>: This virtual function tries to find a + visual that matches the format, reducing the demands if the original + request cannot be met. + + The algorithm for reducing the demands of the format is quite + simple-minded, so override this method in your subclass if your + application has spcific requirements on visual selection. + + \sa chooseContext() +*/ + +void *QGLContext::chooseVisual() +{ + static int bufDepths[] = { 8, 4, 2, 1 }; // Try 16, 12 also? + //todo: if pixmap, also make sure that vi->depth == pixmap->depth + void* vis = 0; + int i = 0; + bool fail = FALSE; + QGLFormat fmt = format(); + bool tryDouble = !fmt.doubleBuffer(); // Some GL impl's only have double + bool triedDouble = FALSE; + while( !fail && !( vis = tryVisual( fmt, bufDepths[i] ) ) ) { + if ( !fmt.rgba() && bufDepths[i] > 1 ) { + i++; + continue; + } + if ( tryDouble ) { + fmt.setDoubleBuffer( TRUE ); + tryDouble = FALSE; + triedDouble = TRUE; + continue; + } + else if ( triedDouble ) { + fmt.setDoubleBuffer( FALSE ); + triedDouble = FALSE; + } + if ( fmt.stereo() ) { + fmt.setStereo( FALSE ); + continue; + } + if ( fmt.accum() ) { + fmt.setAccum( FALSE ); + continue; + } + if ( fmt.stencil() ) { + fmt.setStencil( FALSE ); + continue; + } + if ( fmt.alpha() ) { + fmt.setAlpha( FALSE ); + continue; + } + if ( fmt.depth() ) { + fmt.setDepth( FALSE ); + continue; + } + if ( fmt.doubleBuffer() ) { + fmt.setDoubleBuffer( FALSE ); + continue; + } + fail = TRUE; + } + glFormat = fmt; + return vis; +} + + +/*! + + \internal + + <strong>X11 only</strong>: This virtual function chooses a visual + that matches the OpenGL \link format() format\endlink. Reimplement this + function in a subclass if you need a custom visual. + + \sa chooseContext() +*/ + +void *QGLContext::tryVisual( const QGLFormat& f, int bufDepth ) +{ + int spec[40]; + int i = 0; + spec[i++] = GLX_LEVEL; + spec[i++] = f.plane(); + +#if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info) + static bool useTranspExt = FALSE; + static bool useTranspExtChecked = FALSE; + if ( f.plane() && !useTranspExtChecked && d->paintDevice ) { + QCString estr( glXQueryExtensionsString( d->paintDevice->x11Display(), + d->paintDevice->x11Screen() ) ); + useTranspExt = estr.contains( "GLX_EXT_visual_info" ); + //# (A bit simplistic; that could theoretically be a substring) + if ( useTranspExt ) { + QCString cstr( glXGetClientString( d->paintDevice->x11Display(), + GLX_VENDOR ) ); + useTranspExt = !cstr.contains( "Xi Graphics" ); // bug workaround + if ( useTranspExt ) { + // bug workaround - some systems (eg. FireGL) refuses to return an overlay + // visual if the GLX_TRANSPARENT_TYPE_EXT attribute is specfied, even if + // the implementation supports transparent overlays + int tmpSpec[] = { GLX_LEVEL, f.plane(), GLX_TRANSPARENT_TYPE_EXT, + f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT, + None }; + XVisualInfo * vinf = glXChooseVisual( d->paintDevice->x11Display(), + d->paintDevice->x11Screen(), tmpSpec ); + if ( !vinf ) { + useTranspExt = FALSE; + } + } + } + + useTranspExtChecked = TRUE; + } + if ( f.plane() && useTranspExt ) { + // Required to avoid non-transparent overlay visual(!) on some systems + spec[i++] = GLX_TRANSPARENT_TYPE_EXT; + spec[i++] = f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT; + } +#endif + + if ( f.doubleBuffer() ) + spec[i++] = GLX_DOUBLEBUFFER; + if ( f.depth() ) { + spec[i++] = GLX_DEPTH_SIZE; + spec[i++] = 1; + } + if ( f.stereo() ) { + spec[i++] = GLX_STEREO; + } + if ( f.stencil() ) { + spec[i++] = GLX_STENCIL_SIZE; + spec[i++] = 1; + } + if ( f.rgba() ) { + spec[i++] = GLX_RGBA; + spec[i++] = GLX_RED_SIZE; + spec[i++] = 1; + spec[i++] = GLX_GREEN_SIZE; + spec[i++] = 1; + spec[i++] = GLX_BLUE_SIZE; + spec[i++] = 1; + if ( f.alpha() ) { + spec[i++] = GLX_ALPHA_SIZE; + spec[i++] = 1; + } + if ( f.accum() ) { + spec[i++] = GLX_ACCUM_RED_SIZE; + spec[i++] = 1; + spec[i++] = GLX_ACCUM_GREEN_SIZE; + spec[i++] = 1; + spec[i++] = GLX_ACCUM_BLUE_SIZE; + spec[i++] = 1; + if ( f.alpha() ) { + spec[i++] = GLX_ACCUM_ALPHA_SIZE; + spec[i++] = 1; + } + } + } + else { + spec[i++] = GLX_BUFFER_SIZE; + spec[i++] = bufDepth; + } + + spec[i] = None; + return glXChooseVisual( d->paintDevice->x11Display(), + d->paintDevice->x11Screen(), spec ); +} + + +void QGLContext::reset() +{ + if ( !d->valid ) + return; + doneCurrent(); + if ( gpm ) + glXDestroyGLXPixmap( d->paintDevice->x11Display(), (GLXPixmap)gpm ); + gpm = 0; + glXDestroyContext( d->paintDevice->x11Display(), (GLXContext)cx ); + if ( vi ) + XFree( vi ); + vi = 0; + cx = 0; + d->crWin = FALSE; + d->sharing = FALSE; + d->valid = FALSE; + d->transpColor = QColor(); + d->initDone = FALSE; +} + + +void QGLContext::makeCurrent() +{ + if ( !d->valid ) { +#if defined(QT_CHECK_STATE) + qWarning("QGLContext::makeCurrent(): Cannot make invalid context current."); +#endif + return; + } + bool ok = TRUE; + if ( deviceIsPixmap() ) + ok = glXMakeCurrent( d->paintDevice->x11Display(), + (GLXPixmap)gpm, + (GLXContext)cx ); + + else + ok = glXMakeCurrent( d->paintDevice->x11Display(), + ((QWidget *)d->paintDevice)->winId(), + (GLXContext)cx ); +#if defined(QT_CHECK_NULL) + // qDebug("makeCurrent: %i, vi=%i, vi->vi=%i, vi->id=%i", (int)this, (int)vi, (int)((XVisualInfo*)vi)->visual, (int)((XVisualInfo*)vi)->visualid ); + if ( !ok ) + qWarning("QGLContext::makeCurrent(): Failed."); +#endif + if ( ok ) + currentCtx = this; +} + +void QGLContext::doneCurrent() +{ + glXMakeCurrent( d->paintDevice->x11Display(), 0, 0 ); + currentCtx = 0; +} + + +void QGLContext::swapBuffers() const +{ + if ( !d->valid ) + return; + if ( !deviceIsPixmap() ) + glXSwapBuffers( d->paintDevice->x11Display(), + ((QWidget *)d->paintDevice)->winId() ); +} + +QColor QGLContext::overlayTransparentColor() const +{ + //### make more efficient using the transpColor member + if ( isValid() ) { + if ( !trans_colors_init ) + find_trans_colors(); + + VisualID myVisualId = ((XVisualInfo*)vi)->visualid; + int myScreen = ((XVisualInfo*)vi)->screen; + for ( int i = 0; i < (int)trans_colors.size(); i++ ) { + if ( trans_colors[i].vis == myVisualId && + trans_colors[i].screen == myScreen ) { + XColor col; + col.pixel = trans_colors[i].color; + col.red = col.green = col.blue = 0; + col.flags = 0; + Display *dpy = d->paintDevice->x11Display(); + if (col.pixel > (uint) ((XVisualInfo *)vi)->colormap_size - 1) + col.pixel = ((XVisualInfo *)vi)->colormap_size - 1; + XQueryColor(dpy, choose_cmap(dpy, (XVisualInfo *) vi), &col); + uchar r = (uchar)((col.red / 65535.0) * 255.0 + 0.5); + uchar g = (uchar)((col.green / 65535.0) * 255.0 + 0.5); + uchar b = (uchar)((col.blue / 65535.0) * 255.0 + 0.5); + return QColor(qRgb(r,g,b), trans_colors[i].color); + } + } + } + return QColor(); // Invalid color +} + + +uint QGLContext::colorIndex( const QColor& c ) const +{ + int screen = ((XVisualInfo *)vi)->screen; + if ( isValid() ) { + if ( format().plane() + && c.pixel( screen ) == overlayTransparentColor().pixel( screen ) ) + return c.pixel( screen ); // Special; don't look-up + if ( ((XVisualInfo*)vi)->visualid == + XVisualIDFromVisual( (Visual*)QPaintDevice::x11AppVisual( screen ) ) ) + return c.pixel( screen ); // We're using QColor's cmap + + XVisualInfo *info = (XVisualInfo *) vi; + CMapEntry *x = cmap_dict->find( (long) info->visualid + ( info->screen * 256 ) ); + if ( x && !x->alloc) { // It's a standard colormap + int rf = (int)(((float)c.red() * (x->scmap.red_max+1))/256.0); + int gf = (int)(((float)c.green() * (x->scmap.green_max+1))/256.0); + int bf = (int)(((float)c.blue() * (x->scmap.blue_max+1))/256.0); + uint p = x->scmap.base_pixel + + ( rf * x->scmap.red_mult ) + + ( gf * x->scmap.green_mult ) + + ( bf * x->scmap.blue_mult ); + return p; + } else { + if (!qglcmap_dict) { + qglcmap_dict = new QIntDict< QMap<int, QRgb> >; + } + QMap<int, QRgb> *cmap; + if ((cmap = qglcmap_dict->find((long) info->visualid)) == 0) { + cmap = new QMap<int, QRgb>; + qglcmap_dict->insert((long) info->visualid, cmap); + } + + // already in the map? + QRgb target = c.rgb(); + QMap<int, QRgb>::Iterator it = cmap->begin(); + for (; it != cmap->end(); ++it) { + if ((*it) == target) + return it.key(); + } + + // need to alloc color + unsigned long plane_mask[2]; + unsigned long color_map_entry; + if (!XAllocColorCells (QPaintDevice::x11AppDisplay(), x->cmap, TRUE, plane_mask, 0, + &color_map_entry, 1)) + return c.pixel(screen); + + XColor col; + col.flags = DoRed | DoGreen | DoBlue; + col.pixel = color_map_entry; + col.red = (ushort)((qRed(c.rgb()) / 255.0) * 65535.0 + 0.5); + col.green = (ushort)((qGreen(c.rgb()) / 255.0) * 65535.0 + 0.5); + col.blue = (ushort)((qBlue(c.rgb()) / 255.0) * 65535.0 + 0.5); + XStoreColor(QPaintDevice::x11AppDisplay(), x->cmap, &col); + + cmap->insert(color_map_entry, target); + return color_map_entry; + } + } + return 0; +} + +#ifndef QT_NO_XFTFREETYPE +/*! \internal + This is basically a substitute for glxUseXFont() which can only + handle XLFD fonts. This version relies on XFT v2 to render the + glyphs, but it works with all fonts that XFT2 provides - both + antialiased and aliased bitmap and outline fonts. +*/ +void qgl_use_font(QFontEngineXft *engine, int first, int count, int listBase) +{ + GLfloat color[4]; + glGetFloatv(GL_CURRENT_COLOR, color); + + // save the pixel unpack state + GLint gl_swapbytes, gl_lsbfirst, gl_rowlength, gl_skiprows, gl_skippixels, gl_alignment; + glGetIntegerv (GL_UNPACK_SWAP_BYTES, &gl_swapbytes); + glGetIntegerv (GL_UNPACK_LSB_FIRST, &gl_lsbfirst); + glGetIntegerv (GL_UNPACK_ROW_LENGTH, &gl_rowlength); + glGetIntegerv (GL_UNPACK_SKIP_ROWS, &gl_skiprows); + glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &gl_skippixels); + glGetIntegerv (GL_UNPACK_ALIGNMENT, &gl_alignment); + + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + Bool antialiased = False; +#if 0 // disable antialias support for now + XftPatternGetBool(engine->pattern(), XFT_ANTIALIAS, 0, &antialiased); +#endif +#ifdef QT_XFT2 + FT_Face face = XftLockFace(engine->font()); +#else + FT_Face face = engine->face(); +#endif + // start generating font glyphs + for (int i = first; i < count; ++i) { + int list = listBase + i; + GLfloat x0, y0, dx, dy; + + FT_Error err; + + err = FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT); + if (err) { + qDebug("failed loading glyph %d from font", i); + Q_ASSERT(!err); + } + err = FT_Render_Glyph(face->glyph, (antialiased ? ft_render_mode_normal + : ft_render_mode_mono)); + if (err) { + qDebug("failed rendering glyph %d from font", i); + Q_ASSERT(!err); + } + + FT_Bitmap bm = face->glyph->bitmap; + x0 = face->glyph->metrics.horiBearingX >> 6; + y0 = (face->glyph->metrics.height - face->glyph->metrics.horiBearingY) >> 6; + dx = face->glyph->metrics.horiAdvance >> 6; + dy = 0; + int sz = bm.pitch * bm.rows; + uint *aa_glyph = 0; + uchar *ua_glyph = 0; + + if (antialiased) + aa_glyph = new uint[sz]; + else + ua_glyph = new uchar[sz]; + + // convert to GL format + for (int y = 0; y < bm.rows; ++y) { + for (int x = 0; x < bm.pitch; ++x) { + int c1 = y*bm.pitch + x; + int c2 = (bm.rows - y - 1) > 0 ? (bm.rows-y-1)*bm.pitch + x : x; + if (antialiased) { + aa_glyph[c1] = (int(color[0]*255) << 24) + | (int(color[1]*255) << 16) + | (int(color[2]*255) << 8) | bm.buffer[c2]; + } else { + ua_glyph[c1] = bm.buffer[c2]; + } + } + } + + glNewList(list, GL_COMPILE); + if (antialiased) { + // calling glBitmap() is just a trick to move the current + // raster pos, since glGet*() won't work in display lists + glBitmap(0, 0, 0, 0, x0, -y0, 0); + glDrawPixels(bm.pitch, bm.rows, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, aa_glyph); + glBitmap(0, 0, 0, 0, dx-x0, y0, 0); + } else { + glBitmap(bm.pitch*8, bm.rows, -x0, y0, dx, dy, ua_glyph); + } + glEndList(); + antialiased ? delete[] aa_glyph : delete[] ua_glyph; + } + +#ifdef QT_XFT2 + XftUnlockFace(engine->font()); +#endif + + // restore pixel unpack settings + glPixelStorei(GL_UNPACK_SWAP_BYTES, gl_swapbytes); + glPixelStorei(GL_UNPACK_LSB_FIRST, gl_lsbfirst); + glPixelStorei(GL_UNPACK_ROW_LENGTH, gl_rowlength); + glPixelStorei(GL_UNPACK_SKIP_ROWS, gl_skiprows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, gl_skippixels); + glPixelStorei(GL_UNPACK_ALIGNMENT, gl_alignment); +} +#endif + +void QGLContext::generateFontDisplayLists( const QFont & fnt, int listBase ) +{ + QFont f(fnt); + QFontEngine *engine = f.d->engineForScript(QFont::Latin); + +#ifndef QT_NO_XFTFREETYPE + if(engine->type() == QFontEngine::Xft) { + qgl_use_font((QFontEngineXft *) engine, 0, 256, listBase); + return; + } +#endif + // glXUseXFont() only works with XLFD font structures and a few GL + // drivers crash if 0 is passed as the font handle + f.setStyleStrategy(QFont::OpenGLCompatible); + if (f.handle() && (engine->type() == QFontEngine::XLFD + || engine->type() == QFontEngine::LatinXLFD)) { + glXUseXFont((Font) f.handle(), 0, 256, listBase); + } +} + +/***************************************************************************** + QGLOverlayWidget (Internal overlay class for X11) + *****************************************************************************/ + +class QGLOverlayWidget : public QGLWidget +{ + Q_OBJECT +public: + QGLOverlayWidget( const QGLFormat& format, QGLWidget* parent, + const char* name=0, const QGLWidget* shareWidget=0 ); + +protected: + void initializeGL(); + void paintGL(); + void resizeGL( int w, int h ); + +private: + QGLWidget* realWidget; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QGLOverlayWidget( const QGLOverlayWidget& ); + QGLOverlayWidget& operator=( const QGLOverlayWidget& ); +#endif +}; + + +QGLOverlayWidget::QGLOverlayWidget( const QGLFormat& format, QGLWidget* parent, + const char* name, + const QGLWidget* shareWidget ) + : QGLWidget( format, parent, name, shareWidget ? shareWidget->olw : 0 ) +{ + realWidget = parent; +} + + + +void QGLOverlayWidget::initializeGL() +{ + QColor transparentColor = context()->overlayTransparentColor(); + if ( transparentColor.isValid() ) + qglClearColor( transparentColor ); + else + qWarning( "QGLOverlayWidget::initializeGL(): Could not get transparent color" ); + realWidget->initializeOverlayGL(); +} + + +void QGLOverlayWidget::resizeGL( int w, int h ) +{ + glViewport( 0, 0, w, h ); + realWidget->resizeOverlayGL( w, h ); +} + + +void QGLOverlayWidget::paintGL() +{ + realWidget->paintOverlayGL(); +} + +#undef Bool +#include "qgl_x11.moc" + +/***************************************************************************** + QGLWidget UNIX/GLX-specific code + *****************************************************************************/ +void QGLWidget::init( QGLContext *context, const QGLWidget *shareWidget ) +{ + qt_resolve_gl_symbols(); + + glcx = 0; + olw = 0; + autoSwap = TRUE; + if ( !context->device() ) + context->setDevice( this ); + + if ( shareWidget ) + setContext( context, shareWidget->context() ); + else + setContext( context ); + setBackgroundMode( NoBackground ); + + if ( isValid() && context->format().hasOverlay() ) { + QCString olwName( name() ); + olwName += "-QGL_internal_overlay_widget"; + olw = new QGLOverlayWidget( QGLFormat::defaultOverlayFormat(), + this, olwName, shareWidget ); + if ( olw->isValid() ) { + olw->setAutoBufferSwap( FALSE ); + olw->setFocusProxy( this ); + } + else { + delete olw; + olw = 0; + glcx->glFormat.setOverlay( FALSE ); + } + } +} + +/*! \reimp */ +void QGLWidget::reparent( QWidget* parent, WFlags f, const QPoint& p, + bool showIt ) +{ + if (glcx) + glcx->doneCurrent(); + QWidget::reparent( parent, f, p, FALSE ); + if ( showIt ) + show(); +} + + +void QGLWidget::setMouseTracking( bool enable ) +{ + if ( olw ) + olw->setMouseTracking( enable ); + QWidget::setMouseTracking( enable ); +} + + +void QGLWidget::resizeEvent( QResizeEvent * ) +{ + if ( !isValid() ) + return; + makeCurrent(); + if ( !glcx->initialized() ) + glInit(); + glXWaitX(); + resizeGL( width(), height() ); + if ( olw ) + olw->setGeometry( rect() ); +} + +const QGLContext* QGLWidget::overlayContext() const +{ + if ( olw ) + return olw->context(); + else + return 0; +} + + +void QGLWidget::makeOverlayCurrent() +{ + if ( olw ) + olw->makeCurrent(); +} + + +void QGLWidget::updateOverlayGL() +{ + if ( olw ) + olw->updateGL(); +} + +void QGLWidget::setContext( QGLContext *context, + const QGLContext* shareContext, + bool deleteOldContext ) +{ + if ( context == 0 ) { +#if defined(QT_CHECK_NULL) + qWarning( "QGLWidget::setContext: Cannot set null context" ); +#endif + return; + } + if ( !context->deviceIsPixmap() && context->device() != this ) { +#if defined(QT_CHECK_STATE) + qWarning( "QGLWidget::setContext: Context must refer to this widget" ); +#endif + return; + } + + if ( glcx ) + glcx->doneCurrent(); + QGLContext* oldcx = glcx; + glcx = context; + + bool createFailed = FALSE; + if ( !glcx->isValid() ) { + if ( !glcx->create( shareContext ? shareContext : oldcx ) ) + createFailed = TRUE; + } + if ( createFailed ) { + if ( deleteOldContext ) + delete oldcx; + return; + } + + if ( glcx->windowCreated() || glcx->deviceIsPixmap() ) { + if ( deleteOldContext ) + delete oldcx; + return; + } + + bool visible = isVisible(); + if ( visible ) + hide(); + + XVisualInfo *vi = (XVisualInfo*)glcx->vi; + XSetWindowAttributes a; + + a.colormap = choose_cmap( x11Display(), vi ); // find best colormap + a.background_pixel = backgroundColor().pixel( vi->screen ); + a.border_pixel = black.pixel( vi->screen ); + Window p = RootWindow( x11Display(), vi->screen ); + if ( parentWidget() ) + p = parentWidget()->winId(); + + Window w = XCreateWindow( x11Display(), p, x(), y(), width(), height(), + 0, vi->depth, InputOutput, vi->visual, + CWBackPixel|CWBorderPixel|CWColormap, &a ); + + Window *cmw; + Window *cmwret; + int count; + if ( XGetWMColormapWindows( x11Display(), topLevelWidget()->winId(), + &cmwret, &count ) ) { + cmw = new Window[count+1]; + memcpy( (char *)cmw, (char *)cmwret, sizeof(Window)*count ); + XFree( (char *)cmwret ); + int i; + for ( i=0; i<count; i++ ) { + if ( cmw[i] == winId() ) { // replace old window + cmw[i] = w; + break; + } + } + if ( i >= count ) // append new window + cmw[count++] = w; + } else { + count = 1; + cmw = new Window[count]; + cmw[0] = w; + } + +#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT) + if ( oldcx && oldcx->windowCreated() ) + glXReleaseBuffersMESA( x11Display(), winId() ); +#endif + if ( deleteOldContext ) + delete oldcx; + oldcx = 0; + + create( w ); + + XSetWMColormapWindows( x11Display(), topLevelWidget()->winId(), cmw, + count ); + delete [] cmw; + + if ( visible ) + show(); + XFlush( x11Display() ); + glcx->setWindowCreated( TRUE ); +} + + +bool QGLWidget::renderCxPm( QPixmap* pm ) +{ + if ( ((XVisualInfo*)glcx->vi)->depth != pm->depth() ) + return FALSE; + + GLXPixmap glPm; +#if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT) + glPm = glXCreateGLXPixmapMESA( x11Display(), + (XVisualInfo*)glcx->vi, + (Pixmap)pm->handle(), + choose_cmap( pm->x11Display(), + (XVisualInfo*)glcx->vi ) ); +#else + glPm = (Q_UINT32)glXCreateGLXPixmap( x11Display(), + (XVisualInfo*)glcx->vi, + (Pixmap)pm->handle() ); +#endif + + if ( !glXMakeCurrent( x11Display(), glPm, (GLXContext)glcx->cx ) ) { + glXDestroyGLXPixmap( x11Display(), glPm ); + return FALSE; + } + + glDrawBuffer( GL_FRONT ); + if ( !glcx->initialized() ) + glInit(); + resizeGL( pm->width(), pm->height() ); + paintGL(); + glFlush(); + makeCurrent(); + glXDestroyGLXPixmap( x11Display(), glPm ); + resizeGL( width(), height() ); + return TRUE; +} + +const QGLColormap & QGLWidget::colormap() const +{ + return cmap; +} + +/*\internal + Store color values in the given colormap. +*/ +static void qStoreColors( QWidget * tlw, Colormap cmap, + const QGLColormap & cols ) +{ + XColor c; + QRgb color; + + for ( int i = 0; i < cols.size(); i++ ) { + color = cols.entryRgb( i ); + c.pixel = i; + c.red = (ushort)( (qRed( color ) / 255.0) * 65535.0 + 0.5 ); + c.green = (ushort)( (qGreen( color ) / 255.0) * 65535.0 + 0.5 ); + c.blue = (ushort)( (qBlue( color ) / 255.0) * 65535.0 + 0.5 ); + c.flags = DoRed | DoGreen | DoBlue; + XStoreColor( tlw->x11Display(), cmap, &c ); + } +} + +/*\internal + Check whether the given visual supports dynamic colormaps or not. +*/ +static bool qCanAllocColors( QWidget * w ) +{ + bool validVisual = FALSE; + int numVisuals; + long mask; + XVisualInfo templ; + XVisualInfo * visuals; + VisualID id = XVisualIDFromVisual( (Visual *) + w->topLevelWidget()->x11Visual() ); + + mask = VisualScreenMask; + templ.screen = w->x11Screen(); + visuals = XGetVisualInfo( w->x11Display(), mask, &templ, &numVisuals ); + + for ( int i = 0; i < numVisuals; i++ ) { + if ( visuals[i].visualid == id ) { + switch ( visuals[i].c_class ) { + case TrueColor: + case StaticColor: + case StaticGray: + case GrayScale: + validVisual = FALSE; + break; + case DirectColor: + case PseudoColor: + validVisual = TRUE; + break; + } + break; + } + } + XFree( visuals ); + + if ( !validVisual ) + return FALSE; + return TRUE; +} + +void QGLWidget::setColormap( const QGLColormap & c ) +{ + QWidget * tlw = topLevelWidget(); // must return a valid widget + + cmap = c; + if ( !cmap.d ) + return; + + if ( !cmap.d->cmapHandle && !qCanAllocColors( this ) ) { + qWarning( "QGLWidget::setColormap: Cannot create a read/write " + "colormap for this visual" ); + return; + } + + // If the child GL widget is not of the same visual class as the + // toplevel widget we will get in trouble.. + Window wid = tlw->winId(); + Visual * vis = (Visual *) tlw->x11Visual();; + VisualID cvId = XVisualIDFromVisual( (Visual *) x11Visual() ); + VisualID tvId = XVisualIDFromVisual( (Visual *) tlw->x11Visual() ); + if ( cvId != tvId ) { + wid = winId(); + vis = (Visual *) x11Visual(); + } + + if ( !cmap.d->cmapHandle ) // allocate a cmap if necessary + cmap.d->cmapHandle = XCreateColormap( x11Display(), wid, vis, + AllocAll ); + + qStoreColors( this, (Colormap) cmap.d->cmapHandle, c ); + XSetWindowColormap( x11Display(), wid, (Colormap) cmap.d->cmapHandle ); + + // tell the wm that this window has a special colormap + Window * cmw; + Window * cmwret; + int count; + if ( XGetWMColormapWindows( x11Display(), tlw->winId(), &cmwret, + &count ) ) + { + cmw = new Window[count+1]; + memcpy( (char *) cmw, (char *) cmwret, sizeof(Window) * count ); + XFree( (char *) cmwret ); + int i; + for ( i = 0; i < count; i++ ) { + if ( cmw[i] == winId() ) { + break; + } + } + if ( i >= count ) // append new window only if not in the list + cmw[count++] = winId(); + } else { + count = 1; + cmw = new Window[count]; + cmw[0] = winId(); + } + XSetWMColormapWindows( x11Display(), tlw->winId(), cmw, count ); + delete [] cmw; +} + +/*! \internal + Free up any allocated colormaps. This fn is only called for + top-level widgets. +*/ +void QGLWidget::cleanupColormaps() +{ + if ( !cmap.d ) + return; + + if ( cmap.d->cmapHandle ) { + XFreeColormap( topLevelWidget()->x11Display(), + (Colormap) cmap.d->cmapHandle ); + cmap.d->cmapHandle = 0; + } +} + +void QGLWidget::macInternalFixBufferRect() +{ +} + +#endif diff --git a/src/opengl/qgl_x11_p.h b/src/opengl/qgl_x11_p.h new file mode 100644 index 0000000..323fca1 --- /dev/null +++ b/src/opengl/qgl_x11_p.h @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Definitions needed for resolving GL/GLX symbols using dlopen() +** under X11. +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the OpenGL module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QGL_P_H +#define QGL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. This header file may +// change from version to version without notice, or even be +// removed. +// +// We mean it. +// +// + +#ifdef QT_DLOPEN_OPENGL +// resolve the GL symbols we use ourselves +bool qt_resolve_gl_symbols(bool = TRUE); +extern "C" { +// GL symbols +typedef void (*_glCallLists)( GLsizei n, GLenum type, const GLvoid *lists ); +typedef void (*_glClearColor)( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ); +typedef void (*_glClearIndex)( GLfloat c ); +typedef void (*_glColor3ub)( GLubyte red, GLubyte green, GLubyte blue ); +typedef void (*_glDeleteLists)( GLuint list, GLsizei range ); +typedef void (*_glDrawBuffer)( GLenum mode ); +typedef void (*_glFlush)( void ); +typedef void (*_glIndexi)( GLint c ); +typedef void (*_glListBase)( GLuint base ); +typedef void (*_glLoadIdentity)( void ); +typedef void (*_glMatrixMode)( GLenum mode ); +typedef void (*_glOrtho)( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val ); +typedef void (*_glPopAttrib)( void ); +typedef void (*_glPopMatrix)( void ); +typedef void (*_glPushAttrib)( GLbitfield mask ); +typedef void (*_glPushMatrix)( void ); +typedef void (*_glRasterPos2i)( GLint x, GLint y ); +typedef void (*_glRasterPos3d)( GLdouble x, GLdouble y, GLdouble z ); +typedef void (*_glReadPixels)( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ); +typedef void (*_glViewport)( GLint x, GLint y, GLsizei width, GLsizei height ); +typedef void (*_glPixelStorei)( GLenum pname, GLint param ); +typedef void (*_glBitmap)( GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, + const GLubyte *bitmap ); +typedef void (*_glDrawPixels)( GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ); +typedef void (*_glNewList)( GLuint list, GLenum mode ); +typedef void (*_glGetFloatv)( GLenum pname, GLfloat *params ); +typedef void (*_glGetIntegerv)( GLenum pname, GLint *params ); +typedef void (*_glEndList)( void ); + + +// GLX symbols - should be in the GL lib as well +typedef XVisualInfo* (*_glXChooseVisual)(Display *dpy, int screen, int *attribList); +typedef GLXContext (*_glXCreateContext)(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct); +typedef GLXPixmap (*_glXCreateGLXPixmap)(Display *dpy, XVisualInfo *vis, Pixmap pixmap); +typedef void (*_glXDestroyContext)(Display *dpy, GLXContext ctx); +typedef void (*_glXDestroyGLXPixmap)(Display *dpy, GLXPixmap pix); +typedef const char* (*_glXGetClientString)(Display *dpy, int name ); +typedef int (*_glXGetConfig)(Display *dpy, XVisualInfo *vis, int attrib, int *value); +typedef Bool (*_glXIsDirect)(Display *dpy, GLXContext ctx); +typedef Bool (*_glXMakeCurrent)(Display *dpy, GLXDrawable drawable, GLXContext ctx); +typedef Bool (*_glXQueryExtension)(Display *dpy, int *errorBase, int *eventBase); +typedef const char* (*_glXQueryExtensionsString)(Display *dpy, int screen); +typedef const char* (*_glXQueryServerString)(Display *dpy, int screen, int name); +typedef void (*_glXSwapBuffers)(Display *dpy, GLXDrawable drawable); +typedef void (*_glXUseXFont)(Font font, int first, int count, int listBase); +typedef void (*_glXWaitX)(void); + +extern _glCallLists qt_glCallLists; +extern _glClearColor qt_glClearColor; +extern _glClearIndex qt_glClearIndex; +extern _glColor3ub qt_glColor3ub; +extern _glDeleteLists qt_glDeleteLists; +extern _glDrawBuffer qt_glDrawBuffer; +extern _glFlush qt_glFlush; +extern _glIndexi qt_glIndexi; +extern _glListBase qt_glListBase; +extern _glLoadIdentity qt_glLoadIdentity; +extern _glMatrixMode qt_glMatrixMode; +extern _glOrtho qt_glOrtho; +extern _glPopAttrib qt_glPopAttrib; +extern _glPopMatrix qt_glPopMatrix; +extern _glPushAttrib qt_glPushAttrib; +extern _glPushMatrix qt_glPushMatrix; +extern _glRasterPos2i qt_glRasterPos2i; +extern _glRasterPos3d qt_glRasterPos3d; +extern _glReadPixels qt_glReadPixels; +extern _glViewport qt_glViewport; +extern _glPixelStorei qt_glPixelStorei; +extern _glBitmap qt_glBitmap; +extern _glDrawPixels qt_glDrawPixels; +extern _glNewList qt_glNewList; +extern _glGetFloatv qt_glGetFloatv; +extern _glGetIntegerv qt_glGetIntegerv; +extern _glEndList qt_glEndList; + +extern _glXChooseVisual qt_glXChooseVisual; +extern _glXCreateContext qt_glXCreateContext; +extern _glXCreateGLXPixmap qt_glXCreateGLXPixmap; +extern _glXDestroyContext qt_glXDestroyContext; +extern _glXDestroyGLXPixmap qt_glXDestroyGLXPixmap; +extern _glXGetClientString qt_glXGetClientString; +extern _glXGetConfig qt_glXGetConfig; +extern _glXIsDirect qt_glXIsDirect; +extern _glXMakeCurrent qt_glXMakeCurrent; +extern _glXQueryExtension qt_glXQueryExtension; +extern _glXQueryExtensionsString qt_glXQueryExtensionsString; +extern _glXQueryServerString qt_glXQueryServerString; +extern _glXSwapBuffers qt_glXSwapBuffers; +extern _glXUseXFont qt_glXUseXFont; +extern _glXWaitX qt_glXWaitX; +}; // extern "C" + +#define glCallLists qt_glCallLists +#define glClearColor qt_glClearColor +#define glClearIndex qt_glClearIndex +#define glColor3ub qt_glColor3ub +#define glDeleteLists qt_glDeleteLists +#define glDrawBuffer qt_glDrawBuffer +#define glFlush qt_glFlush +#define glIndexi qt_glIndexi +#define glListBase qt_glListBase +#define glLoadIdentity qt_glLoadIdentity +#define glMatrixMode qt_glMatrixMode +#define glOrtho qt_glOrtho +#define glPopAttrib qt_glPopAttrib +#define glPopMatrix qt_glPopMatrix +#define glPushAttrib qt_glPushAttrib +#define glPushMatrix qt_glPushMatrix +#define glRasterPos2i qt_glRasterPos2i +#define glRasterPos3d qt_glRasterPos3d +#define glReadPixels qt_glReadPixels +#define glViewport qt_glViewport +#define glPixelStorei qt_glPixelStorei +#define glBitmap qt_glBitmap +#define glDrawPixels qt_glDrawPixels +#define glNewList qt_glNewList +#define glGetFloatv qt_glGetFloatv +#define glGetIntegerv qt_glGetIntegerv +#define glEndList qt_glEndList + +#define glXChooseVisual qt_glXChooseVisual +#define glXCreateContext qt_glXCreateContext +#define glXCreateGLXPixmap qt_glXCreateGLXPixmap +#define glXDestroyContext qt_glXDestroyContext +#define glXDestroyGLXPixmap qt_glXDestroyGLXPixmap +#define glXGetClientString qt_glXGetClientString +#define glXGetConfig qt_glXGetConfig +#define glXIsDirect qt_glXIsDirect +#define glXMakeCurrent qt_glXMakeCurrent +#define glXQueryExtension qt_glXQueryExtension +#define glXQueryExtensionsString qt_glXQueryExtensionsString +#define glXQueryServerString qt_glXQueryServerString +#define glXSwapBuffers qt_glXSwapBuffers +#define glXUseXFont qt_glXUseXFont +#define glXWaitX qt_glXWaitX + +#else +inline bool qt_resolve_gl_symbols(bool = TRUE) { return TRUE; } +#endif // QT_DLOPEN_OPENGL +#endif // QGL_P_H diff --git a/src/opengl/qglcolormap.cpp b/src/opengl/qglcolormap.cpp new file mode 100644 index 0000000..2deb46b --- /dev/null +++ b/src/opengl/qglcolormap.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Implementation of QGLColormap class +** +** Created : 20010326 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the opengl module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +/*! + \class QGLColormap qglcolormap.h + \brief The QGLColormap class is used for installing custom colormaps into + QGLWidgets. +\if defined(commercial) + It is part of the <a href="commercialeditions.html">Qt Enterprise Edition</a>. +\endif + + \module OpenGL + \ingroup graphics + \ingroup images + + QGLColormap provides a platform independent way of specifying and + installing indexed colormaps into QGLWidgets. QGLColormap is + especially useful when using the \link opengl.html OpenGL\endlink + color-index mode. + + Under X11 you must use an X server that supports either a \c + PseudoColor or \c DirectColor visual class. If your X server + currently only provides a \c GrayScale, \c TrueColor, \c + StaticColor or \c StaticGray visual, you will not be able to + allocate colorcells for writing. If this is the case, try setting + your X server to 8 bit mode. It should then provide you with at + least a \c PseudoColor visual. Note that you may experience + colormap flashing if your X server is running in 8 bit mode. + + Under Windows the size of the colormap is always set to 256 + colors. Note that under Windows you can also install colormaps + in child widgets. + + This class uses explicit sharing (see \link shclass.html Shared + Classes\endlink). + + Example of use: + \code + #include <qapplication.h> + #include <qglcolormap.h> + + int main() + { + QApplication a( argc, argv ); + + MySuperGLWidget widget( 0 ); // A QGLWidget in color-index mode + QGLColormap colormap; + + // This will fill the colormap with colors ranging from + // black to white. + for ( int i = 0; i < colormap.size(); i++ ) + colormap.setEntry( i, qRgb( i, i, i ) ); + + widget.setColormap( colormap ); + widget.show(); + return a.exec(); + } + \endcode + + \sa QGLWidget::setColormap(), QGLWidget::colormap() +*/ + +#include "qglcolormap.h" +#include "qmemarray.h" + + +/*! + Construct a QGLColormap. +*/ +QGLColormap::QGLColormap() +{ + d = 0; +} + + +/*! + Construct a shallow copy of \a map. +*/ +QGLColormap::QGLColormap( const QGLColormap & map ) +{ + d = map.d; + if ( d ) + d->ref(); +} + +/*! + Dereferences the QGLColormap and deletes it if this was the last + reference to it. +*/ +QGLColormap::~QGLColormap() +{ + if ( d && d->deref() ) { + delete d; + d = 0; + } +} + +/*! + Assign a shallow copy of \a map to this QGLColormap. +*/ +QGLColormap & QGLColormap::operator=( const QGLColormap & map ) +{ + if ( map.d != 0 ) + map.d->ref(); + + if ( d && d->deref() ) + delete d; + d = map.d; + + return *this; +} + +/*! + Detaches this QGLColormap from the shared block. +*/ +void QGLColormap::detach() +{ + if ( d && d->count != 1 ) { + // ### What about the actual colormap handle? + Private * newd = new Private(); + newd->cells = d->cells; + newd->cells.detach(); + if ( d->deref() ) + delete d; + d = newd; + } +} + +/*! + Set cell at index \a idx in the colormap to color \a color. +*/ +void QGLColormap::setEntry( int idx, QRgb color ) +{ + if ( !d ) + d = new Private(); + +#if defined(QT_CHECK_RANGE) + if ( idx < 0 || idx > (int) d->cells.size() ) { + qWarning( "QGLColormap::setRgb: Index out of range." ); + return; + } +#endif + d->cells[ idx ] = color; +} + +/*! + Set an array of cells in this colormap. \a count is the number of + colors that should be set, \a colors is the array of colors, and + \a base is the starting index. +*/ +void QGLColormap::setEntries( int count, const QRgb * colors, int base ) +{ + if ( !d ) + d = new Private(); + + if ( !colors || base < 0 || base >= (int) d->cells.size() ) + return; + + for( int i = base; i < base + count; i++ ) { + if ( i < (int) d->cells.size() ) + setEntry( i, colors[i] ); + else + break; + } +} + +/*! + Returns the QRgb value in the colorcell with index \a idx. +*/ +QRgb QGLColormap::entryRgb( int idx ) const +{ + if ( !d || idx < 0 || idx > (int) d->cells.size() ) + return 0; + else + return d->cells[ idx ]; +} + +/*! + \overload + + Set the cell with index \a idx in the colormap to color \a color. +*/ +void QGLColormap::setEntry( int idx, const QColor & color ) +{ + setEntry( idx, color.rgb() ); +} + +/*! + Returns the QRgb value in the colorcell with index \a idx. +*/ +QColor QGLColormap::entryColor( int idx ) const +{ + if ( !d || idx < 0 || idx > (int) d->cells.size() ) + return QColor(); + else + return QColor( d->cells[ idx ] ); +} + +/*! + Returns TRUE if the colormap is empty; otherwise returns FALSE. A + colormap with no color values set is considered to be empty. +*/ +bool QGLColormap::isEmpty() const +{ + return (d == 0) || (d->cells.size() == 0) || (d->cmapHandle == 0); +} + + +/*! + Returns the number of colorcells in the colormap. +*/ +int QGLColormap::size() const +{ + return d != 0 ? d->cells.size() : 0; +} + +/*! + Returns the index of the color \a color. If \a color is not in the + map, -1 is returned. +*/ +int QGLColormap::find( QRgb color ) const +{ + if ( d ) + return d->cells.find( color ); + return -1; +} + +/*! + Returns the index of the color that is the closest match to color + \a color. +*/ +int QGLColormap::findNearest( QRgb color ) const +{ + int idx = find( color ); + if ( idx >= 0 ) + return idx; + int mapSize = size(); + int mindist = 200000; + int r = qRed( color ); + int g = qGreen( color ); + int b = qBlue( color ); + int rx, gx, bx, dist; + for ( int i=0; i < mapSize; i++ ) { + QRgb ci = d->cells[i]; + rx = r - qRed( ci ); + gx = g - qGreen( ci ); + bx = b - qBlue( ci ); + dist = rx*rx + gx*gx + bx*bx; // calculate distance + if ( dist < mindist ) { // minimal? + mindist = dist; + idx = i; + } + } + return idx; +} diff --git a/src/opengl/qglcolormap.h b/src/opengl/qglcolormap.h new file mode 100644 index 0000000..d759058 --- /dev/null +++ b/src/opengl/qglcolormap.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Definition of QGLColormap class +** +** Created : 20010326 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the opengl module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QGLCOLORMAP_H +#define QGLCOLORMAP_H + +#ifndef QT_H +#include "qcolor.h" +#include "qmemarray.h" +#include "qshared.h" +#endif // QT_H + +#if !defined( QT_MODULE_OPENGL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_OPENGL +#else +#define QM_EXPORT_OPENGL Q_EXPORT +#endif + +class QWidget; +class QM_EXPORT_OPENGL QGLColormap +{ +public: + QGLColormap(); + QGLColormap( const QGLColormap & ); + ~QGLColormap(); + + QGLColormap &operator=( const QGLColormap & ); + + bool isEmpty() const; + int size() const; + void detach(); + + void setEntries( int count, const QRgb * colors, int base = 0 ); + void setEntry( int idx, QRgb color ); + void setEntry( int idx, const QColor & color ); + QRgb entryRgb( int idx ) const; + QColor entryColor( int idx ) const; + int find( QRgb color ) const; + int findNearest( QRgb color ) const; + +private: + class Private : public QShared + { + public: + Private() { + cells.resize( 256 ); // ### hardcoded to 256 entries for now + cmapHandle = 0; + } + + ~Private() { + } + + QMemArray<QRgb> cells; + Qt::HANDLE cmapHandle; + }; + + Private * d; + + friend class QGLWidget; +}; + +#endif diff --git a/src/opengl/qt_opengl.pri b/src/opengl/qt_opengl.pri new file mode 100644 index 0000000..bb0a5d8 --- /dev/null +++ b/src/opengl/qt_opengl.pri @@ -0,0 +1,18 @@ +# Qt opengl module + +opengl { + HEADERS += $$OPENGL_H/qgl.h \ + $$OPENGL_H/qglcolormap.h + SOURCES += $$OPENGL_CPP/qgl.cpp \ + $$OPENGL_CPP/qglcolormap.cpp + x11 { + HEADERS += $$OPENGL_H/qgl_x11_p.h + SOURCES += $$OPENGL_CPP/qgl_x11.cpp + } + else:mac:SOURCES += $$OPENGL_CPP/qgl_mac.cpp + else:win32:SOURCES += $$OPENGL_CPP/qgl_win.cpp + + dlopen_opengl:DEFINES+=QT_DLOPEN_OPENGL +} + + |