source: trunk/src/opengl/qgl_wince.cpp@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 16.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
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.
23**
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.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42
43#include <qgl.h>
44#include <qlist.h>
45#include <qmap.h>
46#include <qpixmap.h>
47#include <qevent.h>
48#include <private/qgl_p.h>
49#include <qcolormap.h>
50#include <qvarlengtharray.h>
51#include <qdebug.h>
52#include <qapplication.h>
53#include <qdesktopwidget>
54
55#include <windows.h>
56
57#include <private/qegl_p.h>
58#include <private/qgl_egl_p.h>
59#include <private/qgl_cl_p.h>
60
61
62QT_BEGIN_NAMESPACE
63
64
65
66class QGLCmapPrivate
67{
68public:
69 QGLCmapPrivate() : count(1) { }
70 void ref() { ++count; }
71 bool deref() { return !--count; }
72 uint count;
73
74 enum AllocState{ UnAllocated = 0, Allocated = 0x01, Reserved = 0x02 };
75
76 int maxSize;
77 QVector<uint> colorArray;
78 QVector<quint8> allocArray;
79 QVector<quint8> contextArray;
80 QMap<uint,int> colorMap;
81};
82
83/*****************************************************************************
84 QColorMap class - temporarily here, until it is ready for prime time
85 *****************************************************************************/
86
87/****************************************************************************
88**
89** Definition of QColorMap class
90**
91****************************************************************************/
92
93#ifndef QGLCMAP_H
94#define QGLCMAP_H
95
96#include <qcolor.h>
97
98/*
99 QGLTemporaryContext implementation
100*/
101
102class QGLTemporaryContextPrivate
103{
104public:
105 QGLWidget *widget;
106};
107
108QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
109 : d(new QGLTemporaryContextPrivate)
110{
111 d->widget = new QGLWidget;
112 d->widget->makeCurrent();
113}
114
115QGLTemporaryContext::~QGLTemporaryContext()
116{
117 delete d->widget;
118}
119
120/*****************************************************************************
121 QGLFormat Win32/WGL-specific code
122 *****************************************************************************/
123
124void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device)
125{
126 int devType = device->devType();
127 if (devType == QInternal::Image)
128 props.setPixelFormat(static_cast<QImage *>(device)->format());
129 else
130 props.setPixelFormat(QImage::Format_RGB16);
131}
132
133
134static bool opengl32dll = false;
135
136bool QGLFormat::hasOpenGLOverlays()
137{
138 return false; // ###
139}
140
141
142bool QGLContext::chooseContext(const QGLContext* shareContext)
143{
144 Q_D(QGLContext);
145
146 // Validate the device.
147 if (!device())
148 return false;
149 int devType = device()->devType();
150 if (devType != QInternal::Pixmap && devType != QInternal::Image && devType != QInternal::Widget) {
151 qWarning("QGLContext::chooseContext(): Cannot create QGLContext's for paint device type %d", devType);
152 return false;
153 }
154
155 // Get the display and initialize it.
156 d->eglContext = new QEglContext();
157 d->eglContext->setApi(QEgl::OpenGL);
158
159 // Construct the configuration we need for this surface.
160 QEglProperties configProps;
161 qt_egl_add_platform_config(configProps, device());
162 qt_egl_set_format(configProps, devType, d->glFormat);
163 configProps.setRenderableType(QEgl::OpenGL);
164
165 // Search for a matching configuration, reducing the complexity
166 // each time until we get something that matches.
167 if (!d->eglContext->chooseConfig(configProps)) {
168 delete d->eglContext;
169 d->eglContext = 0;
170 return false;
171 }
172
173 // Inform the higher layers about the actual format properties.
174 qt_egl_update_format(*(d->eglContext), d->glFormat);
175
176 // Create a new context for the configuration.
177 if (!d->eglContext->createContext
178 (shareContext ? shareContext->d_func()->eglContext : 0)) {
179 delete d->eglContext;
180 d->eglContext = 0;
181 return false;
182 }
183 d->sharing = d->eglContext->isSharing();
184 if (d->sharing && shareContext)
185 const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
186
187#if defined(EGL_VERSION_1_1)
188 if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
189 eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
190#endif
191
192 // Create the EGL surface to draw into.
193 d->eglSurface = d->eglContext->createSurface(device());
194 if (d->eglSurface == EGL_NO_SURFACE) {
195 delete d->eglContext;
196 d->eglContext = 0;
197 return false;
198 }
199
200 return true;
201
202}
203
204
205
206static bool qLogEq(bool a, bool b)
207{
208 return (((!a) && (!b)) || (a && b));
209}
210
211int QGLContext::choosePixelFormat(void* , HDC )
212{
213
214 return 0;
215}
216
217class QGLCmapPrivate;
218
219class /*Q_EXPORT*/ QGLCmap
220{
221public:
222 enum Flags { Reserved = 0x01 };
223
224 QGLCmap(int maxSize = 256);
225 QGLCmap(const QGLCmap& map);
226 ~QGLCmap();
227
228 QGLCmap& operator=(const QGLCmap& map);
229
230 // isEmpty and/or isNull ?
231 int size() const;
232 int maxSize() const;
233
234 void resize(int newSize);
235
236 int find(QRgb color) const;
237 int findNearest(QRgb color) const;
238 int allocate(QRgb color, uint flags = 0, quint8 context = 0);
239
240 void setEntry(int idx, QRgb color, uint flags = 0, quint8 context = 0);
241
242 const QRgb* colors() const;
243
244private:
245 void detach();
246 QGLCmapPrivate* d;
247};
248
249#endif
250
251
252QGLCmap::QGLCmap(int maxSize) // add a bool prealloc?
253{
254 d = new QGLCmapPrivate;
255 d->maxSize = maxSize;
256}
257
258QGLCmap::QGLCmap(const QGLCmap& map)
259{
260 d = map.d;
261 d->ref();
262}
263
264QGLCmap::~QGLCmap()
265{
266 if (d && d->deref())
267 delete d;
268 d = 0;
269}
270
271QGLCmap& QGLCmap::operator=(const QGLCmap& map)
272{
273 map.d->ref();
274 if (d->deref())
275 delete d;
276 d = map.d;
277 return *this;
278}
279
280int QGLCmap::size() const
281{
282 return d->colorArray.size();
283}
284
285int QGLCmap::maxSize() const
286{
287 return d->maxSize;
288}
289
290void QGLCmap::detach()
291{
292 if (d->count != 1) {
293 d->deref();
294 QGLCmapPrivate* newd = new QGLCmapPrivate;
295 newd->maxSize = d->maxSize;
296 newd->colorArray = d->colorArray;
297 newd->allocArray = d->allocArray;
298 newd->contextArray = d->contextArray;
299 newd->colorArray.detach();
300 newd->allocArray.detach();
301 newd->contextArray.detach();
302 newd->colorMap = d->colorMap;
303 d = newd;
304 }
305}
306
307
308void QGLCmap::resize(int newSize)
309{
310 if (newSize < 0 || newSize > d->maxSize) {
311 qWarning("QGLCmap::resize(): size out of range");
312 return;
313 }
314 int oldSize = size();
315 detach();
316 //if shrinking; remove the lost elems from colorMap
317 d->colorArray.resize(newSize);
318 d->allocArray.resize(newSize);
319 d->contextArray.resize(newSize);
320 if (newSize > oldSize) {
321 memset(d->allocArray.data() + oldSize, 0, newSize - oldSize);
322 memset(d->contextArray.data() + oldSize, 0, newSize - oldSize);
323 }
324}
325
326
327int QGLCmap::find(QRgb color) const
328{
329 QMap<uint,int>::ConstIterator it = d->colorMap.find(color);
330 if (it != d->colorMap.end())
331 return *it;
332 return -1;
333}
334
335
336int QGLCmap::findNearest(QRgb color) const
337{
338 int idx = find(color);
339 if (idx >= 0)
340 return idx;
341 int mapSize = size();
342 int mindist = 200000;
343 int r = qRed(color);
344 int g = qGreen(color);
345 int b = qBlue(color);
346 int rx, gx, bx, dist;
347 for (int i=0; i < mapSize; i++) {
348 if (!(d->allocArray[i] & QGLCmapPrivate::Allocated))
349 continue;
350 QRgb ci = d->colorArray[i];
351 rx = r - qRed(ci);
352 gx = g - qGreen(ci);
353 bx = b - qBlue(ci);
354 dist = rx*rx + gx*gx + bx*bx; // calculate distance
355 if (dist < mindist) { // minimal?
356 mindist = dist;
357 idx = i;
358 }
359 }
360 return idx;
361}
362
363
364// Does not always allocate; returns existing c idx if found
365
366int QGLCmap::allocate(QRgb color, uint flags, quint8 context)
367{
368 int idx = find(color);
369 if (idx >= 0)
370 return idx;
371
372 int mapSize = d->colorArray.size();
373 int newIdx = d->allocArray.indexOf(QGLCmapPrivate::UnAllocated);
374
375 if (newIdx < 0) { // Must allocate more room
376 if (mapSize < d->maxSize) {
377 newIdx = mapSize;
378 mapSize++;
379 resize(mapSize);
380 }
381 else {
382 //# add a bool param that says what to do in case no more room -
383 // fail (-1) or return nearest?
384 return -1;
385 }
386 }
387
388 d->colorArray[newIdx] = color;
389 if (flags & QGLCmap::Reserved) {
390 d->allocArray[newIdx] = QGLCmapPrivate::Reserved;
391 }
392 else {
393 d->allocArray[newIdx] = QGLCmapPrivate::Allocated;
394 d->colorMap.insert(color, newIdx);
395 }
396 d->contextArray[newIdx] = context;
397 return newIdx;
398}
399
400
401void QGLCmap::setEntry(int idx, QRgb color, uint flags, quint8 context)
402{
403 if (idx < 0 || idx >= d->maxSize) {
404 qWarning("QGLCmap::set(): Index out of range");
405 return;
406 }
407 detach();
408 int mapSize = size();
409 if (idx >= mapSize) {
410 mapSize = idx + 1;
411 resize(mapSize);
412 }
413 d->colorArray[idx] = color;
414 if (flags & QGLCmap::Reserved) {
415 d->allocArray[idx] = QGLCmapPrivate::Reserved;
416 }
417 else {
418 d->allocArray[idx] = QGLCmapPrivate::Allocated;
419 d->colorMap.insert(color, idx);
420 }
421 d->contextArray[idx] = context;
422}
423
424
425const QRgb* QGLCmap::colors() const
426{
427 return d->colorArray.data();
428}
429
430
431/*****************************************************************************
432 QGLWidget Win32/WGL-specific code
433 *****************************************************************************/
434
435void QGLWidgetPrivate::init(QGLContext *ctx, const QGLWidget* shareWidget)
436{
437 Q_Q(QGLWidget);
438 olcx = 0;
439 initContext(ctx, shareWidget);
440
441 if (q->isValid() && q->context()->format().hasOverlay()) {
442 olcx = new QGLContext(QGLFormat::defaultOverlayFormat(), q);
443 if (!olcx->create(shareWidget ? shareWidget->overlayContext() : 0)) {
444 delete olcx;
445 olcx = 0;
446 glcx->d_func()->glFormat.setOverlay(false);
447 }
448 } else {
449 olcx = 0;
450 }
451}
452
453/*\internal
454 Store color values in the given colormap.
455*/
456static void qStoreColors(HPALETTE cmap, const QGLColormap & cols)
457{
458 QRgb color;
459 PALETTEENTRY pe;
460
461 for (int i = 0; i < cols.size(); i++) {
462 color = cols.entryRgb(i);
463 pe.peRed = qRed(color);
464 pe.peGreen = qGreen(color);
465 pe.peBlue = qBlue(color);
466 pe.peFlags = 0;
467
468 SetPaletteEntries(cmap, i, 1, &pe);
469 }
470}
471
472void QGLWidgetPrivate::updateColormap()
473{
474 Q_Q(QGLWidget);
475 if (!cmap.handle())
476 return;
477 HDC hdc = GetDC(q->winId());
478 SelectPalette(hdc, (HPALETTE) cmap.handle(), TRUE);
479 qStoreColors((HPALETTE) cmap.handle(), cmap);
480 RealizePalette(hdc);
481 ReleaseDC(q->winId(), hdc);
482}
483
484bool QGLWidget::event(QEvent *e)
485{
486 Q_D(QGLWidget);
487 if (e->type() == QEvent::ParentChange) {
488 setContext(new QGLContext(d->glcx->requestedFormat(), this));
489 // the overlay needs to be recreated as well
490 delete d->olcx;
491 if (isValid() && context()->format().hasOverlay()) {
492 d->olcx = new QGLContext(QGLFormat::defaultOverlayFormat(), this);
493 if (!d->olcx->create(isSharing() ? d->glcx : 0)) {
494 delete d->olcx;
495 d->olcx = 0;
496 d->glcx->d_func()->glFormat.setOverlay(false);
497 }
498 } else {
499 d->olcx = 0;
500 }
501 } else if (e->type() == QEvent::Show && !format().rgba()) {
502 d->updateColormap();
503 }
504
505 return QWidget::event(e);
506}
507
508
509void QGLWidget::resizeEvent(QResizeEvent *)
510{
511 Q_D(QGLWidget);
512 if (!isValid())
513 return;
514 makeCurrent();
515 if (!d->glcx->initialized())
516 glInit();
517 resizeGL(width(), height());
518 if (d->olcx) {
519 makeOverlayCurrent();
520 resizeOverlayGL(width(), height());
521 }
522}
523
524
525const QGLContext* QGLWidget::overlayContext() const
526{
527 return d_func()->olcx;
528}
529
530
531void QGLWidget::makeOverlayCurrent()
532{
533 Q_D(QGLWidget);
534 if (d->olcx) {
535 d->olcx->makeCurrent();
536 if (!d->olcx->initialized()) {
537 initializeOverlayGL();
538 d->olcx->setInitialized(true);
539 }
540 }
541}
542
543
544void QGLWidget::updateOverlayGL()
545{
546 Q_D(QGLWidget);
547 if (d->olcx) {
548 makeOverlayCurrent();
549 paintOverlayGL();
550 if (d->olcx->format().doubleBuffer()) {
551 if (d->autoSwap)
552 d->olcx->swapBuffers();
553 }
554 else {
555 glFlush();
556 }
557 }
558}
559
560void QGLWidget::setContext(QGLContext *context,
561 const QGLContext* shareContext,
562 bool deleteOldContext)
563{
564 Q_D(QGLWidget);
565 if (context == 0) {
566 qWarning("QGLWidget::setContext: Cannot set null context");
567 return;
568 }
569 if (!context->deviceIsPixmap() && context->device() != this) {
570 qWarning("QGLWidget::setContext: Context must refer to this widget");
571 return;
572 }
573
574 if (d->glcx)
575 d->glcx->doneCurrent();
576 QGLContext* oldcx = d->glcx;
577 d->glcx = context;
578
579 bool doShow = false;
580 if (oldcx && oldcx->d_func()->win == winId() && !d->glcx->deviceIsPixmap()) {
581 // We already have a context and must therefore create a new
582 // window since Windows does not permit setting a new OpenGL
583 // context for a window that already has one set.
584 doShow = isVisible();
585 QWidget *pW = static_cast<QWidget *>(parent());
586 QPoint pos = geometry().topLeft();
587 setParent(pW, windowFlags());
588 move(pos);
589 }
590
591 if (!d->glcx->isValid()) {
592 d->glcx->create(shareContext ? shareContext : oldcx);
593 // the above is a trick to keep disp lists etc when a
594 // QGLWidget has been reparented, so remove the sharing
595 // flag if we don't actually have a sharing context.
596 if (!shareContext)
597 d->glcx->d_ptr->sharing = false;
598 }
599
600 if (deleteOldContext)
601 delete oldcx;
602
603 if (doShow)
604 show();
605}
606
607
608void QGLWidgetPrivate::cleanupColormaps()
609{
610 Q_Q(QGLWidget);
611 if (cmap.handle()) {
612 HDC hdc = GetDC(q->winId());
613 SelectPalette(hdc, (HPALETTE) GetStockObject(DEFAULT_PALETTE), FALSE);
614 DeleteObject((HPALETTE) cmap.handle());
615 ReleaseDC(q->winId(), hdc);
616 cmap.setHandle(0);
617 }
618 return;
619}
620
621const QGLColormap & QGLWidget::colormap() const
622{
623 return d_func()->cmap;
624}
625
626void QGLWidget::setColormap(const QGLColormap & c)
627{
628 Q_D(QGLWidget);
629 d->cmap = c;
630
631 if (d->cmap.handle()) { // already have an allocated cmap
632 d->updateColormap();
633 } else {
634 LOGPALETTE *lpal = (LOGPALETTE *) malloc(sizeof(LOGPALETTE)
635 +c.size()*sizeof(PALETTEENTRY));
636 lpal->palVersion = 0x300;
637 lpal->palNumEntries = c.size();
638 d->cmap.setHandle(CreatePalette(lpal));
639 free(lpal);
640 d->updateColormap();
641 }
642}
643
644QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.