diff options
| author | Qt by Nokia <qt-info@nokia.com> | 2011-04-27 12:05:43 +0200 |
|---|---|---|
| committer | axis <qt-info@nokia.com> | 2011-04-27 12:05:43 +0200 |
| commit | 38be0d13830efd2d98281c645c3a60afe05ffece (patch) | |
| tree | 6ea73f3ec77f7d153333779883e8120f82820abe /src/opengl/qgl_win.cpp | |
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you
want to look at revision history older than this, please refer to the
Qt Git wiki for how to use Git history grafting. At the time of
writing, this wiki is located here:
http://qt.gitorious.org/qt/pages/GitIntroductionWithQt
If you have already performed the grafting and you don't see any
history beyond this commit, try running "git log" with the "--follow"
argument.
Branched from the monolithic repo, Qt master branch, at commit
896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/opengl/qgl_win.cpp')
| -rw-r--r-- | src/opengl/qgl_win.cpp | 1601 |
1 files changed, 1601 insertions, 0 deletions
diff --git a/src/opengl/qgl_win.cpp b/src/opengl/qgl_win.cpp new file mode 100644 index 00000000000..70016a0825a --- /dev/null +++ b/src/opengl/qgl_win.cpp @@ -0,0 +1,1601 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <qgl.h> +#include <qlist.h> +#include <qmap.h> +#include <qpixmap.h> +#include <qevent.h> +#include <private/qgl_p.h> +#include <qcolormap.h> +#include <qvarlengtharray.h> +#include <qdebug.h> +#include <qcolor.h> + +#include <qt_windows.h> + +typedef bool (APIENTRY *PFNWGLGETPIXELFORMATATTRIBIVARB)(HDC hdc, + int iPixelFormat, + int iLayerPlane, + uint nAttributes, + const int *piAttributes, + int *piValues); +typedef bool (APIENTRY *PFNWGLCHOOSEPIXELFORMATARB)(HDC hdc, + const int *piAttribList, + const float *pfAttribFList, + uint nMaxFormats, + int *piFormats, + UINT *nNumFormats); +#ifndef WGL_ARB_multisample +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 +#endif + +#ifndef WGL_ARB_pixel_format +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_DRAW_TO_BITMAP_ARB 0x2002 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NEED_PALETTE_ARB 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define WGL_SWAP_METHOD_ARB 0x2007 +#define WGL_NUMBER_OVERLAYS_ARB 0x2008 +#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 +#define WGL_TRANSPARENT_ARB 0x200A +#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 +#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 +#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 +#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A +#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B +#define WGL_SHARE_DEPTH_ARB 0x200C +#define WGL_SHARE_STENCIL_ARB 0x200D +#define WGL_SHARE_ACCUM_ARB 0x200E +#define WGL_SUPPORT_GDI_ARB 0x200F +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201A +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ALPHA_SHIFT_ARB 0x201C +#define WGL_ACCUM_BITS_ARB 0x201D +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_SWAP_EXCHANGE_ARB 0x2028 +#define WGL_SWAP_COPY_ARB 0x2029 +#define WGL_SWAP_UNDEFINED_ARB 0x202A +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_COLORINDEX_ARB 0x202C +#endif + +#ifndef WGL_ARB_create_context +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x0001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x0002 +// Error codes returned by GetLastError(). +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif + +#ifndef GL_VERSION_3_2 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 +#endif + +QT_BEGIN_NAMESPACE + +class QGLCmapPrivate +{ +public: + QGLCmapPrivate() : count(1) { } + void ref() { ++count; } + bool deref() { return !--count; } + uint count; + + enum AllocState{ UnAllocated = 0, Allocated = 0x01, Reserved = 0x02 }; + + int maxSize; + QVector<uint> colorArray; + QVector<quint8> allocArray; + QVector<quint8> contextArray; + QMap<uint,int> colorMap; +}; + +/***************************************************************************** + QColorMap class - temporarily here, until it is ready for prime time + *****************************************************************************/ + +/**************************************************************************** +** +** Definition of QColorMap class +** +****************************************************************************/ + +class QGLCmapPrivate; + +class /*Q_EXPORT*/ QGLCmap +{ +public: + enum Flags { Reserved = 0x01 }; + + QGLCmap(int maxSize = 256); + QGLCmap(const QGLCmap& map); + ~QGLCmap(); + + QGLCmap& operator=(const QGLCmap& map); + + // isEmpty and/or isNull ? + int size() const; + int maxSize() const; + + void resize(int newSize); + + int find(QRgb color) const; + int findNearest(QRgb color) const; + int allocate(QRgb color, uint flags = 0, quint8 context = 0); + + void setEntry(int idx, QRgb color, uint flags = 0, quint8 context = 0); + + const QRgb* colors() const; + +private: + void detach(); + QGLCmapPrivate* d; +}; + + +QGLCmap::QGLCmap(int maxSize) // add a bool prealloc? +{ + d = new QGLCmapPrivate; + d->maxSize = maxSize; +} + + +QGLCmap::QGLCmap(const QGLCmap& map) +{ + d = map.d; + d->ref(); +} + + +QGLCmap::~QGLCmap() +{ + if (d && d->deref()) + delete d; + d = 0; +} + + +QGLCmap& QGLCmap::operator=(const QGLCmap& map) +{ + map.d->ref(); + if (d->deref()) + delete d; + d = map.d; + return *this; +} + + +int QGLCmap::size() const +{ + return d->colorArray.size(); +} + + +int QGLCmap::maxSize() const +{ + return d->maxSize; +} + + +void QGLCmap::detach() +{ + if (d->count != 1) { + d->deref(); + QGLCmapPrivate* newd = new QGLCmapPrivate; + newd->maxSize = d->maxSize; + newd->colorArray = d->colorArray; + newd->allocArray = d->allocArray; + newd->contextArray = d->contextArray; + newd->colorArray.detach(); + newd->allocArray.detach(); + newd->contextArray.detach(); + newd->colorMap = d->colorMap; + d = newd; + } +} + + +void QGLCmap::resize(int newSize) +{ + if (newSize < 0 || newSize > d->maxSize) { + qWarning("QGLCmap::resize(): size out of range"); + return; + } + int oldSize = size(); + detach(); + //if shrinking; remove the lost elems from colorMap + d->colorArray.resize(newSize); + d->allocArray.resize(newSize); + d->contextArray.resize(newSize); + if (newSize > oldSize) { + memset(d->allocArray.data() + oldSize, 0, newSize - oldSize); + memset(d->contextArray.data() + oldSize, 0, newSize - oldSize); + } +} + + +int QGLCmap::find(QRgb color) const +{ + QMap<uint,int>::ConstIterator it = d->colorMap.find(color); + if (it != d->colorMap.end()) + return *it; + return -1; +} + + +int QGLCmap::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++) { + if (!(d->allocArray[i] & QGLCmapPrivate::Allocated)) + continue; + QRgb ci = d->colorArray[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; +} + + + + +// Does not always allocate; returns existing c idx if found + +int QGLCmap::allocate(QRgb color, uint flags, quint8 context) +{ + int idx = find(color); + if (idx >= 0) + return idx; + + int mapSize = d->colorArray.size(); + int newIdx = d->allocArray.indexOf(QGLCmapPrivate::UnAllocated); + + if (newIdx < 0) { // Must allocate more room + if (mapSize < d->maxSize) { + newIdx = mapSize; + mapSize++; + resize(mapSize); + } + else { + //# add a bool param that says what to do in case no more room - + // fail (-1) or return nearest? + return -1; + } + } + + d->colorArray[newIdx] = color; + if (flags & QGLCmap::Reserved) { + d->allocArray[newIdx] = QGLCmapPrivate::Reserved; + } + else { + d->allocArray[newIdx] = QGLCmapPrivate::Allocated; + d->colorMap.insert(color, newIdx); + } + d->contextArray[newIdx] = context; + return newIdx; +} + + +void QGLCmap::setEntry(int idx, QRgb color, uint flags, quint8 context) +{ + if (idx < 0 || idx >= d->maxSize) { + qWarning("QGLCmap::set(): Index out of range"); + return; + } + detach(); + int mapSize = size(); + if (idx >= mapSize) { + mapSize = idx + 1; + resize(mapSize); + } + d->colorArray[idx] = color; + if (flags & QGLCmap::Reserved) { + d->allocArray[idx] = QGLCmapPrivate::Reserved; + } + else { + d->allocArray[idx] = QGLCmapPrivate::Allocated; + d->colorMap.insert(color, idx); + } + d->contextArray[idx] = context; +} + + +const QRgb* QGLCmap::colors() const +{ + return d->colorArray.data(); +} + + + +/***************************************************************************** + QGLFormat Win32/WGL-specific code + *****************************************************************************/ + + +void qwglError(const char* method, const char* func) +{ +#ifndef QT_NO_DEBUG + char* lpMsgBuf; + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + 0, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (char*) &lpMsgBuf, 0, 0); + qWarning("%s : %s failed: %s", method, func, lpMsgBuf); + LocalFree(lpMsgBuf); +#else + Q_UNUSED(method); + Q_UNUSED(func); +#endif +} + + + +bool QGLFormat::hasOpenGL() +{ + return true; +} + +static bool opengl32dll = false; + +bool QGLFormat::hasOpenGLOverlays() +{ + // workaround for matrox driver: + // make a cheap call to opengl to force loading of DLL + if (!opengl32dll) { + GLint params; + glGetIntegerv(GL_DEPTH_BITS, ¶ms); + opengl32dll = true; + } + + static bool checkDone = false; + static bool hasOl = false; + + if (!checkDone) { + checkDone = true; + HDC display_dc = GetDC(0); + int pfiMax = DescribePixelFormat(display_dc, 0, 0, NULL); + PIXELFORMATDESCRIPTOR pfd; + for (int pfi = 1; pfi <= pfiMax; pfi++) { + DescribePixelFormat(display_dc, pfi, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + if ((pfd.bReserved & 0x0f) && (pfd.dwFlags & PFD_SUPPORT_OPENGL)) { + // This format has overlays/underlays + LAYERPLANEDESCRIPTOR lpd; + wglDescribeLayerPlane(display_dc, pfi, 1, + sizeof(LAYERPLANEDESCRIPTOR), &lpd); + if (lpd.dwFlags & LPD_SUPPORT_OPENGL) { + hasOl = true; + break; + } + } + } + ReleaseDC(0, display_dc); + } + return hasOl; +} + + +/***************************************************************************** + QGLContext Win32/WGL-specific code + *****************************************************************************/ + +static uchar qgl_rgb_palette_comp(int idx, uint nbits, uint shift) +{ + const uchar map_3_to_8[8] = { + 0, 0111>>1, 0222>>1, 0333>>1, 0444>>1, 0555>>1, 0666>>1, 0377 + }; + const uchar map_2_to_8[4] = { + 0, 0x55, 0xaa, 0xff + }; + const uchar map_1_to_8[2] = { + 0, 255 + }; + + uchar val = (uchar) (idx >> shift); + uchar res = 0; + switch (nbits) { + case 1: + val &= 0x1; + res = map_1_to_8[val]; + break; + case 2: + val &= 0x3; + res = map_2_to_8[val]; + break; + case 3: + val &= 0x7; + res = map_3_to_8[val]; + break; + default: + res = 0; + } + return res; +} + + +static QRgb* qgl_create_rgb_palette(const PIXELFORMATDESCRIPTOR* pfd) +{ + if ((pfd->iPixelType != PFD_TYPE_RGBA) || + !(pfd->dwFlags & PFD_NEED_PALETTE) || + (pfd->cColorBits != 8)) + return 0; + int numEntries = 1 << pfd->cColorBits; + QRgb* pal = new QRgb[numEntries]; + for (int i = 0; i < numEntries; i++) { + int r = qgl_rgb_palette_comp(i, pfd->cRedBits, pfd->cRedShift); + int g = qgl_rgb_palette_comp(i, pfd->cGreenBits, pfd->cGreenShift); + int b = qgl_rgb_palette_comp(i, pfd->cBlueBits, pfd->cBlueShift); + pal[i] = qRgb(r, g, b); + } + + const int syscol_indices[12] = { + 3, 24, 27, 64, 67, 88, 173, 181, 236, 247, 164, 91 + }; + + const uint syscols[20] = { + 0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, + 0x008080, 0xc0c0c0, 0xc0dcc0, 0xa6caf0, 0xfffbf0, 0xa0a0a4, + 0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, + 0x00ffff, 0xffffff + }; // colors #1 - #12 are not present in pal; gets added below + + if ((pfd->cColorBits == 8) && + (pfd->cRedBits == 3) && (pfd->cRedShift == 0) && + (pfd->cGreenBits == 3) && (pfd->cGreenShift == 3) && + (pfd->cBlueBits == 2) && (pfd->cBlueShift == 6)) { + for (int j = 0 ; j < 12 ; j++) + pal[syscol_indices[j]] = QRgb(syscols[j+1]); + } + + return pal; +} + +static QGLFormat pfdToQGLFormat(const PIXELFORMATDESCRIPTOR* pfd) +{ + QGLFormat fmt; + fmt.setDoubleBuffer(pfd->dwFlags & PFD_DOUBLEBUFFER); + fmt.setDepth(pfd->cDepthBits); + if (fmt.depth()) + fmt.setDepthBufferSize(pfd->cDepthBits); + fmt.setRgba(pfd->iPixelType == PFD_TYPE_RGBA); + fmt.setRedBufferSize(pfd->cRedBits); + fmt.setGreenBufferSize(pfd->cGreenBits); + fmt.setBlueBufferSize(pfd->cBlueBits); + fmt.setAlpha(pfd->cAlphaBits); + if (fmt.alpha()) + fmt.setAlphaBufferSize(pfd->cAlphaBits); + fmt.setAccum(pfd->cAccumBits); + if (fmt.accum()) + fmt.setAccumBufferSize(pfd->cAccumRedBits); + fmt.setStencil(pfd->cStencilBits); + if (fmt.stencil()) + fmt.setStencilBufferSize(pfd->cStencilBits); + fmt.setStereo(pfd->dwFlags & PFD_STEREO); + fmt.setDirectRendering((pfd->dwFlags & PFD_GENERIC_ACCELERATED) || + !(pfd->dwFlags & PFD_GENERIC_FORMAT)); + fmt.setOverlay((pfd->bReserved & 0x0f) != 0); + return fmt; +} + +/* + NB! requires a current GL context to work +*/ +QGLFormat pfiToQGLFormat(HDC hdc, int pfi) +{ + QGLFormat fmt; + QVarLengthArray<int> iAttributes(40); + QVarLengthArray<int> iValues(40); + int i = 0; + bool has_sample_buffers = QGLExtensions::glExtensions() & QGLExtensions::SampleBuffers; + + iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB; // 0 + iAttributes[i++] = WGL_DEPTH_BITS_ARB; // 1 + iAttributes[i++] = WGL_PIXEL_TYPE_ARB; // 2 + iAttributes[i++] = WGL_RED_BITS_ARB; // 3 + iAttributes[i++] = WGL_GREEN_BITS_ARB; // 4 + iAttributes[i++] = WGL_BLUE_BITS_ARB; // 5 + iAttributes[i++] = WGL_ALPHA_BITS_ARB; // 6 + iAttributes[i++] = WGL_ACCUM_BITS_ARB; // 7 + iAttributes[i++] = WGL_STENCIL_BITS_ARB; // 8 + iAttributes[i++] = WGL_STEREO_ARB; // 9 + iAttributes[i++] = WGL_ACCELERATION_ARB; // 10 + iAttributes[i++] = WGL_NUMBER_OVERLAYS_ARB; // 11 + if (has_sample_buffers) { + iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB; // 12 + iAttributes[i++] = WGL_SAMPLES_ARB; // 13 + } + PFNWGLGETPIXELFORMATATTRIBIVARB wglGetPixelFormatAttribivARB = + (PFNWGLGETPIXELFORMATATTRIBIVARB) wglGetProcAddress("wglGetPixelFormatAttribivARB"); + + if (wglGetPixelFormatAttribivARB + && wglGetPixelFormatAttribivARB(hdc, pfi, 0, i, + iAttributes.constData(), + iValues.data())) + { + fmt.setDoubleBuffer(iValues[0]); + fmt.setDepth(iValues[1]); + if (fmt.depth()) + fmt.setDepthBufferSize(iValues[1]); + fmt.setRgba(iValues[2] == WGL_TYPE_RGBA_ARB); + fmt.setRedBufferSize(iValues[3]); + fmt.setGreenBufferSize(iValues[4]); + fmt.setBlueBufferSize(iValues[5]); + fmt.setAlpha(iValues[6]); + if (fmt.alpha()) + fmt.setAlphaBufferSize(iValues[6]); + fmt.setAccum(iValues[7]); + if (fmt.accum()) + fmt.setAccumBufferSize(iValues[7]); + fmt.setStencil(iValues[8]); + if (fmt.stencil()) + fmt.setStencilBufferSize(iValues[8]); + fmt.setStereo(iValues[9]); + if (iValues[10] == WGL_FULL_ACCELERATION_ARB) + fmt.setDirectRendering(true); + else + fmt.setDirectRendering(false); + fmt.setOverlay(iValues[11]); + if (has_sample_buffers) { + fmt.setSampleBuffers(iValues[12]); + if (fmt.sampleBuffers()) + fmt.setSamples(iValues[13]); + } + } +#if 0 + qDebug() << "values for pfi:" << pfi; + qDebug() << "doublebuffer 0:" << fmt.doubleBuffer(); + qDebug() << "depthbuffer 1:" << fmt.depthBufferSize(); + qDebug() << "rgba 2:" << fmt.rgba(); + qDebug() << "red size 3:" << fmt.redBufferSize(); + qDebug() << "green size 4:" << fmt.greenBufferSize(); + qDebug() << "blue size 5:" << fmt.blueBufferSize(); + qDebug() << "alpha size 6:" << fmt.alphaBufferSize(); + qDebug() << "accum size 7:" << fmt.accumBufferSize(); + qDebug() << "stencil size 8:" << fmt.stencilBufferSize(); + qDebug() << "stereo 9:" << fmt.stereo(); + qDebug() << "direct 10:" << fmt.directRendering(); + qDebug() << "has overlays 11:" << fmt.hasOverlay(); + qDebug() << "sample buff 12:" << fmt.sampleBuffers(); + qDebug() << "num samples 13:" << fmt.samples(); +#endif + return fmt; +} + + +/* + QGLTemporaryContext implementation +*/ + +Q_GUI_EXPORT const QString qt_getRegisteredWndClass(); + +class QGLTemporaryContextPrivate +{ +public: + HDC dmy_pdc; + HGLRC dmy_rc; + HDC old_dc; + HGLRC old_context; + WId dmy_id; +}; + +QGLTemporaryContext::QGLTemporaryContext(bool directRendering, QWidget *parent) + : d(new QGLTemporaryContextPrivate) +{ + QString windowClassName = qt_getRegisteredWndClass(); + if (parent && !parent->internalWinId()) + parent = parent->nativeParentWidget(); + + d->dmy_id = CreateWindow((const wchar_t *)windowClassName.utf16(), + 0, 0, 0, 0, 1, 1, + parent ? parent->winId() : 0, 0, qWinAppInst(), 0); + + d->dmy_pdc = GetDC(d->dmy_id); + PIXELFORMATDESCRIPTOR dmy_pfd; + memset(&dmy_pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + dmy_pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + dmy_pfd.nVersion = 1; + dmy_pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; + dmy_pfd.iPixelType = PFD_TYPE_RGBA; + if (!directRendering) + dmy_pfd.dwFlags |= PFD_GENERIC_FORMAT; + + int dmy_pf = ChoosePixelFormat(d->dmy_pdc, &dmy_pfd); + SetPixelFormat(d->dmy_pdc, dmy_pf, &dmy_pfd); + d->dmy_rc = wglCreateContext(d->dmy_pdc); + d->old_dc = wglGetCurrentDC(); + d->old_context = wglGetCurrentContext(); + wglMakeCurrent(d->dmy_pdc, d->dmy_rc); +} + +QGLTemporaryContext::~QGLTemporaryContext() +{ + wglMakeCurrent(d->dmy_pdc, 0); + wglDeleteContext(d->dmy_rc); + ReleaseDC(d->dmy_id, d->dmy_pdc); + DestroyWindow(d->dmy_id); + if (d->old_dc && d->old_context) + wglMakeCurrent(d->old_dc, d->old_context); +} + +static bool qgl_create_context(HDC hdc, QGLContextPrivate *d, QGLContextPrivate *shareContext) +{ + d->rc = 0; + + typedef HGLRC (APIENTRYP PFNWGLCREATECONTEXTATTRIBSARB)(HDC, HGLRC, const int *); + PFNWGLCREATECONTEXTATTRIBSARB wglCreateContextAttribsARB = + (PFNWGLCREATECONTEXTATTRIBSARB) wglGetProcAddress("wglCreateContextAttribsARB"); + if (wglCreateContextAttribsARB) { + int attributes[11]; + int attribIndex = 0; + const int major = d->reqFormat.majorVersion(); + const int minor = d->reqFormat.minorVersion(); + attributes[attribIndex++] = WGL_CONTEXT_MAJOR_VERSION_ARB; + attributes[attribIndex++] = major; + attributes[attribIndex++] = WGL_CONTEXT_MINOR_VERSION_ARB; + attributes[attribIndex++] = minor; + + if (major >= 3 && !d->reqFormat.testOption(QGL::DeprecatedFunctions)) { + attributes[attribIndex++] = WGL_CONTEXT_FLAGS_ARB; + attributes[attribIndex++] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + } + + if ((major == 3 && minor >= 2) || major > 3) { + switch (d->reqFormat.profile()) { + case QGLFormat::NoProfile: + break; + case QGLFormat::CoreProfile: + attributes[attribIndex++] = WGL_CONTEXT_PROFILE_MASK_ARB; + attributes[attribIndex++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + break; + case QGLFormat::CompatibilityProfile: + attributes[attribIndex++] = WGL_CONTEXT_PROFILE_MASK_ARB; + attributes[attribIndex++] = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + break; + default: + qWarning("QGLContext::chooseContext(): Context profile not supported."); + return false; + } + } + + if (d->reqFormat.plane() != 0) { + attributes[attribIndex++] = WGL_CONTEXT_LAYER_PLANE_ARB; + attributes[attribIndex++] = d->reqFormat.plane(); + } + + attributes[attribIndex++] = 0; // Terminate list. + d->rc = wglCreateContextAttribsARB(hdc, shareContext && shareContext->valid + ? shareContext->rc : 0, attributes); + if (d->rc) { + if (shareContext) + shareContext->sharing = d->sharing = true; + return true; + } + } + + d->rc = wglCreateLayerContext(hdc, d->reqFormat.plane()); + if (d->rc && shareContext && shareContext->valid) + shareContext->sharing = d->sharing = wglShareLists(shareContext->rc, d->rc); + return d->rc != 0; +} + +void QGLContextPrivate::updateFormatVersion() +{ + const GLubyte *s = glGetString(GL_VERSION); + + if (!(s && s[0] >= '0' && s[0] <= '9' && s[1] == '.' && s[2] >= '0' && s[2] <= '9')) { + if (!s) + qWarning("QGLContext::chooseContext(): OpenGL version string is null."); + else + qWarning("QGLContext::chooseContext(): Unexpected OpenGL version string format."); + glFormat.setVersion(0, 0); + glFormat.setProfile(QGLFormat::NoProfile); + glFormat.setOption(QGL::DeprecatedFunctions); + return; + } + + int major = s[0] - '0'; + int minor = s[2] - '0'; + glFormat.setVersion(major, minor); + + if (major < 3) { + glFormat.setProfile(QGLFormat::NoProfile); + glFormat.setOption(QGL::DeprecatedFunctions); + } else { + GLint value = 0; + if (major > 3 || minor >= 2) + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); + + switch (value) { + case WGL_CONTEXT_CORE_PROFILE_BIT_ARB: + glFormat.setProfile(QGLFormat::CoreProfile); + break; + case WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: + glFormat.setProfile(QGLFormat::CompatibilityProfile); + break; + default: + glFormat.setProfile(QGLFormat::NoProfile); + break; + } + + glGetIntegerv(GL_CONTEXT_FLAGS, &value); + if (value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) + glFormat.setOption(QGL::NoDeprecatedFunctions); + else + glFormat.setOption(QGL::DeprecatedFunctions); + } +} + +bool QGLContext::chooseContext(const QGLContext* shareContext) +{ + QGLContextPrivate *share = shareContext ? const_cast<QGLContext *>(shareContext)->d_func() : 0; + + Q_D(QGLContext); + // workaround for matrox driver: + // make a cheap call to opengl to force loading of DLL + if (!opengl32dll) { + GLint params; + glGetIntegerv(GL_DEPTH_BITS, ¶ms); + opengl32dll = true; + } + + bool result = true; + HDC myDc; + QWidget *widget = 0; + + if (deviceIsPixmap()) { + if (d->glFormat.plane()) + return false; // Pixmaps can't have overlay + d->win = 0; + HDC display_dc = GetDC(0); + myDc = d->hbitmap_hdc = CreateCompatibleDC(display_dc); + QPixmap *px = static_cast<QPixmap *>(d->paintDevice); + + BITMAPINFO bmi; + memset(&bmi, 0, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = px->width(); + bmi.bmiHeader.biHeight = px->height(); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + d->hbitmap = CreateDIBSection(display_dc, &bmi, DIB_RGB_COLORS, 0, 0, 0); + SelectObject(myDc, d->hbitmap); + ReleaseDC(0, display_dc); + } else { + widget = static_cast<QWidget *>(d->paintDevice); + d->win = widget->winId(); + myDc = GetDC(d->win); + } + + // NB! the QGLTemporaryContext object is needed for the + // wglGetProcAddress() calls to succeed and are absolutely + // necessary - don't remove! + QGLTemporaryContext tmp_ctx(d->glFormat.directRendering(), widget); + + if (!myDc) { + qWarning("QGLContext::chooseContext(): Paint device cannot be null"); + result = false; + goto end; + } + + if (d->glFormat.plane()) { + d->pixelFormatId = ((QGLWidget*)d->paintDevice)->context()->d_func()->pixelFormatId; + if (!d->pixelFormatId) { // I.e. the glwidget is invalid + qWarning("QGLContext::chooseContext(): Cannot create overlay context for invalid widget"); + result = false; + goto end; + } + + if (!qgl_create_context(myDc, d, share)) { + qwglError("QGLContext::chooseContext()", "CreateLayerContext"); + result = false; + goto end; + } + + LAYERPLANEDESCRIPTOR lpfd; + wglDescribeLayerPlane(myDc, d->pixelFormatId, d->glFormat.plane(), sizeof(LAYERPLANEDESCRIPTOR), &lpfd); + d->glFormat.setDoubleBuffer(lpfd.dwFlags & LPD_DOUBLEBUFFER); + d->glFormat.setDepth(lpfd.cDepthBits); + d->glFormat.setRgba(lpfd.iPixelType == PFD_TYPE_RGBA); + if (d->glFormat.rgba()) { + if (d->glFormat.redBufferSize() != -1) + d->glFormat.setRedBufferSize(lpfd.cRedBits); + if (d->glFormat.greenBufferSize() != -1) + d->glFormat.setGreenBufferSize(lpfd.cGreenBits); + if (d->glFormat.blueBufferSize() != -1) + d->glFormat.setBlueBufferSize(lpfd.cBlueBits); + } + d->glFormat.setAlpha(lpfd.cAlphaBits); + d->glFormat.setAccum(lpfd.cAccumBits); + d->glFormat.setStencil(lpfd.cStencilBits); + d->glFormat.setStereo(lpfd.dwFlags & LPD_STEREO); + d->glFormat.setDirectRendering(false); + if (d->glFormat.depth()) + d->glFormat.setDepthBufferSize(lpfd.cDepthBits); + if (d->glFormat.alpha()) + d->glFormat.setAlphaBufferSize(lpfd.cAlphaBits); + if (d->glFormat.accum()) + d->glFormat.setAccumBufferSize(lpfd.cAccumRedBits); + if (d->glFormat.stencil()) + d->glFormat.setStencilBufferSize(lpfd.cStencilBits); + + if (d->glFormat.rgba()) { + if (lpfd.dwFlags & LPD_TRANSPARENT) + d->transpColor = QColor(lpfd.crTransparent & 0xff, + (lpfd.crTransparent >> 8) & 0xff, + (lpfd.crTransparent >> 16) & 0xff); + else + d->transpColor = QColor(0, 0, 0); + } + else { + if (lpfd.dwFlags & LPD_TRANSPARENT) + d->transpColor = QColor(qRgb(1, 2, 3));//, lpfd.crTransparent); + else + d->transpColor = QColor(qRgb(1, 2, 3));//, 0); + + d->cmap = new QGLCmap(1 << lpfd.cColorBits); + d->cmap->setEntry(lpfd.crTransparent, qRgb(1, 2, 3));//, QGLCmap::Reserved); + } + } else { + PIXELFORMATDESCRIPTOR pfd; + PIXELFORMATDESCRIPTOR realPfd; + d->pixelFormatId = choosePixelFormat(&pfd, myDc); + if (d->pixelFormatId == 0) { + qwglError("QGLContext::chooseContext()", "ChoosePixelFormat"); + result = false; + goto end; + } + + bool overlayRequested = d->glFormat.hasOverlay(); + DescribePixelFormat(myDc, d->pixelFormatId, sizeof(PIXELFORMATDESCRIPTOR), &realPfd); + + if (!deviceIsPixmap() && wglGetProcAddress("wglGetPixelFormatAttribivARB")) + d->glFormat = pfiToQGLFormat(myDc, d->pixelFormatId); + else + d->glFormat = pfdToQGLFormat(&realPfd); + + d->glFormat.setOverlay(d->glFormat.hasOverlay() && overlayRequested); + + if (deviceIsPixmap() && !(realPfd.dwFlags & PFD_DRAW_TO_BITMAP)) { + qWarning("QGLContext::chooseContext(): Failed to get pixmap rendering context."); + result = false; + goto end; + } + + if (deviceIsPixmap() && + (((QPixmap*)d->paintDevice)->depth() != realPfd.cColorBits)) { + qWarning("QGLContext::chooseContext(): Failed to get pixmap rendering context of suitable depth."); + result = false; + goto end; + } + + if (!SetPixelFormat(myDc, d->pixelFormatId, &realPfd)) { + qwglError("QGLContext::chooseContext()", "SetPixelFormat"); + result = false; + goto end; + } + + if (!qgl_create_context(myDc, d, share)) { + qwglError("QGLContext::chooseContext()", "wglCreateContext"); + result = false; + goto end; + } + + if(!deviceIsPixmap()) { + QRgb* pal = qgl_create_rgb_palette(&realPfd); + if (pal) { + QGLColormap cmap; + cmap.setEntries(256, pal); + ((QGLWidget*)d->paintDevice)->setColormap(cmap); + delete[] pal; + } + } + } + +end: + // vblanking + wglMakeCurrent(myDc, d->rc); + if (d->rc) + d->updateFormatVersion(); + + typedef BOOL (APIENTRYP PFNWGLSWAPINTERVALEXT) (int interval); + typedef int (APIENTRYP PFNWGLGETSWAPINTERVALEXT) (void); + PFNWGLSWAPINTERVALEXT wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXT) wglGetProcAddress("wglSwapIntervalEXT"); + PFNWGLGETSWAPINTERVALEXT wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXT) wglGetProcAddress("wglGetSwapIntervalEXT"); + if (wglSwapIntervalEXT && wglGetSwapIntervalEXT) { + if (d->reqFormat.swapInterval() != -1) + wglSwapIntervalEXT(d->reqFormat.swapInterval()); + d->glFormat.setSwapInterval(wglGetSwapIntervalEXT()); + } + + if (d->win) + ReleaseDC(d->win, myDc); + return result; +} + + + +static bool qLogEq(bool a, bool b) +{ + return (((!a) && (!b)) || (a && b)); +} + +/* + See qgl.cpp for qdoc comment. + */ +int QGLContext::choosePixelFormat(void* dummyPfd, HDC pdc) +{ + Q_D(QGLContext); + // workaround for matrox driver: + // make a cheap call to opengl to force loading of DLL + if (!opengl32dll) { + GLint params; + glGetIntegerv(GL_DEPTH_BITS, ¶ms); + opengl32dll = true; + } + + PFNWGLCHOOSEPIXELFORMATARB wglChoosePixelFormatARB = + (PFNWGLCHOOSEPIXELFORMATARB) wglGetProcAddress("wglChoosePixelFormatARB"); + int chosenPfi = 0; + if (!deviceIsPixmap() && wglChoosePixelFormatARB) { + bool valid; + int pixelFormat = 0; + uint numFormats = 0; + QVarLengthArray<int> iAttributes(40); + int i = 0; + iAttributes[i++] = WGL_ACCELERATION_ARB; + if (d->glFormat.directRendering()) + iAttributes[i++] = WGL_FULL_ACCELERATION_ARB; + else + iAttributes[i++] = WGL_NO_ACCELERATION_ARB; + iAttributes[i++] = WGL_SUPPORT_OPENGL_ARB; + iAttributes[i++] = TRUE; + iAttributes[i++] = WGL_DRAW_TO_WINDOW_ARB; + iAttributes[i++] = TRUE; + iAttributes[i++] = WGL_COLOR_BITS_ARB; + iAttributes[i++] = 24; + iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB; + iAttributes[i++] = d->glFormat.doubleBuffer(); + if (d->glFormat.stereo()) { + iAttributes[i++] = WGL_STEREO_ARB; + iAttributes[i++] = TRUE; + } + if (d->glFormat.depth()) { + iAttributes[i++] = WGL_DEPTH_BITS_ARB; + iAttributes[i++] = d->glFormat.depthBufferSize() == -1 ? 24 : d->glFormat.depthBufferSize(); + } + iAttributes[i++] = WGL_PIXEL_TYPE_ARB; + if (d->glFormat.rgba()) { + iAttributes[i++] = WGL_TYPE_RGBA_ARB; + if (d->glFormat.redBufferSize() != -1) { + iAttributes[i++] = WGL_RED_BITS_ARB; + iAttributes[i++] = d->glFormat.redBufferSize(); + } + if (d->glFormat.greenBufferSize() != -1) { + iAttributes[i++] = WGL_GREEN_BITS_ARB; + iAttributes[i++] = d->glFormat.greenBufferSize(); + } + if (d->glFormat.blueBufferSize() != -1) { + iAttributes[i++] = WGL_BLUE_BITS_ARB; + iAttributes[i++] = d->glFormat.blueBufferSize(); + } + } else { + iAttributes[i++] = WGL_TYPE_COLORINDEX_ARB; + } + if (d->glFormat.alpha()) { + iAttributes[i++] = WGL_ALPHA_BITS_ARB; + iAttributes[i++] = d->glFormat.alphaBufferSize() == -1 ? 8 : d->glFormat.alphaBufferSize(); + } + if (d->glFormat.accum()) { + iAttributes[i++] = WGL_ACCUM_BITS_ARB; + iAttributes[i++] = d->glFormat.accumBufferSize() == -1 ? 16 : d->glFormat.accumBufferSize(); + } + if (d->glFormat.stencil()) { + iAttributes[i++] = WGL_STENCIL_BITS_ARB; + iAttributes[i++] = d->glFormat.stencilBufferSize() == -1 ? 8 : d->glFormat.stencilBufferSize(); + } + if (d->glFormat.hasOverlay()) { + iAttributes[i++] = WGL_NUMBER_OVERLAYS_ARB; + iAttributes[i++] = 1; + } + int si = 0; + bool trySampleBuffers = QGLExtensions::glExtensions() & QGLExtensions::SampleBuffers; + if (trySampleBuffers && d->glFormat.sampleBuffers()) { + iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB; + iAttributes[i++] = TRUE; + iAttributes[i++] = WGL_SAMPLES_ARB; + si = i; + iAttributes[i++] = d->glFormat.samples() == -1 ? 4 : d->glFormat.samples(); + } + iAttributes[i] = 0; + + do { + valid = wglChoosePixelFormatARB(pdc, iAttributes.constData(), 0, 1, + &pixelFormat, &numFormats); + if (trySampleBuffers && (!valid || numFormats < 1) && d->glFormat.sampleBuffers()) + iAttributes[si] /= 2; // try different no. samples - we aim for the best one + else + break; + } while ((!valid || numFormats < 1) && iAttributes[si] > 1); + chosenPfi = pixelFormat; + } + + if (!chosenPfi) { // fallback if wglChoosePixelFormatARB() failed + int pmDepth = deviceIsPixmap() ? ((QPixmap*)d->paintDevice)->depth() : 0; + PIXELFORMATDESCRIPTOR* p = (PIXELFORMATDESCRIPTOR*)dummyPfd; + memset(p, 0, sizeof(PIXELFORMATDESCRIPTOR)); + p->nSize = sizeof(PIXELFORMATDESCRIPTOR); + p->nVersion = 1; + p->dwFlags = PFD_SUPPORT_OPENGL; + if (deviceIsPixmap()) + p->dwFlags |= PFD_DRAW_TO_BITMAP; + else + p->dwFlags |= PFD_DRAW_TO_WINDOW; + if (!d->glFormat.directRendering()) + p->dwFlags |= PFD_GENERIC_FORMAT; + if (d->glFormat.doubleBuffer() && !deviceIsPixmap()) + p->dwFlags |= PFD_DOUBLEBUFFER; + if (d->glFormat.stereo()) + p->dwFlags |= PFD_STEREO; + if (d->glFormat.depth()) + p->cDepthBits = d->glFormat.depthBufferSize() == -1 ? 32 : d->glFormat.depthBufferSize(); + else + p->dwFlags |= PFD_DEPTH_DONTCARE; + if (d->glFormat.rgba()) { + p->iPixelType = PFD_TYPE_RGBA; + if (d->glFormat.redBufferSize() != -1) + p->cRedBits = d->glFormat.redBufferSize(); + if (d->glFormat.greenBufferSize() != -1) + p->cGreenBits = d->glFormat.greenBufferSize(); + if (d->glFormat.blueBufferSize() != -1) + p->cBlueBits = d->glFormat.blueBufferSize(); + if (deviceIsPixmap()) + p->cColorBits = pmDepth; + else + p->cColorBits = 32; + } else { + p->iPixelType = PFD_TYPE_COLORINDEX; + p->cColorBits = 8; + } + if (d->glFormat.alpha()) + p->cAlphaBits = d->glFormat.alphaBufferSize() == -1 ? 8 : d->glFormat.alphaBufferSize(); + if (d->glFormat.accum()) { + p->cAccumRedBits = p->cAccumGreenBits = p->cAccumBlueBits = p->cAccumAlphaBits = + d->glFormat.accumBufferSize() == -1 ? 16 : d->glFormat.accumBufferSize(); + } + if (d->glFormat.stencil()) + p->cStencilBits = d->glFormat.stencilBufferSize() == -1 ? 8 : d->glFormat.stencilBufferSize(); + p->iLayerType = PFD_MAIN_PLANE; + chosenPfi = ChoosePixelFormat(pdc, p); + + if (!chosenPfi) + qErrnoWarning("QGLContext: ChoosePixelFormat failed"); + + // Since the GDI function ChoosePixelFormat() does not handle + // overlay and direct-rendering requests, we must roll our own here + + bool doSearch = chosenPfi <= 0; + PIXELFORMATDESCRIPTOR pfd; + QGLFormat fmt; + if (!doSearch) { + DescribePixelFormat(pdc, chosenPfi, sizeof(PIXELFORMATDESCRIPTOR), + &pfd); + fmt = pfdToQGLFormat(&pfd); + if (d->glFormat.hasOverlay() && !fmt.hasOverlay()) + doSearch = true; + else if (!qLogEq(d->glFormat.directRendering(), fmt.directRendering())) + doSearch = true; + else if (deviceIsPixmap() && (!(pfd.dwFlags & PFD_DRAW_TO_BITMAP) || + pfd.cColorBits != pmDepth)) + doSearch = true; + else if (!deviceIsPixmap() && !(pfd.dwFlags & PFD_DRAW_TO_WINDOW)) + doSearch = true; + else if (!qLogEq(d->glFormat.rgba(), fmt.rgba())) + doSearch = true; + } + + if (doSearch) { + int pfiMax = DescribePixelFormat(pdc, 0, 0, NULL); + int bestScore = -1; + int bestPfi = -1; + for (int pfi = 1; pfi <= pfiMax; pfi++) { + DescribePixelFormat(pdc, pfi, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL)) + continue; + if (deviceIsPixmap() && (!(pfd.dwFlags & PFD_DRAW_TO_BITMAP) || + pfd.cColorBits != pmDepth)) + continue; + if (!deviceIsPixmap() && !(pfd.dwFlags & PFD_DRAW_TO_WINDOW)) + continue; + + fmt = pfdToQGLFormat(&pfd); + if (d->glFormat.hasOverlay() && !fmt.hasOverlay()) + continue; + + int score = pfd.cColorBits; + if (qLogEq(d->glFormat.depth(), fmt.depth())) + score += pfd.cDepthBits; + if (qLogEq(d->glFormat.alpha(), fmt.alpha())) + score += pfd.cAlphaBits; + if (qLogEq(d->glFormat.accum(), fmt.accum())) + score += pfd.cAccumBits; + if (qLogEq(d->glFormat.stencil(), fmt.stencil())) + score += pfd.cStencilBits; + if (qLogEq(d->glFormat.doubleBuffer(), fmt.doubleBuffer())) + score += 1000; + if (qLogEq(d->glFormat.stereo(), fmt.stereo())) + score += 2000; + if (qLogEq(d->glFormat.directRendering(), fmt.directRendering())) + score += 4000; + if (qLogEq(d->glFormat.rgba(), fmt.rgba())) + score += 8000; + if (score > bestScore) { + bestScore = score; + bestPfi = pfi; + } + } + + if (bestPfi > 0) + chosenPfi = bestPfi; + } + } + return chosenPfi; +} + + + +void QGLContext::reset() +{ + Q_D(QGLContext); + // workaround for matrox driver: + // make a cheap call to opengl to force loading of DLL + if (!opengl32dll) { + GLint params; + glGetIntegerv(GL_DEPTH_BITS, ¶ms); + opengl32dll = true; + } + + if (!d->valid) + return; + d->cleanup(); + doneCurrent(); + if (d->rc) + wglDeleteContext(d->rc); + d->rc = 0; + if (d->win && d->dc) + ReleaseDC(d->win, d->dc); + if (deviceIsPixmap()) { + DeleteDC(d->hbitmap_hdc); + DeleteObject(d->hbitmap); + d->hbitmap_hdc = 0; + d->hbitmap = 0; + } + d->dc = 0; + d->win = 0; + d->threadId = 0; + d->pixelFormatId = 0; + d->sharing = false; + d->valid = false; + d->transpColor = QColor(); + delete d->cmap; + d->cmap = 0; + d->initDone = false; + QGLContextGroup::removeShare(this); +} + +// +// NOTE: In a multi-threaded environment, each thread has a current +// context. If we want to make this code thread-safe, we probably +// have to use TLS (thread local storage) for keeping current contexts. +// + +void QGLContext::makeCurrent() +{ + Q_D(QGLContext); + if (d->rc == wglGetCurrentContext() || !d->valid) // already current + return; + + if (d->win && (!d->dc || d->threadId != QThread::currentThreadId())) { + d->dc = GetDC(d->win); + d->threadId = QThread::currentThreadId(); + if (!d->dc) { + qwglError("QGLContext::makeCurrent()", "GetDC()"); + return; + } + } else if (deviceIsPixmap()) { + d->dc = d->hbitmap_hdc; + } + + HPALETTE hpal = QColormap::hPal(); + if (hpal) { + SelectPalette(d->dc, hpal, FALSE); + RealizePalette(d->dc); + } + if (d->glFormat.plane()) { + wglRealizeLayerPalette(d->dc, d->glFormat.plane(), TRUE); + } + + if (wglMakeCurrent(d->dc, d->rc)) { + QGLContextPrivate::setCurrentContext(this); + } else { + qwglError("QGLContext::makeCurrent()", "wglMakeCurrent"); + } +} + + +void QGLContext::doneCurrent() +{ + Q_D(QGLContext); + wglMakeCurrent(0, 0); + QGLContextPrivate::setCurrentContext(0); + if (deviceIsPixmap() && d->hbitmap) { + QPixmap *pm = static_cast<QPixmap *>(d->paintDevice); + *pm = QPixmap::fromWinHBITMAP(d->hbitmap); + } + if (d->win && d->dc) { + ReleaseDC(d->win, d->dc); + d->dc = 0; + d->threadId = 0; + } +} + +void QGLContext::swapBuffers() const +{ + Q_D(const QGLContext); + if (d->dc && d->glFormat.doubleBuffer() && !deviceIsPixmap()) { + if (d->glFormat.plane()) + wglSwapLayerBuffers(d->dc, WGL_SWAP_OVERLAY1); + else { + if (d->glFormat.hasOverlay()) + wglSwapLayerBuffers(d->dc, WGL_SWAP_MAIN_PLANE); + else + SwapBuffers(d->dc); + } + } +} + + +QColor QGLContext::overlayTransparentColor() const +{ + return d_func()->transpColor; +} + + +uint QGLContext::colorIndex(const QColor& c) const +{ + Q_D(const QGLContext); + if (!isValid()) + return 0; + if (d->cmap) { + int idx = d->cmap->find(c.rgb()); + if (idx >= 0) + return idx; + if (d->dc && d->glFormat.plane()) { + idx = d->cmap->allocate(c.rgb()); + if (idx >= 0) { + COLORREF r = RGB(qRed(c.rgb()),qGreen(c.rgb()),qBlue(c.rgb())); + wglSetLayerPaletteEntries(d->dc, d->glFormat.plane(), idx, 1, &r); + wglRealizeLayerPalette(d->dc, d->glFormat.plane(), TRUE); + return idx; + } + } + return d->cmap->findNearest(c.rgb()); + } + QColormap cmap = QColormap::instance(); + return cmap.pixel(c) & 0x00ffffff; // Assumes standard palette +} + +void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase) +{ + if (!isValid()) + return; + + HDC display_dc = GetDC(0); + HDC tmp_dc = CreateCompatibleDC(display_dc); + HGDIOBJ old_font = SelectObject(tmp_dc, fnt.handle()); + + ReleaseDC(0, display_dc); + + if (!wglUseFontBitmaps(tmp_dc, 0, 256, listBase)) + qWarning("QGLContext::generateFontDisplayLists: Could not generate display lists for font '%s'", fnt.family().toLatin1().data()); + + SelectObject(tmp_dc, old_font); + DeleteDC(tmp_dc); +} + +void *QGLContext::getProcAddress(const QString &proc) const +{ + return (void *)wglGetProcAddress(proc.toLatin1()); +} + +/***************************************************************************** + QGLWidget Win32/WGL-specific code + *****************************************************************************/ + +void QGLWidgetPrivate::init(QGLContext *ctx, const QGLWidget* shareWidget) +{ + Q_Q(QGLWidget); + olcx = 0; + initContext(ctx, shareWidget); + + if (q->isValid() && q->context()->format().hasOverlay()) { + olcx = new QGLContext(QGLFormat::defaultOverlayFormat(), q); + if (!olcx->create(shareWidget ? shareWidget->overlayContext() : 0)) { + delete olcx; + olcx = 0; + glcx->d_func()->glFormat.setOverlay(false); + } + } else { + olcx = 0; + } +} + +/*\internal + Store color values in the given colormap. +*/ +static void qStoreColors(HPALETTE cmap, const QGLColormap & cols) +{ + QRgb color; + PALETTEENTRY pe; + + for (int i = 0; i < cols.size(); i++) { + color = cols.entryRgb(i); + pe.peRed = qRed(color); + pe.peGreen = qGreen(color); + pe.peBlue = qBlue(color); + pe.peFlags = 0; + + SetPaletteEntries(cmap, i, 1, &pe); + } +} + +void QGLWidgetPrivate::updateColormap() +{ + Q_Q(QGLWidget); + if (!cmap.handle()) + return; + HDC hdc = GetDC(q->winId()); + SelectPalette(hdc, (HPALETTE) cmap.handle(), TRUE); + qStoreColors((HPALETTE) cmap.handle(), cmap); + RealizePalette(hdc); + ReleaseDC(q->winId(), hdc); +} + +void QGLWidget::setMouseTracking(bool enable) +{ + QWidget::setMouseTracking(enable); +} + + +void QGLWidget::resizeEvent(QResizeEvent *) +{ + Q_D(QGLWidget); + if (!isValid()) + return; + makeCurrent(); + if (!d->glcx->initialized()) + glInit(); + resizeGL(width(), height()); + if (d->olcx) { + makeOverlayCurrent(); + resizeOverlayGL(width(), height()); + } +} + + +const QGLContext* QGLWidget::overlayContext() const +{ + return d_func()->olcx; +} + + +void QGLWidget::makeOverlayCurrent() +{ + Q_D(QGLWidget); + if (d->olcx) { + d->olcx->makeCurrent(); + if (!d->olcx->initialized()) { + initializeOverlayGL(); + d->olcx->setInitialized(true); + } + } +} + + +void QGLWidget::updateOverlayGL() +{ + Q_D(QGLWidget); + if (d->olcx) { + makeOverlayCurrent(); + paintOverlayGL(); + if (d->olcx->format().doubleBuffer()) { + if (d->autoSwap) + d->olcx->swapBuffers(); + } + else { + glFlush(); + } + } +} + + +void QGLWidget::setContext(QGLContext *context, + const QGLContext* shareContext, + bool deleteOldContext) +{ + Q_D(QGLWidget); + if (context == 0) { + qWarning("QGLWidget::setContext: Cannot set null context"); + return; + } + if (!context->deviceIsPixmap() && context->device() != this) { + qWarning("QGLWidget::setContext: Context must refer to this widget"); + return; + } + + if (d->glcx) + d->glcx->doneCurrent(); + QGLContext* oldcx = d->glcx; + d->glcx = context; + + bool doShow = false; + if (oldcx && oldcx->d_func()->win == winId() && !d->glcx->deviceIsPixmap()) { + // We already have a context and must therefore create a new + // window since Windows does not permit setting a new OpenGL + // context for a window that already has one set. + doShow = isVisible(); + QWidget *pW = static_cast<QWidget *>(parent()); + QPoint pos = geometry().topLeft(); + setParent(pW, windowFlags()); + move(pos); + } + + if (!d->glcx->isValid()) { + bool wasSharing = shareContext || (oldcx && oldcx->isSharing()); + d->glcx->create(shareContext ? shareContext : oldcx); + // the above is a trick to keep disp lists etc when a + // QGLWidget has been reparented, so remove the sharing + // flag if we don't actually have a sharing context. + if (!wasSharing) + d->glcx->d_ptr->sharing = false; + } + + if (deleteOldContext) + delete oldcx; + + if (doShow) + show(); +} + + +bool QGLWidgetPrivate::renderCxPm(QPixmap*) +{ + return false; +} + +void QGLWidgetPrivate::cleanupColormaps() +{ + Q_Q(QGLWidget); + if (cmap.handle()) { + HDC hdc = GetDC(q->winId()); + SelectPalette(hdc, (HPALETTE) GetStockObject(DEFAULT_PALETTE), FALSE); + DeleteObject((HPALETTE) cmap.handle()); + ReleaseDC(q->winId(), hdc); + cmap.setHandle(0); + } + return; +} + +const QGLColormap & QGLWidget::colormap() const +{ + return d_func()->cmap; +} + +void QGLWidget::setColormap(const QGLColormap & c) +{ + Q_D(QGLWidget); + d->cmap = c; + + if (d->cmap.handle()) { // already have an allocated cmap + d->updateColormap(); + } else { + LOGPALETTE *lpal = (LOGPALETTE *) malloc(sizeof(LOGPALETTE) + +c.size()*sizeof(PALETTEENTRY)); + lpal->palVersion = 0x300; + lpal->palNumEntries = c.size(); + d->cmap.setHandle(CreatePalette(lpal)); + free(lpal); + d->updateColormap(); + } +} + +QT_END_NAMESPACE |
