QT and Ogre
So, during my time off, I've started looking at QT (something I used at Radical a ways back ... when it was at 3.3 or so) and Ogre. True to what I was just recently doing at my last job, I thought I'd give a go at using both for a world editor.
So, I've been used to using wxWidgets for the last couple of years. There's things I like about it (Free, source code included and DialogBlocks is a relatively nice/non-retarded gui builder) and some things I don't like about it (it's free, so there's little support for it, subclassing compound widgets is a royal pain in the tuckas ).
Anyway, what I wanted to start with was a simple window, with a menu, a status bar and a widget that encompassed a render context.
So, I crack open the designer tool and go to work building a simple app. I create a mainwindow gui. This is nice because it comes with a menu, docking toolbar and status bar all ready to go. Then I add a widget (just a simple one) to the main window and then try to get it to fit completely in the layout. This is a nightmare, because I'm used to how Dialogblocks works (you know, in a way that makes sense). Apparently you have to click on the main background and do some fancy 'layout fitting' garbage. Completely non-intuitive. Not a good start, if you ask me.
Anyway, I work a little more, trying to figure out how to use the Designer to create a subclass of a QWidget that would represent my new render window. Not easy, but significantly less tricky than layout.
Now that's done, I start trying to bind Ogre to the window. This is where it all falls apart. Like a lot of these SDKs, the documentation is woefully inadequate. As soon as I get the widget ready to start rendering my window, I get nothing. Until I resize my window. Then I get this god-awful tearing of the widget and the Ogre based render. So, this leads me to believe that I've improperly overridden the paint method of the QWidget class. I dig and I dig and I dig, but everything I read about subclassing widgets tells me that I'm doing the right thing. That is until I read somewhere on a web site that in QT 4+, each widget automatically double buffers. So, somewhere in the deep internals of QT, they have a hidden swap chain that I have no idea how to override. So, after lots and lots of digging, I finally figure out what I need to set as part of the derived objects construction attributes.
So, for a class like so:
#ifndef __RENDERWINDOW_H__ #define __RENDERWINDOW_H__ #includeAnd where RenderContext is a class I've derived for doing the actual binding to Ogre, we need a constructor that looks like this:#include "context.h" QT_BEGIN_NAMESPACE /// ********************************************************************* /// @brief A RenderWindow is a Widget that is used for rendering /// The RenderContext performs our rendering, but this class manages /// all the window level refreshing. /// /// ********************************************************************* class RenderWindow : public QWidget { public: RenderWindow(void); RenderWindow ( QWidget * parent = 0, Qt::WindowFlags f = 0 ); ~RenderWindow(void); virtual void showEvent( QShowEvent * event ); virtual void paintEvent( QPaintEvent * event ); virtual void resizeEvent(QResizeEvent *evt); void Init( void ); void Update( void ); protected: RenderContext m_RenderContext; bool m_WindowInitialized : 1; }; QT_END_NAMESPACE #endif // __RENDERWINDOW_H__
/// ********************************************************************* /// @brief unparameterized Constructor for the Renderwindow /// Note that we have to set the following attributes to disable QT's /// double buffering, which was causing all sorts of flickering /// /// ********************************************************************* RenderWindow::RenderWindow(void) : m_WindowInitialized( false ) { setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_NoSystemBackground); setAutoFillBackground( false ); } /// ********************************************************************* /// @brief Parameterized Constructor for the RenderWindow /// Note that we have to set the following attributes to disable QT's /// double buffering, which was causing all sorts of flickering /// /// @param parent Parent Window /// @param f Additional window creation flags /// ********************************************************************* RenderWindow::RenderWindow( QWidget * parent, Qt::WindowFlags f ): QWidget( parent, f ), m_WindowInitialized( false ) { setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_NoSystemBackground); setAutoFillBackground( false ); }As well, make sure you override the painting method as well:
/// ********************************************************************* /// @brief Handler for the paint event (overridden from the virutal base) /// In this, we're simply calling the RenderWindow's Update Method. /// /// @param event the event to process (which we don't) /// ********************************************************************* void RenderWindow::paintEvent( QPaintEvent * event ) { Update(); } /// ********************************************************************* /// @brief Update our RenderWindow/// We update one frame of the rendercontext /// /// *********************************************************************void RenderWindow::Update( void ) { g_SceneManager->GetSceneRoot()->_fireFrameStarted(); m_RenderContext.Update( ); g_SceneManager->GetSceneRoot()->_fireFrameEnded(); }And that seems to work fine. As I progress more with this, I'll update with new details.
Comments
Thanks for sharing, your post helped me to start my own qt application embedding an ogre widget.
a comment on your implementation though. One of the things I wish to use Qt for is building an interface "around" ogre, with several embedded "ogre views". The way you fire frame started / ended in widget Update() they'll happen again and again for each render window, which isn't exactly what you want (well, I should say "what I want", but suppose you want multiple views as well). So I ended up writing a special method that fires frame start, updates all ogre widgets, then fires frame end. It isn't very flexible, but OK for the current state of my application... Just my two cents.
I should have been a little more clear with my design strategy for for the view. My intent was to have several views, instead of one large viewport that I would break up into several views. Each 'View' would eventually have a reference to an associated scene graph. As I update it more, I'll post this update.
I'm thinking - if I have several panes that show the scene from different angles, then my intention is to see what I'm doing, what I'm changing in the scene, from different angles as I do it... So I intend to have all panes as close to live as possible. Probably you're right though, I don't want "as close as possible" become "constantly updating everything"... I guess I'll have to see how it goes as my application (and scenes I deal with) grow.
Now I want to play with some multipane level editor and try to guess how they handle view updates :-)
I am using ogre 1.6.1 and qt 4.5.1
on visual studio 2008 in windows XP
Can you please tell me where to find a working simple .cpp and .h
to try it ?
Thanks
Lorenzo
Lorenzo