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_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

View File

@ -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

View File

@ -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);
}
}

View File

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

View File

@ -31,7 +31,6 @@
#include <QuartzCore/CAEAGLLayer.h>
#include <cstring>
@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;

View File

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

View File

@ -26,9 +26,9 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/VideoModeImpl.hpp>
#include <SFML/Window/iOS/SFAppDelegate.hpp>
#include <UIKit/UIKit.h>
namespace sf
{
namespace priv
@ -50,7 +50,8 @@ std::vector<VideoMode> 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

View File

@ -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

View File

@ -33,7 +33,6 @@
#include <SFML/System/Err.hpp>
#include <UIKit/UIKit.h>
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<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
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<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 ...
// 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
if (size.x > size.y)
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft];