From 043e29c62089159061d74213e055f2c521d68272 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sun, 13 Jan 2013 21:32:45 -0400 Subject: [PATCH] Have SDL manage the window instead of OGRE to work around SDL Windows bugs (grumble) --- apps/openmw/engine.cpp | 90 ++++++++++++++++++++++++----- apps/openmw/engine.hpp | 2 + extern/sdl4ogre/sdlinputwrapper.cpp | 23 +------- libs/openengine/ogre/renderer.cpp | 64 +++++++++++++++++++- libs/openengine/ogre/renderer.hpp | 7 +++ 5 files changed, 150 insertions(+), 36 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 12a5d4be7..0619281d0 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1,7 +1,5 @@ #include "engine.hpp" -#include - #include "components/esm/loadcell.hpp" #include @@ -40,6 +38,7 @@ #include "mwmechanics/mechanicsmanagerimp.hpp" +#include void OMW::Engine::executeLocalScripts() { @@ -70,6 +69,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { try { + handleSDLMessages(); + mEnvironment.setFrameDuration (evt.timeSinceLastFrame); // update input @@ -116,6 +117,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); MWBase::Environment::get().getWindowManager()->onFrame(evt.timeSinceLastFrame); + + //Flush any events that weren't handled this frame + SDL_FlushEvents(0x0, 0xFFFFFFFF); } catch (const std::exception& e) { @@ -125,6 +129,65 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) return true; } +void OMW::Engine::handleSDLMessages() +{ + //Pump messages since the last frame + const int max_events = 20; + SDL_Event events[max_events]; + + SDL_PumpEvents(); + int num_events = SDL_PeepEvents(events, max_events, SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT); + + bool move_or_resize = false; + + unsigned int size_x = 0; + unsigned int size_y = 0; + + if(num_events != 0) + { + for(int i=0; i < num_events; ++i) + { + switch(events[i].window.event) + { + case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_MOVED: + printf("Resizing window!\n"); + move_or_resize = true; + size_x = events[i].window.data1; + size_y = events[i].window.data2; + break; + } + } + } + + //handle window movements + if(move_or_resize) + { + mOgre->adjustViewport(); + if(!mOgre->getWindow()->isFullScreen()) + { + SDL_DisplayMode dispMode; + SDL_Window* sdlWindow = mOgre->getSDLWindow(); + + SDL_GetWindowDisplayMode(sdlWindow, &dispMode); + + dispMode.w = size_x; + dispMode.h = size_y; + + SDL_SetWindowDisplayMode(sdlWindow, &dispMode); + + mOgre->getWindow()->windowMovedOrResized(); + mOgre->getWindow()->resize(size_x, size_y); + } + } + + if(SDL_PeepEvents(NULL, 1, SDL_PEEKEVENT, SDL_QUIT, SDL_QUIT) != 0) + { + //user requested a quit, break out. + mOgre->getRoot()->queueEndRendering(); + } +} + OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) : mOgre (0) , mFpsLevel(0) @@ -140,6 +203,16 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) { std::srand ( std::time(NULL) ); MWClass::registerClasses(); + + Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; + if(SDL_WasInit(flags) == 0) + { + //kindly ask SDL not to trash our OGL context + //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + if(SDL_Init(flags) != 0) + throw std::runtime_error("Couldn't initialize SDL!"); + } } OMW::Engine::~Engine() @@ -147,6 +220,7 @@ OMW::Engine::~Engine() mEnvironment.cleanup(); delete mScriptContext; delete mOgre; + SDL_Quit(); } // Load all BSA files in data directory. @@ -317,7 +391,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "shadows"); addZipResource(mResDir / "mygui" / "Obliviontt.zip"); - // Create the window OEngine::Render::WindowSettings windowSettings; windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); windowSettings.window_x = settings.getInt("resolution x", "Video"); @@ -325,20 +398,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) windowSettings.vsync = settings.getBool("vsync", "Video"); std::string aa = settings.getString("antialiasing", "Video"); windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + mOgre->createWindow("OpenMW", windowSettings); loadBSA(); - Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; - if(SDL_WasInit(flags) == 0) - { - //kindly ask SDL not to trash our OGL context - //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - if(SDL_Init(flags) != 0) - throw std::runtime_error("Couldn't initialize SDL!"); - } - // cursor replacer (converts the cursor from the bsa so they can be used by mygui) MWGui::CursorReplace replacer; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e320c6991..971445147 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -103,6 +103,8 @@ namespace OMW void executeLocalScripts(); + void handleSDLMessages(); + virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); /// Load settings from various files, returns the path to the user settings file diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index da65102e7..cf864b20f 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -85,7 +85,6 @@ namespace SFO mSDLWindow = NULL; SDL_StopTextInput(); - SDL_Quit(); } void InputWrapper::capture() @@ -121,24 +120,6 @@ namespace SFO case SDL_KEYUP: mKeyboardListener->keyReleased(evt.key); break; - - case SDL_WINDOWEVENT_FOCUS_GAINED: - mWindowListener->windowFocusChange(true); - break; - case SDL_WINDOWEVENT_FOCUS_LOST: - mWindowListener->windowFocusChange(false); - break; - case SDL_WINDOWEVENT_EXPOSED: - mWindowListener->windowVisibilityChange(true); - break; - case SDL_WINDOWEVENT_HIDDEN: - mWindowListener->windowVisibilityChange(false); - break; - - //SDL traps ^C signals, pass it to OGRE. - case SDL_QUIT: - Ogre::Root::getSingleton().queueEndRendering(); - break; } } } @@ -186,9 +167,7 @@ namespace SFO //now remove all mouse events using the old setting from the queue SDL_PumpEvents(); - - SDL_Event dummy[20]; - SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); + SDL_FlushEvent(SDL_MOUSEMOTION); } /// \brief Internal method for ignoring relative motions as a side effect diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 3cdb00518..7696095eb 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -1,6 +1,9 @@ #include "renderer.hpp" #include "fader.hpp" +#include +#include + #include "OgreRoot.h" #include "OgreRenderWindow.h" #include "OgreLogManager.h" @@ -47,11 +50,16 @@ void OgreRenderer::cleanup() delete mRoot; mRoot = NULL; + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + unloadPlugins(); } void OgreRenderer::start() { + //TODO: Check if we still need to do this if we're using SDL's + //message pump #if defined(__APPLE__) && !defined(__LP64__) // OSX Carbon Message Pump do { @@ -214,6 +222,56 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& params.insert(std::make_pair("FSAA", settings.fsaa)); params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); + // Create an application window with the following settings: + SDL_Window *window = SDL_CreateWindow( + "OpenMW", // window title + SDL_WINDOWPOS_UNDEFINED, // initial x position + SDL_WINDOWPOS_UNDEFINED, // initial y position + settings.window_x, // width, in pixels + settings.window_y, // height, in pixels + SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE + | (settings.fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0) + ); + + + //get the native whnd + struct SDL_SysWMinfo wmInfo; + SDL_VERSION(&wmInfo.version); + + if(-1 == SDL_GetWindowWMInfo(window, &wmInfo)) + throw std::runtime_error("Couldn't get WM Info!"); + + Ogre::String winHandle; + + switch(wmInfo.subsystem) + { +#ifdef WIN32 + case SDL_SYSWM_WINDOWS: + // Windows code + winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.win.window); + break; +#elif MACOS + case SDL_SYSWM_COCOA: + //required to make OGRE play nice with our window + params.insert(std::make_pair("macAPI", "cocoa")); + params.insert(std::make_pair("macAPICocoaUseNSView", "true")); + + winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.cocoa.window); + break; +#else + case SDL_SYSWM_X11: + winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.x11.display); + winHandle += ":0:"; + winHandle += Ogre::StringConverter::toString((unsigned long)wmInfo.info.x11.window); + break; +#endif + default: + throw std::runtime_error("Unexpected WM!"); + break; + } + + params.insert(std::make_pair("externalWindowHandle", winHandle)); + mWindow = mRoot->createRenderWindow(title, settings.window_x, settings.window_y, settings.fullscreen, ¶ms); // create the semi-transparent black background texture used by the GUI. @@ -253,7 +311,11 @@ void OgreRenderer::createScene(const std::string& camName, float fov, float near void OgreRenderer::adjustViewport() { // Alter the camera aspect ratio to match the viewport - mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); + if(mCamera != NULL) + { + mView->setDimensions(0, 0, 1, 1); + mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); + } } void OgreRenderer::setWindowEventListener(Ogre::WindowEventListener* listener) diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index a8788dfca..7e57af927 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -31,6 +31,8 @@ #include #endif +struct SDL_Window; + namespace Ogre { #if !defined(__APPLE__) || defined(__LP64__) @@ -74,6 +76,7 @@ namespace OEngine Ogre::Root *mRoot; #endif Ogre::RenderWindow *mWindow; + SDL_Window *mSDLWindow; Ogre::SceneManager *mScene; Ogre::Camera *mCamera; Ogre::Viewport *mView; @@ -99,6 +102,7 @@ namespace OEngine OgreRenderer() : mRoot(NULL) , mWindow(NULL) + , mSDLWindow(NULL) , mScene(NULL) , mCamera(NULL) , mView(NULL) @@ -169,6 +173,9 @@ namespace OEngine /// Get the rendering window Ogre::RenderWindow *getWindow() { return mWindow; } + /// Get the SDL Window + SDL_Window *getSDLWindow() { return mSDLWindow; } + /// Get the scene manager Ogre::SceneManager *getScene() { return mScene; }