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