# HG changeset patch # User Tim Angus # Date 1327335476 0 # Node ID 46a0bba693ac8d3cf43445161a2d1bcc1d9ade5b # Parent a4be1e781020c14bb5edd5db94eb6d3d813ec8a9 * Fix support for the case where UIScreen.scale is not 1.0 (retina) diff -r a4be1e781020 -r 46a0bba693ac src/video/uikit/SDL_uikitopengles.m --- a/src/video/uikit/SDL_uikitopengles.m Sun Jan 22 23:51:46 2012 -0500 +++ b/src/video/uikit/SDL_uikitopengles.m Mon Jan 23 16:17:56 2012 +0000 @@ -103,10 +103,12 @@ { SDL_uikitopenglview *view; SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + SDL_DisplayData *displaydata = data->displaydata; UIWindow *uiwindow = data->uiwindow; /* construct our view, passing in SDL's OpenGL configuration data */ view = [[SDL_uikitopenglview alloc] initWithFrame: [uiwindow bounds] + scale: data->displaydata->scale retainBacking: _this->gl_config.retained_backing rBits: _this->gl_config.red_size gBits: _this->gl_config.green_size @@ -135,9 +137,10 @@ } /* Make this window the current mouse focus for touch input */ - /* !!! FIXME: only do this if this is the primary screen. */ - SDL_SetMouseFocus(window); - SDL_SetKeyboardFocus(window); + if (displaydata->uiscreen == [UIScreen mainScreen]) { + SDL_SetMouseFocus(window); + SDL_SetKeyboardFocus(window); + } return view; } diff -r a4be1e781020 -r 46a0bba693ac src/video/uikit/SDL_uikitopenglview.h --- a/src/video/uikit/SDL_uikitopenglview.h Sun Jan 22 23:51:46 2012 -0500 +++ b/src/video/uikit/SDL_uikitopenglview.h Mon Jan 23 16:17:56 2012 +0000 @@ -54,6 +54,7 @@ - (void)setCurrentContext; - (id)initWithFrame:(CGRect)frame + scale:(CGFloat)scale retainBacking:(BOOL)retained rBits:(int)rBits gBits:(int)gBits diff -r a4be1e781020 -r 46a0bba693ac src/video/uikit/SDL_uikitopenglview.m --- a/src/video/uikit/SDL_uikitopenglview.m Sun Jan 22 23:51:46 2012 -0500 +++ b/src/video/uikit/SDL_uikitopenglview.m Mon Jan 23 16:17:56 2012 +0000 @@ -37,6 +37,7 @@ } - (id)initWithFrame:(CGRect)frame + scale:(CGFloat)scale retainBacking:(BOOL)retained rBits:(int)rBits gBits:(int)gBits @@ -79,10 +80,9 @@ return nil; } - // !!! FIXME: use the screen this is on! - /* Use the main screen scale (for retina display support) */ + /* Set the appropriate scale (for retina display support) */ if ([self respondsToSelector:@selector(contentScaleFactor)]) - self.contentScaleFactor = [UIScreen mainScreen].scale; + self.contentScaleFactor = scale; /* create the buffers */ glGenFramebuffersOES(1, &viewFramebuffer); diff -r a4be1e781020 -r 46a0bba693ac src/video/uikit/SDL_uikitvideo.h --- a/src/video/uikit/SDL_uikitvideo.h Sun Jan 22 23:51:46 2012 -0500 +++ b/src/video/uikit/SDL_uikitvideo.h Mon Jan 23 16:17:56 2012 +0000 @@ -25,6 +25,14 @@ extern BOOL SDL_UIKit_supports_multiple_displays; +typedef struct SDL_DisplayData SDL_DisplayData; + +struct SDL_DisplayData +{ + UIScreen *uiscreen; + CGFloat scale; +}; + #endif /* _SDL_uikitvideo_h */ /* vi: set ts=4 sw=4 expandtab: */ diff -r a4be1e781020 -r 46a0bba693ac src/video/uikit/SDL_uikitvideo.m --- a/src/video/uikit/SDL_uikitvideo.m Sun Jan 22 23:51:46 2012 -0500 +++ b/src/video/uikit/SDL_uikitvideo.m Mon Jan 23 16:17:56 2012 +0000 @@ -123,14 +123,14 @@ static void UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display) { - UIScreen *uiscreen = (UIScreen *) display->driverdata; + SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; SDL_DisplayMode mode; SDL_zero(mode); // availableModes showed up in 3.2 (the iPad and later). We should only // land here for at least that version of the OS. if (!SDL_UIKit_supports_multiple_displays) { - const CGRect rect = [uiscreen bounds]; + const CGRect rect = [data->uiscreen bounds]; mode.format = SDL_PIXELFORMAT_ABGR8888; mode.refresh_rate = 0; mode.driverdata = NULL; @@ -145,7 +145,7 @@ return; } - for (UIScreenMode *uimode in [uiscreen availableModes]) { + for (UIScreenMode *uimode in [data->uiscreen availableModes]) { CGSize size = [uimode size]; mode.format = SDL_PIXELFORMAT_ABGR8888; mode.refresh_rate = 0; @@ -155,7 +155,7 @@ if (SDL_AddDisplayMode(display, &mode)) [uimode retain]; // retain is needed because of mode.driverdata - if (uiscreen == [UIScreen mainScreen]) { + if (data->uiscreen == [UIScreen mainScreen]) { // Add the mode with swapped width/height mode.w = (int) size.height; mode.h = (int) size.width; @@ -166,15 +166,29 @@ } -static void -UIKit_AddDisplay(UIScreen *uiscreen, int w, int h) +static int +UIKit_AddDisplay(UIScreen *uiscreen, CGSize size) { + // When dealing with UIKit all coordinates are specified in terms of + // what Apple refers to as points. On earlier devices without the + // so called "Retina" display, there is a one to one mapping between + // points and pixels. In other cases [UIScreen scale] indicates the + // relationship between points and pixels. Since SDL has no notion + // of points, we must compensate in all cases where dealing with such + // units. + CGFloat scale; + if ([UIScreen instancesRespondToSelector:@selector(scale)]) { + scale = [uiscreen scale]; // iOS >= 4.0 + } else { + scale = 1.0f; // iOS < 4.0 + } + SDL_VideoDisplay display; SDL_DisplayMode mode; SDL_zero(mode); mode.format = SDL_PIXELFORMAT_ABGR8888; - mode.w = w; - mode.h = h; + mode.w = (int)(size.width * scale); + mode.h = (int)(size.height * scale); mode.refresh_rate = 0; // UIScreenMode showed up in 3.2 (the iPad and later). We're @@ -189,10 +203,24 @@ SDL_zero(display); display.desktop_mode = mode; display.current_mode = mode; + + SDL_DisplayData *data; + /* Allocate the window data */ + data = (SDL_DisplayData *) SDL_malloc(sizeof(*data)); + if (!data) { + SDL_OutOfMemory(); + return -1; + } + [uiscreen retain]; - display.driverdata = uiscreen; + data->uiscreen = uiscreen; + data->scale = scale; + + display.driverdata = data; SDL_AddVideoDisplay(&display); + + return 0; } @@ -207,7 +235,10 @@ // Add the main screen. UIScreen *uiscreen = [UIScreen mainScreen]; const CGSize size = [uiscreen bounds].size; - UIKit_AddDisplay(uiscreen, (int)size.width, (int)size.height); + + if (UIKit_AddDisplay(uiscreen, size) < 0) { + return -1; + } // If this is iPhoneOS < 3.2, all devices are one screen, 320x480 pixels. // The iPad added both a larger main screen and the ability to use @@ -217,7 +248,9 @@ // Only add the other screens if (uiscreen != [UIScreen mainScreen]) { const CGSize size = [uiscreen bounds].size; - UIKit_AddDisplay(uiscreen, (int)size.width, (int)size.height); + if (UIKit_AddDisplay(uiscreen, size) < 0) { + return -1; + } } } } @@ -229,13 +262,13 @@ static int UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) { - UIScreen *uiscreen = (UIScreen *) display->driverdata; + SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; if (!SDL_UIKit_supports_multiple_displays) { // Not on at least iPhoneOS 3.2 (versions prior to iPad). SDL_assert(mode->driverdata == NULL); } else { UIScreenMode *uimode = (UIScreenMode *) mode->driverdata; - [uiscreen setCurrentMode:uimode]; + [data->uiscreen setCurrentMode:uimode]; CGSize size = [uimode size]; if (size.width >= size.height) { @@ -268,8 +301,9 @@ int i, j; for (i = 0; i < _this->num_displays; i++) { SDL_VideoDisplay *display = &_this->displays[i]; - UIScreen *uiscreen = (UIScreen *) display->driverdata; - [uiscreen release]; + SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; + [data->uiscreen release]; + SDL_free(data); display->driverdata = NULL; UIKit_ReleaseUIScreenMode(&display->desktop_mode); UIKit_ReleaseUIScreenMode(&display->current_mode); diff -r a4be1e781020 -r 46a0bba693ac src/video/uikit/SDL_uikitviewcontroller.m --- a/src/video/uikit/SDL_uikitviewcontroller.m Sun Jan 22 23:51:46 2012 -0500 +++ b/src/video/uikit/SDL_uikitviewcontroller.m Mon Jan 23 16:17:56 2012 +0000 @@ -113,11 +113,7 @@ const UIInterfaceOrientation toInterfaceOrientation = [self interfaceOrientation]; SDL_WindowData *data = self->window->driverdata; UIWindow *uiwindow = data->uiwindow; - UIScreen *uiscreen; - if (SDL_UIKit_supports_multiple_displays) - uiscreen = [uiwindow screen]; - else - uiscreen = [UIScreen mainScreen]; + UIScreen *uiscreen = data->displaydata->uiscreen; const int noborder = (self->window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)); CGRect frame = noborder ? [uiscreen bounds] : [uiscreen applicationFrame]; const CGSize size = frame.size; @@ -141,6 +137,9 @@ return; } + w = (int)(w * data->displaydata->scale); + h = (int)(h * data->displaydata->scale); + [uiwindow setFrame:frame]; [data->view setFrame:frame]; [data->view updateFrame]; diff -r a4be1e781020 -r 46a0bba693ac src/video/uikit/SDL_uikitwindow.h --- a/src/video/uikit/SDL_uikitwindow.h Sun Jan 22 23:51:46 2012 -0500 +++ b/src/video/uikit/SDL_uikitwindow.h Mon Jan 23 16:17:56 2012 +0000 @@ -22,6 +22,7 @@ #define _SDL_uikitwindow_h #include "../SDL_sysvideo.h" +#import "SDL_uikitvideo.h" #import "SDL_uikitopenglview.h" #import "SDL_uikitviewcontroller.h" @@ -40,6 +41,7 @@ UIWindow *uiwindow; SDL_uikitopenglview *view; SDL_uikitviewcontroller *viewcontroller; + SDL_DisplayData *displaydata; }; #endif /* _SDL_uikitwindow_h */ diff -r a4be1e781020 -r 46a0bba693ac src/video/uikit/SDL_uikitwindow.m --- a/src/video/uikit/SDL_uikitwindow.m Sun Jan 22 23:51:46 2012 -0500 +++ b/src/video/uikit/SDL_uikitwindow.m Mon Jan 23 16:17:56 2012 +0000 @@ -46,7 +46,7 @@ static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created) { SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); - UIScreen *uiscreen = (UIScreen *) display->driverdata; + SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata; SDL_WindowData *data; /* Allocate the window data */ @@ -58,30 +58,35 @@ data->uiwindow = uiwindow; data->viewcontroller = nil; data->view = nil; + data->displaydata = displaydata; /* Fill in the SDL window with the window data */ { window->x = 0; window->y = 0; + /* Get frame dimensions in pixels */ + int width = (int)(uiwindow.frame.size.width * displaydata->scale); + int height = (int)(uiwindow.frame.size.height * displaydata->scale); + /* We can pick either width or height here and we'll rotate the screen to match, so we pick the closest to what we wanted. */ if (window->w >= window->h) { if (uiwindow.frame.size.width > uiwindow.frame.size.height) { - window->w = (int)uiwindow.frame.size.width; - window->h = (int)uiwindow.frame.size.height; + window->w = width; + window->h = height; } else { - window->w = (int)uiwindow.frame.size.height; - window->h = (int)uiwindow.frame.size.width; + window->w = height; + window->h = width; } } else { if (uiwindow.frame.size.width > uiwindow.frame.size.height) { - window->w = (int)uiwindow.frame.size.height; - window->h = (int)uiwindow.frame.size.width; + window->w = height; + window->h = width; } else { - window->w = (int)uiwindow.frame.size.width; - window->h = (int)uiwindow.frame.size.height; + window->w = width; + window->h = height; } } } @@ -95,7 +100,7 @@ // SDL_WINDOW_BORDERLESS controls whether status bar is hidden. // This is only set if the window is on the main screen. Other screens // just force the window to have the borderless flag. - if ([UIScreen mainScreen] != uiscreen) { + if ([UIScreen mainScreen] != displaydata->uiscreen) { window->flags &= ~SDL_WINDOW_RESIZABLE; // window is NEVER resizeable window->flags &= ~SDL_WINDOW_INPUT_FOCUS; // never has input focus window->flags |= SDL_WINDOW_BORDERLESS; // never has a status bar. @@ -131,8 +136,8 @@ UIKit_CreateWindow(_THIS, SDL_Window *window) { SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); - UIScreen *uiscreen = (UIScreen *) display->driverdata; - const BOOL external = ([UIScreen mainScreen] != uiscreen); + SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; + const BOOL external = ([UIScreen mainScreen] != data->uiscreen); // SDL currently puts this window at the start of display's linked list. We rely on this. SDL_assert(_this->windows == window); @@ -154,7 +159,7 @@ // user, so it's in standby), try to force the display to a resolution // that most closely matches the desired window size. if (SDL_UIKit_supports_multiple_displays) { - const CGSize origsize = [[uiscreen currentMode] size]; + const CGSize origsize = [[data->uiscreen currentMode] size]; if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) { if (display->num_display_modes == 0) { _this->GetDisplayModes(_this, display); @@ -170,7 +175,7 @@ if (bestmode) { UIScreenMode *uimode = (UIScreenMode *) bestmode->driverdata; - [uiscreen setCurrentMode:uimode]; + [data->uiscreen setCurrentMode:uimode]; // desktop_mode doesn't change here (the higher level will // use it to set all the screens back to their defaults @@ -186,16 +191,16 @@ // !!! FIXME: can we have a smaller view? UIWindow *uiwindow = [UIWindow alloc]; if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) - uiwindow = [uiwindow initWithFrame:[uiscreen bounds]]; + uiwindow = [uiwindow initWithFrame:[data->uiscreen bounds]]; else - uiwindow = [uiwindow initWithFrame:[uiscreen applicationFrame]]; + uiwindow = [uiwindow initWithFrame:[data->uiscreen applicationFrame]]; // put the window on an external display if appropriate. This implicitly // does [uiwindow setframe:[uiscreen bounds]], so don't do it on the // main display, where we land by default, as that would eat the // status bar real estate. if (external) { - [uiwindow setScreen:uiscreen]; + [uiwindow setScreen:data->uiscreen]; } if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) { @@ -210,35 +215,39 @@ void UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) { - UIScreen *uiscreen = (UIScreen *) display->driverdata; + SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow; if (fullscreen) { [UIApplication sharedApplication].statusBarHidden = YES; - uiwindow.frame = [uiscreen bounds]; + uiwindow.frame = [data->uiscreen bounds]; } else { [UIApplication sharedApplication].statusBarHidden = NO; - uiwindow.frame = [uiscreen applicationFrame]; + uiwindow.frame = [data->uiscreen applicationFrame]; } + /* Get frame dimensions in pixels */ + int width = (int)(uiwindow.frame.size.width * data->scale); + int height = (int)(uiwindow.frame.size.height * data->scale); + /* We can pick either width or height here and we'll rotate the screen to match, so we pick the closest to what we wanted. */ if (window->w >= window->h) { if (uiwindow.frame.size.width > uiwindow.frame.size.height) { - window->w = (int)uiwindow.frame.size.width; - window->h = (int)uiwindow.frame.size.height; + window->w = width; + window->h = height; } else { - window->w = (int)uiwindow.frame.size.height; - window->h = (int)uiwindow.frame.size.width; + window->w = height; + window->h = width; } } else { if (uiwindow.frame.size.width > uiwindow.frame.size.height) { - window->w = (int)uiwindow.frame.size.height; - window->h = (int)uiwindow.frame.size.width; + window->w = height; + window->h = width; } else { - window->w = (int)uiwindow.frame.size.width; - window->h = (int)uiwindow.frame.size.height; + window->w = width; + window->h = height; } } }