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;
}