fixes for ios window size including device-orientation-changes and retina support

This commit is contained in:
Sebastian Kohl 2014-12-09 20:38:48 +01:00 committed by Lukas Dürrenberger
parent 2cab5789af
commit cac4d58b3d
9 changed files with 112 additions and 32 deletions

View File

@ -58,8 +58,6 @@
#define GLEXT_GL_FRAMEBUFFER GL_FRAMEBUFFER_OES #define GLEXT_GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
#define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_OES #define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_OES
#define GLEXT_GL_RENDERBUFFER GL_RENDERBUFFER_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_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_OES
#define GLEXT_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_OES #define GLEXT_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_OES
#define GLEXT_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES #define GLEXT_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES

View File

@ -100,11 +100,34 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
- (void)notifyCharacter:(sf::Uint32)character; - (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 // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@property (nonatomic) sf::priv::WindowImplUIKit* sfWindow; ///< Main window of the application @property (nonatomic) sf::priv::WindowImplUIKit* sfWindow; ///< Main window of the application
@property (readonly, nonatomic) CMMotionManager* motionManager; ///< Instance of the motion manager @property (readonly, nonatomic) CMMotionManager* motionManager; ///< Instance of the motion manager
@property (nonatomic) CGFloat backingScaleFactor;
@end @end

View File

@ -50,17 +50,18 @@ namespace
@implementation SFAppDelegate @implementation SFAppDelegate
@synthesize sfWindow; @synthesize sfWindow;
@synthesize backingScaleFactor;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
+(SFAppDelegate*)getInstance + (SFAppDelegate*)getInstance
{ {
return delegateInstance; return delegateInstance;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
-(void)runUserMain - (void)runUserMain
{ {
// Arguments intentionally dropped, see comments in main in sfml-main // Arguments intentionally dropped, see comments in main in sfml-main
sfmlMain(0, NULL); sfmlMain(0, NULL);
@ -73,6 +74,8 @@ namespace
// Save the delegate instance // Save the delegate instance
delegateInstance = self; delegateInstance = self;
[self initBackingScale];
// Instantiate the motion manager // Instantiate the motion manager
self.motionManager = [[CMMotionManager alloc] init]; self.motionManager = [[CMMotionManager alloc] init];
@ -90,6 +93,14 @@ namespace
return true; 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 - (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 - (void)deviceOrientationDidChange:(NSNotification *)notification
@ -159,23 +202,20 @@ namespace
{ {
// Get the new orientation // Get the new orientation
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
// Filter interesting orientations // Filter interesting orientations
if ((orientation == UIDeviceOrientationLandscapeLeft) || if (UIDeviceOrientationIsValidInterfaceOrientation(orientation))
(orientation == UIDeviceOrientationLandscapeRight) ||
(orientation == UIDeviceOrientationPortrait) ||
(orientation == UIDeviceOrientationPortraitUpsideDown))
{ {
// Get the new size // Get the new size
sf::Vector2u size = self.sfWindow->getSize(); 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); std::swap(size.x, size.y);
// Send a Resized event to the current window // Send a Resized event to the current window
sf::Event event; sf::Event event;
event.type = sf::Event::Resized; event.type = sf::Event::Resized;
event.size.width = size.x; event.size.width = size.x * backingScaleFactor;
event.size.height = size.y; event.size.height = size.y * backingScaleFactor;
sfWindow->forwardEvent(event); sfWindow->forwardEvent(event);
} }
} }
@ -213,8 +253,8 @@ namespace
sf::Event event; sf::Event event;
event.type = sf::Event::TouchBegan; event.type = sf::Event::TouchBegan;
event.touch.finger = index; event.touch.finger = index;
event.touch.x = position.x; event.touch.x = position.x * backingScaleFactor;
event.touch.y = position.y; event.touch.y = position.y * backingScaleFactor;
sfWindow->forwardEvent(event); sfWindow->forwardEvent(event);
} }
} }
@ -234,8 +274,8 @@ namespace
sf::Event event; sf::Event event;
event.type = sf::Event::TouchMoved; event.type = sf::Event::TouchMoved;
event.touch.finger = index; event.touch.finger = index;
event.touch.x = position.x; event.touch.x = position.x * backingScaleFactor;
event.touch.y = position.y; event.touch.y = position.y * backingScaleFactor;
sfWindow->forwardEvent(event); sfWindow->forwardEvent(event);
} }
} }
@ -254,8 +294,8 @@ namespace
sf::Event event; sf::Event event;
event.type = sf::Event::TouchEnded; event.type = sf::Event::TouchEnded;
event.touch.finger = index; event.touch.finger = index;
event.touch.x = position.x; event.touch.x = position.x * backingScaleFactor;
event.touch.y = position.y; event.touch.y = position.y * backingScaleFactor;
sfWindow->forwardEvent(event); sfWindow->forwardEvent(event);
} }
} }

