Rendering QT widgets in Ogre

Problems building or running the engine, queries about how to use features etc.
User avatar
sirbabyface
Gnoblar
Posts: 14
Joined: Mon Aug 18, 2008 4:02 pm
Location: Coimbra, Portugal
Contact:

Post by sirbabyface »

I've tried the new version and it did work out of the box. So no need to rename the DLL.

I've NVidia Quadro 1600M, and it did look a bit slow, but I got the window perfect. No white part on the screen.

I'm using Vista.
--
Tiago Correia
Slan
Halfling
Posts: 49
Joined: Wed Jun 09, 2004 11:13 pm

Post by Slan »

PolyVox wrote:...
@slan - So did you try it? Did it work?
...
Yes, I decided to rebuild it (with Ogre trunk and my existing Qt4 build) because I couldn't see the embedded window. It appeared after I patched the code :wink:

I noticed the glitch reported by triton too on XP only. FPS are fine on XP / Geforce 6600 but very low on Vista / Geforce 7800.
User avatar
PolyVox
OGRE Contributor
OGRE Contributor
Posts: 1316
Joined: Tue Nov 21, 2006 11:28 am
Location: Groningen, The Netherlands
x 18
Contact:

Post by PolyVox »

Ok, thanks guys, but I'm definitely doing something wrong :? However, I have noticed that the speed is directly proportional to the size of the transparent window. This suggests that the bottleneck is not the context switching (which would be constant time). Actually, I suspect that for some reason the rendered image is being read back from the GPU and the compositing being done in software.

If this is the case, it may be because I'm doing the drawing in QGraphicsView::drawBackground() rather than QGraphicsScene::drawBackground() (as was done in the TrollTech labs example). I may be clutching at straws here but I'll try and give it a go...

Also, I have downloaded the trial of gDebugger but have no idea how to use it. But give it some time and it might tell me what is going on :)
pmax
Gnoblar
Posts: 16
Joined: Sun Aug 17, 2008 8:29 pm

Post by pmax »

@PolyVox Actually, it's 3c: Use Qt's OpenGL API (QGLWidget, etc) directly to create the GL context used by Ogre later. This way, the RenderWindow instance you get back from either Root::initialise() or Root::createRenderWindow() is already a QGLWidget, so you cast it and use it like any other widget. No need to wrap it again to make it Qt compatible.

This is also its biggest advantage: No need to switch GL contexts between Qt and Ogre as they use the same one. You just have to make sure access is serialized, but that should be no problem as long as you only call update() from the main Qt thread.

I'm actually very close to be able to show some pictures with my approach. There is only one problem with unloading the plugins which crashes the program. The lifecycle of GLSupport inside GLRenderSystem is quite complicated, well, at least not very suited for outside management. I'm thinking of letting GLRenderSystem deal with this explicitly such that the GLSupport is instantiated and destroyed at the appropriate time.

I'll report back when I'm done.
pmax
Gnoblar
Posts: 16
Joined: Sun Aug 17, 2008 8:29 pm

Re: Rendering QT widgets in Ogre

Post by pmax »

Quick update. Better late than never, right?

So, I ran into many problems, that's why I abandoned this project shortly after the last message. Turns out, the OpenGL paint engine of Qt expects to own the opengl context. No news there, of course. But so does Ogre. They both mess up each others opengl state. Pushing/popping the complete opengl state before and after doing either update (on RenderWindow or the QGLWidget) helps a little, but of course causes drawing problems on either the Ogre or Qt side.

Also, there is currently no way to replace the GLRenderSystem (or whatever it's called, I forget) in a plugin. Such intrusive changes just to get some small results in Qt aren't worth it, in my opinion. Better use established ways to embed Ogre RenderWindows in Qt widgets.

I had an idea to implement something that works much like the QGraphicsView and renders QWidgets (or maybe even QGraphicsItems in general) into QPixmaps (which can easily be converted to QImages, which in turn are easy to use as Ogre::Textures). I hoped it would be possible to catch events that tell the widget to move (i.e. through mouse drags) and translate that into simple x/y translations in Ogre. However, the problem here is that QWidget explicitly knows about QGraphicsViews it might be displayed in so that QWidget can let the QGraphicsViews when it changed. This is of course horrible design by the Qt people, but understandable, since it's internal. But this means that this "OgreGraphicsView" wouldn't know when to redraw a QWidget's (or QGraphicsItem's) texture. Unless, somehow, it would inherit from QGraphicsView. But I haven't tried any of this out yet.

