Qt Quick 2 integration

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
0xDEADC0DE
Posts: 3
Joined: Mon Jun 17, 2013 7:53 pm

Qt Quick 2 integration

Post by 0xDEADC0DE »

Hello.

I'm trying to use Irrlicht with Qt5 and QML. I've found this great tutorial: http://irrlicht.sourceforge.net/forum/v ... 0ae73bcfda. The problem is Qt5 has different OpenGL architecture and widgets are obsolete now.

I've started with openglunderqml tutorial from Qt examples and added the code from aforementioned tutorial and Irrlicht hello world. Everything works well except Sydney is all white (texture is loaded succesfully). Also with IrrlichtDevice created program spams console with something like "QWindowsGLContext::getProcAddress: Unable to resolve 'glDeleteShader'" on exit. I think the are two causes of these problems: 1) I don't know how to save OpenGL state properly; 2) Irrlicht initialization screws Qt's funtion resolving up.

Considering first cause: I've found some code on the net which saves matrices, attributes and unbinds shaders/buffers, but I don't really know which of this is required. There is a warning in Qt docs about Qt Quick Scene Graph: "Warning: When mixing OpenGL content with scene graph rendering, it is important the application does not leave the OpenGL context in a state with buffers bound, attributes enabled, special values in the z-buffer or stencil-buffer or similar. Doing so can result in unpredictable behavior." I'm quite new to OpenGL and I'm confused about that "or similar", moreover I don't know how exactly Irrlicht changes OpenGL state.

About second cause: I don't have any good idea how to fix this.

There is a way to integrate custom 3D engine with QML using frame buffer, similar to this http://irrlicht.sourceforge.net/forum/v ... hp?t=43556, but I don't want to use it because it's more cumbersome and produces some overhead.

Here is final code (I've trimmed some irrelevant comments and code from the original example):

Code: Select all

 
// squircle.cpp
#include "squircle.h"
 
#include <QtQuick/qquickwindow.h>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFunctions>
 
Squircle::Squircle()
    : m_program(0)
    , m_t(0)
    , m_thread_t(0)
{
 
    connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(handleWindowChanged(QQuickWindow*)));
}
 
Squircle::~Squircle()
{
    if(m_device)
       {
           m_device->closeDevice();
           m_device->drop();
       }
}
 
void Squircle::setT(qreal t)
{
    if (t == m_t)
        return;
    m_t = t;
    emit tChanged();
    if (window())
        window()->update();
}
 
void Squircle::handleWindowChanged(QQuickWindow *win)
{
    if (win) {
        // Connect the beforeRendering signal to our paint function.
        // Since this call is executed on the rendering thread it must be
        // a Qt::DirectConnection
        connect(win, SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection);
        connect(win, SIGNAL(beforeSynchronizing()), this, SLOT(sync()), Qt::DirectConnection);
 
        // If we allow QML to do the clearing, they would clear what we paint
        // and nothing would show.
        win->setClearBeforeRendering(false);
 
        // Set all the device creation parameters
        SIrrlichtCreationParameters params;
        params.AntiAlias = 0;
        params.Bits = 32;
        params.DeviceType = EIDT_WIN32;
        params.Doublebuffer = true;
        params.DriverType = video::EDT_OPENGL;
        params.EventReceiver = 0;
        params.Fullscreen = false;
        params.HighPrecisionFPU = false;
        params.IgnoreInput = false;
        params.LoggingLevel = ELL_INFORMATION;
        params.Stencilbuffer = false;
        params.Stereobuffer = false;
        params.Vsync = true;
        // Specify which window/widget to render to
        params.WindowId = reinterpret_cast<void*>(win->winId());
        params.WindowSize.Width = win->width();
        params.WindowSize.Height = win->height();
        params.WithAlphaChannel = true;
        params.ZBufferBits = 16;
 
        // Create the Irrlicht Device with the previously specified parameters
        m_device = createDeviceEx(params);
        if (!m_device) {
            qCritical("m_device DAMN!");
        }
        m_driver = m_device->getVideoDriver();
        m_smgr = m_device->getSceneManager();
        m_mesh = m_smgr->getMesh("sydney.md2");
        if (!m_mesh)
        {
            m_device->drop();
            qCritical("m_mesh DAMN!");
        }
        m_node = m_smgr->addAnimatedMeshSceneNode( m_mesh );
        if (m_node)
        {
            m_node->setMaterialFlag(EMF_LIGHTING, false);
            m_node->setMD2Animation(scene::EMAT_STAND);
            ITexture *texture = m_driver->getTexture("sydney.bmp");
            if (!texture) qCritical("texture DAMN!");
            m_node->setMaterialTexture( 0,  texture);
        }
        m_smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));
    }
}
 
void Squircle::paint()
{
    if(m_device != 0)
        {
        m_device->getTimer()->tick();
        // PushRenderState (found on the net)
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glPushAttrib(GL_ALL_ATTRIB_BITS);
        QOpenGLContext *m_qtContext = QOpenGLContext::currentContext();
        m_qtContext->functions()->glUseProgram(0);
 
        m_driver->beginScene(true, false, SColor(255,100,101,140));
        m_smgr->drawAll();
        //    m_driver->endScene(); <- this line causes flicker because of conflicting calls to glSwapBuffers or something
 
        // PopRender State (found on the net)
        QOpenGLContext *ctx = QOpenGLContext::currentContext();
        ctx->functions()->glBindBuffer(GL_ARRAY_BUFFER, 0);
        ctx->functions()->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        ctx->functions()->glBindRenderbuffer(GL_RENDERBUFFER, 0);
        ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
        glPopAttrib();
    }
}
 
void Squircle::cleanup()
{
    if (m_program) {
        delete m_program;
        m_program = 0;
    }
}
 
void Squircle::sync()
{
    m_thread_t = m_t;
}
 
I'm working with Qt 5.1.0 beta (compiled for MSVC2010 and native OpenGL) and Irrlicht 1.8 under win7.
0xDEADC0DE
Posts: 3
Joined: Mon Jun 17, 2013 7:53 pm

Re: Qt Quick 2 integration

Post by 0xDEADC0DE »

Bump. No one tried to use Irrlicht with Qt 5? Or doesn't even have some generic advices?
WLGfx
Posts: 9
Joined: Fri Nov 23, 2012 12:56 am

Re: Qt Quick 2 integration

Post by WLGfx »

I'm about to have a go with Qt5 and Irrlicht so I'll be keeping an eye on this thread in case I end up having issues. The built in GUI just hasn't got everything I'm after.
0xDEADC0DE
Posts: 3
Joined: Mon Jun 17, 2013 7:53 pm

Re: Qt Quick 2 integration

Post by 0xDEADC0DE »

OK. I've been reading a lot of material about OpenGL programming lately and leaned something. Looks like the texturing problem exists because of Irrlicht isn't compatible with programmable pipeline and when I call

Code: Select all

m_qtContext->functions()->glUseProgram(0);
I just disable emulated shader program that Irrlicht depens on. So I have new questions. How can I extract/reimplement the shaders need for Irrlicht rendering at the random point of program execution? How can I manually unbind Qt Scenegraph's generated shaders to get clean context? I've heard about Irrlicht 2.0, which is designed with modern hardware in mind. Is it at any point usable by now and if so, how can I get it? Thanks in advance.
P.S.: To make it clear: Qt 5 uses OpenGL/ES compatible context by default to render everything.
Post Reply