[SOLVED] Qt + Ogre on X

Problems building or running the engine, queries about how to use features etc.
Post Reply
Sussch
Gnoblar
Posts: 14
Joined: Mon Jan 04, 2010 6:49 pm

[SOLVED] Qt + Ogre on X

Post by Sussch » Wed Jan 26, 2011 7:22 pm

Hi,

A few questions popped up while trying to get Qt + Ogre Byatis integration working in Ubuntu 10.04 LTS.

Why is using externalWindowHandle deprecated?
In Windows, it works fine with parentWindowHandle, but in linux, it simply crashes with the following exception:

Code: Select all

OGRE EXCEPTION(3:RenderingAPIException): Invalid parentWindowHandle (wrong server or screen) in GLXWindow::create at ../ogre/RenderSystems/GL/src/GLX/OgreGLXWindow.cpp (line 236)
externalWindowHandle seems to be working fine.

The following might be more of a Qt-related question though:
In most of the examples of Qt Ogre widget on the net, winId() of the rendering widget is added to the handle string for externalWindowHandle / parentWindowHandle. My rendering window is simply promoted from the central QWidget in the main window, but whenever I try to create an Ogre render window with its winId (passed as externalWindowHandle), it crashes with the following exception:

Code: Select all

OGRE EXCEPTION(3:RenderingAPIException): Invalid externalWindowHandle (wrong server or screen) in GLXWindow::create at ../ogre/RenderSystems/GL/src/GLX/OgreGLXWindow.cpp (line 249)
However, when I pass the winId of the application's main window as externalWindowHandle, it works. Well, there's the problem that the main window is rendered full of gibberish (parts of the image that is rendered in the rendering window).

I noticed that in Linux nothing is rendered if Ogre rendering window hasn't been set visible. In Windows, it works well even without this.

For some reason, most of the Qt Ogre widget examples on the web get the window ID of Ogre rendering window via "WINDOW" attribute. Even though both "WINDOW" and "GLXWINDOW" are supposed to work, only "GLXWINDOW" actually seems to work on my ubuntu.

There is actually another problem - Ogre viewport seems to be offset, but I think that's probably a portability issue with the resize event or something.

Anyway, here's the code I'm using for initializing Qt Ogre widget:

Code: Select all

    Ogre::NameValuePairList params;
    QWidget *q_parent = dynamic_cast <QWidget *> ( parent() );

#ifdef Q_WS_X11
    // Get the parameters of the window QT created
    QX11Info info = x11Info();
    Ogre::String winHandle;
    winHandle  = Ogre::StringConverter::toString((unsigned long)(info.display()));
    winHandle += ":";
    winHandle += Ogre::StringConverter::toString((unsigned int)(info.screen()));
    winHandle += ":";

    if (q_parent)
        winHandle += Ogre::StringConverter::toString( (unsigned long) q_parent->winId() );
//! \note Crashes
//        winHandle += Ogre::StringConverter::toString( (unsigned long) winId() );

    winHandle += ":";
    winHandle += Ogre::StringConverter::toString((unsigned long) XVisualIDFromVisual( (Visual *) info.visual() ) );
//! \note The following is not supposed to work, but for some reason it does
//    winHandle += Ogre::StringConverter::toString((unsigned long) info.visual() );

    params["externalWindowHandle"] = winHandle;
//! \note Crashes
//    params["parentWindowHandle"] = winHandle;
#endif
#ifdef _WIN32
    if (q_parent)
        params["parentWindowHandle"] = Ogre::StringConverter::toString( ( unsigned long ) q_parent->winId() );
    else
        params["parentWindowHandle"] = Ogre::StringConverter::toString( ( unsigned long ) GetDesktopWindow );
#endif

    // Create Ogre render window
    m_window = m_root->createRenderWindow( "Render window",
                           this->width(),
                           this->height(),
                           false,
                           &params );

    //! \note Only needed on Linux for some reason
    m_window->setVisible( true );

#ifdef Q_WS_X11
	WId window_id;

    //! \note "WINDOW" doesn't work here for some unknown reason
    m_window->getCustomAttribute( "GLXWINDOW", &window_id );

    assert( window_id );

	// Take over the ogre created window.
	QWidget::create( window_id );

    // Activate the window
    m_window->setActive( true );
    m_window->resize(width(), height());
#endif
#ifdef _WIN32
	WId window_id;

    //! \note "HWND" causes mousePressEvent not to be called - "WINDOW" should be used instead
    m_window->getCustomAttribute( "WINDOW", &window_id );

	// Take over the ogre created window.
	QWidget::create( window_id );
