1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
48 #include <private/qgl_p.h>
49 #include <qcolormap.h>
50 #include <qvarlengtharray.h>
52 #include <qapplication.h>
53 #include <qdesktopwidget>
58 #include "qgl_egl_p.h"
69 QGLCmapPrivate() : count(1) { }
70 void ref() { ++count
; }
71 bool deref() { return !--count
; }
74 enum AllocState
{ UnAllocated
= 0, Allocated
= 0x01, Reserved
= 0x02 };
77 QVector
<uint
> colorArray
;
78 QVector
<quint8
> allocArray
;
79 QVector
<quint8
> contextArray
;
80 QMap
<uint
,int> colorMap
;
83 /*****************************************************************************
84 QColorMap class - temporarily here, until it is ready for prime time
85 *****************************************************************************/
87 /****************************************************************************
89 ** Definition of QColorMap class
91 ****************************************************************************/
101 /*****************************************************************************
102 QGLFormat Win32/WGL-specific code
103 *****************************************************************************/
105 void qt_egl_add_platform_config(QEglProperties
& props
, QPaintDevice
*device
)
107 int devType
= device
->devType();
108 if (devType
== QInternal::Image
)
109 props
.setPixelFormat(static_cast<QImage
*>(device
)->format());
111 props
.setPixelFormat(QImage::Format_RGB16
);
115 static bool opengl32dll
= false;
117 bool QGLFormat::hasOpenGLOverlays()
123 bool QGLContext::chooseContext(const QGLContext
* shareContext
)
127 // Validate the device.
130 int devType
= device()->devType();
131 if (devType
!= QInternal::Pixmap
&& devType
!= QInternal::Image
&& devType
!= QInternal::Widget
) {
132 qWarning("QGLContext::chooseContext(): Cannot create QGLContext's for paint device type %d", devType
);
136 // Get the display and initialize it.
137 d
->eglContext
= new QEglContext();
138 d
->eglContext
->setApi(QEgl::OpenGL
);
139 if (!d
->eglContext
->openDisplay(device())) {
140 delete d
->eglContext
;
145 // Construct the configuration we need for this surface.
146 QEglProperties configProps
;
147 qt_egl_add_platform_config(configProps
, device());
148 qt_egl_set_format(configProps
, devType
, d
->glFormat
);
149 configProps
.setRenderableType(QEgl::OpenGL
);
151 // Search for a matching configuration, reducing the complexity
152 // each time until we get something that matches.
153 if (!d
->eglContext
->chooseConfig(configProps
)) {
154 delete d
->eglContext
;
159 // Inform the higher layers about the actual format properties.
160 qt_egl_update_format(*(d
->eglContext
), d
->glFormat
);
162 // Create a new context for the configuration.
163 if (!d
->eglContext
->createContext
164 (shareContext
? shareContext
->d_func()->eglContext
: 0)) {
165 delete d
->eglContext
;
170 #if defined(EGL_VERSION_1_1)
171 if (d
->glFormat
.swapInterval() != -1 && devType
== QInternal::Widget
)
172 eglSwapInterval(d
->eglContext
->display(), d
->glFormat
.swapInterval());
175 // Create the EGL surface to draw into.
176 d
->eglSurface
= d
->eglContext
->createSurface(device());
177 if (d
->eglSurface
== EGL_NO_SURFACE
) {
178 delete d
->eglContext
;
189 static bool qLogEq(bool a
, bool b
)
191 return (((!a
) && (!b
)) || (a
&& b
));
194 int QGLContext::choosePixelFormat(void* , HDC
)
200 class QGLCmapPrivate
;
202 class /*Q_EXPORT*/ QGLCmap
205 enum Flags
{ Reserved
= 0x01 };
207 QGLCmap(int maxSize
= 256);
208 QGLCmap(const QGLCmap
& map
);
211 QGLCmap
& operator=(const QGLCmap
& map
);
213 // isEmpty and/or isNull ?
217 void resize(int newSize
);
219 int find(QRgb color
) const;
220 int findNearest(QRgb color
) const;
221 int allocate(QRgb color
, uint flags
= 0, quint8 context
= 0);
223 void setEntry(int idx
, QRgb color
, uint flags
= 0, quint8 context
= 0);
225 const QRgb
* colors() const;
235 QGLCmap::QGLCmap(int maxSize
) // add a bool prealloc?
237 d
= new QGLCmapPrivate
;
238 d
->maxSize
= maxSize
;
241 QGLCmap::QGLCmap(const QGLCmap
& map
)
254 QGLCmap
& QGLCmap::operator=(const QGLCmap
& map
)
263 int QGLCmap::size() const
265 return d
->colorArray
.size();
268 int QGLCmap::maxSize() const
273 void QGLCmap::detach()
277 QGLCmapPrivate
* newd
= new QGLCmapPrivate
;
278 newd
->maxSize
= d
->maxSize
;
279 newd
->colorArray
= d
->colorArray
;
280 newd
->allocArray
= d
->allocArray
;
281 newd
->contextArray
= d
->contextArray
;
282 newd
->colorArray
.detach();
283 newd
->allocArray
.detach();
284 newd
->contextArray
.detach();
285 newd
->colorMap
= d
->colorMap
;
291 void QGLCmap::resize(int newSize
)
293 if (newSize
< 0 || newSize
> d
->maxSize
) {
294 qWarning("QGLCmap::resize(): size out of range");
297 int oldSize
= size();
299 //if shrinking; remove the lost elems from colorMap
300 d
->colorArray
.resize(newSize
);
301 d
->allocArray
.resize(newSize
);
302 d
->contextArray
.resize(newSize
);
303 if (newSize
> oldSize
) {
304 memset(d
->allocArray
.data() + oldSize
, 0, newSize
- oldSize
);
305 memset(d
->contextArray
.data() + oldSize
, 0, newSize
- oldSize
);
310 int QGLCmap::find(QRgb color
) const
312 QMap
<uint
,int>::ConstIterator it
= d
->colorMap
.find(color
);
313 if (it
!= d
->colorMap
.end())
319 int QGLCmap::findNearest(QRgb color
) const
321 int idx
= find(color
);
324 int mapSize
= size();
325 int mindist
= 200000;
327 int g
= qGreen(color
);
328 int b
= qBlue(color
);
329 int rx
, gx
, bx
, dist
;
330 for (int i
=0; i
< mapSize
; i
++) {
331 if (!(d
->allocArray
[i
] & QGLCmapPrivate::Allocated
))
333 QRgb ci
= d
->colorArray
[i
];
337 dist
= rx
*rx
+ gx
*gx
+ bx
*bx
; // calculate distance
338 if (dist
< mindist
) { // minimal?
347 // Does not always allocate; returns existing c idx if found
349 int QGLCmap::allocate(QRgb color
, uint flags
, quint8 context
)
351 int idx
= find(color
);
355 int mapSize
= d
->colorArray
.size();
356 int newIdx
= d
->allocArray
.indexOf(QGLCmapPrivate::UnAllocated
);
358 if (newIdx
< 0) { // Must allocate more room
359 if (mapSize
< d
->maxSize
) {
365 //# add a bool param that says what to do in case no more room -
366 // fail (-1) or return nearest?
371 d
->colorArray
[newIdx
] = color
;
372 if (flags
& QGLCmap::Reserved
) {
373 d
->allocArray
[newIdx
] = QGLCmapPrivate::Reserved
;
376 d
->allocArray
[newIdx
] = QGLCmapPrivate::Allocated
;
377 d
->colorMap
.insert(color
, newIdx
);
379 d
->contextArray
[newIdx
] = context
;
384 void QGLCmap::setEntry(int idx
, QRgb color
, uint flags
, quint8 context
)
386 if (idx
< 0 || idx
>= d
->maxSize
) {
387 qWarning("QGLCmap::set(): Index out of range");
391 int mapSize
= size();
392 if (idx
>= mapSize
) {
396 d
->colorArray
[idx
] = color
;
397 if (flags
& QGLCmap::Reserved
) {
398 d
->allocArray
[idx
] = QGLCmapPrivate::Reserved
;
401 d
->allocArray
[idx
] = QGLCmapPrivate::Allocated
;
402 d
->colorMap
.insert(color
, idx
);
404 d
->contextArray
[idx
] = context
;
408 const QRgb
* QGLCmap::colors() const
410 return d
->colorArray
.data();
414 /*****************************************************************************
415 QGLWidget Win32/WGL-specific code
416 *****************************************************************************/
418 void QGLWidgetPrivate::init(QGLContext
*ctx
, const QGLWidget
* shareWidget
)
422 initContext(ctx
, shareWidget
);
424 if (q
->isValid() && q
->context()->format().hasOverlay()) {
425 olcx
= new QGLContext(QGLFormat::defaultOverlayFormat(), q
);
426 if (!olcx
->create(shareWidget
? shareWidget
->overlayContext() : 0)) {
429 glcx
->d_func()->glFormat
.setOverlay(false);
437 Store color values in the given colormap.
439 static void qStoreColors(HPALETTE cmap
, const QGLColormap
& cols
)
444 for (int i
= 0; i
< cols
.size(); i
++) {
445 color
= cols
.entryRgb(i
);
446 pe
.peRed
= qRed(color
);
447 pe
.peGreen
= qGreen(color
);
448 pe
.peBlue
= qBlue(color
);
451 SetPaletteEntries(cmap
, i
, 1, &pe
);
455 void QGLWidgetPrivate::updateColormap()
460 HDC hdc
= GetDC(q
->winId());
461 SelectPalette(hdc
, (HPALETTE
) cmap
.handle(), TRUE
);
462 qStoreColors((HPALETTE
) cmap
.handle(), cmap
);
464 ReleaseDC(q
->winId(), hdc
);
467 bool QGLWidget::event(QEvent
*e
)
470 if (e
->type() == QEvent::ParentChange
) {
471 setContext(new QGLContext(d
->glcx
->requestedFormat(), this));
472 // the overlay needs to be recreated as well
474 if (isValid() && context()->format().hasOverlay()) {
475 d
->olcx
= new QGLContext(QGLFormat::defaultOverlayFormat(), this);
476 if (!d
->olcx
->create(isSharing() ? d
->glcx
: 0)) {
479 d
->glcx
->d_func()->glFormat
.setOverlay(false);
484 } else if (e
->type() == QEvent::Show
&& !format().rgba()) {
488 return QWidget::event(e
);
492 void QGLWidget::resizeEvent(QResizeEvent
*)
498 if (!d
->glcx
->initialized())
500 resizeGL(width(), height());
502 makeOverlayCurrent();
503 resizeOverlayGL(width(), height());
508 const QGLContext
* QGLWidget::overlayContext() const
510 return d_func()->olcx
;
514 void QGLWidget::makeOverlayCurrent()
518 d
->olcx
->makeCurrent();
519 if (!d
->olcx
->initialized()) {
520 initializeOverlayGL();
521 d
->olcx
->setInitialized(true);
527 void QGLWidget::updateOverlayGL()
531 makeOverlayCurrent();
533 if (d
->olcx
->format().doubleBuffer()) {
535 d
->olcx
->swapBuffers();
543 void QGLWidget::setContext(QGLContext
*context
,
544 const QGLContext
* shareContext
,
545 bool deleteOldContext
)
549 qWarning("QGLWidget::setContext: Cannot set null context");
552 if (!context
->deviceIsPixmap() && context
->device() != this) {
553 qWarning("QGLWidget::setContext: Context must refer to this widget");
558 d
->glcx
->doneCurrent();
559 QGLContext
* oldcx
= d
->glcx
;
563 if (oldcx
&& oldcx
->d_func()->win
== winId() && !d
->glcx
->deviceIsPixmap()) {
564 // We already have a context and must therefore create a new
565 // window since Windows does not permit setting a new OpenGL
566 // context for a window that already has one set.
567 doShow
= isVisible();
568 QWidget
*pW
= static_cast<QWidget
*>(parent());
569 QPoint pos
= geometry().topLeft();
570 setParent(pW
, windowFlags());
574 if (!d
->glcx
->isValid()) {
575 d
->glcx
->create(shareContext
? shareContext
: oldcx
);
576 // the above is a trick to keep disp lists etc when a
577 // QGLWidget has been reparented, so remove the sharing
578 // flag if we don't actually have a sharing context.
580 d
->glcx
->d_ptr
->sharing
= false;
583 if (deleteOldContext
)
591 void QGLWidgetPrivate::cleanupColormaps()
595 HDC hdc
= GetDC(q
->winId());
596 SelectPalette(hdc
, (HPALETTE
) GetStockObject(DEFAULT_PALETTE
), FALSE
);
597 DeleteObject((HPALETTE
) cmap
.handle());
598 ReleaseDC(q
->winId(), hdc
);
604 const QGLColormap
& QGLWidget::colormap() const
606 return d_func()->cmap
;
609 void QGLWidget::setColormap(const QGLColormap
& c
)
614 if (d
->cmap
.handle()) { // already have an allocated cmap
617 LOGPALETTE
*lpal
= (LOGPALETTE
*) malloc(sizeof(LOGPALETTE
)
618 +c
.size()*sizeof(PALETTEENTRY
));
619 lpal
->palVersion
= 0x300;
620 lpal
->palNumEntries
= c
.size();
621 d
->cmap
.setHandle(CreatePalette(lpal
));
627 void QGLExtensions::init()
629 static bool init_done
= false;
635 // We need a context current to initialize the extensions.
637 tmpWidget
.makeCurrent();
641 tmpWidget
.doneCurrent();