| /**************************************************************************** |
| ** |
| ** 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$ |
| ** GNU Lesser General Public License Usage |
| ** 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. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $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->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 = GetDC(d->win); |
| 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; |
| } |
| } |
| |
| 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 |