View Single Post
bbns's Avatar
Posts: 101 | Thanked: 129 times | Joined on Oct 2009 @ Los Angeles, CA
#1
Hi all,

I found N900 has been the most amazing game design device so far, yet not many people tell you how to do it. I try to give a start for people who are interested in how to blend QML and OpenGL together.

My background is software architecture and game engine. I have written game engine on iPhone but now I found N900 is easier and have more varieties to achieve the same goal, especially with the help of QML.

If you don't know what QML is, you can visit the Qt4.6 Kinetic online document here.

Now, let's take a look how to write a OpenGL program in Qt and also use QML as UI like this (it's a simple camera application powered by OpenGL).

To write a OpenGL program, we can simply use QGLWidget. However, since we want to blend with QML, directly using QGLWidget is not a good option. Instead, we want to use QGraphicsScene, that's the the fundamental element for Qt rendering objects. Note that QGraphicsScene does not discriminate OpenGL or non-OpenGL. It's decided by QPaintEngine, which later on we will use QGraphicsView to tell Qt to use OpenGL as backend.

In my first introduction of QML, I used QmlView to load QML. Although QmlView allows you to load QML quickly and easily; however, it will intercept all touch events even you click on non-interactive area. Thus, you will not be able to interact with your OpenGL content (for instance, circle a group of soldiers on the field). In this case, we will use QmlEngine directly (QmlView's backend). One more benefit, it's also faster because we just reduce a layer of wrapping.

Enough of talking, let see some code then you will know how it works in nature.

Code:
#include <QtGui>
#include <QtOpenGL>
#include <QtDeclarative>

class MyGraphicsScene: public QGraphicsScene {
public:
  MyGraphicsScene()
  {
     // load your QML before drawBackground being called.
     QmlEngine *engine = new QmlEngine();
     QmlComponent component(engine, QUrl::fromLocalFile(qmlfilename));
     QGraphicsObject *object = qobject_cast<QGraphicsObject*>(component.create());

     addItem(object);
     // done! that's all.
  }
  void drawBackground(QPainter *painter, const QRectF &)
  {
      if (painter->paintEngine()->type() != QPaintEngine::OpenGL) {
          qWarning("OpenGLScene: drawBackground needs a QGLWidget to be set as viewport on the graphics view");
            return;
      }
      // beginning of OpenGL instructions
      glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

      // end of OpenGL instructions
      QTimer::singleShot(20, this, SLOT(update()));
   }
}
That's it. It's simpler than my first though.

Now, we want to trigger our QGraphicsScene class in main.cpp:

Code:
#include "mygraphicsscene.h"

#include <QtGui>
#include <QGLWidget>
class GraphicsView : public QGraphicsView
{
    public:
        GraphicsView()
        {
            setWindowTitle(tr("Hello QML and OpenGL"));
        }
    
    protected:
        void resizeEvent(QResizeEvent *event) {
            if (scene())
                scene()->setSceneRect(
                    QRect(QPoint(0, 0), event->size()));
            QGraphicsView::resizeEvent(event);
        }
};

int main(int argc, char **argv)
{
        QApplication app(argc, argv);
    
        GraphicsView view;
        QGLFormat format = QGLFormat::defaultFormat();
        // disable AA.
        format.setSampleBuffers(false); 
        view.setViewport(new QGLWidget(QGLFormat(format)));
        view.setViewportUpdateMode(
                QGraphicsView::FullViewportUpdate);
        view.setScene(new MyGraphicsScene);
        view.showFullScreen();
        view.show();
        return app.exec();
}
That's it. You shall be able to see your QML UI overlay works perfectly with OpenGL content. The background is default to what you have been drawn within drawBackground. There are a few guideline regarding performance:
1. Try to avoid non-opaque UI (i.e. alpha blending). It hurts performance also may bring rendering issues (because QML is rendered via pixmap to texture within EGL).
2. Avoid complex animation. It's not necessary to bring nice user experience as well.
3. Solid and linear gradient color on UI element is acceptable. But more than that, you might witness performance being hurt badly.
4. Clutter your OpenGL instruction together as much as possible.

If you are a game developer, you will be happy to see how QML help you avoid complex UI design! The only thing you need is focus on your OpenGL content (i.e. the 3D graphics itself). If you just want to write a 2D or pseudo-3D game, it's even easier. All you need is QML itself. See Samegame demo.

Last edited by bbns; 2010-01-10 at 03:50.
 

The Following 19 Users Say Thank You to bbns For This Useful Post: