From cac4d58b3d009a95c41748f2aefbe489740c1798 Mon Sep 17 00:00:00 2001 From: Sebastian Kohl Date: Tue, 9 Dec 2014 20:38:48 +0100 Subject: [PATCH] fixes for ios window size including device-orientation-changes and retina support --- src/SFML/Graphics/GLExtensions.hpp | 2 - src/SFML/Window/iOS/SFAppDelegate.hpp | 23 ++++++++ src/SFML/Window/iOS/SFAppDelegate.mm | 72 +++++++++++++++++++------ src/SFML/Window/iOS/SFView.hpp | 2 +- src/SFML/Window/iOS/SFView.mm | 11 ++-- src/SFML/Window/iOS/SFViewController.mm | 2 - src/SFML/Window/iOS/VideoModeImpl.mm | 5 +- src/SFML/Window/iOS/WindowImplUIKit.hpp | 1 + src/SFML/Window/iOS/WindowImplUIKit.mm | 26 +++++++-- 9 files changed, 112 insertions(+), 32 deletions(-) diff --git a/src/SFML/Graphics/GLExtensions.hpp b/src/SFML/Graphics/GLExtensions.hpp index d42fd0f0..ae97741d 100644 --- a/src/SFML/Graphics/GLExtensions.hpp +++ b/src/SFML/Graphics/GLExtensions.hpp @@ -58,8 +58,6 @@ #define GLEXT_GL_FRAMEBUFFER GL_FRAMEBUFFER_OES #define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_OES #define GLEXT_GL_RENDERBUFFER GL_RENDERBUFFER_OES - #define GLEXT_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES - #define GLEXT_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_OES #define GLEXT_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_OES #define GLEXT_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_OES #define GLEXT_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES diff --git a/src/SFML/Window/iOS/SFAppDelegate.hpp b/src/SFML/Window/iOS/SFAppDelegate.hpp index 77f1a63b..c5e77aa4 100644 --- a/src/SFML/Window/iOS/SFAppDelegate.hpp +++ b/src/SFML/Window/iOS/SFAppDelegate.hpp @@ -100,11 +100,34 @@ //////////////////////////////////////////////////////////// - (void)notifyCharacter:(sf::Uint32)character; +//////////////////////////////////////////////////////////// +/// \brief Tells if the dimensions of the current window must be flipped when switching to a given orientation +/// +/// \param orientation the device has changed to +/// +//////////////////////////////////////////////////////////// +- (bool)needsToFlipFrameForOrientation:(UIDeviceOrientation)orientation; + +//////////////////////////////////////////////////////////// +/// \brief Tells if app and view support a requested device orientation or not +/// +/// \param orientation the device has changed to +/// +//////////////////////////////////////////////////////////// +- (bool)supportsOrientation:(UIDeviceOrientation)orientation; + +//////////////////////////////////////////////////////////// +/// \brief Initializes the factor which is required to convert from points to pixels and back +/// +//////////////////////////////////////////////////////////// +- (void)initBackingScale; + //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// @property (nonatomic) sf::priv::WindowImplUIKit* sfWindow; ///< Main window of the application @property (readonly, nonatomic) CMMotionManager* motionManager; ///< Instance of the motion manager +@property (nonatomic) CGFloat backingScaleFactor; @end diff --git a/src/SFML/Window/iOS/SFAppDelegate.mm b/src/SFML/Window/iOS/SFAppDelegate.mm index f63060b2..bbe7eea8 100644 --- a/src/SFML/Window/iOS/SFAppDelegate.mm +++ b/src/SFML/Window/iOS/SFAppDelegate.mm @@ -50,17 +50,18 @@ namespace @implementation SFAppDelegate @synthesize sfWindow; +@synthesize backingScaleFactor; //////////////////////////////////////////////////////////// -+(SFAppDelegate*)getInstance ++ (SFAppDelegate*)getInstance { return delegateInstance; } //////////////////////////////////////////////////////////// --(void)runUserMain +- (void)runUserMain { // Arguments intentionally dropped, see comments in main in sfml-main sfmlMain(0, NULL); @@ -73,6 +74,8 @@ namespace // Save the delegate instance delegateInstance = self; + [self initBackingScale]; + // Instantiate the motion manager self.motionManager = [[CMMotionManager alloc] init]; @@ -90,6 +93,14 @@ namespace return true; } +- (void)initBackingScale +{ + id data = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSHighResolutionCapable"]; + if(data && [data boolValue]) + backingScaleFactor = [[UIScreen mainScreen] scale]; + else + backingScaleFactor = 1; +} //////////////////////////////////////////////////////////// - (void)applicationWillResignActive:(UIApplication *)application @@ -151,6 +162,38 @@ namespace } } +- (bool)supportsOrientation:(UIDeviceOrientation)orientation +{ + if (!self.sfWindow) + return false; + + UIViewController* rootViewController = [((__bridge UIWindow*)(self.sfWindow->getSystemHandle())) rootViewController]; + if (!rootViewController || ![rootViewController shouldAutorotate]) + return false; + + NSArray *supportedOrientations = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UISupportedInterfaceOrientations"]; + if (!supportedOrientations) + return false; + + int appFlags = 0; + if ([supportedOrientations containsObject:@"UIInterfaceOrientationPortrait"]) + appFlags += UIInterfaceOrientationMaskPortrait; + if ([supportedOrientations containsObject:@"UIInterfaceOrientationPortraitUpsideDown"]) + appFlags += UIInterfaceOrientationMaskPortraitUpsideDown; + if ([supportedOrientations containsObject:@"UIInterfaceOrientationLandscapeLeft"]) + appFlags += UIInterfaceOrientationMaskLandscapeLeft; + if ([supportedOrientations containsObject:@"UIInterfaceOrientationLandscapeRight"]) + appFlags += UIInterfaceOrientationMaskLandscapeRight; + + return (1 << orientation) & [rootViewController supportedInterfaceOrientations] & appFlags; +} + +- (bool)needsToFlipFrameForOrientation:(UIDeviceOrientation)orientation +{ + sf::Vector2u size = self.sfWindow->getSize(); + return ((!UIDeviceOrientationIsLandscape(orientation) && size.x > size.y) + || (UIDeviceOrientationIsLandscape(orientation) && size.y > size.x)); +} //////////////////////////////////////////////////////////// - (void)deviceOrientationDidChange:(NSNotification *)notification @@ -159,23 +202,20 @@ namespace { // Get the new orientation UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; - // Filter interesting orientations - if ((orientation == UIDeviceOrientationLandscapeLeft) || - (orientation == UIDeviceOrientationLandscapeRight) || - (orientation == UIDeviceOrientationPortrait) || - (orientation == UIDeviceOrientationPortraitUpsideDown)) + if (UIDeviceOrientationIsValidInterfaceOrientation(orientation)) { // Get the new size sf::Vector2u size = self.sfWindow->getSize(); - if (UIDeviceOrientationIsLandscape(orientation)) + // Check if the app can switch to this orientation and if so if the window's size must be adjusted + if ([self supportsOrientation:orientation] && [self needsToFlipFrameForOrientation:orientation]) std::swap(size.x, size.y); // Send a Resized event to the current window sf::Event event; event.type = sf::Event::Resized; - event.size.width = size.x; - event.size.height = size.y; + event.size.width = size.x * backingScaleFactor; + event.size.height = size.y * backingScaleFactor; sfWindow->forwardEvent(event); } } @@ -213,8 +253,8 @@ namespace sf::Event event; event.type = sf::Event::TouchBegan; event.touch.finger = index; - event.touch.x = position.x; - event.touch.y = position.y; + event.touch.x = position.x * backingScaleFactor; + event.touch.y = position.y * backingScaleFactor; sfWindow->forwardEvent(event); } } @@ -234,8 +274,8 @@ namespace sf::Event event; event.type = sf::Event::TouchMoved; event.touch.finger = index; - event.touch.x = position.x; - event.touch.y = position.y; + event.touch.x = position.x * backingScaleFactor; + event.touch.y = position.y * backingScaleFactor; sfWindow->forwardEvent(event); } } @@ -254,8 +294,8 @@ namespace sf::Event event; event.type = sf::Event::TouchEnded; event.touch.finger = index; - event.touch.x = position.x; - event.touch.y = position.y; + event.touch.x = position.x * backingScaleFactor; + event.touch.y = position.y * backingScaleFactor; sfWindow->forwardEvent(event); } } diff --git a/src/SFML/Window/iOS/SFView.hpp b/src/SFML/Window/iOS/SFView.hpp index 1720a609..99056b40 100644 --- a/src/SFML/Window/iOS/SFView.hpp +++ b/src/SFML/Window/iOS/SFView.hpp @@ -47,7 +47,7 @@ /// \return Id of the view /// //////////////////////////////////////////////////////////// --(id)initWithFrame:(CGRect)frame; +- (id)initWithFrame:(CGRect)frame andContentScaleFactor:(CGFloat)factor; //////////////////////////////////////////////////////////// // Member data diff --git a/src/SFML/Window/iOS/SFView.mm b/src/SFML/Window/iOS/SFView.mm index bac46c85..2fc12235 100644 --- a/src/SFML/Window/iOS/SFView.mm +++ b/src/SFML/Window/iOS/SFView.mm @@ -31,7 +31,6 @@ #include #include - @interface SFView() @property (nonatomic) NSMutableArray* touches; @@ -170,16 +169,18 @@ //////////////////////////////////////////////////////////// -+(Class)layerClass ++ (Class)layerClass { return [CAEAGLLayer class]; } - //////////////////////////////////////////////////////////// --(id)initWithFrame:(CGRect)frame +- (id)initWithFrame:(CGRect)frame andContentScaleFactor:(CGFloat)factor { - self = [super initWithFrame:frame]; + self = [super initWithFrame:frame]; + + self.contentScaleFactor = factor; + if (self) { self.context = NULL; diff --git a/src/SFML/Window/iOS/SFViewController.mm b/src/SFML/Window/iOS/SFViewController.mm index 748ced1b..049108bf 100644 --- a/src/SFML/Window/iOS/SFViewController.mm +++ b/src/SFML/Window/iOS/SFViewController.mm @@ -36,8 +36,6 @@ //////////////////////////////////////////////////////////// - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - (void)interfaceOrientation; - return self.orientationCanChange; } diff --git a/src/SFML/Window/iOS/VideoModeImpl.mm b/src/SFML/Window/iOS/VideoModeImpl.mm index 96adb7b0..05deaf1a 100644 --- a/src/SFML/Window/iOS/VideoModeImpl.mm +++ b/src/SFML/Window/iOS/VideoModeImpl.mm @@ -26,9 +26,9 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include - namespace sf { namespace priv @@ -50,7 +50,8 @@ std::vector VideoModeImpl::getFullscreenModes() VideoMode VideoModeImpl::getDesktopMode() { CGRect bounds = [[UIScreen mainScreen] bounds]; - return VideoMode(bounds.size.width, bounds.size.height); + float backingScale = [SFAppDelegate getInstance].backingScaleFactor; + return VideoMode(bounds.size.width * backingScale, bounds.size.height * backingScale); } } // namespace priv diff --git a/src/SFML/Window/iOS/WindowImplUIKit.hpp b/src/SFML/Window/iOS/WindowImplUIKit.hpp index 5bb98ed3..3d4a691b 100644 --- a/src/SFML/Window/iOS/WindowImplUIKit.hpp +++ b/src/SFML/Window/iOS/WindowImplUIKit.hpp @@ -215,6 +215,7 @@ private: SFView* m_view; ///< OpenGL view of the window SFViewController* m_viewController; ///< Controller attached to the view bool m_hasFocus; ///< Current focus state of the window + float m_backingScale; ///< Converts from points to pixels and vice versa }; } // namespace priv diff --git a/src/SFML/Window/iOS/WindowImplUIKit.mm b/src/SFML/Window/iOS/WindowImplUIKit.mm index 4d401b8f..9901b4ec 100644 --- a/src/SFML/Window/iOS/WindowImplUIKit.mm +++ b/src/SFML/Window/iOS/WindowImplUIKit.mm @@ -33,7 +33,6 @@ #include #include - namespace sf { namespace priv @@ -51,6 +50,8 @@ WindowImplUIKit::WindowImplUIKit(VideoMode mode, unsigned long style, const ContextSettings& /*settings*/) { + m_backingScale = [SFAppDelegate getInstance].backingScaleFactor; + // Apply the fullscreen flag [UIApplication sharedApplication].statusBarHidden = !(style & Style::Titlebar) || (style & Style::Fullscreen); @@ -68,8 +69,15 @@ WindowImplUIKit::WindowImplUIKit(VideoMode mode, // Assign it to the application delegate [SFAppDelegate getInstance].sfWindow = this; + CGRect viewRect = frame; + // if UI-orientation doesn't match window-layout, swap the view size and notify the window about it + // iOS 7 and 8 do different stuff here. In iOS 7 frame.x mode.height) != (frame.size.width > frame.size.height)) + std::swap(viewRect.size.width, viewRect.size.height); + // Create the view - m_view = [[SFView alloc] initWithFrame:frame]; + m_view = [[SFView alloc] initWithFrame:viewRect andContentScaleFactor:m_backingScale]; [m_view resignFirstResponder]; // Create the view controller @@ -107,7 +115,8 @@ WindowHandle WindowImplUIKit::getSystemHandle() const //////////////////////////////////////////////////////////// Vector2i WindowImplUIKit::getPosition() const { - return Vector2i(m_window.frame.origin.x, m_window.frame.origin.y); + CGPoint origin = m_window.frame.origin; + return Vector2i(origin.x * m_backingScale, origin.y * m_backingScale); } @@ -120,7 +129,12 @@ void WindowImplUIKit::setPosition(const Vector2i& position) //////////////////////////////////////////////////////////// Vector2u WindowImplUIKit::getSize() const { - return Vector2u(m_window.frame.size.width, m_window.frame.size.height); + auto physicalFrame = m_window.frame; + // iOS 7 and 8 do different stuff here. In iOS 7 frame.x size.y) [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft];