Added orientation rotation for iOS.
authorRyan C. Gordon <icculus@icculus.org>
Mon, 28 Mar 2011 23:21:22 -0400
changeset 5520 09b500e0656d
parent 5519 c425e4e8fc75
child 5521 ef550bdb8c1b
Added orientation rotation for iOS.
src/video/uikit/SDL_uikitopengles.m
src/video/uikit/SDL_uikitopenglview.m
src/video/uikit/SDL_uikitview.h
src/video/uikit/SDL_uikitwindow.h
src/video/uikit/SDL_uikitwindow.m
test/testgles.c
test/testsprite2.c
--- a/src/video/uikit/SDL_uikitopengles.m	Mon Mar 28 15:18:01 2011 -0400
+++ b/src/video/uikit/SDL_uikitopengles.m	Mon Mar 28 23:21:22 2011 -0400
@@ -117,13 +117,15 @@
                                     majorVersion: _this->gl_config.major_version];
     
     data->view = view;
-    
+    view->viewcontroller = data->viewcontroller;
+    if (view->viewcontroller != nil) {
+        [view->viewcontroller setView:view];
+        [view->viewcontroller retain];
+    }
+
     /* add the view to our window */
     [uiwindow addSubview: view ];
-    
-    /* Don't worry, the window retained the view */
-    [view release];
-    
+
     if ( UIKit_GL_MakeCurrent(_this, window, view) < 0 ) {
         UIKit_GL_DeleteContext(_this, view);
         return NULL;
@@ -140,8 +142,12 @@
 {
     /* the delegate has retained the view, this will release him */
     SDL_uikitopenglview *view = (SDL_uikitopenglview *)context;
-    /* this will also delete it */
+    if (view->viewcontroller) {
+        [view->viewcontroller setView:nil];
+        [view->viewcontroller release];
+    }
     [view removeFromSuperview];
+    [view release];
 }
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/uikit/SDL_uikitopenglview.m	Mon Mar 28 15:18:01 2011 -0400
+++ b/src/video/uikit/SDL_uikitopenglview.m	Mon Mar 28 23:21:22 2011 -0400
@@ -121,9 +121,12 @@
         }
         /* end create buffers */
 
+        // !!! FIXME: use the screen this is on!
         /* Use the main screen scale (for retina display support) */
         if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
             self.contentScaleFactor = [UIScreen mainScreen].scale;
+
+        self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
     }
     return self;
 }
--- a/src/video/uikit/SDL_uikitview.h	Mon Mar 28 15:18:01 2011 -0400
+++ b/src/video/uikit/SDL_uikitview.h	Mon Mar 28 23:21:22 2011 -0400
@@ -30,6 +30,16 @@
 #define MAX_SIMULTANEOUS_TOUCHES 5
 #endif
 
+@interface SDL_uikitviewcontroller : UIViewController {
+@private
+    SDL_Window *window;
+}
+- (id)initWithSDLWindow:(SDL_Window *)_window;
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient;
+- (void)loadView;
+- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
+@end
+
 /* *INDENT-OFF* */
 #if SDL_IPHONE_KEYBOARD
 @interface SDL_uikitview : UIView<UITextFieldDelegate> {
@@ -48,7 +58,9 @@
     UITextField *textField;
     BOOL keyboardVisible;
 #endif    
-    
+
+@public
+    SDL_uikitviewcontroller *viewcontroller;
 }
 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
--- a/src/video/uikit/SDL_uikitwindow.h	Mon Mar 28 15:18:01 2011 -0400
+++ b/src/video/uikit/SDL_uikitwindow.h	Mon Mar 28 23:21:22 2011 -0400
@@ -40,6 +40,7 @@
 {
     UIWindow *uiwindow;
     SDL_uikitopenglview *view;
+    SDL_uikitviewcontroller *viewcontroller;
 };
 
 
--- a/src/video/uikit/SDL_uikitwindow.m	Mon Mar 28 15:18:01 2011 -0400
+++ b/src/video/uikit/SDL_uikitwindow.m	Mon Mar 28 23:21:22 2011 -0400
@@ -38,6 +38,58 @@
 
 #include <Foundation/Foundation.h>
 
+@implementation SDL_uikitviewcontroller
+
+- (id)initWithSDLWindow:(SDL_Window *)_window {
+    [self init];
+    self->window = _window;
+    return self;
+}
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient {
+    return YES;
+}
+
+- (void)loadView  {
+    // do nothing.
+}
+
+// Send a resized event when the orientation changes.
+- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
+    SDL_WindowData *data = self->window->driverdata;
+    UIWindow *uiwindow = data->uiwindow;
+    CGRect frame = [uiwindow frame];
+    const CGSize size = frame.size;
+    int w, h;
+
+    switch (toInterfaceOrientation) {
+        case UIInterfaceOrientationPortrait:
+        case UIInterfaceOrientationPortraitUpsideDown:
+            w = (size.width < size.height) ? size.width : size.height;
+            h = (size.width > size.height) ? size.width : size.height;
+            break;
+
+        case UIInterfaceOrientationLandscapeLeft:
+        case UIInterfaceOrientationLandscapeRight:
+            w = (size.width > size.height) ? size.width : size.height;
+            h = (size.width < size.height) ? size.width : size.height;
+            break;
+
+        default:
+            SDL_assert(0 && "Unexpected interface orientation!");
+            return;
+    }
+    self->window->w = w;
+    self->window->h = h;
+    frame.size.width = w;
+    frame.size.height = h;
+    SDL_SendWindowEvent(self->window, SDL_WINDOWEVENT_RESIZED, w, h);
+}
+
+@end
+
+
+
 static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created)
 {
     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
@@ -51,6 +103,7 @@
         return -1;
     }
     data->uiwindow = uiwindow;
