Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Commit

Permalink
* On iOS, fix support for the case where [UIScreen scale] is not 1.0 …
Browse files Browse the repository at this point in the history
…(retina)

* Allow selection of non-retina modes on retina devices
  • Loading branch information
Tim Angus committed Jan 25, 2012
1 parent bc0b07c commit 9c4c413
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 95 deletions.
11 changes: 8 additions & 3 deletions src/video/uikit/SDL_uikitopengles.m
Expand Up @@ -103,10 +103,14 @@ SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window)
{
SDL_uikitopenglview *view;
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
SDL_DisplayData *displaydata = display->driverdata;
SDL_DisplayModeData *displaymodedata = display->current_mode.driverdata;
UIWindow *uiwindow = data->uiwindow;

/* construct our view, passing in SDL's OpenGL configuration data */
view = [[SDL_uikitopenglview alloc] initWithFrame: [uiwindow bounds]
scale: displaymodedata->scale
retainBacking: _this->gl_config.retained_backing
rBits: _this->gl_config.red_size
gBits: _this->gl_config.green_size
Expand Down Expand Up @@ -135,9 +139,10 @@ SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window)
}

/* 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;
}
Expand Down
1 change: 1 addition & 0 deletions src/video/uikit/SDL_uikitopenglview.h
Expand Up @@ -54,6 +54,7 @@
- (void)setCurrentContext;

- (id)initWithFrame:(CGRect)frame
scale:(CGFloat)scale
retainBacking:(BOOL)retained
rBits:(int)rBits
gBits:(int)gBits
Expand Down
6 changes: 3 additions & 3 deletions src/video/uikit/SDL_uikitopenglview.m
Expand Up @@ -37,6 +37,7 @@ + (Class)layerClass
}

- (id)initWithFrame:(CGRect)frame
scale:(CGFloat)scale
retainBacking:(BOOL)retained
rBits:(int)rBits
gBits:(int)gBits
Expand Down Expand Up @@ -79,10 +80,9 @@ - (id)initWithFrame:(CGRect)frame
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);
Expand Down
16 changes: 16 additions & 0 deletions src/video/uikit/SDL_uikitvideo.h
Expand Up @@ -25,6 +25,22 @@

extern BOOL SDL_UIKit_supports_multiple_displays;

typedef struct SDL_DisplayData SDL_DisplayData;

struct SDL_DisplayData
{
UIScreen *uiscreen;
CGFloat scale;
};

typedef struct SDL_DisplayModeData SDL_DisplayModeData;

struct SDL_DisplayModeData
{
UIScreenMode *uiscreenmode;
CGFloat scale;
};

#endif /* _SDL_uikitvideo_h */

/* vi: set ts=4 sw=4 expandtab: */
205 changes: 150 additions & 55 deletions src/video/uikit/SDL_uikitvideo.m
Expand Up @@ -120,79 +120,167 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device)
*/

static void
UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
static int
UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h,
UIScreenMode * uiscreenmode, CGFloat scale)
{
UIScreen *uiscreen = (UIScreen *) 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];
mode.format = SDL_PIXELFORMAT_ABGR8888;
mode.refresh_rate = 0;
mode.driverdata = NULL;

mode.w = (int) rect.size.width;
mode.h = (int) rect.size.height;
SDL_AddDisplayMode(display, &mode);

mode.w = (int) rect.size.height; // swap the orientation, add again.
mode.h = (int) rect.size.width;
SDL_AddDisplayMode(display, &mode);
return;

SDL_DisplayModeData *data = NULL;

if (uiscreenmode != nil) {
/* Allocate the display mode data */
data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
if (!data) {
SDL_OutOfMemory();
return -1;
}

data->uiscreenmode = uiscreenmode;
data->scale = scale;
}

for (UIScreenMode *uimode in [uiscreen availableModes]) {
CGSize size = [uimode size];
mode.format = SDL_PIXELFORMAT_ABGR8888;
mode.refresh_rate = 0;
mode.driverdata = uimode;
mode.w = (int) size.width;
mode.h = (int) size.height;
if (SDL_AddDisplayMode(display, &mode))
[uimode retain]; // retain is needed because of mode.driverdata

if (uiscreen == [UIScreen mainScreen]) {
// Add the mode with swapped width/height
mode.w = (int) size.height;
mode.h = (int) size.width;
if (SDL_AddDisplayMode(display, &mode))
[uimode retain];

mode.format = SDL_PIXELFORMAT_ABGR8888;
mode.refresh_rate = 0;
mode.driverdata = data;

mode.w = w;
mode.h = h;
if (SDL_AddDisplayMode(display, &mode)) {
if (uiscreenmode != nil) {
[uiscreenmode retain];
}

return 0;
}

SDL_free(data);

return -1;
}

static int
UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, CGFloat scale,
UIScreenMode * uiscreenmode, BOOL rotated)
{
if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode, scale) < 0) {
return -1;
}

