Home · All Classes · Main Classes · Grouped Classes · Modules · Functions

qscreenahigl_qws.cpp Example File
qtopiacore/ahigl/qscreenahigl_qws.cpp

 /****************************************************************************
 **
 ** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.
 **
 ** This file is part of the example classes of the Qt Toolkit.
 **
 ** This file may be used under the terms of the GNU General Public
 ** License version 2.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 GNU
 ** General Public Licensing requirements will be met:
 ** http://www.trolltech.com/products/qt/opensource.html
 **
 ** If you are unsure which license is appropriate for your use, please
 ** review the following information:
 ** http://www.trolltech.com/products/qt/licensing.html or contact the
 ** sales department at sales@trolltech.com.
 **
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 **
 ****************************************************************************/

 #include "qscreenahigl_qws.h"
 #include "qwindowsurface_ahigl_p.h"

 #include <QWSServer>
 #include <QMap>
 #include <QTimer>
 #include <QTimeLine>

 #include <qwindowsystem_qws.h>
 #include <private/qwindowsurface_qws_p.h>
 #include <private/qtextengine_p.h>

 #include <GLES/egl.h>
 #include <GLES/gl.h>
 #include <math.h>

 const int animationLength = 30;
 const int frameSpan = 20;

 class ShowAnimation : public QTimeLine
 {
 public:
     ShowAnimation(QAhiGLScreenPrivate *screen);
     qreal valueForTime(int msec);
 };

 struct WindowInfo
 {
     WindowInfo() : texture(0), animation(0) {}

     GLuint texture;
     QPointer<ShowAnimation> animation;
 };

 static QMap<QWSWindow*, WindowInfo*> windowMap;

 class QAhiGLScreenPrivate : public QObject
 {
     Q_OBJECT

 public:
     QAhiGLScreenPrivate(QAhiGLScreen *s);

 public slots:
     void windowEvent(QWSWindow *w, QWSServer::WindowEvent e);
     void redrawScreen();

 public:
     QAhiGLScreen *screen;

     EGLContext eglContext;
     EGLDisplay eglDisplay;
     EGLSurface eglSurface;

     QTimer updateTimer;
     bool doEffects;
 };

 ShowAnimation::ShowAnimation(QAhiGLScreenPrivate *screen)
     : QTimeLine(4 * 1000)
 {
     setUpdateInterval(frameSpan);
     connect(this, SIGNAL(valueChanged(qreal)), screen, SLOT(redrawScreen()));
     connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
     start();
 }

 qreal ShowAnimation::valueForTime(int msec)
 {
     const qreal t = msec / qreal(duration());
     return 3*t*t - 2*t*t*t;
 }

 QAhiGLScreenPrivate::QAhiGLScreenPrivate(QAhiGLScreen *s)
     : screen(s), doEffects(false)
 {
     connect(&updateTimer, SIGNAL(timeout()), this, SLOT(redrawScreen()));
 }

 void QAhiGLScreenPrivate::windowEvent(QWSWindow *window,
                                       QWSServer::WindowEvent event)
 {
     switch (event) {
     case QWSServer::Create:
         windowMap[window] = new WindowInfo;
         break;
     case QWSServer::Show:
         if (doEffects)
             windowMap[window]->animation = new ShowAnimation(this);
         break;
     case QWSServer::Destroy:
         delete windowMap[window];
         windowMap.remove(window);
         break;
     default:
         break;
     }
 }

 void QAhiGLScreenPrivate::redrawScreen()
 {
     updateTimer.stop();
     screen->redrawScreen();
 }

 QAhiGLScreen::QAhiGLScreen(int displayId) : QGLScreen(displayId)
 {
     d_ptr = new QAhiGLScreenPrivate(this);
     d_ptr->eglDisplay = EGL_NO_DISPLAY;
     d_ptr->eglSurface = EGL_NO_SURFACE;
 }

 QAhiGLScreen::~QAhiGLScreen()
 {
     delete d_ptr;
 }

 bool QAhiGLScreen::connect(const QString &displaySpec)
 {
     // Hardcoded values for this device
     w = 480;
     h = 640;
     dw = w;
     dh = h;
     d = 16;

     const int dpi = 120;
     physWidth = qRound(dw * 25.4 / dpi);
     physHeight = qRound(dh * 25.4 / dpi);

     if (displaySpec.section(':', 1, 1).contains("effects"))
         d_ptr->doEffects = true;

     return true;
 }

 bool QAhiGLScreen::initDevice()
 {
     EGLint version, subversion;
     EGLint attrs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
                        EGL_STENCIL_SIZE, 8, EGL_DEPTH_SIZE, 16,
                        EGL_NONE };
     EGLint numConfig;
     EGLConfig eglConfig;

     d_ptr->eglDisplay = eglGetDisplay(0);
     if (d_ptr->eglDisplay == EGL_NO_DISPLAY) {
         qCritical("QAhiGLScreen::initDevice(): eglGetDisplay failed: 0x%x",
                   eglGetError());
         return false;
     }

     if (!eglInitialize(d_ptr->eglDisplay, &version, &subversion)) {
         qCritical("QAhiGLScreen::initDevice(): eglInitialize failed: 0x%x",
                   eglGetError());
         return false;
     }

     if (!eglChooseConfig(d_ptr->eglDisplay, attrs, &eglConfig, 1, &numConfig)) {
         qCritical("QAhiGLScreen::initDevice(): eglChooseConfig failed: 0x%x",
                   eglGetError());
         return false;
     }

     static DummyScreen win = { w, h };
     d_ptr->eglSurface = eglCreateWindowSurface(d_ptr->eglDisplay, eglConfig,
                                                &win, 0);
     if (d_ptr->eglSurface == EGL_NO_SURFACE) {
         qCritical("QAhiGLScreen::initDevice(): eglCreateWindowSurface failed: 0x%x",
                   eglGetError());
         return false;
     }

     d_ptr->eglContext = eglCreateContext(d_ptr->eglDisplay, eglConfig,
                                          EGL_NO_CONTEXT, 0);
     if (d_ptr->eglContext == EGL_NO_CONTEXT) {
         qCritical("QAhiGLScreen::initDevice(): eglCreateContext failed: 0x%x",
                   eglGetError());
         return false;
     }

     if (!eglMakeCurrent(d_ptr->eglDisplay, d_ptr->eglSurface, d_ptr->eglSurface, d_ptr->eglContext)) {
         qCritical("QAhiGLScreen::initDevice(): eglMakeCurrent failed: 0x%x",
                   eglGetError());
         return false;
     }

     d_ptr->connect(QWSServer::instance(),
                    SIGNAL(windowEvent(QWSWindow*, QWSServer::WindowEvent)),
                    SLOT(windowEvent(QWSWindow*, QWSServer::WindowEvent)));
     QScreenCursor::initSoftwareCursor();

     return true;
 }

 void QAhiGLScreen::shutdownDevice()
 {
     eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE,
                    EGL_NO_SURFACE, EGL_NO_CONTEXT);
     eglDestroyContext(d_ptr->eglDisplay, d_ptr->eglContext);
     eglDestroySurface(d_ptr->eglDisplay, d_ptr->eglSurface);
     eglTerminate(d_ptr->eglDisplay);
 }

 void QAhiGLScreen::disconnect()
 {
 }

 inline static uint nextPowerOfTwo(uint v)
 {
     v--;
     v |= v >> 1;
     v |= v >> 2;
     v |= v >> 4;
     v |= v >> 8;
     v |= v >> 16;
     ++v;
     return v;
 }

 static GLuint createTexture(const QImage &img)
 {
     if (img.isNull())
         return 0;

     int width = img.width();
     int height = img.height();
     int textureWidth;
     int textureHeight;
     GLuint texture;

     glGenTextures(1, &texture);
     textureWidth = nextPowerOfTwo(width);
     textureHeight = nextPowerOfTwo(height);
     glBindTexture(GL_TEXTURE_2D, texture);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

     switch (img.format()) {
     case QImage::Format_RGB16:
         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
                      textureWidth,
                      textureHeight, 0,
                      GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);

         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
                         GL_RGB, GL_UNSIGNED_SHORT_5_6_5, img.bits());
         break;

     case QImage::Format_ARGB32_Premultiplied:
     case QImage::Format_ARGB32:
     case QImage::Format_RGB32:
         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                      textureWidth,
                      textureHeight, 0,
                      GL_RGBA, GL_UNSIGNED_BYTE, 0);
         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
                         GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
         break;

     default:
         break;
     }

     return texture;
 }

 static void drawQuad_helper(GLshort *coords, GLfloat *texCoords)
 {
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
     glEnableClientState(GL_VERTEX_ARRAY);
     glVertexPointer(2, GL_SHORT, 0, coords);
     glEnable(GL_TEXTURE_2D);
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
     glDisable(GL_TEXTURE_2D);
     glDisableClientState(GL_VERTEX_ARRAY);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 }

 static void drawQuad_helper(GLshort *coords, GLfloat *texCoords,
                             int arraySize, int numArrays)
 {
     glEnable(GL_TEXTURE_2D);
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
     glEnableClientState(GL_VERTEX_ARRAY);
     glVertexPointer(2, GL_SHORT, 0, coords);

     for (int i = 0; i < numArrays-1; ++i)
         glDrawArrays(GL_TRIANGLE_STRIP, i*arraySize, arraySize);
     glDisableClientState(GL_VERTEX_ARRAY);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     glDisable(GL_TEXTURE_2D);
 }

 static void setRectCoords(GLshort *coords, QRect rect)
 {
     coords[0] = GLshort(rect.left());
     coords[1] = GLshort(rect.top());

     coords[2] = GLshort(rect.right());
     coords[3] = GLshort(rect.top());

     coords[4] = GLshort(rect.right());
     coords[5] = GLshort(rect.bottom());

     coords[6] = GLshort(rect.left());
     coords[7] = GLshort(rect.bottom());
 }

 void QAhiGLScreen::drawQuad(const QRect &textureGeometry,
                             const QRect &subGeometry,
                             const QRect &screenGeometry)
 {
     qreal textureWidth = qreal(nextPowerOfTwo(textureGeometry.width()));
     qreal textureHeight = qreal(nextPowerOfTwo(textureGeometry.height()));

     GLshort coords[8];
     setRectCoords(coords, screenGeometry);

     GLfloat texcoords[8];
     texcoords[0] = (subGeometry.left() - textureGeometry.left()) / textureWidth;
     texcoords[1] = (subGeometry.top() - textureGeometry.top()) / textureHeight;

     texcoords[2] = (subGeometry.right() - textureGeometry.left()) / textureWidth;
     texcoords[3] = (subGeometry.top() - textureGeometry.top()) / textureHeight;

     texcoords[4] = (subGeometry.right() - textureGeometry.left()) / textureWidth;
     texcoords[5] = (subGeometry.bottom() - textureGeometry.top()) / textureHeight;

     texcoords[6] = (subGeometry.left() - textureGeometry.left()) / textureWidth;
     texcoords[7] = (subGeometry.bottom() - textureGeometry.top()) / textureHeight;

     drawQuad_helper(coords, texcoords);
 }

 static qreal mySin(QFixed radians)
 {
     const QFixed twoPI = QFixed::fromReal(2*M_PI);

     const int tableSize = 40;
     static int *table = 0;

     if (!table) {
         table = new int[tableSize];
         for (int i = 0; i < tableSize; ++i) {
             table[i] = qRound(sin(M_PI*(i*360.0/40.0)/180.0) * 16776960.0);
         }
     }

     QFixed tableLookup = radians*tableSize/twoPI;
     return table[tableLookup.truncate()%tableSize]/16776960.0;
 }

 static qreal myCos(QFixed radians)
 {
     const int twoPI = qRound(2*M_PI);

     const int tableSize = 40;
     static int *table = 0;

     if (!table) {
         table = new int[tableSize];
         for (int i = 0; i < tableSize; ++i) {
             table[i] = int(cos(M_PI*(i*360.0/40.0)/180.0) * 16776960.0);
         }
     }

     QFixed tableLookup = radians*tableSize/twoPI;
     return table[tableLookup.truncate()%tableSize]/16776960.0;
 }

 // number of grid cells in wavy flag tesselation in x- and y-direction
 const int subdivisions = 10;

 static void setFlagCoords(GLshort *coords, QRectF screenGeometry,
                           int frameNum, qreal progress)
 {
     int coordIndex = 0;
     qreal waveHeight = 30.0*(1.0-progress);
     for (int j = 0; j < subdivisions-1; ++j) {
         for (int i = 0; i < subdivisions; ++i) {
             qreal c;
             c = screenGeometry.left()
                 + (i * screenGeometry.width() / (subdivisions - 1))
                 + waveHeight * qRound(mySin(QFixed::fromReal(M_PI * 20 * (frameNum + i) / 180.0)))
                 + waveHeight * qRound(myCos(QFixed::fromReal(M_PI * 20 * (frameNum + j) / 180.0)));
             coords[coordIndex++] = qRound(c);
             c = screenGeometry.top()
                 + (j * screenGeometry.height() / (subdivisions - 1))
                 + waveHeight * mySin(QFixed::fromReal(M_PI * 20 * (frameNum + i) / 180.0))
                 + waveHeight * myCos(QFixed::fromReal(M_PI * 20 * (frameNum + j) / 180.0));
             coords[coordIndex++] = qRound(c);
             c = screenGeometry.left() + (i * screenGeometry.width() / (subdivisions - 1))
                 + waveHeight * mySin(QFixed::fromReal(M_PI * 20 * (frameNum + i) / 180.0))
                 + waveHeight * myCos(QFixed::fromReal(M_PI * 20 * (frameNum + (j+1)) / 180.0));
             coords[coordIndex++] = qRound(c);

             c = screenGeometry.top()
                 + ((j + 1) * screenGeometry.height() / (subdivisions - 1))
                 + waveHeight * mySin(QFixed::fromReal(M_PI * 20 * (frameNum + i) / 180.0))
                 + waveHeight * myCos(QFixed::fromReal(M_PI * 20 * (frameNum + (j + 1)) / 180.0));
             coords[coordIndex++] = qRound(c);
         }
     }
 }

 static void setFlagTexCoords(GLfloat *texcoords,
                              const QRectF &subTexGeometry,
                              const QRectF &textureGeometry,
                              int textureWidth, int textureHeight)
 {
     qreal topLeftX = (subTexGeometry.left() - textureGeometry.left())/textureWidth;
     qreal topLeftY = (textureGeometry.height() - (subTexGeometry.top() - textureGeometry.top()))/textureHeight;

     qreal width = (subTexGeometry.right() - textureGeometry.left())/textureWidth - topLeftX;
     qreal height = (textureGeometry.height() - (subTexGeometry.bottom() - textureGeometry.top()))/textureHeight - topLeftY;

     int coordIndex = 0;
     qreal spacing = subdivisions - 1;
     for (int j = 0; j < subdivisions-1; ++j) {
         for (int i = 0; i < subdivisions; ++i) {
             texcoords[coordIndex++] = topLeftX + (i*width) / spacing;
             texcoords[coordIndex++] = topLeftY + (j*height) / spacing;
             texcoords[coordIndex++] = topLeftX + (i*width) / spacing;
             texcoords[coordIndex++] = topLeftY + ((j+1)*height) / spacing;
         }
     }
 }

 void QAhiGLScreen::drawQuadWavyFlag(const QRect &textureGeometry,
                                     const QRect &subTexGeometry,
                                     const QRect &screenGeometry,
                                     qreal progress)
 {
     const int textureWidth = nextPowerOfTwo(textureGeometry.width());
     const int textureHeight = nextPowerOfTwo(textureGeometry.height());

     static int frameNum = 0;

     GLshort coords[subdivisions*subdivisions*2*2];
     setFlagCoords(coords, screenGeometry, frameNum++, progress);

     GLfloat texcoords[subdivisions*subdivisions*2*2];
     setFlagTexCoords(texcoords, subTexGeometry, textureGeometry,
                      textureWidth, textureHeight);

     drawQuad_helper(coords, texcoords, subdivisions*2, subdivisions);
 }

 void QAhiGLScreen::updateTexture(int windowIndex)
 {
     if (windowIndex < 0)
         return;

     QList<QWSWindow*> windows = QWSServer::instance()->clientWindows();
     if (windowIndex > windows.size() - 1)
         return;

     QWSWindow *win = windows.at(windowIndex);
     if (!win)
         return;
     QWSWindowSurface *surface = win->windowSurface();
     if (!surface)
         return;
     const QImage image = surface->image();
     if (image.isNull())
         return;

     WindowInfo *info = windowMap[win];
     if (info->texture != 0)
         glDeleteTextures(1, &info->texture);

     info->texture = createTexture(image);
 }

 void QAhiGLScreen::drawWindow(QWSWindow *win, qreal progress)
 {
     const QRect screenRect = win->allocatedRegion().boundingRect();
     QRect drawRect = screenRect;

     glColor4f(1.0, 1.0, 1.0, progress);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     glEnable(GL_BLEND);

     QWSWindowSurface *surface = win->windowSurface();
     if (!surface)
         return;

     if (progress >= 1.0) {
         if (surface->key() == QLatin1String("ahigl")) {
             drawRect.setCoords(drawRect.left(), drawRect.bottom(),
                                drawRect.right(), drawRect.top());
         }
         drawQuad(win->requestedRegion().boundingRect(), screenRect, drawRect);
         return;
     }

     const int dx = qRound((1 - progress) * drawRect.width() / 2);
     const int dy = qRound((1 - progress) * drawRect.height() / 2);

     drawRect.adjust(dx, dy, -dx, -dy);

     if (surface->key() != QLatin1String("ahigl")) {
         drawRect.setCoords(drawRect.left(), drawRect.bottom(),
                            drawRect.right(), drawRect.top());
     }

     drawQuadWavyFlag(win->requestedRegion().boundingRect(), screenRect,
                      drawRect, progress);
 }

 void QAhiGLScreen::redrawScreen()
 {
     glBindFramebufferOES(GL_FRAMEBUFFER_EXT, 0);
     glMatrixMode(GL_PROJECTION);
     glPushMatrix();
     glMatrixMode(GL_MODELVIEW);
     glPushMatrix();

     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     glOrthof(0, w, h, 0, -999999, 999999);
     glViewport(0, 0, w, h);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();

     // Fill background color

     QColor bgColor = QWSServer::instance()->backgroundBrush().color();
     glClearColor(bgColor.redF(), bgColor.greenF(),
                  bgColor.blueF(), bgColor.alphaF());
     glClear(GL_COLOR_BUFFER_BIT);

     // Draw all windows

     glDisable(GL_CULL_FACE);
     glDisable(GL_DEPTH_TEST);
     glDisable(GL_STENCIL_TEST);
     glEnable(GL_BLEND);
     glBlendFunc(GL_ONE, GL_ZERO);
     glDisable(GL_ALPHA_TEST);
     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

     QList<QWSWindow*> windows = QWSServer::instance()->clientWindows();
     for (int i = windows.size() - 1; i >= 0; --i) {
         QWSWindow *win = windows.at(i);
         QWSWindowSurface *surface = win->windowSurface();
         if (!surface)
             continue;

         WindowInfo *info = windowMap[win];
         GLuint texture = info->texture;
         qreal progress = 1.0;

         if (surface->key() == QLatin1String("ahigl"))
             texture = static_cast<QAhiGLWindowSurface*>(surface)->textureId();
         if (info->animation)
             progress = info->animation->currentValue();

         glBindTexture(GL_TEXTURE_2D, texture);
         drawWindow(win, progress);
         glBindTexture(GL_TEXTURE_2D, 0);
     }

     // Draw cursor

     QScreenCursor *cursor = QScreenCursor::instance();
     if (cursor && !cursor->isAccelerated()) {
         QImage image = cursor->image();

         if (!image.isNull()) {
             glEnable(GL_BLEND);
             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

             image = image.convertToFormat(QImage::Format_ARGB32);
             GLuint tex = createTexture(image);

             drawQuad(cursor->boundingRect(), cursor->boundingRect(),
                      cursor->boundingRect());
             glBindTexture(GL_TEXTURE_2D, 0);
             glEnable(GL_BLEND);
             glBlendFunc(GL_ONE, GL_ZERO);

             glDeleteTextures(1, &tex);
         }
     }

     glPopMatrix();
     glMatrixMode(GL_PROJECTION);
     glPopMatrix();
     glMatrixMode(GL_MODELVIEW);

     eglSwapBuffers(d_ptr->eglDisplay, d_ptr->eglSurface);
 }

 void QAhiGLScreen::exposeRegion(QRegion r, int windowIndex)
 {
     if ((r & region()).isEmpty())
         return;

     updateTexture(windowIndex);

     if (!d_ptr->updateTimer.isActive())
         d_ptr->updateTimer.start(frameSpan);
 }

 QWSWindowSurface* QAhiGLScreen::createSurface(const QString &key) const
 {
     if (key == QLatin1String("ahigl")) {
         return new QAhiGLWindowSurface(d_ptr->eglDisplay, d_ptr->eglSurface,
                                        d_ptr->eglContext);
     }

     return QScreen::createSurface(key);
 }

 QWSWindowSurface* QAhiGLScreen::createSurface(QWidget *widget) const
 {
     if (QApplication::type() == QApplication::GuiServer) {
         if (qobject_cast<QGLWidget*>(widget)) {
             return new QAhiGLWindowSurface(widget, d_ptr->eglDisplay,
                                            d_ptr->eglSurface,
                                            d_ptr->eglContext);
         }

         const QRect rect = widget->frameGeometry();
         if (rect.width() <= 256 && rect.height() <= 256) {
             return new QAhiGLWindowSurface(widget, d_ptr->eglDisplay,
                                            d_ptr->eglSurface,
                                            d_ptr->eglContext);
         }
     }

     return QScreen::createSurface(widget);
 }

 void QAhiGLScreen::setMode(int width, int height, int depth)
 {
     Q_UNUSED(width);
     Q_UNUSED(height);
     Q_UNUSED(depth);
 }

 void QAhiGLScreen::blank(bool on)
 {
     Q_UNUSED(on);
 }

 bool QAhiGLScreen::hasOpenGL()
 {
     return true;
 }

 #include "qscreenahigl_qws.moc"


Copyright © 2007 Trolltech Trademarks
Qt 4.3.0