From da1d41bf855566a529f983909d564fc97c3aa674 Mon Sep 17 00:00:00 2001 From: Benau Date: Thu, 4 Jun 2020 15:49:34 +0800 Subject: [PATCH] Add resizing of GUIEngine (only works with some screen) --- .../source/Irrlicht/CIrrDeviceSDL.cpp | 5 ++ src/font/font_with_face.cpp | 1 + src/graphics/irr_driver.cpp | 68 +++++++++++++++++-- src/graphics/irr_driver.hpp | 5 +- src/guiengine/abstract_state_manager.cpp | 21 +++++- src/guiengine/abstract_state_manager.hpp | 5 ++ src/guiengine/engine.cpp | 12 ++++ src/guiengine/engine.hpp | 5 ++ src/guiengine/message_queue.cpp | 11 +-- src/guiengine/screen.hpp | 16 ++++- src/guiengine/skin.hpp | 1 + src/main.cpp | 2 + 12 files changed, 139 insertions(+), 13 deletions(-) diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp b/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp index a078c02e3..3b85abd3c 100644 --- a/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp @@ -633,6 +633,11 @@ video::IVideoModeList* CIrrDeviceSDL::getVideoModeList() //! Sets if the window should be resizable in windowed mode. void CIrrDeviceSDL::setResizable(bool resize) { +#if SDL_VERSION_ATLEAST(2, 0, 5) + if (CreationParams.Fullscreen) + return; + SDL_SetWindowResizable(Window, resize ? SDL_TRUE : SDL_FALSE); +#endif } diff --git a/src/font/font_with_face.cpp b/src/font/font_with_face.cpp index e87a8195a..f8705bc3f 100644 --- a/src/font/font_with_face.cpp +++ b/src/font/font_with_face.cpp @@ -82,6 +82,7 @@ FontWithFace::~FontWithFace() */ void FontWithFace::init() { + m_glyph_max_height = 0; setDPI(); #ifndef SERVER_ONLY if (GUIEngine::isNoGraphics()) diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 56bf96956..32b751be8 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -20,7 +20,10 @@ #include "challenges/story_mode_timer.hpp" #include "config/player_manager.hpp" #include "config/user_config.hpp" +#include "font/bold_face.hpp" +#include "font/digit_face.hpp" #include "font/font_manager.hpp" +#include "font/regular_face.hpp" #include "graphics/2dutils.hpp" #include "graphics/b3d_mesh_loader.hpp" #include "graphics/camera.hpp" @@ -54,6 +57,8 @@ #include "guiengine/modaldialog.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" +#include "guiengine/screen_keyboard.hpp" +#include "guiengine/skin.hpp" #include "io/file_manager.hpp" #include "items/item_manager.hpp" #include "items/powerup_manager.hpp" @@ -1982,6 +1987,24 @@ void IrrDriver::doScreenShot() image->drop(); } // doScreenShot +// ---------------------------------------------------------------------------- +void IrrDriver::handleWindowResize() +{ + if (m_actual_screen_size != m_video_driver->getCurrentRenderTargetSize()) + { + // Don't update when dialog is opened + if (GUIEngine::ModalDialog::isADialogActive() || + GUIEngine::ScreenKeyboard::isActive() || + StateManager::get()->getGameState() != GUIEngine::MENU) + return; + + m_actual_screen_size = m_video_driver->getCurrentRenderTargetSize(); + UserConfigParams::m_width = m_actual_screen_size.Width; + UserConfigParams::m_height = m_actual_screen_size.Height; + resizeWindow(); + } +} // handleWindowResize + // ---------------------------------------------------------------------------- /** Update, called once per frame. * \param dt Time since last update @@ -1990,18 +2013,23 @@ void IrrDriver::doScreenShot() */ void IrrDriver::update(float dt, bool is_loading) { + bool show_dialog_yes = m_resolution_changing == RES_CHANGE_YES; + bool show_dialog_warn = m_resolution_changing == RES_CHANGE_YES_WARN; // 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(m_resolution_changing != RES_CHANGE_SAME); - if(m_resolution_changing==RES_CHANGE_YES) - new ConfirmResolutionDialog(false); - else if(m_resolution_changing==RES_CHANGE_YES_WARN) - new ConfirmResolutionDialog(true); m_resolution_changing = RES_CHANGE_NONE; } + handleWindowResize(); + + if (show_dialog_yes) + new ConfirmResolutionDialog(false); + else if (show_dialog_warn) + new ConfirmResolutionDialog(true); + m_wind->update(); PropertyAnimator::get()->update(dt); @@ -2301,3 +2329,35 @@ void IrrDriver::resetDebugModes() SP::sp_debug_view = false; #endif } + +// ---------------------------------------------------------------------------- +void IrrDriver::resizeWindow() +{ + // Reload fonts + font_manager->getFont()->init(); + font_manager->getFont()->init(); + font_manager->getFont()->init(); + // Reload GUIEngine + GUIEngine::reloadForNewSize(); + +#ifdef ENABLE_RECORDER + ogrDestroy(); + RecorderConfig cfg; + cfg.m_triple_buffering = 1; + cfg.m_record_audio = 1; + cfg.m_width = m_actual_screen_size.Width; + cfg.m_height = m_actual_screen_size.Height; + int vf = UserConfigParams::m_video_format; + cfg.m_video_format = (VideoFormat)vf; + cfg.m_audio_format = OGR_AF_VORBIS; + cfg.m_audio_bitrate = UserConfigParams::m_audio_bitrate; + cfg.m_video_bitrate = UserConfigParams::m_video_bitrate; + cfg.m_record_fps = UserConfigParams::m_record_fps; + cfg.m_record_jpg_quality = UserConfigParams::m_recorder_jpg_quality; + if (ogrInitConfig(&cfg) == 0) + { + Log::error("irr_driver", + "RecorderConfig is invalid, use the default one."); + } +#endif +} diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index b6fd72737..ef4ecb623 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -194,7 +194,8 @@ private: /** Used to visualise skeletons. */ std::vector m_debug_meshes; #endif - + // ------------------------------------------------------------------------ + void resizeWindow(); public: void doScreenShot(); public: @@ -534,6 +535,8 @@ public: // ------------------------------------------------------------------------ u32 getDefaultFramebuffer() const { return m_video_driver->getDefaultFramebuffer(); } + // ------------------------------------------------------------------------ + void handleWindowResize(); }; // IrrDriver extern IrrDriver *irr_driver; diff --git a/src/guiengine/abstract_state_manager.cpp b/src/guiengine/abstract_state_manager.cpp index 3cf77ea5d..486681f4d 100644 --- a/src/guiengine/abstract_state_manager.cpp +++ b/src/guiengine/abstract_state_manager.cpp @@ -295,7 +295,8 @@ void AbstractStateManager::resetAndSetStack(Screen* screens[]) assert(!ModalDialog::isADialogActive()); assert(!ScreenKeyboard::isActive()); - if (m_game_mode != GAME) getCurrentScreen()->tearDown(); + if (m_game_mode != GAME && getCurrentScreen()) + getCurrentScreen()->tearDown(); m_menu_stack.clear(); for (int n=0; screens[n] != NULL; n++) @@ -311,3 +312,21 @@ void AbstractStateManager::resetAndSetStack(Screen* screens[]) onTopMostScreenChanged(); } // resetAndSetStack +// ---------------------------------------------------------------------------- + +void AbstractStateManager::onResize() +{ + // Happens in the first resize in main.cpp + if (m_menu_stack.empty()) + return; + + std::vector > screen_function; + for (auto& p : m_menu_stack) + screen_function.push_back(p.second->getNewScreenPointer()); + clearScreenCache(); + std::vector new_screen; + for (auto& screen : screen_function) + new_screen.push_back(screen()); + new_screen.push_back(NULL); + resetAndSetStack(new_screen.data()); +} // onResize diff --git a/src/guiengine/abstract_state_manager.hpp b/src/guiengine/abstract_state_manager.hpp index bc6c41c46..9e2f105a8 100644 --- a/src/guiengine/abstract_state_manager.hpp +++ b/src/guiengine/abstract_state_manager.hpp @@ -110,6 +110,11 @@ namespace GUIEngine */ void resetAndSetStack(Screen* screens[]); + /** + * \brief Called when resizing of stk window + */ + void onResize(); + /** * \brief Used in no graphics STK to enter menu screen (when server is * idle state) diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index a5cea73a4..ecb1c4676 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -1176,6 +1176,18 @@ namespace GUIEngine assert(g_skin->getReferenceCount() == 1); } // reloadSkin + // ----------------------------------------------------------------------- + void reloadForNewSize() + { + g_skin->resetBackgroundImage(); + Private::font_height = g_font->getDimension( L"X" ).Height; + Private::large_font_height = g_large_font->getDimension( L"X" ).Height; + Private::small_font_height = g_small_font->getDimension( L"X" ).Height; + Private::title_font_height = + g_title_font->getDimension( L"X" ).Height; + StateManager::get()->onResize(); + } // reloadForNewSize + // ----------------------------------------------------------------------- void addGUIFunctionBeforeRendering(std::function func) { diff --git a/src/guiengine/engine.hpp b/src/guiengine/engine.hpp index b193e0628..7dbbd514d 100644 --- a/src/guiengine/engine.hpp +++ b/src/guiengine/engine.hpp @@ -257,6 +257,11 @@ namespace GUIEngine */ void reloadSkin(); + /** + * \brief call when screen size changed + */ + void reloadForNewSize(); + /** * \brief Add gui-related function before rendering GUI (from other thread) */ diff --git a/src/guiengine/message_queue.cpp b/src/guiengine/message_queue.cpp index 397cb67aa..20e0bacc4 100644 --- a/src/guiengine/message_queue.cpp +++ b/src/guiengine/message_queue.cpp @@ -102,8 +102,9 @@ protected: /** A pointer to the Container for the Message */ SkinWidgetContainer* m_container; - /** Font used to detect if re-initialization is needed */ + /** Font and screen size used to detect if re-initialization is needed */ gui::IGUIFont* m_font; + core::dimension2du m_screen_size; public: TextMessage(MessageQueue::MessageType mt, const core::stringw &message) : Message(5.0f, message) @@ -135,8 +136,9 @@ public: { const GUIEngine::BoxRenderParams &brp = GUIEngine::getSkin()->getBoxRenderParams(m_render_type); - const unsigned width = irr_driver->getActualScreenSize().Width; - const unsigned height = irr_driver->getActualScreenSize().Height; + m_screen_size = irr_driver->getActualScreenSize(); + const unsigned width = m_screen_size.Width; + const unsigned height = m_screen_size.Height; m_font = GUIEngine::getFont(); m_font->initGlyphLayouts(m_message, m_gls); // Reserve space for 3 lines of text, it will occupy the circle @@ -204,7 +206,8 @@ public: Message::draw(dt); // This happen when GUIEngine is reset (when font size changed for // example) - if (m_font != GUIEngine::getFont()) + if (m_font != GUIEngine::getFont() || + m_screen_size != irr_driver->getActualScreenSize()) init(); int pos_transform = 0; if (m_container == g_container.get()) diff --git a/src/guiengine/screen.hpp b/src/guiengine/screen.hpp index b3bae4c6d..36db2aa28 100644 --- a/src/guiengine/screen.hpp +++ b/src/guiengine/screen.hpp @@ -39,9 +39,10 @@ using namespace irr; #include "guiengine/event_handler.hpp" #include "guiengine/widget.hpp" #include "input/input.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" -#include "utils/leak_check.hpp" +#include /** * \ingroup guiengine @@ -58,7 +59,6 @@ namespace GUIEngine { protected: static SCREEN* singleton; - public: ~ScreenSingleton() @@ -71,12 +71,14 @@ namespace GUIEngine if (singleton == NULL) { singleton = new SCREEN(); + std::function new_screen_function = []() + { return ScreenSingleton::getInstance(); }; + singleton->setScreenPointerFunction(new_screen_function); GUIEngine::addScreenToList(singleton); } return singleton; } - }; template SCREEN* ScreenSingleton::singleton = nullptr; @@ -118,6 +120,8 @@ namespace GUIEngine */ bool m_update_in_background; + /** For runtime screen reloading without template */ + std::function m_screen_func; protected: bool m_throttle_FPS; @@ -137,6 +141,12 @@ namespace GUIEngine PtrVector& append_to, irr::gui::IGUIElement* parent = NULL); + /** Save the function before GUIEngine::clearScreenCache, call it after + * to get the new screen instance pointer + */ + std::function getNewScreenPointer() const { return m_screen_func; } + + void setScreenPointerFunction(const std::function& f) { m_screen_func = f; } Screen(bool pause_race=true); diff --git a/src/guiengine/skin.hpp b/src/guiengine/skin.hpp index b92a00475..7441cee76 100644 --- a/src/guiengine/skin.hpp +++ b/src/guiengine/skin.hpp @@ -334,6 +334,7 @@ namespace GUIEngine ~Skin(); + void resetBackgroundImage() { m_bg_image = NULL; } static video::SColor getColor(const std::string &name); void renderSections(PtrVector* within_vector=NULL); void drawBgImage(); diff --git a/src/main.cpp b/src/main.cpp index 616e96b96..9949f7d83 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2152,6 +2152,8 @@ int main(int argc, char *argv[]) #ifndef SERVER_ONLY if (!GUIEngine::isNoGraphics()) { + // The screen size may change after loading + irr_driver->handleWindowResize(); // Some Android devices have only 320x240 and height >= 480 is bare // minimum to make the GUI working as expected. if (irr_driver->getActualScreenSize().Height < 480)