if (rotated) {
// Add the rotated version
if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode, scale) < 0) {
return -1;
}
}

return 0;
}

static void
UIKit_AddDisplay(UIScreen *uiscreen, int w, int h)
UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
{
SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;

if (SDL_UIKit_supports_multiple_displays) {
// availableModes showed up in 3.2 (the iPad and later). We should only
// land here for at least that version of the OS.
for (UIScreenMode *uimode in [data->uiscreen availableModes]) {
BOOL mainscreen = (data->uiscreen == [UIScreen mainScreen]);
CGSize size = [uimode size];
int w = (int)size.width;
int h = (int)size.height;

// Add the native screen resolution.
UIKit_AddDisplayMode(display, w, h, data->scale, uimode, mainscreen);

if (data->scale != 1.0f) {
// Add the native screen resolution divided by its scale.
// This is so devices capable of e.g. 640x960 also advertise
// 320x480.
UIKit_AddDisplayMode(display,
(int)(w / data->scale), (int)(h / data->scale),
1.0f, uimode, mainscreen);
}
}
} else {
const CGRect rect = [data->uiscreen bounds];
UIKit_AddDisplayMode(display,
(int)rect.size.width, (int)rect.size.height,
1.0f, nil, YES);
}
}


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
// misusing this supports_multiple_displays flag here for that.
if (SDL_UIKit_supports_multiple_displays) {
UIScreenMode *uimode = [uiscreen currentMode];
[uimode retain]; // once for the desktop_mode
[uimode retain]; // once for the current_mode
mode.driverdata = uimode;
SDL_DisplayModeData *data;

/* Allocate the mode data */
data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
if (!data) {
SDL_OutOfMemory();
return -1;
}

data->uiscreenmode = [uiscreen currentMode];
[data->uiscreenmode retain]; // once for the desktop_mode
[data->uiscreenmode retain]; // once for the current_mode

data->scale = scale;

mode.driverdata = data;
}

SDL_zero(display);
display.desktop_mode = mode;
display.current_mode = mode;

SDL_DisplayData *data;

/* Allocate the display data */
data = (SDL_DisplayData *) SDL_malloc(sizeof(*data));
if (!data) {
SDL_free(mode.driverdata);
SDL_OutOfMemory();
return -1;
}

[uiscreen retain];
display.driverdata = uiscreen;
data->uiscreen = uiscreen;
data->scale = scale;

display.driverdata = data;
SDL_AddVideoDisplay(&display);

return 0;
}


Expand All @@ -207,7 +295,10 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device)
// 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
Expand All @@ -217,7 +308,9 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device)
// 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;
}
}
}
}
Expand All @@ -229,15 +322,15 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device)
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];
SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
[data->uiscreen setCurrentMode:modedata->uiscreenmode];

CGSize size = [uimode size];
CGSize size = [modedata->uiscreenmode size];
if (size.width >= size.height) {
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
} else {
Expand All @@ -255,8 +348,9 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device)
// Not on at least iPhoneOS 3.2 (versions prior to iPad).
SDL_assert(mode->driverdata == NULL);
} else {
UIScreenMode *uimode = (UIScreenMode *) mode->driverdata;
[uimode release];
SDL_DisplayModeData *data = (SDL_DisplayModeData *)mode->driverdata;
[data->uiscreenmode release];
SDL_free(data);
mode->driverdata = NULL;
}
}
Expand All @@ -268,8 +362,9 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device)
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);
Expand Down
12 changes: 7 additions & 5 deletions src/video/uikit/SDL_uikitviewcontroller.m
Expand Up @@ -113,11 +113,10 @@ - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceO
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];
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(self->window);
SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
UIScreen *uiscreen = 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;
Expand All @@ -141,6 +140,9 @@ - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceO
return;
}

w = (int)(w * displaymodedata->scale);
h = (int)(h * displaymodedata->scale);

[uiwindow setFrame:frame];
[data->view setFrame:frame];
[data->view updateFrame];
Expand Down
1 change: 1 addition & 0 deletions src/video/uikit/SDL_uikitwindow.h
Expand Up @@ -22,6 +22,7 @@
#define _SDL_uikitwindow_h

#include "../SDL_sysvideo.h"
#import "SDL_uikitvideo.h"
#import "SDL_uikitopenglview.h"
#import "SDL_uikitviewcontroller.h"

Expand Down

0 comments on commit 9c4c413

Please sign in to comment.