#endif

    // Resize the widget and Ogre render window
    resizeEvent( NULL );

    setAttribute( Qt::WA_PaintOnScreen );
    setAttribute( Qt::WA_NoSystemBackground );
    setAttribute( Qt::WA_NoBackground );
    setAttribute( Qt::WA_NativeWindow );
I hope this post doesn't seem like a whining after weeks of wall-banging due to portability issues. Perhaps some of it might be useful for other people with similar problems.

If anyone has an idea or two of what might be wrong here, I would appreciate it.

Thanks
0 x

Sussch
Gnoblar
Posts: 14
Joined: Mon Jan 04, 2010 6:49 pm

Re: [SOLVED] Qt + Ogre on X

Post by Sussch » Thu Jan 27, 2011 1:30 pm

Nice, got it working :D.

It turned out that what I thought was resize problem, was actually a problem with the visual.
Also, when I commented out the setting of visual parameter, it no longer crashed with parentWindowHandle.

Furthermore, without setting the visual parameter, "WINDOW" works better than "GLXWINDOW" for the same
reason that "WINDOW" works better than "HWND" in windows. With "WINDOW", mouse events are correctly
propagated down to the render window from its parent.

Haven't re-tested it in windows now, but the following code seems to be working like a charm in linux:

Code: Select all

void RenderWindow::init_window() {
    Ogre::NameValuePairList params;
    QWidget *q_parent = dynamic_cast <QWidget *> ( parent() );

#ifdef Q_WS_X11
    // Get the parameters of the window QT created
    QX11Info info = x11Info();
    Ogre::String winHandle;
    winHandle  = Ogre::StringConverter::toString((unsigned long)(info.display()));
    winHandle += ":";
    winHandle += Ogre::StringConverter::toString((unsigned int)(info.screen()));
    winHandle += ":";

    assert( q_parent );

    winHandle += Ogre::StringConverter::toString( (unsigned long) q_parent->winId() );

    params["parentWindowHandle"] = winHandle;
#endif
#ifdef _WIN32
    if (q_parent)
        params["parentWindowHandle"] = Ogre::StringConverter::toString( ( unsigned long ) q_parent->winId() );
    else
        params["parentWindowHandle"] = Ogre::StringConverter::toString( ( unsigned long ) GetDesktopWindow );
#endif

    // Create Ogre render window
    m_window = m_root->createRenderWindow( "Render window",
                           this->width(),
                           this->height(),
                           false,
                           &params );

    m_window->setActive( true );
    m_window->resize(width(), height());
    m_window->setVisible( true );

    // Get the ID of Ogre render window
	WId window_id;
    m_window->getCustomAttribute( "WINDOW", &window_id );
    assert( window_id );

    // Take over the ogre created window.
    QWidget::create( window_id );

    resizeEvent( NULL );

    setAttribute( Qt::WA_PaintOnScreen );
/*    setAttribute( Qt::WA_NoSystemBackground );
    setAttribute( Qt::WA_NoBackground );
    setAttribute( Qt::WA_NativeWindow );*/
    setAttribute( Qt::WA_OpaquePaintEvent );
}
And here are the paint, resize and update event handlers just for reference:

Code: Select all

void RenderWindow::paintEvent( QPaintEvent *p_event ) {
    resizeEvent( NULL );

    update();
}

void RenderWindow::resizeEvent( QResizeEvent *p_event ) {
    if (p_event)
        QWidget::resizeEvent( p_event );

    if (m_window) {
	    m_window->reposition( x(), y() );
	    m_window->resize( width(), height() );
	    m_window->windowMovedOrResized();
    }
}

// Called by a timer
void RenderWindow::update() {
    QWidget::update();

    if (m_root)
        m_root->renderOneFrame();
}
Well, it throws a few X Errors when closing the program though:

Code: Select all

X Error: RenderBadPicture (invalid Picture parameter) 163
  Extension:    154 (RENDER)
  Minor opcode: 7 (RenderFreePicture)
  Resource id:  0xa400015
X Error: BadWindow (invalid Window parameter) 3
  Major opcode: 4 (X_DestroyWindow)
  Resource id:  0xaa00002
Thanks
0 x

dermont
Orc Shaman
Posts: 781
Joined: Thu Dec 09, 2004 2:51 am
x 9

Re: [SOLVED] Qt + Ogre on X

Post by dermont » Thu Jan 27, 2011 1:51 pm

Sussch wrote:Nice, got it working :D.

It turned out that what I thought was resize problem, was actually a problem with the visual.
Also, when I commented out the setting of visual parameter, it no longer crashed with parentWindowHandle.