So, in closing, this particular project, albeit immensely interesting and cool, is done for me. For now, the best alternative is http://www.ogre3d.org/forums/viewtopic.php?f=11&t=45709.
User avatar
PolyVox
OGRE Contributor
OGRE Contributor
Posts: 1316
Joined: Tue Nov 21, 2006 11:28 am
Location: Groningen, The Netherlands
x 18
Contact:

Re: Rendering QT widgets in Ogre

Post by PolyVox »

Well, you had more perseverance than me :-) But I'm still wondering whether it's possible to utilise features introduced in Qt 4.5. In particular, there are now several different render systems which can be used to draw widgets, including an OpenGL one. Maybe it's possible to write one built on Ogre instead of OpenGL?
Marseyeah
Gnoblar
Posts: 8
Joined: Sat Jul 25, 2009 10:05 pm
Location: Oslo, Norway

Re: Rendering QT widgets in Ogre

Post by Marseyeah »

Hi guys,

From what I have seen on the forums, a lot of people is struggling to get Ogre working in a QGraphicsView. I have been working lately on that subject and after trying several approaches, I managed to obtain a pretty decent result with Qt 4.5. I thought I could share it with you :wink:

First off, here's an example screenshot, all three overlay elements are Qt widgets or QGraphicsItems:
Image

This approach is based on using two separates openGL contexts, one for Qt and one for Ogre; and make sure each will always use his own.
The key principles are the following:
  • - Subclass QGLWidget and disable automatic buffer swapping ( setAutoBufferSwap(false) )
  • - Create Ogre render window using "externalWindowHandle" and "externalGLControl" but not "externalGLContext". This way Ogre will use the widget as his paint device but will have his own context.
  • - Just after creating the render window, save the Ogre context using wglGetCurrentContext (or glXGetCurrentContext for Linux)
  • - Then the trick is to use the appropriate context for Ogre and Qt. You can restore Qt's context using QGLWidget::makeCurrent().
    As for Ogre you can create a function like this one that will restore the previously saved context:

Code: Select all

void makeOgreCurrent() 
{ 
	HPALETTE hpal = QColormap::hPal();
	if (hpal) {
		SelectPalette(winDC, hpal, FALSE);
		RealizePalette(winDC);
	}
	if ( ogreContext != wglGetCurrentContext() )
	{
		wglMakeCurrent(winDC,ogreContext); 
	}		
};
  • - Then make sure the widget is properly updated overloading paintGL() function like this:

Code: Select all

void QOgreWidget::paintGL()
{
    makeOgreCurrent(); // Make ogre context current
    Ogre::WindowEventUtilities::messagePump();
    ogreRoot->renderOneFrame(); // Render Ogre
    makeCurrent(); // Make Qt context current and let QGLWidget draw on top.
    QGLWidget::paintGL();
}
  • - Subclass QGraphicsScene, overload drawBackground() and just call QOgreWidget::paintGL() in it.
  • - Set up your QGraphicsView setting the QOgreWidget as the viewport (make sure the graphicsView is also the parent widget of the ogreWidget), and the previously created QGraphicsScene as the scene
  • - Then on your main loop, call update() then swapBuffers() on your Ogre widget (swapBuffers is required here since we disabled autoBufferSwap)
  • - Finally, and probably the most important, you have to make sure Ogre will always use his own context. Indeed, even if we made the Ogre context current before calling renderOneFrame(), Ogre can call GL functions outside of if. For example, this can happen when you load for the first time a mesh; and you can't be sure the current context will be the Ogre one at that precise moment. So just call "makeOgreCurrent" each time your code is likely to send GL commands. If you don't do this, it can lead to unpredictable results such as widgets disappearing, perf slowing down and recurring crashes.
