diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 189820683..1d31f5f38 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -52,8 +52,8 @@ const int MIN_SUPPORTED_WIDTH = 800; IrrDriver::IrrDriver() { - m_res_switching = false; - m_device = NULL; + m_resolution_changing = RES_CHANGE_NONE; + m_device = NULL; file_manager->dropFileSystem(); initDevice(); } // IrrDriver @@ -317,19 +317,22 @@ void IrrDriver::changeResolution(const int w, const int h, const bool fullscreen UserConfigParams::m_height = h; UserConfigParams::m_fullscreen = fullscreen; - doApplyResSettings(); - - new ConfirmResolutionDialog(); -} + // Setting this flag will trigger a call to applyResolutionSetting() + // in the next update call. This avoids the problem that changeResolution + // is actually called from the gui, i.e. the event loop, i.e. while the + // old device is active - so we can't delete this device (which we must + // do in applyResolutionSettings + m_resolution_changing = RES_CHANGE_YES; +} // changeResolution //----------------------------------------------------------------------------- -void IrrDriver::doApplyResSettings() +void IrrDriver::applyResolutionSettings() { - m_res_switching = true; - - // show black before resolution switch so we don't see OpenGL's buffer garbage during switch - m_device->getVideoDriver()->beginScene(true, true, video::SColor(255,100,101,140)); + // show black before resolution switch so we don't see OpenGL's buffer + // garbage during switch + m_device->getVideoDriver()->beginScene(true, true, + video::SColor(255,100,101,140)); m_device->getVideoDriver()->draw2DRectangle( SColor(255, 0, 0, 0), core::rect(0, 0, UserConfigParams::m_prev_width, @@ -407,8 +410,17 @@ void IrrDriver::cancelResChange() UserConfigParams::m_width = UserConfigParams::m_prev_width; UserConfigParams::m_height = UserConfigParams::m_prev_height; UserConfigParams::m_fullscreen = UserConfigParams::m_prev_fullscreen; - - doApplyResSettings(); + + // This will trigger calling applyResolutionSettings in update(). This is + // necessary to avoid that the old screen is deleted, while it is + // still active (i.e. sending out events which triggered the change + // of resolution // Setting this flag will trigger a call to applyResolutionSetting() + // in the next update call. This avoids the problem that changeResolution + // is actually called from the gui, i.e. the event loop, i.e. while the + // old device is active - so we can't delete this device (which we must + // do in applyResolutionSettings) + m_resolution_changing=RES_CHANGE_CANCEL; + } // cancelResChange // ---------------------------------------------------------------------------- @@ -420,15 +432,15 @@ void IrrDriver::printRenderStats() { io::IAttributes * attr = m_scene_manager->getParameters(); printf("[%ls], FPS:%3d Tri:%.03fm Cull %d/%d nodes (%d,%d,%d)\n", - m_video_driver->getName(), - m_video_driver->getFPS (), - (f32) m_video_driver->getPrimitiveCountDrawn( 0 ) * ( 1.f / 1000000.f ), - attr->getAttributeAsInt ( "culled" ), - attr->getAttributeAsInt ( "calls" ), - attr->getAttributeAsInt ( "drawn_solid" ), - attr->getAttributeAsInt ( "drawn_transparent" ), - attr->getAttributeAsInt ( "drawn_transparent_effect" ) - ); + m_video_driver->getName(), + m_video_driver->getFPS (), + (f32) m_video_driver->getPrimitiveCountDrawn( 0 ) * ( 1.f / 1000000.f ), + attr->getAttributeAsInt ( "culled" ), + attr->getAttributeAsInt ( "calls" ), + attr->getAttributeAsInt ( "drawn_solid" ), + attr->getAttributeAsInt ( "drawn_transparent" ), + attr->getAttributeAsInt ( "drawn_transparent_effect" ) + ); } // printRenderStats @@ -818,16 +830,22 @@ void IrrDriver::displayFPS() */ void IrrDriver::update(float dt) { + // If the resolution should be switched, do it now. This will delete the + // old device and create a new one. + if (m_resolution_changing!=RES_CHANGE_NONE) + { + applyResolutionSettings(); + if(m_resolution_changing==RES_CHANGE_YES) + new ConfirmResolutionDialog(); + m_resolution_changing = RES_CHANGE_NONE; + } + + if (!m_device->run()) { - // FIXME: I have NO idea why, after performing resolution switch, the irrlicht device asks once to be deleted - if (m_res_switching) m_res_switching = false; - else main_loop->abort(); - } - else if (m_res_switching) - { - m_res_switching = false; + main_loop->abort(); } + World *world = World::getWorld(); diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index 4488c7ba3..36769be89 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -60,9 +60,13 @@ private: /** Irrlicht race font. */ irr::gui::IGUIFont *m_race_font; - /** Flag set during resolution switching, so that the game doesn't think it needs - * to exit because no frame is open */ - bool m_res_switching; + /** Flag to indicate if a resolution change is pending (which will be + * acted upon in the next update). None means no change, yes means + * change to new resolution and trigger confirmation dialog. + * Cancel indicates a change of the resolution (back to the original + * one), but no confirmation dialog. */ + enum {RES_CHANGE_NONE, RES_CHANGE_YES, + RES_CHANGE_CANCEL} m_resolution_changing; void setAllMaterialFlags(scene::IAnimatedMesh *mesh) const; std::vector m_modes; @@ -74,7 +78,7 @@ private: bool m_pointer_shown; /** Internal method that applies the resolution in user settings. */ - void doApplyResSettings(); + void applyResolutionSettings(); public: IrrDriver(); @@ -136,7 +140,7 @@ public: /** Call to change resolution */ void changeResolution(const int w, const int h, const bool fullscreen); - /** Call this to roll back to the previous resolution if a resolution switch attempt goes bad */ + /** Call this to roll back to the previous resolution if a resolution switch attempt goes bad */ void cancelResChange(); void showPointer();