src/opengl/qgl_wince.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/opengl/qgl_wince.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,644 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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 <qapplication.h>
+#include <qdesktopwidget>
+
+#include <windows.h>
+
+#include "qegl_p.h"
+#include "qgl_egl_p.h"
+#include "qgl_cl_p.h"
+
+
+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
+**
+****************************************************************************/
+
+#ifndef QGLCMAP_H
+#define QGLCMAP_H
+
+#include <qcolor.h>
+
+
+
+
+/*****************************************************************************
+  QGLFormat Win32/WGL-specific code
+ *****************************************************************************/
+
+void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device)
+{
+    int devType = device->devType();
+    if (devType == QInternal::Image)
+        props.setPixelFormat(static_cast<QImage *>(device)->format());
+    else
+        props.setPixelFormat(QImage::Format_RGB16);
+}
+
+
+static bool opengl32dll = false;
+
+bool QGLFormat::hasOpenGLOverlays()
+{
+    return false; // ###
+}
+
+
+bool QGLContext::chooseContext(const QGLContext* shareContext)
+{
+        Q_D(QGLContext);
+
+    // Validate the device.
+    if (!device())
+        return false;
+    int devType = device()->devType();
+    if (devType != QInternal::Pixmap && devType != QInternal::Image && devType != QInternal::Widget) {
+        qWarning("QGLContext::chooseContext(): Cannot create QGLContext's for paint device type %d", devType);
+        return false;
+    }
+
+    // Get the display and initialize it.
+    d->eglContext = new QEglContext();
+    d->eglContext->setApi(QEgl::OpenGL);
+    if (!d->eglContext->openDisplay(device())) {
+        delete d->eglContext;
+        d->eglContext = 0;
+        return false;
+    }
+
+    // Construct the configuration we need for this surface.
+    QEglProperties configProps;
+    qt_egl_add_platform_config(configProps, device());
+    qt_egl_set_format(configProps, devType, d->glFormat);
+    configProps.setRenderableType(QEgl::OpenGL);
+
+    // Search for a matching configuration, reducing the complexity
+    // each time until we get something that matches.
+    if (!d->eglContext->chooseConfig(configProps)) {
+        delete d->eglContext;
+        d->eglContext = 0;
+        return false;
+    }
+
+    // Inform the higher layers about the actual format properties.
+    qt_egl_update_format(*(d->eglContext), d->glFormat);
+
+    // Create a new context for the configuration.
+    if (!d->eglContext->createContext
+            (shareContext ? shareContext->d_func()->eglContext : 0)) {
+        delete d->eglContext;
+        d->eglContext = 0;
+        return false;
+    }
+
+#if defined(EGL_VERSION_1_1)
+    if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
+        eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
+#endif
+
+    // Create the EGL surface to draw into.
+    d->eglSurface = d->eglContext->createSurface(device());
+    if (d->eglSurface == EGL_NO_SURFACE) {
+        delete d->eglContext;
+        d->eglContext = 0;
+        return false;
+    }
+
+    return true;
+
+}
+
+
+
+static bool qLogEq(bool a, bool b)
+{
+    return (((!a) && (!b)) || (a && b));
+}
+
+int QGLContext::choosePixelFormat(void* , HDC )
+{
+
+    return 0;
+}
+
+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;
+};
+
+#endif
+
+
+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();
+}
+
+
+/*****************************************************************************
+  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);
+}
+
+bool QGLWidget::event(QEvent *e)
+{
+    Q_D(QGLWidget);
+    if (e->type() == QEvent::ParentChange) {
+        setContext(new QGLContext(d->glcx->requestedFormat(), this));
+        // the overlay needs to be recreated as well
+        delete d->olcx;
+        if (isValid() && context()->format().hasOverlay()) {
+            d->olcx = new QGLContext(QGLFormat::defaultOverlayFormat(), this);
+            if (!d->olcx->create(isSharing() ? d->glcx : 0)) {
+                delete d->olcx;
+                d->olcx = 0;
+                d->glcx->d_func()->glFormat.setOverlay(false);
+            }
+        } else {
+            d->olcx = 0;
+        }
+    } else if (e->type() == QEvent::Show && !format().rgba()) {
+        d->updateColormap();
+    }
+
+    return QWidget::event(e);
+}
+
+
+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()) {
+        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 (!shareContext)
+            d->glcx->d_ptr->sharing = false;
+    }
+
+    if (deleteOldContext)
+        delete oldcx;
+
+    if (doShow)
+        show();
+}
+
+
+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();
+    }
+}
+
+void QGLExtensions::init()
+{
+    static bool init_done = false;
+
+    if (init_done)
+        return;
+    init_done = true;
+
+    // We need a context current to initialize the extensions.
+    QGLWidget tmpWidget;
+    tmpWidget.makeCurrent();
+
+    init_extensions();
+
+    tmpWidget.doneCurrent();
+}
+
+QT_END_NAMESPACE