From 1c8fd2ecdb7251b60ca16aa78617fc014660e3d3 Mon Sep 17 00:00:00 2001 From: unrelentingtech Date: Mon, 12 Sep 2022 08:18:08 +0000 Subject: [PATCH] Implement system-scaled HiDPI support (SDL_WINDOW_ALLOW_HIGHDPI - Wayland, macOS, etc) --- apps/openmw/engine.cpp | 14 ++++++++++-- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +++++- components/sdlutil/sdlgraphicswindow.cpp | 7 +++++- components/sdlutil/sdlinputwrapper.cpp | 27 ++++++++++++++++++------ components/sdlutil/sdlinputwrapper.hpp | 4 ++++ components/sdlutil/sdlvideowrapper.cpp | 11 +++++++--- 6 files changed, 56 insertions(+), 14 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index c8ea05e15e..724c2e48bb 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -584,7 +584,7 @@ void OMW::Engine::createWindow() pos_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(screen); } - Uint32 flags = SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE; + Uint32 flags = SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI; if(windowMode == Settings::WindowMode::Fullscreen) flags |= SDL_WINDOW_FULLSCREEN; else if (windowMode == Settings::WindowMode::WindowedFullscreen) @@ -640,11 +640,21 @@ void OMW::Engine::createWindow() } } + // Since we use physical resolution internally, we have to create the window with scaled resolution, + // but we can't get the scale before the window exists, so instead we have to resize aftewards. + int w,h; + SDL_GetWindowSize(mWindow, &w, &h); + int dw,dh; + SDL_GL_GetDrawableSize(mWindow, &dw, &dh); + if (dw != w || dh != h) { + SDL_SetWindowSize(mWindow, width / (dw / w), height / (dh / h)); + } + setWindowIcon(); osg::ref_ptr traits = new osg::GraphicsContext::Traits; SDL_GetWindowPosition(mWindow, &traits->x, &traits->y); - SDL_GetWindowSize(mWindow, &traits->width, &traits->height); + SDL_GL_GetDrawableSize(mWindow, &traits->width, &traits->height); traits->windowName = SDL_GetWindowTitle(mWindow); traits->windowDecoration = !(SDL_GetWindowFlags(mWindow)&SDL_WINDOW_BORDERLESS); traits->screenNum = SDL_GetWindowDisplayIndex(mWindow); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6927229fa9..79f4312590 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -177,7 +177,12 @@ namespace MWGui , mVersionDescription(versionDescription) , mWindowVisible(true) { - mScalingFactor = std::clamp(Settings::Manager::getFloat("scaling factor", "GUI"), 0.5f, 8.f); + int w,h; + SDL_GetWindowSize(window, &w, &h); + int dw,dh; + SDL_GL_GetDrawableSize(window, &dw, &dh); + + mScalingFactor = std::clamp(Settings::Manager::getFloat("scaling factor", "GUI"), 0.5f, 8.f) * (dw / w); mGuiPlatform = std::make_unique(viewer, guiRoot, resourceSystem->getImageManager(), resourceSystem->getVFS(), mScalingFactor, "mygui", logpath / "MyGUI.log"); diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 43284c216d..ca59ac68c4 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -54,8 +54,13 @@ bool GraphicsWindowSDL2::setWindowRectangleImplementation(int x, int y, int widt { if(!mWindow) return false; + int w,h; + SDL_GetWindowSize(mWindow, &w, &h); + int dw,dh; + SDL_GL_GetDrawableSize(mWindow, &dw, &dh); + SDL_SetWindowPosition(mWindow, x, y); - SDL_SetWindowSize(mWindow, width, height); + SDL_SetWindowSize(mWindow, width / (dw / w), height / (dh / h)); return true; } diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 4273cf5b96..0f28a959fe 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -36,12 +36,23 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v Uint32 flags = SDL_GetWindowFlags(mSDLWindow); mWindowHasFocus = (flags & SDL_WINDOW_INPUT_FOCUS); mMouseInWindow = (flags & SDL_WINDOW_MOUSE_FOCUS); + _setWindowScale(); } InputWrapper::~InputWrapper() { } + void InputWrapper::_setWindowScale() + { + int w,h; + SDL_GetWindowSize(mSDLWindow, &w, &h); + int dw,dh; + SDL_GL_GetDrawableSize(mSDLWindow, &dw, &dh); + mScaleX = dw / w; + mScaleY = dh / h; + } + void InputWrapper::capture(bool windowEventsOnly) { mViewer->getEventQueue()->frame(0.f); @@ -231,7 +242,7 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v break; case SDL_WINDOWEVENT_SIZE_CHANGED: int w,h; - SDL_GetWindowSize(mSDLWindow, &w, &h); + SDL_GL_GetDrawableSize(mSDLWindow, &w, &h); int x,y; SDL_GetWindowPosition(mSDLWindow, &x,&y); mViewer->getCamera()->getGraphicsContext()->resized(x,y,w,h); @@ -241,6 +252,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v if (mWindowListener) mWindowListener->windowResized(w, h); + _setWindowScale(); + break; case SDL_WINDOWEVENT_RESIZED: @@ -383,16 +396,16 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v MouseMotionEvent InputWrapper::_packageMouseMotion(const SDL_Event &evt) { MouseMotionEvent pack_evt = {}; - pack_evt.x = mMouseX; - pack_evt.y = mMouseY; + pack_evt.x = mMouseX * mScaleX; + pack_evt.y = mMouseY * mScaleY; pack_evt.z = mMouseZ; if(evt.type == SDL_MOUSEMOTION) { - pack_evt.x = mMouseX = evt.motion.x; - pack_evt.y = mMouseY = evt.motion.y; - pack_evt.xrel = evt.motion.xrel; - pack_evt.yrel = evt.motion.yrel; + pack_evt.x = mMouseX = evt.motion.x * mScaleX; + pack_evt.y = mMouseY = evt.motion.y * mScaleY; + pack_evt.xrel = evt.motion.xrel * mScaleX; + pack_evt.yrel = evt.motion.yrel * mScaleY; pack_evt.type = SDL_MOUSEMOTION; if (mFirstMouseMove) { diff --git a/components/sdlutil/sdlinputwrapper.hpp b/components/sdlutil/sdlinputwrapper.hpp index 39b6530feb..e50431e1fc 100644 --- a/components/sdlutil/sdlinputwrapper.hpp +++ b/components/sdlutil/sdlinputwrapper.hpp @@ -49,6 +49,7 @@ namespace SDLUtil bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); void _wrapMousePointer(const SDL_MouseMotionEvent &evt); MouseMotionEvent _packageMouseMotion(const SDL_Event& evt); + void _setWindowScale(); SDL_Window* mSDLWindow; osg::ref_ptr mViewer; @@ -79,6 +80,9 @@ namespace SDLUtil bool mWindowHasFocus; bool mMouseInWindow; + + Uint16 mScaleX; + Uint16 mScaleY; }; } diff --git a/components/sdlutil/sdlvideowrapper.cpp b/components/sdlutil/sdlvideowrapper.cpp index 7d62979e7f..ad8fbba566 100644 --- a/components/sdlutil/sdlvideowrapper.cpp +++ b/components/sdlutil/sdlvideowrapper.cpp @@ -76,18 +76,23 @@ namespace SDLUtil if (SDL_GetWindowFlags(mWindow) & SDL_WINDOW_MAXIMIZED) SDL_RestoreWindow(mWindow); + int w,h; + SDL_GetWindowSize(mWindow, &w, &h); + int dw,dh; + SDL_GL_GetDrawableSize(mWindow, &dw, &dh); + if (windowMode == Settings::WindowMode::Fullscreen || windowMode == Settings::WindowMode::WindowedFullscreen) { SDL_DisplayMode mode; SDL_GetWindowDisplayMode(mWindow, &mode); - mode.w = width; - mode.h = height; + mode.w = width / (dw / w); + mode.h = height / (dh / h); SDL_SetWindowDisplayMode(mWindow, &mode); SDL_SetWindowFullscreen(mWindow, windowMode == Settings::WindowMode::Fullscreen ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP); } else { - SDL_SetWindowSize(mWindow, width, height); + SDL_SetWindowSize(mWindow, width / (dw / w), height / (dh / h)); SDL_SetWindowBordered(mWindow, windowBorder ? SDL_TRUE : SDL_FALSE); centerWindow();