+    data->viewcontroller = nil;
     data->view = nil;
 
     /* Fill in the SDL window with the window data */
@@ -62,9 +115,11 @@
     }
     
     window->driverdata = data;
-    
+
+    // !!! FIXME: should we force this? Shouldn't specifying FULLSCREEN
+    // !!! FIXME:  imply BORDERLESS?
     window->flags |= SDL_WINDOW_FULLSCREEN;        /* window is always fullscreen */
-    window->flags |= SDL_WINDOW_SHOWN;            /* only one window on iPod touch, always shown */
+    window->flags |= SDL_WINDOW_SHOWN;            /* only one window on iOS, always shown */
 
     // SDL_WINDOW_BORDERLESS controls whether status bar is hidden.
     // This is only set if the window is on the main screen. Other screens
@@ -72,6 +127,7 @@
     if ([UIScreen mainScreen] != 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.
     } else {
         window->flags |= SDL_WINDOW_INPUT_FOCUS;  // always has input focus
 
@@ -81,21 +137,34 @@
             [UIApplication sharedApplication].statusBarHidden = NO;
         }
 
-        // Rotate the view if we have to, but only on the main screen
-        //  (presumably, an external display doesn't report orientation).
         const CGSize uisize = [[uiscreen currentMode] size];
-        if ( ((window->w > window->h) && (uisize.width < uisize.height)) ||
-             ((window->w < window->h) && (uisize.width > uisize.height)) ) {
-            // !!! FIXME: flip orientation.
-        }
+        const UIDeviceOrientation o = [[UIDevice currentDevice] orientation];
+        const BOOL landscape = (o == UIDeviceOrientationLandscapeLeft) ||
+                                   (o == UIDeviceOrientationLandscapeRight);
+        const BOOL rotate = ( ((window->w > window->h) && (!landscape)) ||
+                              ((window->w < window->h) && (landscape)) );
 
         if (window->flags & SDL_WINDOW_RESIZABLE) {
-            // !!! FIXME: register for orientation change alerts.
+            // The View Controller will handle rotating the view when the
+            //  device orientation changes. We expose these as resize events.
+            SDL_uikitviewcontroller *controller;
+            controller = [SDL_uikitviewcontroller alloc];
+            data->viewcontroller = [controller initWithSDLWindow:window];
+            [data->viewcontroller setTitle:@"SDL App"];  // !!! FIXME: hook up SDL_SetWindowTitle()
+            // !!! FIXME: if (rotate), force a "resize" right at the start
+        } else {
+            // Rotate the view if we have to, but only on the main screen
+            //  (presumably, an external display doesn't report orientation).
+            if (rotate) {
+                #define D2R(x) (M_PI * (x) / 180.0)   // degrees to radians.
+                [uiwindow setTransform:CGAffineTransformIdentity];
+                [uiwindow setTransform:CGAffineTransformMakeRotation(D2R(90))];
+                #undef D2R
+            }
         }
     }
 
     return 0;
-    
 }
 
 int
@@ -107,7 +176,7 @@
     // SDL currently puts this window at the start of display's linked list. We rely on this.
     SDL_assert(_this->windows == window);
 
-    /* We currently only handle a single window per display on iPhone */
+    /* We currently only handle a single window per display on iOS */
     if (window->next != NULL) {
         SDL_SetError("Only one window allowed per display.");
         return -1;
@@ -172,6 +241,7 @@
 UIKit_DestroyWindow(_THIS, SDL_Window * window) {
     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
     if (data) {
+        [data->viewcontroller release];
         [data->uiwindow release];
         SDL_free(data);
         window->driverdata = NULL;
--- a/test/testgles.c	Mon Mar 28 15:18:01 2011 -0400
+++ b/test/testgles.c	Mon Mar 28 23:21:22 2011 -0400
@@ -140,7 +140,7 @@
     }
 
     /* Set OpenGL parameters */
-    state->window_flags |= SDL_WINDOW_OPENGL;
+    state->window_flags |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS;
     state->gl_red_size = 5;
     state->gl_green_size = 5;
     state->gl_blue_size = 5;
--- a/test/testsprite2.c	Mon Mar 28 15:18:01 2011 -0400
+++ b/test/testsprite2.c	Mon Mar 28 23:21:22 2011 -0400
@@ -219,6 +219,9 @@
     if (!state) {
         return 1;
     }
+
+    state->window_flags |= SDL_WINDOW_RESIZABLE;
+
     for (i = 1; i < argc;) {
         int consumed;