From 375b736e74d83696720a85dfb78ad41f873e9cbe Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 May 2015 02:52:04 +0200 Subject: [PATCH] Use SDL to create the window No input nor event loop handling yet, so the window will "stop responding" after a few seconds. Thanks to KittyCat for the GraphicsWindowSDL2 code. --- apps/openmw/engine.cpp | 103 +++++++-- apps/openmw/engine.hpp | 5 + apps/openmw/mwclass/creature.cpp | 10 - apps/openmw/mwclass/creature.hpp | 4 - apps/openmw/mwclass/npc.cpp | 10 - apps/openmw/mwclass/npc.hpp | 4 - apps/openmw/mwworld/class.cpp | 5 - apps/openmw/mwworld/class.hpp | 4 - components/CMakeLists.txt | 5 + components/sdlutil/sdlgraphicswindow.cpp | 272 +++++++++++++++++++++++ components/sdlutil/sdlgraphicswindow.hpp | 108 +++++++++ 11 files changed, 477 insertions(+), 53 deletions(-) create mode 100644 components/sdlutil/sdlgraphicswindow.cpp create mode 100644 components/sdlutil/sdlgraphicswindow.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4c6d1585b..a77b3e293 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -6,16 +6,15 @@ #include #include -#include - #include -// TODO: move to component #include #include #include +#include + #include #include @@ -182,7 +181,8 @@ void OMW::Engine::frame(float frametime) } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) - : mEncoding(ToUTF8::WINDOWS_1252) + : mWindow(NULL) + , mEncoding(ToUTF8::WINDOWS_1252) , mEncoder(NULL) , mVerboseScripts (false) , mSkipMenu (false) @@ -219,6 +219,13 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { + mResourceSystem.reset(); + + mViewer = NULL; + + SDL_DestroyWindow(mWindow); + mWindow = NULL; + mEnvironment.cleanup(); delete mScriptContext; SDL_Quit(); @@ -293,24 +300,88 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) return settingspath; } +void OMW::Engine::createWindow(Settings::Manager& settings) +{ + int screen = settings.getInt("screen", "Video"); + int width = settings.getInt("resolution x", "Video"); + int height = settings.getInt("resolution y", "Video"); + bool fullscreen = settings.getBool("fullscreen", "Video"); + bool windowBorder = settings.getBool("window border", "Video"); + bool vsync = settings.getBool("vsync", "Video"); + int antialiasing = settings.getInt("antialiasing", "Video"); + + int pos_x = SDL_WINDOWPOS_CENTERED_DISPLAY(screen), + pos_y = SDL_WINDOWPOS_CENTERED_DISPLAY(screen); + + if(fullscreen) + { + pos_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(screen); + pos_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(screen); + } + + Uint32 flags = SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE; + if(fullscreen) + flags |= SDL_WINDOW_FULLSCREEN; + + if (!windowBorder) + flags |= SDL_WINDOW_BORDERLESS; + + SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, + settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); + + if (antialiasing > 0) + { + if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) != 0) + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing) != 0) + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + } + + mWindow = SDL_CreateWindow("OpenMW", pos_x, pos_y, width, height, flags); + if (mWindow == NULL) + { + std::cerr << "Failed to create SDL window: " << SDL_GetError() << std::endl; + return; + } + + // TODO: set window icon + + SDLUtil::setupWindowingSystemInterface(); + + osg::ref_ptr traits = new osg::GraphicsContext::Traits; + SDL_GetWindowPosition(mWindow, &traits->x, &traits->y); + SDL_GetWindowSize(mWindow, &traits->width, &traits->height); + traits->windowName = SDL_GetWindowTitle(mWindow); + traits->windowDecoration = !(SDL_GetWindowFlags(mWindow)&SDL_WINDOW_BORDERLESS); + traits->screenNum = SDL_GetWindowDisplayIndex(mWindow); + // FIXME: Some way to get these settings back from the SDL window? + traits->red = 8; + traits->green = 8; + traits->blue = 8; + traits->alpha = 8; + traits->depth = 24; + traits->stencil = 8; + traits->vsync = vsync; + traits->doubleBuffer = true; + traits->inheritedWindowData = new SDLUtil::GraphicsWindowSDL2::WindowData(mWindow); + + osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + if(!gc.valid()) throw std::runtime_error("Failed to create GraphicsContext"); + + osg::ref_ptr camera = mViewer->getCamera(); + camera->setGraphicsContext(gc.get()); + camera->setViewport(0, 0, width, height); + + mViewer->realize(); +} + void OMW::Engine::prepareEngine (Settings::Manager & settings) { mEnvironment.setStateManager ( new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0))); - //OEngine::Render::WindowSettings windowSettings; - //windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); - //windowSettings.window_border = settings.getBool("window border", "Video"); - //windowSettings.vsync = settings.getBool("vsync", "Video"); - //windowSettings.icon = "openmw.png"; - //std::string aa = settings.getString("antialiasing", "Video"); - //windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + createWindow(settings); - SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, - settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); - - // not handling fullscreen yet, we should figure this out when adding SDL to the mix - mViewer->setUpViewInWindow(0, 0, settings.getInt("resolution x", "Video"), settings.getInt("resolution y", "Video"), settings.getInt("screen", "Video")); osg::ref_ptr rootNode (new osg::Group); mViewer->setSceneData(rootNode); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e94b5e3ff..420121a8e 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -53,11 +53,14 @@ namespace Files struct ConfigurationManager; } +struct SDL_Window; + namespace OMW { /// \brief Main engine class, that brings together all the components of OpenMW class Engine { + SDL_Window* mWindow; std::auto_ptr mVFS; std::auto_ptr mResourceSystem; MWBase::Environment mEnvironment; @@ -112,6 +115,8 @@ namespace OMW /// Prepare engine for game play void prepareEngine (Settings::Manager & settings); + void createWindow(Settings::Manager& settings); + public: Engine(Files::ConfigurationManager& configurationManager); virtual ~Engine(); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 89302dcc0..1e41aea24 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -580,16 +580,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - Ogre::Vector3 Creature::getMovementVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - Ogre::Vector3 vec(movement.mPosition); - movement.mPosition[0] = 0.0f; - movement.mPosition[1] = 0.0f; - movement.mPosition[2] = 0.0f; - return vec; - } - Ogre::Vector3 Creature::getRotationVector (const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 7a50968bf..f5a2402f3 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -113,10 +113,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getMovementVector (const MWWorld::Ptr& ptr) const; - ///< Return desired movement vector (determined based on movement settings, - /// stance and stats). - virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6f969146b..463209df8 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -961,16 +961,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - Ogre::Vector3 vec(movement.mPosition); - movement.mPosition[0] = 0.0f; - movement.mPosition[1] = 0.0f; - movement.mPosition[2] = 0.0f; - return vec; - } - Ogre::Vector3 Npc::getRotationVector (const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index e0ebbec2b..f72a9bb2c 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -105,10 +105,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getMovementVector (const MWWorld::Ptr& ptr) const; - ///< Return desired movement vector (determined based on movement settings, - /// stance and stats). - virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; ///< Return desired rotations, as euler angles. diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 0ab18699d..5999979de 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -186,11 +186,6 @@ namespace MWWorld throw std::runtime_error ("movement settings not supported by class"); } - Ogre::Vector3 Class::getMovementVector (const Ptr& ptr) const - { - return Ogre::Vector3 (0, 0, 0); - } - Ogre::Vector3 Class::getRotationVector (const Ptr& ptr) const { return Ogre::Vector3 (0, 0, 0); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 15058294f..02afd8960 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -192,10 +192,6 @@ namespace MWWorld virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; ///< Return desired movement. - virtual Ogre::Vector3 getMovementVector (const Ptr& ptr) const; - ///< Return desired movement vector (determined based on movement settings, - /// stance and stats). - virtual Ogre::Vector3 getRotationVector (const Ptr& ptr) const; ///< Return desired rotations, as euler angles. diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ef32e10dc..d62ff3f00 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -126,6 +126,10 @@ add_component_dir (fontloader fontloader ) +add_component_dir (sdlutil + sdlgraphicswindow + ) + add_component_dir (version version ) @@ -172,6 +176,7 @@ target_link_libraries(components ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES} ${BULLET_LIBRARIES} + ${SDL2_LIBRARY} # For MyGUI platform ${OPENGL_gl_LIBRARY} ) diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp new file mode 100644 index 000000000..5a9db5923 --- /dev/null +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -0,0 +1,272 @@ +#include "sdlgraphicswindow.hpp" + +#include + +#include + +namespace SDLUtil +{ + +GraphicsWindowSDL2::~GraphicsWindowSDL2() +{ + close(true); +} + + +bool GraphicsWindowSDL2::setWindowDecorationImplementation(bool flag) +{ + if(!mWindow) return false; + + SDL_SetWindowBordered(mWindow, flag ? SDL_TRUE : SDL_FALSE); + return true; +} + +bool GraphicsWindowSDL2::setWindowRectangleImplementation(int x, int y, int width, int height) +{ + if(!mWindow) return false; + + SDL_SetWindowPosition(mWindow, x, y); + SDL_SetWindowSize(mWindow, width, height); + return true; +} + +void GraphicsWindowSDL2::setWindowName(const std::string &name) +{ + if(!mWindow) return; + + SDL_SetWindowTitle(mWindow, name.c_str()); + _traits->windowName = name; +} + +void GraphicsWindowSDL2::setCursor(MouseCursor mouseCursor) +{ + _traits->useCursor = false; +} + + +void GraphicsWindowSDL2::init() +{ + if(mValid) return; + + if(!_traits.valid()) + return; + + // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get()); + + WindowData *inheritedWindowData = dynamic_cast(_traits->inheritedWindowData.get()); + mWindow = inheritedWindowData ? inheritedWindowData->mWindow : NULL; + + mOwnsWindow = (mWindow == 0); + if(mOwnsWindow) + { + OSG_NOTICE<<"Error: No SDL window provided."<vsync); + + SDL_GL_MakeCurrent(oldWin, oldCtx); + + mValid = true; + + getEventQueue()->syncWindowRectangleWithGraphcisContext(); +} + + +bool GraphicsWindowSDL2::realizeImplementation() +{ + if(mRealized) + { + OSG_NOTICE<< "GraphicsWindowSDL2::realizeImplementation() Already realized" <syncWindowRectangleWithGraphcisContext(); + + mRealized = true; + + return true; +} + +bool GraphicsWindowSDL2::makeCurrentImplementation() +{ + if(!mRealized) + { + OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<setNumFramesToRetainObjects(0); + osg::Referenced::getDeleteHandler()->flushAll(); + } + + //OSG_NOTICE<< "~SDL2WindowingSystemInterface()" <pbuffer) + return NULL; + + osg::ref_ptr window = new GraphicsWindowSDL2(traits); + if(window->valid()) return window.release(); + return NULL; + } +}; + +void setupWindowingSystemInterface() +{ + osg::GraphicsContext::setWindowingSystemInterface(new SDL2WindowingSystemInterface); +} + +} // namespace TK diff --git a/components/sdlutil/sdlgraphicswindow.hpp b/components/sdlutil/sdlgraphicswindow.hpp new file mode 100644 index 000000000..27b9e8e28 --- /dev/null +++ b/components/sdlutil/sdlgraphicswindow.hpp @@ -0,0 +1,108 @@ +#ifndef OSGGRAPHICSWINDOW_H +#define OSGGRAPHICSWINDOW_H + +#include + +#include + +namespace SDLUtil +{ + +class GraphicsWindowSDL2 : public osgViewer::GraphicsWindow +{ + SDL_Window* mWindow; + SDL_GLContext mContext; + + bool mValid; + bool mRealized; + bool mOwnsWindow; + + void init(); + + virtual ~GraphicsWindowSDL2(); + +public: + GraphicsWindowSDL2(osg::GraphicsContext::Traits *traits) + : mWindow(0) + , mContext(0) + , mValid(false) + , mRealized(false) + , mOwnsWindow(false) + { + _traits = traits; + + init(); + if(valid()) + { + setState(new osg::State); + getState()->setGraphicsContext(this); + + if(_traits.valid() && _traits->sharedContext.valid()) + { + getState()->setContextID(_traits->sharedContext->getState()->getContextID()); + incrementContextIDUsageCount(getState()->getContextID()); + } + else + { + getState()->setContextID(osg::GraphicsContext::createNewContextID()); + } + } + } + + virtual bool isSameKindAs(const Object* object) const { return dynamic_cast(object)!=0; } + virtual const char* libraryName() const { return "osgViewer"; } + virtual const char* className() const { return "GraphicsWindowSDL2"; } + + virtual bool valid() const { return mValid; } + + /** Realise the GraphicsContext.*/ + virtual bool realizeImplementation(); + + /** Return true if the graphics context has been realised and is ready to use.*/ + virtual bool isRealizedImplementation() const { return mRealized; } + + /** Close the graphics context.*/ + virtual void closeImplementation(); + + /** Make this graphics context current.*/ + virtual bool makeCurrentImplementation(); + + /** Release the graphics context.*/ + virtual bool releaseContextImplementation(); + + /** Swap the front and back buffers.*/ + virtual void swapBuffersImplementation(); + + /** Set sync-to-vblank. */ + virtual void setSyncToVBlank(bool on); + + /** Set Window decoration.*/ + virtual bool setWindowDecorationImplementation(bool flag); + + /** Raise specified window */ + virtual void raiseWindow(); + + /** Set the window's position and size.*/ + virtual bool setWindowRectangleImplementation(int x, int y, int width, int height); + + /** Set the name of the window */ + virtual void setWindowName(const std::string &name); + + /** Set mouse cursor to a specific shape.*/ + virtual void setCursor(MouseCursor cursor); + + /** WindowData is used to pass in the SDL2 window handle attached the GraphicsContext::Traits structure. */ + struct WindowData : public osg::Referenced + { + WindowData(SDL_Window *window) : mWindow(window) + { } + + SDL_Window *mWindow; + }; +}; + +void setupWindowingSystemInterface(); + +} // namespace TK + +#endif /* OSGGRAPHICSWINDOW_H */