blob: 87c39cfd9a98e332a1358e31c034a29ae66ffbf5 [file] [log] [blame]
/****************************************************************************
**
** 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, &params);
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, &params);
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, &params);
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, &params);
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