As for the performance part of this approach, it doesn't seem to have a significant impact. I tested it on two radically different computers (Vista/Core2Duo/NVidia8800GTX and XP/Atom/Intel865GMA) and FPS was around 60 on both machines.

That's all! I hope it will help. If you need further explanations just ask me :)
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Rendering QT widgets in Ogre

Post by nullsquared »

This is all interesting... However, what I'm looking for is to render Qt stuff to a render texture. Any ideas? I don't want Qt rendering directly to the window (which is a Qt window, which I also don't want).
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: Rendering QT widgets in Ogre

Post by jacmoe »

Nullsquared - what you want is interesting and all that..
However, what Marseyeah just posted is highly interesting. :)
A lot of people have asked lately just how on Earth do you allow both Ogre and QT to grab the GL context.
Pretty clever technique.
I am definitely going to bookmark this. :)
Thanks Marseyeah.
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Rendering QT widgets in Ogre

Post by nullsquared »

jacmoe wrote:Nullsquared - what you want is interesting and all that..
However, what Marseyeah just posted is highly interesting. :)
No doubt, of course it is. But my interest comes from this image from the 4.4 changelist:
Image
Marseyeah
Gnoblar
Posts: 8
Joined: Sat Jul 25, 2009 10:05 pm
Location: Oslo, Norway

Re: Rendering QT widgets in Ogre

Post by Marseyeah »

You're welcome Jacmoe :)

Nullsquared, you can try with QPixmap::grabWidget() then convert it to a QImage and finally save it in a file or a buffer for using it as a texture in ogre. But I doubt this technique would be efficient...
The example you showed is a classic use of QGraphicsView/QGraphicsScene, widgets are rendered using QGraphicsScene capabilities (transformation, rotation, etc.). There is no texture in it. If your interest is to do the same thing with Ogre, well I guess the only solution is to use grabWidget().
User avatar
milliams
Gremlin
Posts: 172
Joined: Fri Feb 16, 2007 1:47 am
Location: Portsmouth, UK
Contact:

Re: Rendering QT widgets in Ogre

Post by milliams »

Well QPixmaps are saved as a simple pixmap in video memory (usually) so would it not be possible to grab that raw data somehow and render it to a texture in an OGRE scene. This way it would avoid having to copy it between video and main memory too much.

The QPixmap of a widget is available via QPixmap QPixmap::grabWidget(QWidget* widget, ...) and maybe something like ExternalTextureSource at the OGRE end?

This is obviously vastly oversimplifying but do you reckon this method is even slightly feasible?

Of course this doesn't take into account any sort of interaction.

The other solution is to 'port' Qt to OGRE, creating a OGRE front-end much like there are currently Windows, X11, MacOS and S60 front-ends (obviously this would be a fair amount of work :)).
User avatar
PolyVox
OGRE Contributor
OGRE Contributor
Posts: 1316
Joined: Tue Nov 21, 2006 11:28 am
Location: Groningen, The Netherlands
x 18
Contact:

Re: Rendering QT widgets in Ogre

Post by PolyVox »

Hey, that's some great work!
Marseyeah wrote:This approach is based on using two separates openGL contexts, one for Qt and one for Ogre; and make sure each will always use his own.
I think I did try someting similar to this (I remember reading about makeCurrent(), wglGetCurrentContext(), etc) but I didn't get it working as well as you appear to have. So well done :-) But I do have some questions:

1) What happens if you want to use the Direct3D render system? I assume you can't overlay an OpenGL context over a Direct3D window?
2) Besides performance, what is the advantage of rendering the QtWidget into the OpenGL context? I mean, could you just use 'regular' Qt drawing to draw the over the top of the Ogre scene? I did play around with this but I forget what the results were (I tried to many things!). I seems to recall this works but you only get transparency on Vista, but I notice you are running that anyway.

