From 969fa538c75b03716df4172e8b1651be47b5506e Mon Sep 17 00:00:00 2001 From: Hugh Sanderson Date: Tue, 4 Jan 2022 22:31:48 +0800 Subject: [PATCH] Add highDpi window attribute to allow full-res on mac retina displays. For #704 --- project/include/Display.h | 9 +++++ project/src/mac/System.mm | 26 ++++++++++++- project/src/sdl2/SDL2Stage.cpp | 63 ++++++++++++++++++++++++++----- src/nme/app/Application.hx | 1 + templates/haxe/ApplicationMain.hx | 1 + tools/nme/src/project/Window.hx | 2 + 6 files changed, 90 insertions(+), 12 deletions(-) diff --git a/project/include/Display.h b/project/include/Display.h index 80020f423..0369357da 100644 --- a/project/include/Display.h +++ b/project/include/Display.h @@ -79,6 +79,14 @@ enum Cursor { curNone, curPointer, curHand, extern const char *sTextCursorData[]; extern const char *sHandCursorData[]; +#if defined(HX_MACOS) +extern void enableRetinaScale(bool enable); +extern double getRetinaScale(); +#else +inline void enableRetinaScale(bool enable) { } +inline double getRetinaScale() { return 1.0; } +#endif + extern bool gMouseShowCursor; class DisplayObject : public Object @@ -573,6 +581,7 @@ enum WindowFlags wfScaleMask = 0x0000f000, wfHardwareMetal = 0x00010000, wfAlwaysOnTop = 0x00020000, + wfHighDpi = 0x00040000, }; enum WindowScaleMode diff --git a/project/src/mac/System.mm b/project/src/mac/System.mm index 2befc4d69..a20cdf9d3 100644 --- a/project/src/mac/System.mm +++ b/project/src/mac/System.mm @@ -62,6 +62,24 @@ void GetVolumeInfo( std::vector &outInfo ) } #endif +static bool includeRetinaScale = false; +void enableRetinaScale(bool enable) +{ + includeRetinaScale = enable; +} + +double getRetinaScale() +{ + @autoreleasepool { + NSScreen *screen = [NSScreen mainScreen]; + + double retinaScale = 1.0; + if (includeRetinaScale && [screen respondsToSelector:@selector(backingScaleFactor)]) + retinaScale = [NSScreen mainScreen].backingScaleFactor; + + return retinaScale; + } +} double CapabilitiesGetScreenDPI() { @@ -70,16 +88,20 @@ void GetVolumeInfo( std::vector &outInfo ) #endif NSScreen *screen = [NSScreen mainScreen]; + double retinaScale = 1.0; + if (includeRetinaScale && [screen respondsToSelector:@selector(backingScaleFactor)]) + retinaScale = [NSScreen mainScreen].backingScaleFactor; + NSDictionary *description = [screen deviceDescription]; NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue]; CGSize displayPhysicalSize = CGDisplayScreenSize( [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); double result = ((displayPixelSize.width / displayPhysicalSize.width) + (displayPixelSize.height / displayPhysicalSize.height)) * 0.5 * 25.4; - + #ifndef OBJC_ARC [pool drain]; #endif - return result; + return result * retinaScale; } double CapabilitiesGetPixelAspectRatio() { diff --git a/project/src/sdl2/SDL2Stage.cpp b/project/src/sdl2/SDL2Stage.cpp index 5d0c0b336..2b3829d02 100644 --- a/project/src/sdl2/SDL2Stage.cpp +++ b/project/src/sdl2/SDL2Stage.cpp @@ -130,14 +130,16 @@ class HardwareRenderSurface : public HardwareSurface { int width = 0; int height = 0; - SDL_GetWindowSize(window, &width, &height); + //SDL_GetWindowSize(window, &width, &height); + SDL_GL_GetDrawableSize(window, &width, &height); return width; } int Height() const { int width = 0; int height = 0; - SDL_GetWindowSize(window, &width, &height); + //SDL_GetWindowSize(window, &width, &height); + SDL_GL_GetDrawableSize(window, &width, &height); return height; } RenderTarget BeginRender(const Rect &inRect,bool inForHitTest) @@ -147,7 +149,8 @@ class HardwareRenderSurface : public HardwareSurface lastWindow = window; int width = 0; int height = 0; - SDL_GetWindowSize(window, &width, &height); + SDL_GL_GetDrawableSize(window, &width, &height); + //SDL_GetWindowSize(window, &width, &height); mHardware->SetWindowSize(width,height); SDL_GL_MakeCurrent(window, context); } @@ -531,7 +534,8 @@ class SDLStage : public Stage if (!mIsFullscreen) { SDL_GetWindowPosition(mSDLWindow, &sgWindowRect.x, &sgWindowRect.y); - SDL_GetWindowSize(mSDLWindow, &sgWindowRect.w, &sgWindowRect.h); + //SDL_GetWindowSize(mSDLWindow, &sgWindowRect.w, &sgWindowRect.h); + SDL_GL_GetDrawableSize(mSDLWindow, &sgWindowRect.w, &sgWindowRect.h); } mIsFullscreen = inFullscreen; @@ -942,6 +946,7 @@ class SDLFrame : public Frame SDL_Window *mWindow; bool mIsHardware; uint32 mWindowFlags; + double retinaScale; double mAccX; double mAccY; @@ -958,6 +963,8 @@ class SDLFrame : public Frame windowID = SDL_GetWindowID(inWindow); mStage = new SDLStage(inWindow, inRenderer, mWindowFlags, inIsHardware, inWidth, inHeight); mStage->IncRef(); + + retinaScale = getRetinaScale(); } @@ -988,6 +995,15 @@ class SDLFrame : public Frame { mStage->Resize(inWidth, inHeight); } + + void scaleMouseDpi(Event &ioEvent) + { + if (retinaScale!=1.0) + { + ioEvent.x = (int)(ioEvent.x*retinaScale + 0.5); + ioEvent.y = (int)(ioEvent.y*retinaScale + 0.5); + } + } // --- Frame Interface ---------------------------------------------------- @@ -1660,7 +1676,8 @@ void ProcessEvent(SDL_Event &inEvent) if (frame) { Event resize(etResize, inEvent.window.data1, inEvent.window.data2); - frame->Resize(inEvent.window.data1, inEvent.window.data2); + frame->scaleMouseDpi(resize); + frame->Resize(resize.x, resize.y); frame->ProcessEvent(resize); Event redraw(etRedraw); frame->ProcessEvent(redraw); @@ -1689,7 +1706,8 @@ void ProcessEvent(SDL_Event &inEvent) int width = 0; int height = 0; - SDL_GetWindowSize(frame->mWindow, &width, &height); + //SDL_GetWindowSize(frame->mWindow, &width, &height); + SDL_GL_GetDrawableSize(frame->mWindow, &width, &height); Event resize(etResize, width, height); frame->Resize(width,height); @@ -1754,6 +1772,7 @@ void ProcessEvent(SDL_Event &inEvent) int y=0; SDL_GetMouseState(&x,&y); Event event(etDropEnd, x, y); + frame->scaleMouseDpi(event); AddModStates(event.flags); frame->ProcessEvent(event); break; @@ -1781,10 +1800,14 @@ void ProcessEvent(SDL_Event &inEvent) //pass the delta in as well through as deltaX if(SDL_GetRelativeMouseMode()) { SDL_GetRelativeMouseState( &deltaX, &deltaY ); + deltaX = (int)(deltaX * frame->retinaScale); + deltaY = (int)(deltaY * frame->retinaScale); } //int inValue=0, int inID=0, int inFlags=0, float inScaleX=1,float inScaleY=1, int inDeltaX=0,int inDeltaY=0 Event mouse(etMouseMove, inEvent.motion.x, inEvent.motion.y, 0, 0, 0, 1.0f, 1.0f, deltaX, deltaY); + frame->scaleMouseDpi(mouse); + #if defined(WEBOS) || defined(BLACKBERRY) mouse.value = inEvent.motion.which; mouse.flags |= efLeftDown; @@ -1798,6 +1821,7 @@ void ProcessEvent(SDL_Event &inEvent) { SDLFrame *frame = getEventFrame(inEvent.button.windowID); Event mouse(etMouseDown, inEvent.button.x, inEvent.button.y, inEvent.button.button - 1); + frame->scaleMouseDpi(mouse); #if defined(WEBOS) || defined(BLACKBERRY) mouse.value = inEvent.motion.which; mouse.flags |= efLeftDown; @@ -1811,6 +1835,7 @@ void ProcessEvent(SDL_Event &inEvent) { SDLFrame *frame = getEventFrame(inEvent.button.windowID); Event mouse(etMouseUp, inEvent.button.x, inEvent.button.y, inEvent.button.button - 1); + frame->scaleMouseDpi(mouse); #if defined(WEBOS) || defined(BLACKBERRY) mouse.value = inEvent.motion.which; #else @@ -1838,6 +1863,7 @@ void ProcessEvent(SDL_Event &inEvent) mouse.deltaY = inEvent.wheel.y; //add flags for modifier keys AddModStates(mouse.flags); + frame->scaleMouseDpi(mouse); //and done. frame->ProcessEvent(mouse); break; @@ -1848,7 +1874,8 @@ void ProcessEvent(SDL_Event &inEvent) SDLFrame *frame = getEventFrame(inEvent.tfinger.windowID); int width = 0; int height = 0; - SDL_GetWindowSize(frame->mWindow, &width, &height); + //SDL_GetWindowSize(frame->mWindow, &width, &height); + SDL_GL_GetDrawableSize(frame->mWindow, &width, &height); // button? Event mouse(etMouseDown, inEvent.tfinger.x*width, inEvent.tfinger.y*height, 0); @@ -1862,7 +1889,8 @@ void ProcessEvent(SDL_Event &inEvent) SDLFrame *frame = getEventFrame(inEvent.tfinger.windowID); int width = 0; int height = 0; - SDL_GetWindowSize(frame->mWindow, &width, &height); + //SDL_GetWindowSize(frame->mWindow, &width, &height); + SDL_GL_GetDrawableSize(frame->mWindow, &width, &height); // button? Event mouse(etMouseUp, inEvent.tfinger.x*width, inEvent.tfinger.y*height, 0); @@ -1876,7 +1904,8 @@ void ProcessEvent(SDL_Event &inEvent) SDLFrame *frame = getEventFrame(inEvent.tfinger.windowID); int width = 0; int height = 0; - SDL_GetWindowSize(frame->mWindow, &width, &height); + //SDL_GetWindowSize(frame->mWindow, &width, &height); + SDL_GL_GetDrawableSize(frame->mWindow, &width, &height); // button? Event mouse(etMouseMove, inEvent.tfinger.x*width, inEvent.tfinger.y*height, 0); @@ -2116,6 +2145,7 @@ void CreateMainFrame(FrameCreationCallback inOnFrame, int inWidth, int inHeight, bool resizable = (inFlags & wfResizable) != 0; bool borderless = (inFlags & wfBorderless) != 0; bool vsync = (inFlags & wfVSync) != 0; + bool tryHighDpi = (inFlags & wfHighDpi) != 0; //WindowScaleMode scaleMode = (WindowScaleMode)( (inFlags & wfScaleMask)/wfScaleBase ); #ifdef HX_LINUX @@ -2180,6 +2210,11 @@ void CreateMainFrame(FrameCreationCallback inOnFrame, int inWidth, int inHeight, if (resizable) requestWindowFlags |= SDL_WINDOW_RESIZABLE; if (borderless) requestWindowFlags |= SDL_WINDOW_BORDERLESS; if (fullscreen) requestWindowFlags |= FullscreenMode; //SDL_WINDOW_FULLSCREEN_DESKTOP; + if (tryHighDpi) + { + requestWindowFlags |= SDL_WINDOW_ALLOW_HIGHDPI; + enableRetinaScale(true); + } if (inFlags & wfAlwaysOnTop) requestWindowFlags |= SDL_WINDOW_ALWAYS_ON_TOP; @@ -2223,7 +2258,11 @@ void CreateMainFrame(FrameCreationCallback inOnFrame, int inWidth, int inHeight, } } + // Get DPI without retina, "sdl window coordinates" + enableRetinaScale(false); double dpiScale = CapabilitiesGetScreenDPI()/96.0; + enableRetinaScale(tryHighDpi); + int targetW = dpiScale<1.5 ? inWidth : dpiScale*inWidth; if (targetW>sgDesktopWidth) targetW = sgDesktopWidth; @@ -2372,6 +2411,7 @@ void CreateMainFrame(FrameCreationCallback inOnFrame, int inWidth, int inHeight, } int width, height; + /* if (windowFlags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP) ) { //SDL_DisplayMode mode; @@ -2382,8 +2422,10 @@ void CreateMainFrame(FrameCreationCallback inOnFrame, int inWidth, int inHeight, height = sgDesktopHeight; } else + */ { - SDL_GetWindowSize(window, &width, &height); + SDL_GL_GetDrawableSize(window, &width, &height); + //SDL_GetWindowSize(window, &width, &height); } @@ -2394,6 +2436,7 @@ void CreateMainFrame(FrameCreationCallback inOnFrame, int inWidth, int inHeight, else if (sgMainRenderer==renderer) renderer = 0; + SDLFrame *frame = new SDLFrame(window, renderer, windowFlags, hardware, width, height); if (isMain) diff --git a/src/nme/app/Application.hx b/src/nme/app/Application.hx index 24b378642..6df4cdc4b 100644 --- a/src/nme/app/Application.hx +++ b/src/nme/app/Application.hx @@ -58,6 +58,7 @@ class Application public inline static var SCALE_BASE = 0x1000; public inline static var HARDWARE_METAL =0x10000; public inline static var ALWAYS_ON_TOP =0x20000; + public inline static var HIGH_DPI =0x40000; public static var nmeFrameHandle:Dynamic = null; public static var nmeWindow:Window = null; diff --git a/templates/haxe/ApplicationMain.hx b/templates/haxe/ApplicationMain.hx index 4d9bfe3ec..3fe570282 100644 --- a/templates/haxe/ApplicationMain.hx +++ b/templates/haxe/ApplicationMain.hx @@ -192,6 +192,7 @@ class ApplicationMain (::WIN_ANTIALIASING:: == 4 ? nme.app.Application.HW_AA_HIRES : 0) | (::WIN_ANTIALIASING:: == 2 ? nme.app.Application.HW_AA : 0)| (::WIN_SINGLE_INSTANCE:: ? nme.app.Application.SINGLE_INSTANCE : 0) | + (::WIN_HIGH_DPI:: ? nme.app.Application.HIGH_DPI : 0) | (::WIN_SCALE_FLAGS:: * nme.app.Application.SCALE_BASE) ; diff --git a/tools/nme/src/project/Window.hx b/tools/nme/src/project/Window.hx index 71831839d..c9fc0535f 100644 --- a/tools/nme/src/project/Window.hx +++ b/tools/nme/src/project/Window.hx @@ -21,6 +21,7 @@ class Window public var alphaBuffer:Bool; public var ui:String; public var singleInstance:Bool; + public var highDpi:Bool; public var scaleMode:ScaleMode; public function new() @@ -43,6 +44,7 @@ class Window depthBuffer = false; stencilBuffer = false; alphaBuffer = false; + highDpi = false; ui = ""; singleInstance = true; scaleMode = ScaleNative;