From 90e466fab465d0c0062bd7706bcc8c4518313e91 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 29 Apr 2010 22:53:18 -0400 Subject: [PATCH] Implemented display mode functionality for UIKit. The iPad (and iPhoneOS 3.2) introduce both a larger screen and the ability to enumerate and configure external displays. This hooks up SDL's multi-display API to this new functionality, and removes the hardcoded iPhone resolution. --- src/video/uikit/SDL_uikitvideo.m | 146 ++++++++++++++++++++++++++----- 1 file changed, 125 insertions(+), 21 deletions(-) diff --git a/src/video/uikit/SDL_uikitvideo.m b/src/video/uikit/SDL_uikitvideo.m index 6cfb97d96..dd5454882 100644 --- a/src/video/uikit/SDL_uikitvideo.m +++ b/src/video/uikit/SDL_uikitvideo.m @@ -19,6 +19,9 @@ Sam Lantinga slouken@libsdl.org */ + +#import + #include "SDL_config.h" #include "SDL_video.h" @@ -35,14 +38,19 @@ #include "SDL_renderer_sw.h" #include "SDL_renderer_gles.h" +#include "SDL_assert.h" + #define UIKITVID_DRIVER_NAME "uikit" /* Initialization/Query functions */ static int UIKit_VideoInit(_THIS); +static void UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display); static int UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); static void UIKit_VideoQuit(_THIS); +static BOOL supports_multiple_displays = NO; + /* DUMMY driver bootstrap functions */ static int @@ -74,6 +82,7 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device) /* Set the function pointers */ device->VideoInit = UIKit_VideoInit; device->VideoQuit = UIKit_VideoQuit; + device->GetDisplayModes = UIKit_GetDisplayModes; device->SetDisplayMode = UIKit_SetDisplayMode; device->PumpEvents = UIKit_PumpEvents; device->CreateWindow = UIKit_CreateWindow; @@ -100,33 +109,103 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device) }; -int -UIKit_VideoInit(_THIS) +/* +!!! FIXME: + +The main screen should list a AxB mode for portrait orientation, and then + also list BxA for landscape mode. When setting a given resolution, we should + rotate the view's transform appropriately (extra credit if you check the + accelerometer and rotate the display so it's never upside down). + + http://iphonedevelopment.blogspot.com/2008/10/starting-in-landscape-mode-without.html + +*/ + +static void +UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display) { + const UIScreen *screen = (UIScreen *) display->driverdata; SDL_DisplayMode mode; - - _this->gl_config.driver_loaded = 1; + 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 (!supports_multiple_displays) { + const CGRect rect = [screen bounds]; + mode.format = SDL_PIXELFORMAT_ABGR8888; + mode.w = (int) rect.size.width; + mode.h = (int) rect.size.height; + mode.refresh_rate = 0; + mode.driverdata = NULL; + SDL_AddDisplayMode(display, &mode); + return; + } + + const NSArray *modes = [screen availableModes]; + const NSUInteger mode_count = [modes count]; + NSUInteger i; + for (i = 0; i < mode_count; i++) { + UIScreenMode *uimode = (UIScreenMode *) [modes objectAtIndex:i]; + const CGSize size = [uimode size]; + mode.format = SDL_PIXELFORMAT_ABGR8888; + mode.w = (int) size.width; + mode.h = (int) size.height; + mode.refresh_rate = 0; + mode.driverdata = uimode; + [uimode retain]; + SDL_AddDisplayMode(display, &mode); + } +} - SDL_VideoDisplay display; - SDL_zero(display); - /* Use a 32-bpp desktop mode */ +static void +UIKit_AddDisplay(UIScreen *screen, int w, int h) +{ + SDL_VideoDisplay display; + SDL_DisplayMode mode; + SDL_zero(mode); - mode.format = SDL_PIXELFORMAT_ABGR8888; - mode.w = 320; - mode.h = 480; + mode.format = SDL_PIXELFORMAT_ABGR8888; + mode.w = w; + mode.h = h; mode.refresh_rate = 0; - mode.driverdata = NULL; - - display.num_display_modes = 1; - display.max_display_modes = 1; - display.display_modes = (SDL_DisplayMode *)SDL_malloc(display.max_display_modes * sizeof(SDL_DisplayMode)); - - display.display_modes[0] = mode; - display.desktop_mode = mode; - display.current_mode = mode; - - SDL_AddVideoDisplay(&display); + + SDL_zero(display); + display.desktop_mode = mode; + display.current_mode = mode; + display.driverdata = screen; + [screen retain]; + SDL_AddVideoDisplay(&display); +} + + +int +UIKit_VideoInit(_THIS) +{ + _this->gl_config.driver_loaded = 1; + + const float version = [[[UIDevice currentDevice] systemVersion] floatValue]; + supports_multiple_displays = (version >= 3.2f); + + // 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 + // external displays. + if (!supports_multiple_displays) { + // Just give 'em the whole main screen. + UIScreen *screen = [UIScreen mainScreen]; + const CGRect rect = [screen bounds]; + UIKit_AddDisplay(screen, (int)rect.size.width, (int)rect.size.height); + } else { + const NSArray *screens = [UIScreen screens]; + const NSUInteger screen_count = [screens count]; + NSUInteger i; + for (i = 0; i < screen_count; i++) { + // the main screen is the first element in the array. + UIScreen *screen = (UIScreen *) [screens objectAtIndex:i]; + const CGSize size = [[screen currentMode] size]; + UIKit_AddDisplay(screen, (int) size.width, (int) size.height); + } + } /* We're done! */ return 0; @@ -135,12 +214,37 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device) static int UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) { + UIScreen *screen = (UIScreen *) display->driverdata; + if (!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; + [screen setCurrentMode:uimode]; + } + return 0; } void UIKit_VideoQuit(_THIS) { + // Release Objective-C objects, so higher level doesn't free() them. + int i, j; + for (i = 0; i < _this->num_displays; i++) { + SDL_VideoDisplay *display = &_this->displays[i]; + UIScreen *screen = (UIScreen *) display->driverdata; + [((UIScreen *) display->driverdata) release]; + display->driverdata = NULL; + for (j = 0; j < display->num_display_modes; j++) { + SDL_DisplayMode *mode = &display->display_modes[j]; + UIScreenMode *uimode = (UIScreenMode *) mode->driverdata; + if (uimode) { + [uimode release]; + mode->driverdata = NULL; + } + } + } } /* vi: set ts=4 sw=4 expandtab: */