But seriously, well done. I know this stuff is hard work!
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Rendering QT widgets in Ogre

Post by nullsquared »

milliams wrote: This is obviously vastly oversimplifying but do you reckon this method is even slightly feasible?
Genius! I think we have a start here!

Image

Code: Select all

    QApplication app(argc, argv); // it NEEDS an application object :/

    QPushButton quit("testing");

    quit.resize(128, 64);
    quit.setFont(QFont("Times", 18, QFont::Bold));

    /* render via the corona image library, totally unrelated to Qt */
It's not even Ogre, I know :lol: . But I think this just might work! Work shall be continued after the watching of a comedy film :mrgreen:

Edit:
This time, it's not an offline image, but rather a real-time image in SDL!
Image
Ohhhh yeaahhh, a nice, big ... completely useless button :D Time to figure out how to hack input in there.

Edit:
The button is now CLICKABLE!!! :mrgreen: :mrgreen:

Edit:
And ... it is unclickable again! Adding it to a parent widget broke it :|
Image
Marseyeah
Gnoblar
Posts: 8
Joined: Sat Jul 25, 2009 10:05 pm
Location: Oslo, Norway

Re: Rendering QT widgets in Ogre

Post by Marseyeah »

Thanks Polyvox,
PolyVox wrote: 1) What happens if you want to use the Direct3D render system? I assume you can't overlay an OpenGL context over a Direct3D window?
I guess not, of course Direct3D is not an option for this approach. But anyway I think one of the advantages of using both Qt and Ogre is to have a portable application, Direct3D is not :wink:
PolyVox wrote: 2) Besides performance, what is the advantage of rendering the QtWidget into the OpenGL context? I mean, could you just use 'regular' Qt drawing to draw the over the top of the Ogre scene? I did play around with this but I forget what the results were (I tried to many things!). I seems to recall this works but you only get transparency on Vista, but I notice you are running that anyway.
Well the main purpose is to use the full range of benefits provided by the QGraphicsView framework, that is having a fully embedded GUI in a single 3D window while benefiting of transparency. Besides, the QGraphicsScene allow you to have a three-dimensional GUI (like the example posted by Nullsquared).
Finally the purpose of this approach in my specific case, is to use a SVG file as my GUI. That SVG would embed Javascript code used to trigger events associated to each button or anything else. This kind of thing is really easy to do with QtSVG and QtScript frameworks and allow you to make quickly a really nice GUI that is furthermore easily upgradeable or customizable.
dermont
Bugbear
Posts: 812
Joined: Thu Dec 09, 2004 2:51 am
x 42

Re: Rendering QT widgets in Ogre

Post by dermont »

Marseyeah wrote:Hi guys,

From what I have seen on the forums, a lot of people is struggling to get Ogre working in a QGraphicsView. I have been working lately on that subject and after trying several approaches, I managed to obtain a pretty decent result with Qt 4.5. I thought I could share it with you :wink:
...
This approach is based on using two separates openGL contexts, one for Qt and one for Ogre; and make sure each will always use his own...
I think the problem that most people are having with Ogre and a QGraphicsView is sharing an "externalGLContext". The approach of using two separates openGL contexts is fairly easy to implement and was suggested by Waywocket a couple of years back. There's even a code example from Waywocket using this approach:

http://www.ogre3d.org/forums/viewtopic.php?f=2&t=33065
http://www.qtcentre.org/forum/f-qt-prog ... -7337.html

Maybe you could elaborate on what's new in your approach?
Marseyeah
Gnoblar
Posts: 8
Joined: Sat Jul 25, 2009 10:05 pm
Location: Oslo, Norway

Re: Rendering QT widgets in Ogre

Post by Marseyeah »

Oh I didn't read that one... it could have saved me some time :?
Well from what I saw it's basically the same concept, except that I implemented it on Windows instead of Linux. Everything else looks the same!
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Rendering QT widgets in Ogre

Post by nullsquared »

Image

