MyGUI and Ogre3D Resolution Change Problem

magestick

25-10-2010 07:59:23

Hi

We recently discovered an issue with MyGUI and Ogre3D. We decided to share our workaround here, seeing how somebody else might run into the same problem.

http://www.magestick.com/devblog/programming/63-mygui-and-ogre3d-resolution-change-problem.html
We have been playing with MyGUI on Ogre3D for few weeks, and the result has been very satisfying. MyGUI team did such an excellent job at creating very simple but effective GUI library for Ogre3D. Big Kudos to them!

However, we’ve ran into a problem this week, which did cost us a few hours of debugging and hair pulling. To save other developers time, efforts and hair count, we’ve decided to share the information on the source of problem and our "glorious" hackery workaround.

Our software versions:

* Ogre3D: 1.7.1
* MyGUI: 3.0.1

The Problem:

When an Ogre app switches from full-screen to windowed mode while changing resolution at the same time, MyGUI’s drawing area, or viewport, isn’t updated to new resolution.

Investigation:

* MyGUI
o MyGUI’s OgreRenderManager properly listens to windowResized event.
o In windowResized() function, it reads Ogre render window’s viewport dimension and updates mViewSize with it. mViewSize is essentially the drawing area for MyGUI.
o However, when the above problem happens, it’s getting old viewport dimension from Ogre.
* OgreD3D9RenderWindow
o in setFullscreen() method, whenever switching between fullscreen and windowed mode happens, it sets mSwitchingFullscreen to true.
o Later, this flag is read by _beingupdate() method, which is called when frame is being rendered, and if the flag is set, it calls _finishSwitchingFullScreen() method internally.
o Finally, _finishSwitchingFullscreen() updates all the viewport dimensions.
* Where things are broken
o When switching from full-screen to windowed mode, the viewport dimension of Ogre Render Window is not updated in windowResized event chain.
o Instead, it’s updated way later when the frame starts.
o However, MyGUI’s OgreRenderManager assumes that by the time its windowResized event is being called, Ogre’s render window has the correct dimension info for the viewports. :(

Our workaround:

* The proper way of hading this might be calling another event after a render target’s viewport dimension is updated. But we did not want to change anything in either Ogre or MyGUI.
* After reading through MyGUI’s source code for a bit, we found that OgreRenderManager::setActiveViewport() calls windowResized() function manually, thus invokes the recalculation of MyGUI viewport dimension.
* So we simply call this function once a frame is rendered after fullscreen-to-windowed switching happens. (The render window has to be updated at least once to get proper viewport dimension)

This workaround code in our project looks like this:

OptionsHandler.cpp (where user can choose new resolution and full-screen toggle)

if ( fullscreenChanged || inWindowMode )
{
mGameStateManager->setUpdateGUIResolutionOnNextFrame( true );
}

GameStateManager.cpp (where we are calling OgreRoot::RenderOneFrame())

Ogre::Root::getSingleton().renderOneFrame();
// GLORIOUS HACKERY WORKAROUND
//
// Mygui uses viewport for size, but when fullscreen-to-window
// switch happens, D3D RenderWindow’s viewport doesn't
// get updated until renderOneFrame() is called. So this here
// will force MyGUI to resize itself by setting the viewport again
if ( getUpdateGUIResolutionOnNextFrame() )
{
size_t activeViewport = mGUIRenderManager->getActiveViewport();
mGUIRenderManager->setActiveViewport( activeViewport );
setUpdateGUIResolutionOnNextFrame( false );
}

That’s it. Hopefully, this issue will be addressed by super smart programmers from either Ogre3D team or MyGUI team in the future. :D

my.name

27-10-2010 23:55:57

we try fix it

my.name

28-10-2010 01:11:51

try

if (Ogre::Root::getSingletonPtr()->getAutoCreatedWindow()->isFullScreen())
{
Ogre::Root::getSingletonPtr()->getAutoCreatedWindow()->setFullscreen(false, 1024, 768);
}
else
{
Ogre::Root::getSingletonPtr()->getAutoCreatedWindow()->setFullscreen(true, 1024, 768);
Ogre::Root::getSingletonPtr()->getAutoCreatedWindow()->getViewport(0)->_updateDimensions();
MyGUI::OgreRenderManager::getInstance().setActiveViewport(0);
}

Altren

04-11-2010 13:19:36

Fixed in Ogre 1.7.2.

magestick

04-11-2010 15:41:15

That is rad.. Thanks guys (both from Ogre and MyGUI)
:D