Furthermore, without setting the visual parameter, "WINDOW" works better than "GLXWINDOW" for the same
reason that "WINDOW" works better than "HWND" in windows. With "WINDOW", mouse events are correctly
propagated down to the render window from its parent.

Haven't re-tested it in windows now, but the following code seems to be working like a charm in linux:

Code: Select all

void RenderWindow::init_window() {
    Ogre::NameValuePairList params;
    QWidget *q_parent = dynamic_cast <QWidget *> ( parent() );

#ifdef Q_WS_X11
    // Get the parameters of the window QT created
    QX11Info info = x11Info();
    Ogre::String winHandle;
    winHandle  = Ogre::StringConverter::toString((unsigned long)(info.display()));
    winHandle += ":";
    winHandle += Ogre::StringConverter::toString((unsigned int)(info.screen()));
    winHandle += ":";

    assert( q_parent );

    winHandle += Ogre::StringConverter::toString( (unsigned long) q_parent->winId() );

    params["parentWindowHandle"] = winHandle;
#endif
#ifdef _WIN32
    if (q_parent)
        params["parentWindowHandle"] = Ogre::StringConverter::toString( ( unsigned long ) q_parent->winId() );
    else
        params["parentWindowHandle"] = Ogre::StringConverter::toString( ( unsigned long ) GetDesktopWindow );
#endif

    // Create Ogre render window
    m_window = m_root->createRenderWindow( "Render window",
                           this->width(),
                           this->height(),
                           false,
                           &params );

    m_window->setActive( true );
    m_window->resize(width(), height());
    m_window->setVisible( true );

    // Get the ID of Ogre render window
	WId window_id;
    m_window->getCustomAttribute( "WINDOW", &window_id );
    assert( window_id );

    // Take over the ogre created window.
    QWidget::create( window_id );

    resizeEvent( NULL );

    setAttribute( Qt::WA_PaintOnScreen );
/*    setAttribute( Qt::WA_NoSystemBackground );
    setAttribute( Qt::WA_NoBackground );
    setAttribute( Qt::WA_NativeWindow );*/
    setAttribute( Qt::WA_OpaquePaintEvent );
}
And here are the paint, resize and update event handlers just for reference:

Code: Select all

void RenderWindow::paintEvent( QPaintEvent *p_event ) {
    resizeEvent( NULL );

    update();
}

void RenderWindow::resizeEvent( QResizeEvent *p_event ) {
    if (p_event)
        QWidget::resizeEvent( p_event );

    if (m_window) {
	    m_window->reposition( x(), y() );
	    m_window->resize( width(), height() );
	    m_window->windowMovedOrResized();
    }
}

// Called by a timer
void RenderWindow::update() {
    QWidget::update();

    if (m_root)
        m_root->renderOneFrame();
}
Well, it throws a few X Errors when closing the program though:

Code: Select all

X Error: RenderBadPicture (invalid Picture parameter) 163
  Extension:    154 (RENDER)
  Minor opcode: 7 (RenderFreePicture)
  Resource id:  0xa400015
X Error: BadWindow (invalid Window parameter) 3
  Major opcode: 4 (X_DestroyWindow)
  Resource id:  0xaa00002
Thanks
I think that you may be making this it a bit more complex than you need to, you can create the render window in showEvent (you need the flush) or the paint event.

Code: Select all

void OgreWidget::showEvent(QShowEvent *e)
{
    // either here or in the paint event   
    if(!m_window)
    {
	    QApplication::flush();
        //XFlush(QX11Info::display());
        init_window();
    }
    QWidget::showEvent(e);
}
and in init_window no need to take over the ogre created window, just use external window handle:

Code: Select all

   
    Ogre::NameValuePairList params;
    params["externalWindowHandle"] = Ogre::StringConverter::toString((unsigned long)winId());
    m_window = Ogre::Root::getSingletonPtr()->createRenderWindow("My Test Window",     width(), height(), false, &params);
Edit:
Also you can do a search through the forums, there are numerous examples of using Qt and Ogre.
0 x

Sussch
Gnoblar
Posts: 14
Joined: Mon Jan 04, 2010 6:49 pm

Re: [SOLVED] Qt + Ogre on X

Post by Sussch » Thu Jan 27, 2011 2:56 pm

Thanks for the answer.

There are a few problems though.
  • I can't use winId(), because it causes the aforementioned exception. I can, however, use the winId() of the parent.
  • When I use the winId() of the parent widget and don't take over the Ogre created window, then nothing is displayed.
Thanks, I have already looked through all google entries mentioning Qt and Ogre.
The problem was that none of them seemed to solve my problems.
0 x

Post Reply