Certainly getting somewhere :mrgreen: (not a real texture, it's an SDL_Surface - but the same concept applies).

Mouse events seem to be half-working, now I'm trying to figure out how Qt wants keyboard events to work properly :|

Edit:
Question: how do I get the "currently active" Qt widget? I want to find which widget the user is "currently interacting" with...

Anyways:
Image
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Rendering QT widgets in Ogre

Post by nullsquared »

Image

This is getting interesting...

I fixed the "active widget" problem via my own active widget tracking (this seems to be necessary since I'm not using a Qt app or Qt input).
pmax
Gnoblar
Posts: 16
Joined: Sun Aug 17, 2008 8:29 pm

Re: Rendering QT widgets in Ogre

Post by pmax »

In the end, the cleanest solution would be to implement a custom QPaintEngine / QPaintDevice, see
http://doc.trolltech.com/4.5/paintsyste ... int-device

This is the same that Qt people have done with the QGLWidget. The good thing is this can be completely transparent to Qt. All QPainter calls just go through your new QPaintEngine instead. My idea was to use Bekas' Ogre/Cairo integration to do much of the vector things Qt requires on the GPU:
http://www.ogre3d.org/forums/viewtopic. ... 37&start=0

Many of the obvious optimizations, like not redrawing the widget if it hasn't changed, will be hard to do though. Some widget might be very expensive to redraw, so some caching must be done. Maybe this can be solved with a clever vertex/pixel shader, but I have no idea how to do that.

Looking forward to your new developments! Cheers!
User avatar
PolyVox
OGRE Contributor
OGRE Contributor
Posts: 1316
Joined: Tue Nov 21, 2006 11:28 am
Location: Groningen, The Netherlands
x 18
Contact:

Re: Rendering QT widgets in Ogre

Post by PolyVox »

@nullsquared - looks like your making good progress!
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Rendering QT widgets in Ogre

Post by nullsquared »

PolyVox wrote:@nullsquared - looks like your making good progress!
Now with a quit button that actually works:
Image
Courtesy of: http://www.ogre3d.org/forums/viewtopic. ... 25#p350267

The most annoying part is translating all of the events properly and sending them properly on the Qt side. Also, right now I'm simply memcpy'ing the pixmap. This has a linear performance loss with a higher resolution, so I might have to go the custom QPaintEngine route.
machado
Gnoblar
Posts: 7
Joined: Mon Mar 02, 2009 4:46 pm
Location: Coimbra, Portugal

Re: Rendering QT widgets in Ogre

Post by machado »

Hi!

Marseyeah, the Ogre in Qt windows lokes pretty grate.
I tried to implement it, following your instructions, but I only get a white window.

I'm posting my test project classes.
teste.zip
(3.04 KiB) Downloaded 208 times
Can someone take a look and see what I'm doing wrong?

Thanks.
____________
Nuno Machado
Marseyeah
Gnoblar
Posts: 8
Joined: Sat Jul 25, 2009 10:05 pm
Location: Oslo, Norway

Re: Rendering QT widgets in Ogre

Post by Marseyeah »

Hi,

Machado, the problem with your code is that initializeGL() from your QOgreGLWidget is never called. Indeed, this function is usually called the first time updateGL() is invoked.
So in your main.cpp, just call updateGL() on your widget after its creation and it should be fine.
You will also need to subclass QGraphicsView in order to redirect events to your widget, such as resizeEvent. This way your ogre viewport will stretch with the window each time you resize it.
machado
Gnoblar
Posts: 7
Joined: Mon Mar 02, 2009 4:46 pm
Location: Coimbra, Portugal

Re: Rendering QT widgets in Ogre

Post by machado »

Hi!

Thanks Marseyeah, after calling updateGL() the ogre scene appears, but small.
So I subclassed QGraphicsView resize event:

Code: Select all

void QOgreGraphicsView::resizeEvent( QResizeEvent *event )
{
	QOgreGLWidget* qOgreGL = (QOgreGLWidget*)viewport();
	QSize size = event->size();
	qOgreGL->resizeGL( size.width(), size.height() );
}
The result was a black window :( .
____________
Nuno Machado
Post Reply