diff src/video/uikit/SDL_uikitvideo.m @ 4443:c598e440c87c

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.
author Ryan C. Gordon <icculus@icculus.org>
date Thu, 29 Apr 2010 22:53:18 -0400
parents 41253c0fa9b3
children 06becafcac89
line wrap: on
line diff
--- a/src/video/uikit/SDL_uikitvideo.m	Fri Apr 23 02:19:34 2010 -0700
+++ b/src/video/uikit/SDL_uikitvideo.m	Thu Apr 29 22:53:18 2010 -0400
@@ -19,6 +19,9 @@
     Sam Lantinga
     slouken@libsdl.org
 */
+
+#import <UIKit/UIKit.h>
+
 #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 @@
     /* 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 @@
 };
 
 
+/*
+!!! 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;
+    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);
+    }
+}
+
+
+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 = w;
+    mode.h = h;
+    mode.refresh_rate = 0;
+
+    SDL_zero(display);
+    display.desktop_mode = mode;
+    display.current_mode = mode;
+    display.driverdata = screen;
+    [screen retain];
+    SDL_AddVideoDisplay(&display);
+}
+
+
 int
 UIKit_VideoInit(_THIS)
 {
-    SDL_DisplayMode mode;
-		
-	_this->gl_config.driver_loaded = 1;
+    _this->gl_config.driver_loaded = 1;
 
-	SDL_VideoDisplay display;
-	SDL_zero(display);
+    const float version = [[[UIDevice currentDevice] systemVersion] floatValue];
+    supports_multiple_displays = (version >= 3.2f);
 
-    /* Use a 32-bpp desktop mode */
-    SDL_zero(mode);
-	mode.format = SDL_PIXELFORMAT_ABGR8888;
-    mode.w = 320;
-    mode.h = 480;
-    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);
+    // 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 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: */