View File

@ -47,7 +47,7 @@
/// \return Id of the view /// \return Id of the view
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
-(id)initWithFrame:(CGRect)frame; - (id)initWithFrame:(CGRect)frame andContentScaleFactor:(CGFloat)factor;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data

View File

@ -31,7 +31,6 @@
#include <QuartzCore/CAEAGLLayer.h> #include <QuartzCore/CAEAGLLayer.h>
#include <cstring> #include <cstring>
@interface SFView() @interface SFView()
@property (nonatomic) NSMutableArray* touches; @property (nonatomic) NSMutableArray* touches;
@ -170,16 +169,18 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
+(Class)layerClass + (Class)layerClass
{ {
return [CAEAGLLayer class]; 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) if (self)
{ {
self.context = NULL; self.context = NULL;

View File

@ -36,8 +36,6 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{ {
(void)interfaceOrientation;
return self.orientationCanChange; return self.orientationCanChange;
} }

View File

@ -26,9 +26,9 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/VideoModeImpl.hpp> #include <SFML/Window/VideoModeImpl.hpp>
#include <SFML/Window/iOS/SFAppDelegate.hpp>
#include <UIKit/UIKit.h> #include <UIKit/UIKit.h>
namespace sf namespace sf
{ {
namespace priv namespace priv
@ -50,7 +50,8 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
VideoMode VideoModeImpl::getDesktopMode() VideoMode VideoModeImpl::getDesktopMode()
{ {
CGRect bounds = [[UIScreen mainScreen] bounds]; 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 } // namespace priv

View File

@ -215,6 +215,7 @@ private:
SFView* m_view; ///< OpenGL view of the window SFView* m_view; ///< OpenGL view of the window
SFViewController* m_viewController; ///< Controller attached to the view SFViewController* m_viewController; ///< Controller attached to the view
bool m_hasFocus; ///< Current focus state of the window bool m_hasFocus; ///< Current focus state of the window
float m_backingScale; ///< Converts from points to pixels and vice versa
}; };
} // namespace priv } // namespace priv

View File

@ -33,7 +33,6 @@
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <UIKit/UIKit.h> #include <UIKit/UIKit.h>
namespace sf namespace sf
{ {
namespace priv namespace priv
@ -51,6 +50,8 @@ WindowImplUIKit::WindowImplUIKit(VideoMode mode,
unsigned long style, unsigned long style,
const ContextSettings& /*settings*/) const ContextSettings& /*settings*/)
{ {
m_backingScale = [SFAppDelegate getInstance].backingScaleFactor;
// Apply the fullscreen flag // Apply the fullscreen flag
[UIApplication sharedApplication].statusBarHidden = !(style & Style::Titlebar) || (style & Style::Fullscreen); [UIApplication sharedApplication].statusBarHidden = !(style & Style::Titlebar) || (style & Style::Fullscreen);
@ -68,8 +69,15 @@ WindowImplUIKit::WindowImplUIKit(VideoMode mode,
// Assign it to the application delegate // Assign it to the application delegate
[SFAppDelegate getInstance].sfWindow = this; [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<frame.y always! In iOS 8 it correctly depends on orientation
if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
if ((mode.width > mode.height) != (frame.size.width > frame.size.height))
std::swap(viewRect.size.width, viewRect.size.height);
// Create the view // Create the view
m_view = [[SFView alloc] initWithFrame:frame]; m_view = [[SFView alloc] initWithFrame:viewRect andContentScaleFactor:m_backingScale];
[m_view resignFirstResponder]; [m_view resignFirstResponder];
// Create the view controller // Create the view controller
@ -107,7 +115,8 @@ WindowHandle WindowImplUIKit::getSystemHandle() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Vector2i WindowImplUIKit::getPosition() 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 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<frame.y always! In iOS 8 it correctly depends on orientation
if ((NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
&& UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]))
std::swap(physicalFrame.size.width, physicalFrame.size.height);
return Vector2u(physicalFrame.size.width * m_backingScale, physicalFrame.size.height * m_backingScale);
} }
@ -129,6 +143,10 @@ void WindowImplUIKit::setSize(const Vector2u& size)
{ {
// @todo ... // @todo ...
// if these sizes are required one day, don't forget to scale them!
// size.x /= m_backingScale;
// size.y /= m_backingScale;
// Set the orientation according to the requested size // Set the orientation according to the requested size
if (size.x > size.y) if (size.x > size.y)
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft]; [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft];