mirror of https://github.com/encounter/SDL.git
Merged default into iOS-improvements
This commit is contained in:
commit
df98b11c47
|
@ -8,6 +8,9 @@ Makefile
|
|||
sdl-config
|
||||
SDL2.spec
|
||||
build
|
||||
Build
|
||||
*xcuserdata*
|
||||
*xcworkspacedata*
|
||||
|
||||
# for Xcode
|
||||
*.orig
|
||||
|
|
|
@ -387,6 +387,9 @@ main(int argc, char *argv[])
|
|||
SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
||||
|
||||
/* create main window and renderer */
|
||||
window = SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
|
||||
SDL_WINDOW_OPENGL |
|
||||
|
|
|
@ -1274,8 +1274,14 @@
|
|||
FD6526640DE8FCCB002AD96B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
|
||||
GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES;
|
||||
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
PRODUCT_NAME = SDL2;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
|
@ -1284,8 +1290,14 @@
|
|||
FD6526650DE8FCCB002AD96B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
|
||||
GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES;
|
||||
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
PRODUCT_NAME = SDL2;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
|
|
|
@ -145,6 +145,9 @@
|
|||
/* enable iPhone keyboard support */
|
||||
#define SDL_IPHONE_KEYBOARD 1
|
||||
|
||||
/* enable iOS extended launch screen */
|
||||
#define SDL_IPHONE_LAUNCHSCREEN 1
|
||||
|
||||
/* enable joystick subsystem */
|
||||
#define SDL_JOYSTICK_DISABLED 0
|
||||
|
||||
|
|
|
@ -261,8 +261,9 @@ extern "C" {
|
|||
#define SDL_HINT_ORIENTATIONS "SDL_IOS_ORIENTATIONS"
|
||||
|
||||
/**
|
||||
* \brief A variable controlling whether an Android built-in accelerometer should be
|
||||
* listed as a joystick device, rather than listing actual joysticks only.
|
||||
* \brief A variable controlling whether the Android / iOS built-in
|
||||
* accelerometer should be listed as a joystick device, rather than listing
|
||||
* actual joysticks only.
|
||||
*
|
||||
* This variable can be set to the following values:
|
||||
* "0" - List only real joysticks and accept input from them
|
||||
|
@ -345,7 +346,7 @@ extern "C" {
|
|||
|
||||
|
||||
/**
|
||||
* \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac)
|
||||
* \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac and iOS)
|
||||
*/
|
||||
#define SDL_HINT_VIDEO_HIGHDPI_DISABLED "SDL_VIDEO_HIGHDPI_DISABLED"
|
||||
|
||||
|
|
|
@ -76,6 +76,20 @@ extern DECLSPEC SDL_bool SDLCALL SDL_DXGIGetOutputInfo( int displayIndex, int *a
|
|||
extern DECLSPEC int SDLCALL SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam);
|
||||
extern DECLSPEC void SDLCALL SDL_iPhoneSetEventPump(SDL_bool enabled);
|
||||
|
||||
/**
|
||||
\brief Returns the OpenGL Renderbuffer Object associated with the window's main view.
|
||||
|
||||
The Renderbuffer must be bound when calling SDL_GL_SwapWindow.
|
||||
*/
|
||||
extern DECLSPEC Uint32 SDLCALL SDL_iPhoneGetViewRenderbuffer(SDL_Window * window);
|
||||
|
||||
/**
|
||||
\brief Returns the OpenGL Framebuffer Object associated with the window's main view.
|
||||
|
||||
The Framebuffer must be bound when rendering to the screen.
|
||||
*/
|
||||
extern DECLSPEC Uint32 SDLCALL SDL_iPhoneGetViewFramebuffer(SDL_Window * window);
|
||||
|
||||
#endif /* __IPHONEOS__ */
|
||||
|
||||
|
||||
|
|
|
@ -126,6 +126,9 @@
|
|||
#ifndef SDL_IPHONE_KEYBOARD
|
||||
#define SDL_IPHONE_KEYBOARD 1
|
||||
#endif
|
||||
#ifndef SDL_IPHONE_LAUNCHSCREEN
|
||||
#define SDL_IPHONE_LAUNCHSCREEN 1
|
||||
#endif
|
||||
#ifndef SDL_POWER_UIKIT
|
||||
#define SDL_POWER_UIKIT 1
|
||||
#endif
|
||||
|
|
|
@ -50,14 +50,13 @@ FILE* SDL_OpenFPFromBundleOrFallback(const char *file, const char *mode)
|
|||
NSString* full_path_with_file_to_try = [resource_path stringByAppendingPathComponent:ns_string_file_component];
|
||||
if([file_manager fileExistsAtPath:full_path_with_file_to_try]) {
|
||||
fp = fopen([full_path_with_file_to_try fileSystemRepresentation], mode);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
fp = fopen(file, mode);
|
||||
}
|
||||
|
||||
return fp;
|
||||
}}
|
||||
|
||||
#endif /* __MACOSX__ */
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -41,6 +41,7 @@ SDL_GetBasePath(void)
|
|||
const char* baseType = [[[bundle infoDictionary] objectForKey:@"SDL_FILESYSTEM_BASE_DIR_TYPE"] UTF8String];
|
||||
const char *base = NULL;
|
||||
char *retval = NULL;
|
||||
|
||||
if (baseType == NULL) {
|
||||
baseType = "resource";
|
||||
}
|
||||
|
@ -52,6 +53,7 @@ SDL_GetBasePath(void)
|
|||
/* this returns the exedir for non-bundled and the resourceDir for bundled apps */
|
||||
base = [[bundle resourcePath] fileSystemRepresentation];
|
||||
}
|
||||
|
||||
if (base) {
|
||||
const size_t len = SDL_strlen(base) + 2;
|
||||
retval = (char *) SDL_malloc(len);
|
||||
|
@ -69,9 +71,10 @@ char *
|
|||
SDL_GetPrefPath(const char *org, const char *app)
|
||||
{ @autoreleasepool
|
||||
{
|
||||
NSArray *array = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
char *retval = NULL;
|
||||
|
||||
NSArray *array = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
|
||||
if ([array count] > 0) { /* we only want the first item in the list. */
|
||||
NSString *str = [array objectAtIndex:0];
|
||||
const char *base = [str fileSystemRepresentation];
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
/* This is the iOS implementation of the SDL joystick API */
|
||||
|
||||
#include "SDL_joystick.h"
|
||||
#include "SDL_hints.h"
|
||||
#include "SDL_stdinc.h"
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "../SDL_joystick_c.h"
|
||||
|
@ -32,9 +33,10 @@
|
|||
/* needed for SDL_IPHONE_MAX_GFORCE macro */
|
||||
#import "SDL_config_iphoneos.h"
|
||||
|
||||
const char *accelerometerName = "iOS accelerometer";
|
||||
const char *accelerometerName = "iOS Accelerometer";
|
||||
|
||||
static CMMotionManager *motionManager = nil;
|
||||
static int numjoysticks = 0;
|
||||
|
||||
/* Function to scan the system for joysticks.
|
||||
* Joystick 0 should be the system default joystick.
|
||||
|
@ -43,12 +45,18 @@ static CMMotionManager *motionManager = nil;
|
|||
int
|
||||
SDL_SYS_JoystickInit(void)
|
||||
{
|
||||
return (1);
|
||||
const char *hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK);
|
||||
if (!hint || SDL_atoi(hint)) {
|
||||
/* Default behavior, accelerometer as joystick */
|
||||
numjoysticks = 1;
|
||||
}
|
||||
|
||||
return numjoysticks;
|
||||
}
|
||||
|
||||
int SDL_SYS_NumJoysticks()
|
||||
{
|
||||
return 1;
|
||||
return numjoysticks;
|
||||
}
|
||||
|
||||
void SDL_SYS_JoystickDetect()
|
||||
|
@ -81,13 +89,15 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
|||
joystick->nballs = 0;
|
||||
joystick->nbuttons = 0;
|
||||
|
||||
if (motionManager == nil) {
|
||||
motionManager = [[CMMotionManager alloc] init];
|
||||
}
|
||||
@autoreleasepool {
|
||||
if (motionManager == nil) {
|
||||
motionManager = [[CMMotionManager alloc] init];
|
||||
}
|
||||
|
||||
/* Shorter times between updates can significantly increase CPU usage. */
|
||||
motionManager.accelerometerUpdateInterval = 0.1;
|
||||
[motionManager startAccelerometerUpdates];
|
||||
/* Shorter times between updates can significantly increase CPU usage. */
|
||||
motionManager.accelerometerUpdateInterval = 0.1;
|
||||
[motionManager startAccelerometerUpdates];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -104,11 +114,13 @@ static void SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick)
|
|||
const SInt16 maxsint16 = 0x7FFF;
|
||||
CMAcceleration accel;
|
||||
|
||||
if (!motionManager.accelerometerActive) {
|
||||
return;
|
||||
}
|
||||
@autoreleasepool {
|
||||
if (!motionManager.accelerometerActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
accel = [[motionManager accelerometerData] acceleration];
|
||||
accel = motionManager.accelerometerData.acceleration;
|
||||
}
|
||||
|
||||
/*
|
||||
Convert accelerometer data from floating point to Sint16, which is what
|
||||
|
@ -152,17 +164,20 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
|||
void
|
||||
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
[motionManager stopAccelerometerUpdates];
|
||||
@autoreleasepool {
|
||||
[motionManager stopAccelerometerUpdates];
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
void
|
||||
SDL_SYS_JoystickQuit(void)
|
||||
{
|
||||
if (motionManager != nil) {
|
||||
[motionManager release];
|
||||
@autoreleasepool {
|
||||
motionManager = nil;
|
||||
}
|
||||
|
||||
numjoysticks = 0;
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
|
||||
|
|
|
@ -50,24 +50,24 @@ SDL_UIKit_UpdateBatteryMonitoring(void)
|
|||
SDL_bool
|
||||
SDL_GetPowerInfo_UIKit(SDL_PowerState * state, int *seconds, int *percent)
|
||||
{
|
||||
UIDevice *uidev = [UIDevice currentDevice];
|
||||
@autoreleasepool {
|
||||
UIDevice *uidev = [UIDevice currentDevice];
|
||||
|
||||
if (!SDL_UIKitLastPowerInfoQuery) {
|
||||
SDL_assert([uidev isBatteryMonitoringEnabled] == NO);
|
||||
[uidev setBatteryMonitoringEnabled:YES];
|
||||
}
|
||||
if (!SDL_UIKitLastPowerInfoQuery) {
|
||||
SDL_assert(uidev.isBatteryMonitoringEnabled == NO);
|
||||
uidev.batteryMonitoringEnabled = YES;
|
||||
}
|
||||
|
||||
/* UIKit_GL_SwapWindow() (etc) will check this and disable the battery
|
||||
* monitoring if the app hasn't queried it in the last X seconds.
|
||||
* Apparently monitoring the battery burns battery life. :)
|
||||
* Apple's docs say not to monitor the battery unless you need it.
|
||||
*/
|
||||
SDL_UIKitLastPowerInfoQuery = SDL_GetTicks();
|
||||
/* UIKit_GL_SwapWindow() (etc) will check this and disable the battery
|
||||
* monitoring if the app hasn't queried it in the last X seconds.
|
||||
* Apparently monitoring the battery burns battery life. :)
|
||||
* Apple's docs say not to monitor the battery unless you need it.
|
||||
*/
|
||||
SDL_UIKitLastPowerInfoQuery = SDL_GetTicks();
|
||||
|
||||
*seconds = -1; /* no API to estimate this in UIKit. */
|
||||
*seconds = -1; /* no API to estimate this in UIKit. */
|
||||
|
||||
switch ([uidev batteryState])
|
||||
{
|
||||
switch (uidev.batteryState) {
|
||||
case UIDeviceBatteryStateCharging:
|
||||
*state = SDL_POWERSTATE_CHARGING;
|
||||
break;
|
||||
|
@ -84,11 +84,12 @@ SDL_GetPowerInfo_UIKit(SDL_PowerState * state, int *seconds, int *percent)
|
|||
default:
|
||||
*state = SDL_POWERSTATE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const float level = [uidev batteryLevel];
|
||||
*percent = ( (level < 0.0f) ? -1 : ((int) ((level * 100) + 0.5f)) );
|
||||
return SDL_TRUE; /* always the definitive answer on iOS. */
|
||||
const float level = uidev.batteryLevel;
|
||||
*percent = ( (level < 0.0f) ? -1 : ((int) ((level * 100) + 0.5f)) );
|
||||
return SDL_TRUE; /* always the definitive answer on iOS. */
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_POWER_UIKIT */
|
||||
|
|
|
@ -55,6 +55,7 @@ static const float inv255f = 1.0f / 255.0f;
|
|||
static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags);
|
||||
static void GLES_WindowEvent(SDL_Renderer * renderer,
|
||||
const SDL_WindowEvent *event);
|
||||
static int GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
|
||||
static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
|
||||
static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * rect, const void *pixels,
|
||||
|
@ -321,6 +322,7 @@ GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
}
|
||||
|
||||
renderer->WindowEvent = GLES_WindowEvent;
|
||||
renderer->GetOutputSize = GLES_GetOutputSize;
|
||||
renderer->CreateTexture = GLES_CreateTexture;
|
||||
renderer->UpdateTexture = GLES_UpdateTexture;
|
||||
renderer->LockTexture = GLES_LockTexture;
|
||||
|
@ -438,6 +440,13 @@ GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
|
||||
{
|
||||
SDL_GL_GetDrawableSize(renderer->window, w, h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SDL_INLINE int
|
||||
power_of_2(int input)
|
||||
{
|
||||
|
|
|
@ -369,6 +369,13 @@ GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
GLES2_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
|
||||
{
|
||||
SDL_GL_GetDrawableSize(renderer->window, w, h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
GLES2_UpdateViewport(SDL_Renderer * renderer)
|
||||
{
|
||||
|
@ -2059,6 +2066,7 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
|
|||
|
||||
/* Populate the function pointers for the module */
|
||||
renderer->WindowEvent = &GLES2_WindowEvent;
|
||||
renderer->GetOutputSize = &GLES2_GetOutputSize;
|
||||
renderer->CreateTexture = &GLES2_CreateTexture;
|
||||
renderer->UpdateTexture = &GLES2_UpdateTexture;
|
||||
renderer->UpdateTextureYUV = &GLES2_UpdateTextureYUV;
|
||||
|
|
|
@ -1107,22 +1107,22 @@ SDL_RestoreMousePosition(SDL_Window *window)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
|
||||
{
|
||||
SDL_VideoDisplay *display;
|
||||
SDL_Window *other;
|
||||
|
||||
CHECK_WINDOW_MAGIC(window,);
|
||||
CHECK_WINDOW_MAGIC(window,-1);
|
||||
|
||||
/* if we are in the process of hiding don't go back to fullscreen */
|
||||
if ( window->is_hiding && fullscreen )
|
||||
return;
|
||||
return 0;
|
||||
|
||||
#ifdef __MACOSX__
|
||||
if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
|
||||
window->last_fullscreen_flags = window->flags;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1139,7 +1139,7 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
|
|||
/* See if anything needs to be done now */
|
||||
if ((display->fullscreen_window == window) == fullscreen) {
|
||||
if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1168,9 +1168,13 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
|
|||
|
||||
/* only do the mode change if we want exclusive fullscreen */
|
||||
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
|
||||
SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
|
||||
if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
SDL_SetDisplayModeForDisplay(display, NULL);
|
||||
if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (_this->SetWindowFullscreen) {
|
||||
|
@ -1189,7 +1193,7 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
|
|||
SDL_RestoreMousePosition(other);
|
||||
|
||||
window->last_fullscreen_flags = window->flags;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1209,6 +1213,7 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
|
|||
SDL_RestoreMousePosition(window);
|
||||
|
||||
window->last_fullscreen_flags = window->flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CREATE_FLAGS \
|
||||
|
@ -1935,9 +1940,7 @@ SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
|
|||
window->flags &= ~FULLSCREEN_MASK;
|
||||
window->flags |= flags;
|
||||
|
||||
SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
|
||||
|
||||
return 0;
|
||||
return SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
|
||||
}
|
||||
|
||||
static SDL_Surface *
|
||||
|
|
|
@ -21,12 +21,21 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface SDLUIKitDelegate : NSObject<UIApplicationDelegate> {
|
||||
}
|
||||
@interface SDLLaunchScreenController : UIViewController
|
||||
|
||||
+ (id) sharedAppDelegate;
|
||||
- (instancetype)init;
|
||||
- (void)loadView;
|
||||
- (NSUInteger)supportedInterfaceOrientations;
|
||||
|
||||
@end
|
||||
|
||||
@interface SDLUIKitDelegate : NSObject<UIApplicationDelegate>
|
||||
|
||||
+ (id)sharedAppDelegate;
|
||||
+ (NSString *)getAppDelegateClassName;
|
||||
|
||||
- (void)hideLaunchScreen;
|
||||
|
||||
@end
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -28,8 +28,10 @@
|
|||
#include "SDL_system.h"
|
||||
#include "SDL_main.h"
|
||||
|
||||
#include "SDL_uikitappdelegate.h"
|
||||
#include "SDL_uikitmodes.h"
|
||||
#import "SDL_uikitappdelegate.h"
|
||||
#import "SDL_uikitmodes.h"
|
||||
#import "SDL_uikitwindow.h"
|
||||
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
#ifdef main
|
||||
|
@ -39,12 +41,10 @@
|
|||
static int forward_argc;
|
||||
static char **forward_argv;
|
||||
static int exit_status;
|
||||
static UIWindow *launch_window;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
/* store arguments */
|
||||
forward_argc = argc;
|
||||
|
@ -56,7 +56,9 @@ int main(int argc, char **argv)
|
|||
forward_argv[i] = NULL;
|
||||
|
||||
/* Give over control to run loop, SDLUIKitDelegate will handle most things from here */
|
||||
UIApplicationMain(argc, argv, NULL, [SDLUIKitDelegate getAppDelegateClassName]);
|
||||
@autoreleasepool {
|
||||
UIApplicationMain(argc, argv, nil, [SDLUIKitDelegate getAppDelegateClassName]);
|
||||
}
|
||||
|
||||
/* free the memory we used to hold copies of argc and argv */
|
||||
for (i = 0; i < forward_argc; i++) {
|
||||
|
@ -64,7 +66,6 @@ int main(int argc, char **argv)
|
|||
}
|
||||
free(forward_argv);
|
||||
|
||||
[pool release];
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
|
@ -75,224 +76,262 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa
|
|||
[UIApplication sharedApplication].idleTimerDisabled = disable;
|
||||
}
|
||||
|
||||
/* Load a launch image using the old UILaunchImageFile-era naming rules. */
|
||||
static UIImage *
|
||||
SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
{
|
||||
UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
|
||||
UIUserInterfaceIdiom idiom = [UIDevice currentDevice].userInterfaceIdiom;
|
||||
UIImage *image = nil;
|
||||
|
||||
@interface SDL_launchscreenviewcontroller : UIViewController {
|
||||
if (idiom == UIUserInterfaceIdiomPhone && screenh == 568) {
|
||||
/* The image name for the iPhone 5 uses its height as a suffix. */
|
||||
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-568h", name]];
|
||||
} else if (idiom == UIUserInterfaceIdiomPad) {
|
||||
/* iPad apps can launch in any orientation. */
|
||||
if (UIInterfaceOrientationIsLandscape(curorient)) {
|
||||
if (curorient == UIInterfaceOrientationLandscapeLeft) {
|
||||
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeLeft", name]];
|
||||
} else {
|
||||
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeRight", name]];
|
||||
}
|
||||
if (!image) {
|
||||
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Landscape", name]];
|
||||
}
|
||||
} else {
|
||||
if (curorient == UIInterfaceOrientationPortraitUpsideDown) {
|
||||
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-PortraitUpsideDown", name]];
|
||||
}
|
||||
if (!image) {
|
||||
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Portrait", name]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!image) {
|
||||
image = [UIImage imageNamed:name];
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@end
|
||||
@implementation SDLLaunchScreenController {
|
||||
UIInterfaceOrientationMask supportedOrientations;
|
||||
}
|
||||
|
||||
@implementation SDL_launchscreenviewcontroller
|
||||
|
||||
- (id)init
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self == nil) {
|
||||
if (!(self = [super initWithNibName:nil bundle:nil])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString* launch_screen_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
|
||||
NSBundle *bundle = [NSBundle mainBundle];
|
||||
NSString *screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
|
||||
|
||||
if(launch_screen_name) {
|
||||
// TODO: If the NIB is not in the bundle, this will throw an exception. We might consider a pre-emptive check, but returning a useless viewcontroller isn't helpful and the check should be outside.
|
||||
UIView* launch_screen = [[[NSBundle mainBundle] loadNibNamed:launch_screen_name owner:self options:nil] objectAtIndex:0];
|
||||
CGSize size = [UIScreen mainScreen].bounds.size;
|
||||
/* Normally we don't want to rotate from the initial orientation. */
|
||||
supportedOrientations = (1 << [UIApplication sharedApplication].statusBarOrientation);
|
||||
|
||||
CGRect bounds = CGRectMake(0, 0, size.width, size.height);
|
||||
|
||||
[launch_screen setFrame:bounds];
|
||||
[self setView:launch_screen];
|
||||
[launch_screen release];
|
||||
/* Launch screens were added in iOS 8. Otherwise we use launch images. */
|
||||
if (screenname && UIKit_IsSystemVersionAtLeast(8.0)) {
|
||||
@try {
|
||||
self.view = [bundle loadNibNamed:screenname owner:self options:nil][0];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
/* iOS displays a blank screen rather than falling back to an image,
|
||||
* if a launch screen name is specified but it fails to load. */
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
if (!self.view) {
|
||||
NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"];
|
||||
UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
|
||||
NSString *imagename = nil;
|
||||
UIImage *image = nil;
|
||||
|
||||
int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5);
|
||||
int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5);
|
||||
|
||||
/* We always want portrait-oriented size, to match UILaunchImageSize. */
|
||||
if (screenw > screenh) {
|
||||
int width = screenw;
|
||||
screenw = screenh;
|
||||
screenh = width;
|
||||
}
|
||||
|
||||
/* Xcode 5 introduced a dictionary of launch images in Info.plist. */
|
||||
if (launchimages) {
|
||||
for (NSDictionary *dict in launchimages) {
|
||||
UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
|
||||
NSString *minversion = dict[@"UILaunchImageMinimumOSVersion"];
|
||||
NSString *sizestring = dict[@"UILaunchImageSize"];
|
||||
NSString *orientstring = dict[@"UILaunchImageOrientation"];
|
||||
|
||||
/* Ignore this image if the current version is too low. */
|
||||
if (minversion && !UIKit_IsSystemVersionAtLeast(minversion.doubleValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ignore this image if the size doesn't match. */
|
||||
if (sizestring) {
|
||||
CGSize size = CGSizeFromString(sizestring);
|
||||
if ((int)(size.width + 0.5) != screenw || (int)(size.height + 0.5) != screenh) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (orientstring) {
|
||||
if ([orientstring isEqualToString:@"PortraitUpsideDown"]) {
|
||||
orientmask = UIInterfaceOrientationMaskPortraitUpsideDown;
|
||||
} else if ([orientstring isEqualToString:@"Landscape"]) {
|
||||
orientmask = UIInterfaceOrientationMaskLandscape;
|
||||
} else if ([orientstring isEqualToString:@"LandscapeLeft"]) {
|
||||
orientmask = UIInterfaceOrientationMaskLandscapeLeft;
|
||||
} else if ([orientstring isEqualToString:@"LandscapeRight"]) {
|
||||
orientmask = UIInterfaceOrientationMaskLandscapeRight;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ignore this image if the orientation doesn't match. */
|
||||
if ((orientmask & (1 << curorient)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
imagename = dict[@"UILaunchImageName"];
|
||||
}
|
||||
|
||||
if (imagename) {
|
||||
image = [UIImage imageNamed:imagename];
|
||||
}
|
||||
} else {
|
||||
imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"];
|
||||
|
||||
if (imagename) {
|
||||
image = SDL_LoadLaunchImageNamed(imagename, screenh);
|
||||
}
|
||||
|
||||
if (!image) {
|
||||
image = SDL_LoadLaunchImageNamed(@"Default", screenh);
|
||||
}
|
||||
}
|
||||
|
||||
if (image) {
|
||||
if (image.size.width > image.size.height) {
|
||||
supportedOrientations = UIInterfaceOrientationMaskLandscape;
|
||||
} else {
|
||||
supportedOrientations = UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
|
||||
self.view = [[UIImageView alloc] initWithImage:image];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSUInteger)supportedInterfaceOrientations
|
||||
- (void)loadView
|
||||
{
|
||||
NSUInteger orientationMask = UIInterfaceOrientationMaskAll;
|
||||
|
||||
/* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
|
||||
orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
|
||||
}
|
||||
return orientationMask;
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
|
||||
{
|
||||
NSUInteger orientationMask = [self supportedInterfaceOrientations];
|
||||
return (orientationMask & (1 << orient));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface SDL_splashviewcontroller : UIViewController {
|
||||
UIImageView *splash;
|
||||
UIImage *splashPortrait;
|
||||
UIImage *splashLandscape;
|
||||
}
|
||||
|
||||
- (void)updateSplashImage:(UIInterfaceOrientation)interfaceOrientation;
|
||||
@end
|
||||
|
||||
@implementation SDL_splashviewcontroller
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self->splash = [[UIImageView alloc] init];
|
||||
[self setView:self->splash];
|
||||
|
||||
CGSize size = [UIScreen mainScreen].bounds.size;
|
||||
float height = SDL_max(size.width, size.height);
|
||||
/* FIXME: Some where around iOS 7, UILaunchImages in the Info.plist was introduced which explicitly maps image names to devices and orientations.
|
||||
This gets rid of the hardcoded magic file names and allows more control for OS version, orientation, retina, and device.
|
||||
But this existing code needs to be modified to look in the Info.plist for each key and act appropriately for the correct iOS version.
|
||||
But iOS 8 superscedes this process and introduces the LaunchScreen NIB which uses autolayout to handle all orientations and devices.
|
||||
Since we now have a LaunchScreen solution, this may never get fixed,
|
||||
but this note is here for anybody trying to debug their program on iOS 7 and doesn't understand why their Info.plist isn't working.
|
||||
*/
|
||||
self->splashPortrait = [UIImage imageNamed:[NSString stringWithFormat:@"Default-%dh.png", (int)height]];
|
||||
if (!self->splashPortrait) {
|
||||
self->splashPortrait = [UIImage imageNamed:@"Default.png"];
|
||||
}
|
||||
self->splashLandscape = [UIImage imageNamed:@"Default-Landscape.png"];
|
||||
if (!self->splashLandscape && self->splashPortrait) {
|
||||
self->splashLandscape = [[UIImage alloc] initWithCGImage: self->splashPortrait.CGImage
|
||||
scale: 1.0
|
||||
orientation: UIImageOrientationRight];
|
||||
}
|
||||
if (self->splashPortrait) {
|
||||
[self->splashPortrait retain];
|
||||
}
|
||||
if (self->splashLandscape) {
|
||||
[self->splashLandscape retain];
|
||||
}
|
||||
|
||||
[self updateSplashImage:[[UIApplication sharedApplication] statusBarOrientation]];
|
||||
|
||||
return self;
|
||||
/* Do nothing. */
|
||||
}
|
||||
|
||||
- (NSUInteger)supportedInterfaceOrientations
|
||||
{
|
||||
NSUInteger orientationMask = UIInterfaceOrientationMaskAll;
|
||||
|
||||
/* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
|
||||
orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
|
||||
}
|
||||
return orientationMask;
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
|
||||
{
|
||||
NSUInteger orientationMask = [self supportedInterfaceOrientations];
|
||||
return (orientationMask & (1 << orient));
|
||||
}
|
||||
|
||||
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
|
||||
{
|
||||
[self updateSplashImage:interfaceOrientation];
|
||||
}
|
||||
|
||||
- (void)updateSplashImage:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
UIImage *image;
|
||||
|
||||
if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
|
||||
image = self->splashLandscape;
|
||||
} else {
|
||||
image = self->splashPortrait;
|
||||
}
|
||||
if (image)
|
||||
{
|
||||
splash.image = image;
|
||||
}
|
||||
return supportedOrientations;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation SDLUIKitDelegate
|
||||
@implementation SDLUIKitDelegate {
|
||||
UIWindow *launchWindow;
|
||||
}
|
||||
|
||||
/* convenience method */
|
||||
+ (id) sharedAppDelegate
|
||||
+ (id)sharedAppDelegate
|
||||
{
|
||||
/* the delegate is set in UIApplicationMain(), which is garaunteed to be called before this method */
|
||||
return [[UIApplication sharedApplication] delegate];
|
||||
/* the delegate is set in UIApplicationMain(), which is guaranteed to be
|
||||
* called before this method */
|
||||
return [UIApplication sharedApplication].delegate;
|
||||
}
|
||||
|
||||
+ (NSString *)getAppDelegateClassName
|
||||
{
|
||||
/* subclassing notice: when you subclass this appdelegate, make sure to add a category to override
|
||||
this method and return the actual name of the delegate */
|
||||
/* subclassing notice: when you subclass this appdelegate, make sure to add
|
||||
* a category to override this method and return the actual name of the
|
||||
* delegate */
|
||||
return @"SDLUIKitDelegate";
|
||||
}
|
||||
|
||||
- (id)init
|
||||
- (void)hideLaunchScreen
|
||||
{
|
||||
self = [super init];
|
||||
return self;
|
||||
UIWindow *window = launchWindow;
|
||||
|
||||
if (!window || window.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
launchWindow = nil;
|
||||
|
||||
/* Do a nice animated fade-out (roughly matches the real launch behavior.) */
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
window.alpha = 0.0;
|
||||
} completion:^(BOOL finished) {
|
||||
window.hidden = YES;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)postFinishLaunch
|
||||
{
|
||||
/* Hide the launch screen the next time the run loop is run. SDL apps will
|
||||
* have a chance to load resources while the launch screen is still up. */
|
||||
[self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0];
|
||||
|
||||
/* run the user's application, passing argc and argv */
|
||||
SDL_iPhoneSetEventPump(SDL_TRUE);
|
||||
exit_status = SDL_main(forward_argc, forward_argv);
|
||||
SDL_iPhoneSetEventPump(SDL_FALSE);
|
||||
|
||||
/* If we showed a splash image, clean it up */
|
||||
if (launch_window) {
|
||||
[launch_window release];
|
||||
launch_window = NULL;
|
||||
if (launchWindow) {
|
||||
launchWindow.hidden = YES;
|
||||
launchWindow = nil;
|
||||
}
|
||||
|
||||
/* exit, passing the return status from the user's application */
|
||||
/* We don't actually exit to support applications that do setup in
|
||||
* their main function and then allow the Cocoa event loop to run.
|
||||
*/
|
||||
/* We don't actually exit to support applications that do setup in their
|
||||
* main function and then allow the Cocoa event loop to run. */
|
||||
/* exit(exit_status); */
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
/* Keep the launch image up until we set a video mode */
|
||||
launch_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
NSBundle *bundle = [NSBundle mainBundle];
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
|
||||
/* iOS 8 introduces LaunchScreen NIBs which use autolayout to handle all devices and orientations with a single NIB instead of multiple launch images.
|
||||
This is also the only way to get the App Store badge "Optimized for iPhone 6 and iPhone 6 Plus".
|
||||
So if the application is running on iOS 8 or greater AND has specified a LaunchScreen in their Info.plist, we should use the LaunchScreen NIB.
|
||||
Otherwise, we should fallback to the legacy behavior of launch screen images.
|
||||
*/
|
||||
NSString* launch_screen_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
|
||||
if( ([[UIDevice currentDevice].systemVersion intValue] >= 8) && (nil != launch_screen_name) ) {
|
||||
// iOS 8.0 and above uses LaunchScreen.xib
|
||||
SDL_launchscreenviewcontroller* launch_screen_view_controller = [[SDL_launchscreenviewcontroller alloc] init];
|
||||
launch_window.rootViewController = launch_screen_view_controller;
|
||||
[launch_window addSubview:launch_screen_view_controller.view];
|
||||
[launch_window makeKeyAndVisible];
|
||||
} else {
|
||||
// Anything less than iOS 8.0
|
||||
#if SDL_IPHONE_LAUNCHSCREEN
|
||||
/* The normal launch screen is displayed until didFinishLaunching returns,
|
||||
* but SDL_main is called after that happens and there may be a noticeable
|
||||
* delay between the start of SDL_main and when the first real frame is
|
||||
* displayed (e.g. if resources are loaded before SDL_GL_SwapWindow is
|
||||
* called), so we show the launch screen programmatically until the first
|
||||
* time events are pumped. */
|
||||
UIViewController *viewcontroller = [[SDLLaunchScreenController alloc] init];
|
||||
|
||||
UIViewController *splashViewController = [[SDL_splashviewcontroller alloc] init];
|
||||
launch_window.rootViewController = splashViewController;
|
||||
[launch_window addSubview:splashViewController.view];
|
||||
[launch_window makeKeyAndVisible];
|
||||
if (viewcontroller.view) {
|
||||
launchWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
|
||||
/* We don't want the launch window immediately hidden when a real SDL
|
||||
* window is shown - we fade it out ourselves when we're ready. */
|
||||
launchWindow.windowLevel = UIWindowLevelNormal + 1.0;
|
||||
|
||||
/* Show the window but don't make it key. Events should always go to
|
||||
* other windows when possible. */
|
||||
launchWindow.hidden = NO;
|
||||
|
||||
launchWindow.rootViewController = viewcontroller;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set working directory to resource path */
|
||||
[[NSFileManager defaultManager] changeCurrentDirectoryPath: [[NSBundle mainBundle] resourcePath]];
|
||||
[[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]];
|
||||
|
||||
/* register a callback for the idletimer hint */
|
||||
SDL_AddHintCallback(SDL_HINT_IDLE_TIMER_DISABLED,
|
||||
|
@ -314,7 +353,35 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa
|
|||
SDL_SendAppEvent(SDL_APP_LOWMEMORY);
|
||||
}
|
||||
|
||||
- (void) applicationWillResignActive:(UIApplication*)application
|
||||
- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
|
||||
{
|
||||
BOOL isLandscape = UIInterfaceOrientationIsLandscape(application.statusBarOrientation);
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (_this && _this->num_displays > 0) {
|
||||
SDL_DisplayMode *desktopmode = &_this->displays[0].desktop_mode;
|
||||
SDL_DisplayMode *currentmode = &_this->displays[0].current_mode;
|
||||
|
||||
/* The desktop display mode should be kept in sync with the screen
|
||||
* orientation so that updating a window's fullscreen state to
|
||||
* SDL_WINDOW_FULLSCREEN_DESKTOP keeps the window dimensions in the
|
||||
* correct orientation. */
|
||||
if (isLandscape != (desktopmode->w > desktopmode->h)) {
|
||||
int height = desktopmode->w;
|
||||
desktopmode->w = desktopmode->h;
|
||||
desktopmode->h = height;
|
||||
}
|
||||
|
||||
/* Same deal with the current mode + SDL_GetCurrentDisplayMode. */
|
||||
if (isLandscape != (currentmode->w > currentmode->h)) {
|
||||
int height = currentmode->w;
|
||||
currentmode->w = currentmode->h;
|
||||
currentmode->h = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication*)application
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
if (_this) {
|
||||
|
@ -327,17 +394,17 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa
|
|||
SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
|
||||
}
|
||||
|
||||
- (void) applicationDidEnterBackground:(UIApplication*)application
|
||||
- (void)applicationDidEnterBackground:(UIApplication*)application
|
||||
{
|
||||
SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
|
||||
}
|
||||
|
||||
- (void) applicationWillEnterForeground:(UIApplication*)application
|
||||
- (void)applicationWillEnterForeground:(UIApplication*)application
|
||||
{
|
||||
SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
|
||||
}
|
||||
|
||||
- (void) applicationDidBecomeActive:(UIApplication*)application
|
||||
- (void)applicationDidBecomeActive:(UIApplication*)application
|
||||
{
|
||||
SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
|
||||
|
||||
|
@ -353,11 +420,11 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa
|
|||
|
||||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
|
||||
{
|
||||
NSURL *fileURL = [url filePathURL];
|
||||
NSURL *fileURL = url.filePathURL;
|
||||
if (fileURL != nil) {
|
||||
SDL_SendDropFile([[fileURL path] UTF8String]);
|
||||
SDL_SendDropFile([fileURL.path UTF8String]);
|
||||
} else {
|
||||
SDL_SendDropFile([[url absoluteString] UTF8String]);
|
||||
SDL_SendDropFile([url.absoluteString UTF8String]);
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
|
|
@ -40,8 +40,9 @@ SDL_iPhoneSetEventPump(SDL_bool enabled)
|
|||
void
|
||||
UIKit_PumpEvents(_THIS)
|
||||
{
|
||||
if (!UIKit_EventPumpEnabled)
|
||||
if (!UIKit_EventPumpEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Let the run loop run for a short amount of time: long enough for
|
||||
touch events to get processed (which is important to get certain
|
||||
|
|
|
@ -30,35 +30,20 @@
|
|||
|
||||
static SDL_bool s_showingMessageBox = SDL_FALSE;
|
||||
|
||||
@interface UIKit_UIAlertViewDelegate : NSObject <UIAlertViewDelegate> {
|
||||
@private
|
||||
int *clickedButtonIndex;
|
||||
}
|
||||
@interface SDLAlertViewDelegate : NSObject <UIAlertViewDelegate>
|
||||
|
||||
- (id)initWithButtonIndex:(int *)_buttonIndex;
|
||||
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex;
|
||||
@property (nonatomic, assign) int clickedIndex;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIKit_UIAlertViewDelegate
|
||||
@implementation SDLAlertViewDelegate
|
||||
|
||||
- (id)initWithButtonIndex:(int *)buttonIndex
|
||||
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
self = [self init];
|
||||
if (self == nil) {
|
||||
return nil;
|
||||
}
|
||||
self->clickedButtonIndex = buttonIndex;
|
||||
|
||||
return self;
|
||||
_clickedIndex = (int)buttonIndex;
|
||||
}
|
||||
|
||||
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex;
|
||||
{
|
||||
*clickedButtonIndex = (int)buttonIndex;
|
||||
}
|
||||
|
||||
@end /* UIKit_UIAlertViewDelegate */
|
||||
@end
|
||||
|
||||
|
||||
SDL_bool
|
||||
|
@ -70,42 +55,39 @@ UIKit_ShowingMessageBox()
|
|||
int
|
||||
UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
|
||||
{
|
||||
int clicked;
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
UIAlertView* alert = [[UIAlertView alloc] init];
|
||||
|
||||
alert.title = [NSString stringWithUTF8String:messageboxdata->title];
|
||||
alert.message = [NSString stringWithUTF8String:messageboxdata->message];
|
||||
alert.delegate = [[UIKit_UIAlertViewDelegate alloc] initWithButtonIndex:&clicked];
|
||||
|
||||
const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
|
||||
int i;
|
||||
for (i = 0; i < messageboxdata->numbuttons; ++i) {
|
||||
[alert addButtonWithTitle:[[NSString alloc] initWithUTF8String:buttons[i].text]];
|
||||
const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
|
||||
|
||||
@autoreleasepool {
|
||||
UIAlertView *alert = [[UIAlertView alloc] init];
|
||||
SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init];
|
||||
|
||||
alert.delegate = delegate;
|
||||
alert.title = @(messageboxdata->title);
|
||||
alert.message = @(messageboxdata->message);
|
||||
|
||||
for (i = 0; i < messageboxdata->numbuttons; ++i) {
|
||||
[alert addButtonWithTitle:@(buttons[i].text)];
|
||||
}
|
||||
|
||||
/* Set up for showing the alert */
|
||||
delegate.clickedIndex = messageboxdata->numbuttons;
|
||||
|
||||
[alert show];
|
||||
|
||||
/* Run the main event loop until the alert has finished */
|
||||
/* Note that this needs to be done on the main thread */
|
||||
s_showingMessageBox = SDL_TRUE;
|
||||
while (delegate.clickedIndex == messageboxdata->numbuttons) {
|
||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
|
||||
}
|
||||
s_showingMessageBox = SDL_FALSE;
|
||||
|
||||
*buttonid = messageboxdata->buttons[delegate.clickedIndex].buttonid;
|
||||
|
||||
alert.delegate = nil;
|
||||
}
|
||||
|
||||
/* Set up for showing the alert */
|
||||
clicked = messageboxdata->numbuttons;
|
||||
|
||||
[alert show];
|
||||
|
||||
/* Run the main event loop until the alert has finished */
|
||||
/* Note that this needs to be done on the main thread */
|
||||
s_showingMessageBox = SDL_TRUE;
|
||||
while (clicked == messageboxdata->numbuttons) {
|
||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
|
||||
}
|
||||
s_showingMessageBox = SDL_FALSE;
|
||||
|
||||
*buttonid = messageboxdata->buttons[clicked].buttonid;
|
||||
|
||||
[alert.delegate release];
|
||||
[alert release];
|
||||
|
||||
[pool release];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,17 +25,17 @@
|
|||
|
||||
#include "SDL_uikitvideo.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UIScreen *uiscreen;
|
||||
CGFloat scale;
|
||||
} SDL_DisplayData;
|
||||
@interface SDL_DisplayData : NSObject
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UIScreenMode *uiscreenmode;
|
||||
CGFloat scale;
|
||||
} SDL_DisplayModeData;
|
||||
@property (nonatomic, strong) UIScreen *uiscreen;
|
||||
|
||||
@end
|
||||
|
||||
@interface SDL_DisplayModeData : NSObject
|
||||
|
||||
@property (nonatomic, strong) UIScreenMode *uiscreenmode;
|
||||
|
||||
@end
|
||||
|
||||
extern SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen);
|
||||
|
||||
|
|
|
@ -25,27 +25,36 @@
|
|||
#include "SDL_assert.h"
|
||||
#include "SDL_uikitmodes.h"
|
||||
|
||||
@implementation SDL_DisplayData
|
||||
|
||||
@synthesize uiscreen;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDL_DisplayModeData
|
||||
|
||||
@synthesize uiscreenmode;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
static int
|
||||
UIKit_AllocateDisplayModeData(SDL_DisplayMode * mode,
|
||||
UIScreenMode * uiscreenmode, CGFloat scale)
|
||||
UIScreenMode * uiscreenmode)
|
||||
{
|
||||
SDL_DisplayModeData *data = NULL;
|
||||
SDL_DisplayModeData *data = nil;
|
||||
|
||||
if (uiscreenmode != nil) {
|
||||
/* Allocate the display mode data */
|
||||
data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
|
||||
data = [[SDL_DisplayModeData alloc] init];
|
||||
if (!data) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
data->uiscreenmode = uiscreenmode;
|
||||
[data->uiscreenmode retain];
|
||||
|
||||
data->scale = scale;
|
||||
data.uiscreenmode = uiscreenmode;
|
||||
}
|
||||
|
||||
mode->driverdata = data;
|
||||
mode->driverdata = (void *) CFBridgingRetain(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -54,23 +63,21 @@ static void
|
|||
UIKit_FreeDisplayModeData(SDL_DisplayMode * mode)
|
||||
{
|
||||
if (mode->driverdata != NULL) {
|
||||
SDL_DisplayModeData *data = (SDL_DisplayModeData *)mode->driverdata;
|
||||
[data->uiscreenmode release];
|
||||
SDL_free(data);
|
||||
CFRelease(mode->driverdata);
|
||||
mode->driverdata = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h,
|
||||
UIScreenMode * uiscreenmode, CGFloat scale)
|
||||
UIScreenMode * uiscreenmode)
|
||||
{
|
||||
SDL_DisplayMode mode;
|
||||
SDL_zero(mode);
|
||||
|
||||
mode.format = SDL_PIXELFORMAT_ABGR8888;
|
||||
mode.refresh_rate = 0;
|
||||
if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode, scale) < 0) {
|
||||
if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -85,16 +92,16 @@ UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h,
|
|||
}
|
||||
|
||||
static int
|
||||
UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, CGFloat scale,
|
||||
UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h,
|
||||
UIScreenMode * uiscreenmode, SDL_bool addRotation)
|
||||
{
|
||||
if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode, scale) < 0) {
|
||||
if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addRotation) {
|
||||
/* Add the rotated version */
|
||||
if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode, scale) < 0) {
|
||||
if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +112,7 @@ UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, CGFloat scale,
|
|||
static int
|
||||
UIKit_AddDisplay(UIScreen *uiscreen)
|
||||
{
|
||||
CGSize size = [uiscreen bounds].size;
|
||||
CGSize size = uiscreen.bounds.size;
|
||||
|
||||
/* Make sure the width/height are oriented correctly */
|
||||
if (UIKit_IsDisplayLandscape(uiscreen) != (size.width > size.height)) {
|
||||
|
@ -114,24 +121,16 @@ UIKit_AddDisplay(UIScreen *uiscreen)
|
|||
size.height = height;
|
||||
}
|
||||
|
||||
/* When dealing with UIKit all coordinates are specified in terms of
|
||||
* what Apple refers to as points. [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 = [uiscreen scale];
|
||||
|
||||
SDL_VideoDisplay display;
|
||||
SDL_DisplayMode mode;
|
||||
SDL_zero(mode);
|
||||
mode.format = SDL_PIXELFORMAT_ABGR8888;
|
||||
mode.w = (int)(size.width * scale);
|
||||
mode.h = (int)(size.height * scale);
|
||||
mode.w = (int) size.width;
|
||||
mode.h = (int) size.height;
|
||||
|
||||
UIScreenMode * uiscreenmode = [uiscreen currentMode];
|
||||
UIScreenMode *uiscreenmode = uiscreen.currentMode;
|
||||
|
||||
if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode, scale) < 0) {
|
||||
if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -140,17 +139,15 @@ UIKit_AddDisplay(UIScreen *uiscreen)
|
|||
display.current_mode = mode;
|
||||
|
||||
/* Allocate the display data */
|
||||
SDL_DisplayData *data = (SDL_DisplayData *) SDL_malloc(sizeof(*data));
|
||||
SDL_DisplayData *data = [[SDL_DisplayData alloc] init];
|
||||
if (!data) {
|
||||
UIKit_FreeDisplayModeData(&display.desktop_mode);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
[uiscreen retain];
|
||||
data->uiscreen = uiscreen;
|
||||
data->scale = scale;
|
||||
data.uiscreen = uiscreen;
|
||||
|
||||
display.driverdata = data;
|
||||
display.driverdata = (void *) CFBridgingRetain(data);
|
||||
SDL_AddVideoDisplay(&display);
|
||||
|
||||
return 0;
|
||||
|
@ -160,9 +157,9 @@ SDL_bool
|
|||
UIKit_IsDisplayLandscape(UIScreen *uiscreen)
|
||||
{
|
||||
if (uiscreen == [UIScreen mainScreen]) {
|
||||
return UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]);
|
||||
return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
|
||||
} else {
|
||||
CGSize size = [uiscreen bounds].size;
|
||||
CGSize size = uiscreen.bounds.size;
|
||||
return (size.width > size.height);
|
||||
}
|
||||
}
|
||||
|
@ -170,9 +167,11 @@ UIKit_IsDisplayLandscape(UIScreen *uiscreen)
|
|||
int
|
||||
UIKit_InitModes(_THIS)
|
||||
{
|
||||
for (UIScreen *uiscreen in [UIScreen screens]) {
|
||||
if (UIKit_AddDisplay(uiscreen) < 0) {
|
||||
return -1;
|
||||
@autoreleasepool {
|
||||
for (UIScreen *uiscreen in [UIScreen screens]) {
|
||||
if (UIKit_AddDisplay(uiscreen) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,34 +181,35 @@ UIKit_InitModes(_THIS)
|
|||
void
|
||||
UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
||||
{
|
||||
SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
|
||||
@autoreleasepool {
|
||||
SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
|
||||
|
||||
SDL_bool isLandscape = UIKit_IsDisplayLandscape(data->uiscreen);
|
||||
SDL_bool addRotation = (data->uiscreen == [UIScreen mainScreen]);
|
||||
SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen);
|
||||
SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]);
|
||||
CGFloat scale = data.uiscreen.scale;
|
||||
|
||||
for (UIScreenMode *uimode in [data->uiscreen availableModes]) {
|
||||
CGSize size = [uimode size];
|
||||
int w = (int)size.width;
|
||||
int h = (int)size.height;
|
||||
|
||||
/* Make sure the width/height are oriented correctly */
|
||||
if (isLandscape != (w > h)) {
|
||||
int tmp = w;
|
||||
w = h;
|
||||
h = tmp;
|
||||
#ifdef __IPHONE_8_0
|
||||
/* The UIScreenMode of an iPhone 6 Plus should be 1080x1920 rather than
|
||||
* 1242x2208 (414x736@3x), so we should use the native scale. */
|
||||
if ([data.uiscreen respondsToSelector:@selector(nativeScale)]) {
|
||||
scale = data.uiscreen.nativeScale;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Add the native screen resolution. */
|
||||
UIKit_AddDisplayMode(display, w, h, data->scale, uimode, addRotation);
|
||||
for (UIScreenMode *uimode in data.uiscreen.availableModes) {
|
||||
/* The size of a UIScreenMode is in pixels, but we deal exclusively
|
||||
* in points (except in SDL_GL_GetDrawableSize.) */
|
||||
int w = (int)(uimode.size.width / scale);
|
||||
int h = (int)(uimode.size.height / scale);
|
||||
|
||||
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)(size.width / data->scale),
|
||||
(int)(size.height / data->scale),
|
||||
1.0f, uimode, addRotation);
|
||||
/* Make sure the width/height are oriented correctly */
|
||||
if (isLandscape != (w > h)) {
|
||||
int tmp = w;
|
||||
w = h;
|
||||
h = tmp;
|
||||
}
|
||||
|
||||
UIKit_AddDisplayMode(display, w, h, uimode, addRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -217,19 +217,24 @@ UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
|||
int
|
||||
UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
|
||||
{
|
||||
SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
|
||||
SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
|
||||
@autoreleasepool {
|
||||
SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
|
||||
SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata;
|
||||
|
||||
[data->uiscreen setCurrentMode:modedata->uiscreenmode];
|
||||
[data.uiscreen setCurrentMode:modedata.uiscreenmode];
|
||||
|
||||
if (data->uiscreen == [UIScreen mainScreen]) {
|
||||
if (mode->w > mode->h) {
|
||||
if (!UIKit_IsDisplayLandscape(data->uiscreen)) {
|
||||
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
|
||||
}
|
||||
} else if (mode->w < mode->h) {
|
||||
if (UIKit_IsDisplayLandscape(data->uiscreen)) {
|
||||
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
|
||||
if (data.uiscreen == [UIScreen mainScreen]) {
|
||||
/* [UIApplication setStatusBarOrientation:] no longer works reliably
|
||||
* in recent iOS versions, so we can't rotate the screen when setting
|
||||
* the display mode. */
|
||||
if (mode->w > mode->h) {
|
||||
if (!UIKit_IsDisplayLandscape(data.uiscreen)) {
|
||||
return SDL_SetError("Screen orientation does not match display mode size");
|
||||
}
|
||||
} else if (mode->w < mode->h) {
|
||||
if (UIKit_IsDisplayLandscape(data.uiscreen)) {
|
||||
return SDL_SetError("Screen orientation does not match display mode size");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -242,19 +247,21 @@ UIKit_QuitModes(_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];
|
||||
@autoreleasepool {
|
||||
for (i = 0; i < _this->num_displays; i++) {
|
||||
SDL_VideoDisplay *display = &_this->displays[i];
|
||||
|
||||
UIKit_FreeDisplayModeData(&display->desktop_mode);
|
||||
for (j = 0; j < display->num_display_modes; j++) {
|
||||
SDL_DisplayMode *mode = &display->display_modes[j];
|
||||
UIKit_FreeDisplayModeData(mode);
|
||||
UIKit_FreeDisplayModeData(&display->desktop_mode);
|
||||
for (j = 0; j < display->num_display_modes; j++) {
|
||||
SDL_DisplayMode *mode = &display->display_modes[j];
|
||||
UIKit_FreeDisplayModeData(mode);
|
||||
}
|
||||
|
||||
if (display->driverdata != NULL) {
|
||||
CFRelease(display->driverdata);
|
||||
display->driverdata = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
|
||||
[data->uiscreen release];
|
||||
SDL_free(data);
|
||||
display->driverdata = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
extern int UIKit_GL_MakeCurrent(_THIS, SDL_Window * window,
|
||||
SDL_GLContext context);
|
||||
extern void UIKit_GL_GetDrawableSize(_THIS, SDL_Window * window,
|
||||
int * w, int * h);
|
||||
extern void UIKit_GL_SwapWindow(_THIS, SDL_Window * window);
|
||||
extern SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window);
|
||||
extern void UIKit_GL_DeleteContext(_THIS, SDL_GLContext context);
|
||||
|
|
|
@ -23,10 +23,10 @@
|
|||
#if SDL_VIDEO_DRIVER_UIKIT
|
||||
|
||||
#include "SDL_uikitopengles.h"
|
||||
#include "SDL_uikitopenglview.h"
|
||||
#include "SDL_uikitappdelegate.h"
|
||||
#import "SDL_uikitopenglview.h"
|
||||
#include "SDL_uikitmodes.h"
|
||||
#include "SDL_uikitwindow.h"
|
||||
#include "SDL_uikitevents.h"
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
|
@ -40,148 +40,189 @@ void *
|
|||
UIKit_GL_GetProcAddress(_THIS, const char *proc)
|
||||
{
|
||||
/* Look through all SO's for the proc symbol. Here's why:
|
||||
-Looking for the path to the OpenGL Library seems not to work in the iPhone Simulator.
|
||||
-We don't know that the path won't change in the future.
|
||||
*/
|
||||
* -Looking for the path to the OpenGL Library seems not to work in the iOS Simulator.
|
||||
* -We don't know that the path won't change in the future. */
|
||||
return dlsym(RTLD_DEFAULT, proc);
|
||||
}
|
||||
|
||||
/*
|
||||
note that SDL_GL_Delete context makes it current without passing the window
|
||||
note that SDL_GL_DeleteContext makes it current without passing the window
|
||||
*/
|
||||
int UIKit_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
|
||||
int
|
||||
UIKit_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
|
||||
{
|
||||
[EAGLContext setCurrentContext: context];
|
||||
@autoreleasepool {
|
||||
SDLEAGLContext *eaglcontext = (__bridge SDLEAGLContext *) context;
|
||||
|
||||
if (![EAGLContext setCurrentContext:eaglcontext]) {
|
||||
return SDL_SetError("Could not make EAGL context current");
|
||||
}
|
||||
|
||||
if (eaglcontext) {
|
||||
[eaglcontext.sdlView setSDLWindow:window];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
|
||||
UIView *view = data.viewcontroller.view;
|
||||
if ([view isKindOfClass:[SDL_uikitopenglview class]]) {
|
||||
SDL_uikitopenglview *glview = (SDL_uikitopenglview *) view;
|
||||
if (w) {
|
||||
*w = glview.backingWidth;
|
||||
}
|
||||
if (h) {
|
||||
*h = glview.backingHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
UIKit_GL_LoadLibrary(_THIS, const char *path)
|
||||
{
|
||||
/*
|
||||
shouldn't be passing a path into this function
|
||||
why? Because we've already loaded the library
|
||||
and because the SDK forbids loading an external SO
|
||||
*/
|
||||
/* We shouldn't pass a path to this function, since we've already loaded the
|
||||
* library. */
|
||||
if (path != NULL) {
|
||||
return SDL_SetError("iPhone GL Load Library just here for compatibility");
|
||||
return SDL_SetError("iOS GL Load Library just here for compatibility");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UIKit_GL_SwapWindow(_THIS, SDL_Window * window)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDLEAGLContext *context = (__bridge SDLEAGLContext *) SDL_GL_GetCurrentContext();
|
||||
|
||||
#if SDL_POWER_UIKIT
|
||||
/* Check once a frame to see if we should turn off the battery monitor. */
|
||||
SDL_UIKit_UpdateBatteryMonitoring();
|
||||
/* Check once a frame to see if we should turn off the battery monitor. */
|
||||
SDL_UIKit_UpdateBatteryMonitoring();
|
||||
#endif
|
||||
|
||||
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
|
||||
[context.sdlView swapBuffers];
|
||||
|
||||
if (nil == data->view) {
|
||||
return;
|
||||
/* You need to pump events in order for the OS to make changes visible.
|
||||
* We don't pump events here because we don't want iOS application events
|
||||
* (low memory, terminate, etc.) to happen inside low level rendering. */
|
||||
}
|
||||
[data->view swapBuffers];
|
||||
|
||||
/* You need to pump events in order for the OS to make changes visible.
|
||||
We don't pump events here because we don't want iOS application events
|
||||
(low memory, terminate, etc.) to happen inside low level rendering.
|
||||
*/
|
||||
}
|
||||
|
||||
SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window)
|
||||
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;
|
||||
EAGLSharegroup *share_group = nil;
|
||||
@autoreleasepool {
|
||||
SDL_uikitopenglview *view;
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
|
||||
CGRect frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen);
|
||||
EAGLSharegroup *sharegroup = nil;
|
||||
CGFloat scale = 1.0;
|
||||
|
||||
if (_this->gl_config.share_with_current_context) {
|
||||
SDL_uikitopenglview *view = (SDL_uikitopenglview *) SDL_GL_GetCurrentContext();
|
||||
share_group = [view.context sharegroup];
|
||||
}
|
||||
if (_this->gl_config.share_with_current_context) {
|
||||
EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext();
|
||||
sharegroup = context.sharegroup;
|
||||
}
|
||||
|
||||
/* construct our view, passing in SDL's OpenGL configuration data */
|
||||
CGRect frame;
|
||||
if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
|
||||
frame = [displaydata->uiscreen bounds];
|
||||
} else {
|
||||
frame = [displaydata->uiscreen applicationFrame];
|
||||
}
|
||||
view = [[SDL_uikitopenglview alloc] initWithFrame: frame
|
||||
scale: displaymodedata->scale
|
||||
retainBacking: _this->gl_config.retained_backing
|
||||
rBits: _this->gl_config.red_size
|
||||
gBits: _this->gl_config.green_size
|
||||
bBits: _this->gl_config.blue_size
|
||||
aBits: _this->gl_config.alpha_size
|
||||
depthBits: _this->gl_config.depth_size
|
||||
stencilBits: _this->gl_config.stencil_size
|
||||
majorVersion: _this->gl_config.major_version
|
||||
shareGroup: share_group];
|
||||
if (!view) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data->view = view;
|
||||
view->viewcontroller = data->viewcontroller;
|
||||
if (view->viewcontroller != nil) {
|
||||
[view->viewcontroller setView:view];
|
||||
[view->viewcontroller retain];
|
||||
}
|
||||
[uiwindow addSubview: view];
|
||||
|
||||
/* The view controller needs to be the root in order to control rotation on iOS 6.0 */
|
||||
if (uiwindow.rootViewController == nil) {
|
||||
uiwindow.rootViewController = view->viewcontroller;
|
||||
}
|
||||
|
||||
EAGLContext *context = view.context;
|
||||
if (UIKit_GL_MakeCurrent(_this, window, context) < 0) {
|
||||
UIKit_GL_DeleteContext(_this, context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make this window the current mouse focus for touch input */
|
||||
if (displaydata->uiscreen == [UIScreen mainScreen]) {
|
||||
SDL_SetMouseFocus(window);
|
||||
SDL_SetKeyboardFocus(window);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void UIKit_GL_DeleteContext(_THIS, SDL_GLContext context)
|
||||
{
|
||||
SDL_Window *window;
|
||||
|
||||
/* Find the view associated with this context */
|
||||
for (window = _this->windows; window; window = window->next) {
|
||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
SDL_uikitopenglview *view = data->view;
|
||||
if (view.context == context) {
|
||||
/* the delegate has retained the view, this will release him */
|
||||
if (view->viewcontroller) {
|
||||
UIWindow *uiwindow = (UIWindow *)view.superview;
|
||||
if (uiwindow.rootViewController == view->viewcontroller) {
|
||||
uiwindow.rootViewController = nil;
|
||||
}
|
||||
[view->viewcontroller setView:nil];
|
||||
[view->viewcontroller release];
|
||||
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
|
||||
/* Set the scale to the natural scale factor of the screen - the
|
||||
* backing dimensions of the OpenGL view will match the pixel
|
||||
* dimensions of the screen rather than the dimensions in points. */
|
||||
#ifdef __IPHONE_8_0
|
||||
if ([data.uiwindow.screen respondsToSelector:@selector(nativeScale)]) {
|
||||
scale = data.uiwindow.screen.nativeScale;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
scale = data.uiwindow.screen.scale;
|
||||
}
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
|
||||
/* FIXME: This doesn't actually call view dealloc - what is holding a reference to it? */
|
||||
[view release];
|
||||
return;
|
||||
/* construct our view, passing in SDL's OpenGL configuration data */
|
||||
view = [[SDL_uikitopenglview alloc] initWithFrame:frame
|
||||
scale:scale
|
||||
retainBacking:_this->gl_config.retained_backing
|
||||
rBits:_this->gl_config.red_size
|
||||
gBits:_this->gl_config.green_size
|
||||
bBits:_this->gl_config.blue_size
|
||||
aBits:_this->gl_config.alpha_size
|
||||
depthBits:_this->gl_config.depth_size
|
||||
stencilBits:_this->gl_config.stencil_size
|
||||
sRGB:_this->gl_config.framebuffer_srgb_capable
|
||||
majorVersion:_this->gl_config.major_version
|
||||
shareGroup:sharegroup];
|
||||
if (!view) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDLEAGLContext *context = view.context;
|
||||
if (UIKit_GL_MakeCurrent(_this, window, (__bridge SDL_GLContext) context) < 0) {
|
||||
UIKit_GL_DeleteContext(_this, (SDL_GLContext) CFBridgingRetain(context));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We return a +1'd context. The window's driverdata owns the view (via
|
||||
* MakeCurrent.) */
|
||||
return (SDL_GLContext) CFBridgingRetain(context);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_GL_DeleteContext(_THIS, SDL_GLContext context)
|
||||
{
|
||||
@autoreleasepool {
|
||||
/* Transfer ownership the +1'd context to ARC. */
|
||||
SDLEAGLContext *eaglcontext = (SDLEAGLContext *) CFBridgingRelease(context);
|
||||
|
||||
/* Detach the context's view from its window. */
|
||||
[eaglcontext.sdlView setSDLWindow:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
Uint32
|
||||
SDL_iPhoneGetViewRenderbuffer(SDL_Window * window)
|
||||
{
|
||||
if (!window) {
|
||||
SDL_SetError("Invalid window");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
|
||||
UIView *view = data.viewcontroller.view;
|
||||
if ([view isKindOfClass:[SDL_uikitopenglview class]]) {
|
||||
SDL_uikitopenglview *glview = (SDL_uikitopenglview *) view;
|
||||
return glview.drawableRenderbuffer;
|
||||
}
|
||||
}
|
||||
|
||||
/* View not found... delete the context anyway? */
|
||||
[(EAGLContext *)context release];
|
||||
SDL_SetError("Window does not have an attached OpenGL view");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Uint32
|
||||
SDL_iPhoneGetViewFramebuffer(SDL_Window * window)
|
||||
{
|
||||
if (!window) {
|
||||
SDL_SetError("Invalid window");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
|
||||
UIView *view = data.viewcontroller.view;
|
||||
if ([view isKindOfClass:[SDL_uikitopenglview class]]) {
|
||||
SDL_uikitopenglview *glview = (SDL_uikitopenglview *) view;
|
||||
return glview.drawableFramebuffer;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetError("Window does not have an attached OpenGL view");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_UIKIT */
|
||||
|
|
|
@ -21,66 +21,48 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <OpenGLES/EAGL.h>
|
||||
#import <OpenGLES/ES1/gl.h>
|
||||
#import <OpenGLES/ES1/glext.h>
|
||||
#import <OpenGLES/ES2/gl.h>
|
||||
|
||||
#import "SDL_uikitview.h"
|
||||
/*
|
||||
This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass.
|
||||
The view content is basically an EAGL surface you render your OpenGL scene into.
|
||||
Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel.
|
||||
*/
|
||||
@interface SDL_uikitopenglview : SDL_uikitview {
|
||||
#include "SDL_uikitvideo.h"
|
||||
|
||||
@private
|
||||
/* The pixel dimensions of the backbuffer */
|
||||
GLint backingWidth;
|
||||
GLint backingHeight;
|
||||
@class SDL_uikitopenglview;
|
||||
|
||||
EAGLContext *context;
|
||||
@interface SDLEAGLContext : EAGLContext
|
||||
|
||||
/* OpenGL names for the renderbuffer and framebuffers used to render to this view */
|
||||
GLuint viewRenderbuffer, viewFramebuffer;
|
||||
@property (nonatomic, weak) SDL_uikitopenglview *sdlView;
|
||||
|
||||
/* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */
|
||||
GLuint depthRenderbuffer;
|
||||
@end
|
||||
|
||||
/* format of depthRenderbuffer */
|
||||
GLenum depthBufferFormat;
|
||||
@interface SDL_uikitopenglview : SDL_uikitview
|
||||
|
||||
id displayLink;
|
||||
int animationInterval;
|
||||
void (*animationCallback)(void*);
|
||||
void *animationCallbackParam;
|
||||
}
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
scale:(CGFloat)scale
|
||||
retainBacking:(BOOL)retained
|
||||
rBits:(int)rBits
|
||||
gBits:(int)gBits
|
||||
bBits:(int)bBits
|
||||
aBits:(int)aBits
|
||||
depthBits:(int)depthBits
|
||||
stencilBits:(int)stencilBits
|
||||
sRGB:(BOOL)sRGB
|
||||
majorVersion:(int)majorVersion
|
||||
shareGroup:(EAGLSharegroup*)shareGroup;
|
||||
|
||||
@property (nonatomic, retain, readonly) EAGLContext *context;
|
||||
@property (nonatomic, readonly, strong) SDLEAGLContext *context;
|
||||
|
||||
/* The width and height of the drawable in pixels (as opposed to points.) */
|
||||
@property (nonatomic, readonly) int backingWidth;
|
||||
@property (nonatomic, readonly) int backingHeight;
|
||||
|
||||
@property (nonatomic, readonly) GLuint drawableRenderbuffer;
|
||||
@property (nonatomic, readonly) GLuint drawableFramebuffer;
|
||||
|
||||
- (void)swapBuffers;
|
||||
- (void)setCurrentContext;
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
scale:(CGFloat)scale
|
||||
retainBacking:(BOOL)retained
|
||||
rBits:(int)rBits
|
||||
gBits:(int)gBits
|
||||
bBits:(int)bBits
|
||||
aBits:(int)aBits
|
||||
depthBits:(int)depthBits
|
||||
stencilBits:(int)stencilBits
|
||||
majorVersion:(int)majorVersion
|
||||
shareGroup:(EAGLSharegroup*)shareGroup;
|
||||
|
||||
- (void)updateFrame;
|
||||
|
||||
- (void)setAnimationCallback:(int)interval
|
||||
callback:(void (*)(void*))callback
|
||||
callbackParam:(void*)callbackParam;
|
||||
|
||||
- (void)startAnimation;
|
||||
- (void)stopAnimation;
|
||||
|
||||
- (void)doLoop:(CADisplayLink*)sender;
|
||||
|
||||
@end
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -22,170 +22,190 @@
|
|||
|
||||
#if SDL_VIDEO_DRIVER_UIKIT
|
||||
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
#include <OpenGLES/EAGLDrawable.h>
|
||||
#include "SDL_uikitopenglview.h"
|
||||
#include "SDL_uikitmessagebox.h"
|
||||
#include <OpenGLES/ES2/glext.h>
|
||||
#import "SDL_uikitopenglview.h"
|
||||
#include "SDL_uikitwindow.h"
|
||||
|
||||
@implementation SDLEAGLContext
|
||||
|
||||
@implementation SDL_uikitopenglview
|
||||
@end
|
||||
|
||||
@implementation SDL_uikitopenglview {
|
||||
/* The renderbuffer and framebuffer used to render to this layer. */
|
||||
GLuint viewRenderbuffer, viewFramebuffer;
|
||||
|
||||
/* The depth buffer that is attached to viewFramebuffer, if it exists. */
|
||||
GLuint depthRenderbuffer;
|
||||
|
||||
/* format of depthRenderbuffer */
|
||||
GLenum depthBufferFormat;
|
||||
}
|
||||
|
||||
@synthesize context;
|
||||
@synthesize backingWidth;
|
||||
@synthesize backingHeight;
|
||||
|
||||
+ (Class)layerClass
|
||||
{
|
||||
return [CAEAGLLayer class];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
scale:(CGFloat)scale
|
||||
retainBacking:(BOOL)retained
|
||||
rBits:(int)rBits
|
||||
gBits:(int)gBits
|
||||
bBits:(int)bBits
|
||||
aBits:(int)aBits
|
||||
depthBits:(int)depthBits
|
||||
stencilBits:(int)stencilBits
|
||||
majorVersion:(int)majorVersion
|
||||
shareGroup:(EAGLSharegroup*)shareGroup
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
scale:(CGFloat)scale
|
||||
retainBacking:(BOOL)retained
|
||||
rBits:(int)rBits
|
||||
gBits:(int)gBits
|
||||
bBits:(int)bBits
|
||||
aBits:(int)aBits
|
||||
depthBits:(int)depthBits
|
||||
stencilBits:(int)stencilBits
|
||||
sRGB:(BOOL)sRGB
|
||||
majorVersion:(int)majorVersion
|
||||
shareGroup:(EAGLSharegroup*)shareGroup
|
||||
{
|
||||
depthBufferFormat = 0;
|
||||
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
const BOOL useStencilBuffer = (stencilBits != 0);
|
||||
const BOOL useDepthBuffer = (depthBits != 0);
|
||||
NSString *colorFormat = nil;
|
||||
|
||||
/* The EAGLRenderingAPI enum values currently map 1:1 to major GLES
|
||||
versions, and this allows us to handle future OpenGL ES versions.
|
||||
*/
|
||||
* versions, and this allows us to handle future OpenGL ES versions. */
|
||||
EAGLRenderingAPI api = majorVersion;
|
||||
|
||||
if (rBits == 8 && gBits == 8 && bBits == 8) {
|
||||
/* if user specifically requests rbg888 or some color format higher than 16bpp */
|
||||
colorFormat = kEAGLColorFormatRGBA8;
|
||||
} else {
|
||||
/* default case (faster) */
|
||||
colorFormat = kEAGLColorFormatRGB565;
|
||||
}
|
||||
|
||||
/* Get the layer */
|
||||
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
|
||||
|
||||
eaglLayer.opaque = YES;
|
||||
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithBool: retained], kEAGLDrawablePropertyRetainedBacking, colorFormat, kEAGLDrawablePropertyColorFormat, nil];
|
||||
|
||||
context = [[EAGLContext alloc] initWithAPI:api sharegroup:shareGroup];
|
||||
context = [[SDLEAGLContext alloc] initWithAPI:api sharegroup:shareGroup];
|
||||
if (!context || ![EAGLContext setCurrentContext:context]) {
|
||||
[self release];
|
||||
SDL_SetError("OpenGL ES %d not supported", majorVersion);
|
||||
return nil;
|
||||
}
|
||||
|
||||
context.sdlView = self;
|
||||
|
||||
if (sRGB) {
|
||||
/* sRGB EAGL drawable support was added in iOS 7. */
|
||||
if (UIKit_IsSystemVersionAtLeast(7.0)) {
|
||||
colorFormat = kEAGLColorFormatSRGBA8;
|
||||
} else {
|
||||
SDL_SetError("sRGB drawables are not supported.");
|
||||
return nil;
|
||||
}
|
||||
} else if (rBits >= 8 || gBits >= 8 || bBits >= 8) {
|
||||
/* if user specifically requests rbg888 or some color format higher than 16bpp */
|
||||
colorFormat = kEAGLColorFormatRGBA8;
|
||||
} else {
|
||||
/* default case (potentially faster) */
|
||||
colorFormat = kEAGLColorFormatRGB565;
|
||||
}
|
||||
|
||||
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
|
||||
|
||||
eaglLayer.opaque = YES;
|
||||
eaglLayer.drawableProperties = @{
|
||||
kEAGLDrawablePropertyRetainedBacking:@(retained),
|
||||
kEAGLDrawablePropertyColorFormat:colorFormat
|
||||
};
|
||||
|
||||
/* Set the appropriate scale (for retina display support) */
|
||||
self.contentScaleFactor = scale;
|
||||
|
||||
/* create the buffers */
|
||||
glGenFramebuffersOES(1, &viewFramebuffer);
|
||||
glGenRenderbuffersOES(1, &viewRenderbuffer);
|
||||
/* Create the color Renderbuffer Object */
|
||||
glGenRenderbuffers(1, &viewRenderbuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
|
||||
|
||||
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
|
||||
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
|
||||
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
|
||||
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
|
||||
if (![context renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer]) {
|
||||
SDL_SetError("Failed to create OpenGL ES drawable");
|
||||
return nil;
|
||||
}
|
||||
|
||||
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
|
||||
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
|
||||
/* Create the Framebuffer Object */
|
||||
glGenFramebuffers(1, &viewFramebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);
|
||||
|
||||
/* attach the color renderbuffer to the FBO */
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, viewRenderbuffer);
|
||||
|
||||
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
|
||||
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
|
||||
|
||||
if ((useDepthBuffer) || (useStencilBuffer)) {
|
||||
if (useStencilBuffer) {
|
||||
/* Apparently you need to pack stencil and depth into one buffer. */
|
||||
depthBufferFormat = GL_DEPTH24_STENCIL8_OES;
|
||||
} else if (useDepthBuffer) {
|
||||
/* iOS only has 24-bit depth buffers, even with GL_DEPTH_COMPONENT16_OES */
|
||||
/* iOS only uses 32-bit float (exposed as fixed point 24-bit)
|
||||
* depth buffers. */
|
||||
depthBufferFormat = GL_DEPTH_COMPONENT24_OES;
|
||||
}
|
||||
|
||||
glGenRenderbuffersOES(1, &depthRenderbuffer);
|
||||
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
|
||||
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
|
||||
glGenRenderbuffers(1, &depthRenderbuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, depthBufferFormat, backingWidth, backingHeight);
|
||||
if (useDepthBuffer) {
|
||||
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
|
||||
}
|
||||
if (useStencilBuffer) {
|
||||
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
|
||||
return NO;
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
SDL_SetError("Failed creating OpenGL ES framebuffer");
|
||||
return nil;
|
||||
}
|
||||
|
||||
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
|
||||
/* end create buffers */
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
|
||||
|
||||
self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
|
||||
self.autoresizesSubviews = YES;
|
||||
[self setDebugLabels];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (GLuint)drawableRenderbuffer
|
||||
{
|
||||
return viewRenderbuffer;
|
||||
}
|
||||
|
||||
- (GLuint)drawableFramebuffer
|
||||
{
|
||||
return viewFramebuffer;
|
||||
}
|
||||
|
||||
- (void)updateFrame
|
||||
{
|
||||
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
|
||||
glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);
|
||||
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, 0);
|
||||
glDeleteRenderbuffersOES(1, &viewRenderbuffer);
|
||||
GLint prevRenderbuffer = 0;
|
||||
glGetIntegerv(GL_RENDERBUFFER_BINDING, &prevRenderbuffer);
|
||||
|
||||
glGenRenderbuffersOES(1, &viewRenderbuffer);
|
||||
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
|
||||
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
|
||||
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
|
||||
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
|
||||
|
||||
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
|
||||
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
|
||||
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
|
||||
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
|
||||
|
||||
if (depthRenderbuffer != 0) {
|
||||
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
|
||||
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, depthBufferFormat, backingWidth, backingHeight);
|
||||
}
|
||||
|
||||
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, prevRenderbuffer);
|
||||
}
|
||||
|
||||
- (void)setAnimationCallback:(int)interval
|
||||
callback:(void (*)(void*))callback
|
||||
callbackParam:(void*)callbackParam
|
||||
- (void)setDebugLabels
|
||||
{
|
||||
[self stopAnimation];
|
||||
if (viewFramebuffer != 0) {
|
||||
glLabelObjectEXT(GL_FRAMEBUFFER, viewFramebuffer, 0, "context FBO");
|
||||
}
|
||||
|
||||
animationInterval = interval;
|
||||
animationCallback = callback;
|
||||
animationCallbackParam = callbackParam;
|
||||
if (viewRenderbuffer != 0) {
|
||||
glLabelObjectEXT(GL_RENDERBUFFER, viewRenderbuffer, 0, "context color buffer");
|
||||
}
|
||||
|
||||
if (animationCallback)
|
||||
[self startAnimation];
|
||||
}
|
||||
|
||||
- (void)startAnimation
|
||||
{
|
||||
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
|
||||
[displayLink setFrameInterval:animationInterval];
|
||||
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
- (void)stopAnimation
|
||||
{
|
||||
[displayLink invalidate];
|
||||
displayLink = nil;
|
||||
}
|
||||
|
||||
- (void)doLoop:(CADisplayLink*)sender
|
||||
{
|
||||
/* Don't run the game loop while a messagebox is up */
|
||||
if (!UIKit_ShowingMessageBox()) {
|
||||
animationCallback(animationCallbackParam);
|
||||
if (depthRenderbuffer != 0) {
|
||||
if (depthBufferFormat == GL_DEPTH24_STENCIL8_OES) {
|
||||
glLabelObjectEXT(GL_RENDERBUFFER, depthRenderbuffer, 0, "context depth-stencil buffer");
|
||||
} else {
|
||||
glLabelObjectEXT(GL_RENDERBUFFER, depthRenderbuffer, 0, "context depth buffer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,44 +214,60 @@
|
|||
[EAGLContext setCurrentContext:context];
|
||||
}
|
||||
|
||||
|
||||
- (void)swapBuffers
|
||||
{
|
||||
/* viewRenderbuffer should always be bound here. Code that binds something
|
||||
else is responsible for rebinding viewRenderbuffer, to reduce
|
||||
duplicate state changes. */
|
||||
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
|
||||
* else is responsible for rebinding viewRenderbuffer, to reduce duplicate
|
||||
* state changes. */
|
||||
[context presentRenderbuffer:GL_RENDERBUFFER];
|
||||
}
|
||||
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[EAGLContext setCurrentContext:context];
|
||||
[self updateFrame];
|
||||
[super layoutSubviews];
|
||||
|
||||
int width = (int) (self.bounds.size.width * self.contentScaleFactor);
|
||||
int height = (int) (self.bounds.size.height * self.contentScaleFactor);
|
||||
|
||||
/* Update the color and depth buffer storage if the layer size has changed. */
|
||||
if (width != backingWidth || height != backingHeight) {
|
||||
EAGLContext *prevContext = [EAGLContext currentContext];
|
||||
if (prevContext != context) {
|
||||
[EAGLContext setCurrentContext:context];
|
||||
}
|
||||
|
||||
[self updateFrame];
|
||||
|
||||
if (prevContext != context) {
|
||||
[EAGLContext setCurrentContext:prevContext];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)destroyFramebuffer
|
||||
{
|
||||
glDeleteFramebuffersOES(1, &viewFramebuffer);
|
||||
viewFramebuffer = 0;
|
||||
glDeleteRenderbuffersOES(1, &viewRenderbuffer);
|
||||
viewRenderbuffer = 0;
|
||||
if (viewFramebuffer != 0) {
|
||||
glDeleteFramebuffers(1, &viewFramebuffer);
|
||||
viewFramebuffer = 0;
|
||||
}
|
||||
|
||||
if (depthRenderbuffer) {
|
||||
glDeleteRenderbuffersOES(1, &depthRenderbuffer);
|
||||
if (viewRenderbuffer != 0) {
|
||||
glDeleteRenderbuffers(1, &viewRenderbuffer);
|
||||
viewRenderbuffer = 0;
|
||||
}
|
||||
|
||||
if (depthRenderbuffer != 0) {
|
||||
glDeleteRenderbuffers(1, &depthRenderbuffer);
|
||||
depthRenderbuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self destroyFramebuffer];
|
||||
if ([EAGLContext currentContext] == context) {
|
||||
[self destroyFramebuffer];
|
||||
[EAGLContext setCurrentContext:nil];
|
||||
}
|
||||
[context release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -25,20 +25,8 @@
|
|||
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
#ifndef __IPHONE_6_0
|
||||
/* This enum isn't available in older SDKs, but we use it for our own purposes on iOS 5.1 and for the system on iOS 6.0 */
|
||||
enum UIInterfaceOrientationMask
|
||||
{
|
||||
UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
|
||||
UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
|
||||
UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
|
||||
UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
|
||||
UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
|
||||
UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
|
||||
UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
|
||||
};
|
||||
#endif /* !__IPHONE_6_0 */
|
||||
|
||||
BOOL UIKit_IsSystemVersionAtLeast(double version);
|
||||
CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen);
|
||||
|
||||
#endif /* _SDL_uikitvideo_h */
|
||||
|
||||
|
|
|
@ -75,15 +75,15 @@ UIKit_CreateDevice(int devindex)
|
|||
device->SetDisplayMode = UIKit_SetDisplayMode;
|
||||
device->PumpEvents = UIKit_PumpEvents;
|
||||
device->CreateWindow = UIKit_CreateWindow;
|
||||
device->SetWindowTitle = UIKit_SetWindowTitle;
|
||||
device->ShowWindow = UIKit_ShowWindow;
|
||||
device->HideWindow = UIKit_HideWindow;
|
||||
device->RaiseWindow = UIKit_RaiseWindow;
|
||||
device->SetWindowBordered = UIKit_SetWindowBordered;
|
||||
device->SetWindowFullscreen = UIKit_SetWindowFullscreen;
|
||||
device->DestroyWindow = UIKit_DestroyWindow;
|
||||
device->GetWindowWMInfo = UIKit_GetWindowWMInfo;
|
||||
|
||||
/* !!! FIXME: implement SetWindowBordered */
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
device->HasScreenKeyboardSupport = UIKit_HasScreenKeyboardSupport;
|
||||
device->ShowScreenKeyboard = UIKit_ShowScreenKeyboard;
|
||||
|
@ -93,12 +93,13 @@ UIKit_CreateDevice(int devindex)
|
|||
#endif
|
||||
|
||||
/* OpenGL (ES) functions */
|
||||
device->GL_MakeCurrent = UIKit_GL_MakeCurrent;
|
||||
device->GL_SwapWindow = UIKit_GL_SwapWindow;
|
||||
device->GL_MakeCurrent = UIKit_GL_MakeCurrent;
|
||||
device->GL_GetDrawableSize = UIKit_GL_GetDrawableSize;
|
||||
device->GL_SwapWindow = UIKit_GL_SwapWindow;
|
||||
device->GL_CreateContext = UIKit_GL_CreateContext;
|
||||
device->GL_DeleteContext = UIKit_GL_DeleteContext;
|
||||
device->GL_GetProcAddress = UIKit_GL_GetProcAddress;
|
||||
device->GL_LoadLibrary = UIKit_GL_LoadLibrary;
|
||||
device->GL_LoadLibrary = UIKit_GL_LoadLibrary;
|
||||
device->free = UIKit_DeleteDevice;
|
||||
|
||||
device->gl_config.accelerated = 1;
|
||||
|
@ -129,6 +130,25 @@ UIKit_VideoQuit(_THIS)
|
|||
UIKit_QuitModes(_this);
|
||||
}
|
||||
|
||||
BOOL
|
||||
UIKit_IsSystemVersionAtLeast(double version)
|
||||
{
|
||||
return [[UIDevice currentDevice].systemVersion doubleValue] >= version;
|
||||
}
|
||||
|
||||
CGRect
|
||||
UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
|
||||
{
|
||||
BOOL hasiOS7 = UIKit_IsSystemVersionAtLeast(7.0);
|
||||
|
||||
if (hasiOS7 || (window->flags & (SDL_WINDOW_BORDERLESS|SDL_WINDOW_FULLSCREEN))) {
|
||||
/* The view should always show behind the status bar in iOS 7+. */
|
||||
return screen.bounds;
|
||||
} else {
|
||||
return screen.applicationFrame;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* iOS log support.
|
||||
*
|
||||
|
|
|
@ -20,59 +20,22 @@
|
|||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "SDL_uikitviewcontroller.h"
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
#include "SDL_touch.h"
|
||||
|
||||
#define IPHONE_TOUCH_EFFICIENT_DANGEROUS
|
||||
@interface SDL_uikitview : UIView
|
||||
|
||||
#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS
|
||||
#define MAX_SIMULTANEOUS_TOUCHES 5
|
||||
#endif
|
||||
- (instancetype)initWithFrame:(CGRect)frame;
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
@interface SDL_uikitview : UIView<UITextFieldDelegate> {
|
||||
#else
|
||||
@interface SDL_uikitview : UIView {
|
||||
#endif
|
||||
- (void)setSDLWindow:(SDL_Window *)window;
|
||||
|
||||
SDL_TouchID touchId;
|
||||
UITouch *leftFingerDown;
|
||||
#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS
|
||||
UITouch *finger[MAX_SIMULTANEOUS_TOUCHES];
|
||||
#endif
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
UITextField *textField;
|
||||
BOOL keyboardVisible;
|
||||
SDL_Rect textInputRect;
|
||||
int keyboardHeight;
|
||||
#endif
|
||||
|
||||
@public
|
||||
SDL_uikitviewcontroller *viewcontroller;
|
||||
}
|
||||
- (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize;
|
||||
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
|
||||
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
|
||||
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
- (void)showKeyboard;
|
||||
- (void)hideKeyboard;
|
||||
- (void)initializeKeyboard;
|
||||
@property (readonly) BOOL keyboardVisible;
|
||||
@property (nonatomic,assign) SDL_Rect textInputRect;
|
||||
@property (nonatomic,assign) int keyboardHeight;
|
||||
|
||||
SDL_bool UIKit_HasScreenKeyboardSupport(_THIS);
|
||||
void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window);
|
||||
void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window);
|
||||
SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window);
|
||||
void UIKit_SetTextInputRect(_THIS, SDL_Rect *rect);
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -24,438 +24,167 @@
|
|||
|
||||
#include "SDL_uikitview.h"
|
||||
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
#include "../../events/SDL_touch_c.h"
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
#include "keyinfotable.h"
|
||||
#endif
|
||||
#include "SDL_uikitappdelegate.h"
|
||||
#include "SDL_uikitmodes.h"
|
||||
#include "SDL_uikitwindow.h"
|
||||
#import "SDL_uikitappdelegate.h"
|
||||
#import "SDL_uikitmodes.h"
|
||||
#import "SDL_uikitwindow.h"
|
||||
|
||||
void _uikit_keyboard_init() ;
|
||||
@implementation SDL_uikitview {
|
||||
SDL_Window *sdlwindow;
|
||||
|
||||
@implementation SDL_uikitview
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
SDL_TouchID touchId;
|
||||
UITouch * __weak firstFingerDown;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame: frame];
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
self.autoresizesSubviews = YES;
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
[self initializeKeyboard];
|
||||
#endif
|
||||
self.multipleTouchEnabled = YES;
|
||||
|
||||
self.multipleTouchEnabled = YES;
|
||||
|
||||
touchId = 1;
|
||||
SDL_AddTouch(touchId, "");
|
||||
touchId = 1;
|
||||
SDL_AddTouch(touchId, "");
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setSDLWindow:(SDL_Window *)window
|
||||
{
|
||||
SDL_WindowData *data = nil;
|
||||
|
||||
if (window == sdlwindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sdlwindow) {
|
||||
SDL_uikitview *view = nil;
|
||||
data = (__bridge SDL_WindowData *) sdlwindow->driverdata;
|
||||
|
||||
[data.views removeObject:self];
|
||||
|
||||
[self removeFromSuperview];
|
||||
|
||||
/* Restore the next-oldest view in the old window. */
|
||||
if (data.views.count > 0) {
|
||||
view = data.views[data.views.count - 1];
|
||||
}
|
||||
|
||||
data.viewcontroller.view = view;
|
||||
|
||||
if (data.uiwindow.rootViewController != data.viewcontroller) {
|
||||
data.uiwindow.rootViewController = data.viewcontroller;
|
||||
} else if (view) {
|
||||
[data.uiwindow addSubview:view];
|
||||
}
|
||||
|
||||
[data.uiwindow layoutIfNeeded];
|
||||
}
|
||||
|
||||
if (window) {
|
||||
data = (__bridge SDL_WindowData *) window->driverdata;
|
||||
|
||||
/* Make sure the SDL window has a strong reference to this view. */
|
||||
[data.views addObject:self];
|
||||
|
||||
/* Replace the view controller's old view with this one. */
|
||||
[data.viewcontroller.view removeFromSuperview];
|
||||
data.viewcontroller.view = self;
|
||||
|
||||
if (data.uiwindow.rootViewController != data.viewcontroller) {
|
||||
/* The root view controller handles rotation and the status bar.
|
||||
* Assigning it also adds the controller's view to the window. */
|
||||
data.uiwindow.rootViewController = data.viewcontroller;
|
||||
} else {
|
||||
[data.uiwindow addSubview:self];
|
||||
}
|
||||
|
||||
/* The view's bounds may not be correct until the next event cycle. That
|
||||
* might happen after the current dimensions are queried, so we force a
|
||||
* layout now to immediately update the bounds. */
|
||||
[data.uiwindow layoutIfNeeded];
|
||||
}
|
||||
|
||||
sdlwindow = window;
|
||||
}
|
||||
|
||||
- (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
|
||||
{
|
||||
CGPoint point = [touch locationInView: self];
|
||||
|
||||
/* Get the display scale and apply that to the input coordinates */
|
||||
SDL_Window *window = self->viewcontroller.window;
|
||||
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
|
||||
SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
|
||||
CGPoint point = [touch locationInView:self];
|
||||
|
||||
if (normalize) {
|
||||
CGRect bounds = [self bounds];
|
||||
CGRect bounds = self.bounds;
|
||||
point.x /= bounds.size.width;
|
||||
point.y /= bounds.size.height;
|
||||
} else {
|
||||
point.x *= displaymodedata->scale;
|
||||
point.y *= displaymodedata->scale;
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
NSEnumerator *enumerator = [touches objectEnumerator];
|
||||
UITouch *touch = (UITouch*)[enumerator nextObject];
|
||||
|
||||
while (touch) {
|
||||
if (!leftFingerDown) {
|
||||
for (UITouch *touch in touches) {
|
||||
if (!firstFingerDown) {
|
||||
CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
|
||||
|
||||
/* send moved event */
|
||||
SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
|
||||
/* send mouse moved event */
|
||||
SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
|
||||
|
||||
/* send mouse down event */
|
||||
SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
|
||||
SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
|
||||
|
||||
leftFingerDown = touch;
|
||||
firstFingerDown = touch;
|
||||
}
|
||||
|
||||
CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
|
||||
#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
|
||||
/* FIXME: TODO: Using touch as the fingerId is potentially dangerous
|
||||
* It is also much more efficient than storing the UITouch pointer
|
||||
* and comparing it to the incoming event.
|
||||
*/
|
||||
SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
|
||||
SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
|
||||
#else
|
||||
int i;
|
||||
for(i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
|
||||
if (finger[i] == NULL) {
|
||||
finger[i] = touch;
|
||||
SDL_SendTouch(touchId, i,
|
||||
SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
touch = (UITouch*)[enumerator nextObject];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
NSEnumerator *enumerator = [touches objectEnumerator];
|
||||
UITouch *touch = (UITouch*)[enumerator nextObject];
|
||||
|
||||
while(touch) {
|
||||
if (touch == leftFingerDown) {
|
||||
for (UITouch *touch in touches) {
|
||||
if (touch == firstFingerDown) {
|
||||
/* send mouse up */
|
||||
SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
|
||||
leftFingerDown = nil;
|
||||
SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
|
||||
firstFingerDown = nil;
|
||||
}
|
||||
|
||||
CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
|
||||
#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
|
||||
SDL_SendTouch(touchId, (long)touch,
|
||||
SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
|
||||
SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
|
||||
#else
|
||||
int i;
|
||||
for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
|
||||
if (finger[i] == touch) {
|
||||
SDL_SendTouch(touchId, i,
|
||||
SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
|
||||
finger[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
touch = (UITouch*)[enumerator nextObject];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
/*
|
||||
this can happen if the user puts more than 5 touches on the screen
|
||||
at once, or perhaps in other circumstances. Usually (it seems)
|
||||
all active touches are canceled.
|
||||
*/
|
||||
[self touchesEnded: touches withEvent: event];
|
||||
[self touchesEnded:touches withEvent:event];
|
||||
}
|
||||
|
||||
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
NSEnumerator *enumerator = [touches objectEnumerator];
|
||||
UITouch *touch = (UITouch*)[enumerator nextObject];
|
||||
|
||||
while (touch) {
|
||||
if (touch == leftFingerDown) {
|
||||
for (UITouch *touch in touches) {
|
||||
if (touch == firstFingerDown) {
|
||||
CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
|
||||
|
||||
/* send moved event */
|
||||
SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
|
||||
SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
|
||||
}
|
||||
|
||||
CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
|
||||
#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
|
||||
SDL_SendTouchMotion(touchId, (long)touch,
|
||||
SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch),
|
||||
locationInView.x, locationInView.y, 1.0f);
|
||||
#else
|
||||
int i;
|
||||
for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
|
||||
if (finger[i] == touch) {
|
||||
SDL_SendTouchMotion(touchId, i,
|
||||
locationInView.x, locationInView.y, 1.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
touch = (UITouch*)[enumerator nextObject];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
---- Keyboard related functionality below this line ----
|
||||
*/
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
|
||||
@synthesize textInputRect = textInputRect;
|
||||
@synthesize keyboardHeight = keyboardHeight;
|
||||
|
||||
/* Is the iPhone virtual keyboard visible onscreen? */
|
||||
- (BOOL)keyboardVisible
|
||||
{
|
||||
return keyboardVisible;
|
||||
}
|
||||
|
||||
/* Set ourselves up as a UITextFieldDelegate */
|
||||
- (void)initializeKeyboard
|
||||
{
|
||||
textField = [[UITextField alloc] initWithFrame: CGRectZero];
|
||||
textField.delegate = self;
|
||||
/* placeholder so there is something to delete! */
|
||||
textField.text = @" ";
|
||||
|
||||
/* set UITextInputTrait properties, mostly to defaults */
|
||||
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
textField.autocorrectionType = UITextAutocorrectionTypeNo;
|
||||
textField.enablesReturnKeyAutomatically = NO;
|
||||
textField.keyboardAppearance = UIKeyboardAppearanceDefault;
|
||||
textField.keyboardType = UIKeyboardTypeDefault;
|
||||
textField.returnKeyType = UIReturnKeyDefault;
|
||||
textField.secureTextEntry = NO;
|
||||
|
||||
textField.hidden = YES;
|
||||
keyboardVisible = NO;
|
||||
/* add the UITextField (hidden) to our view */
|
||||
[self addSubview: textField];
|
||||
[textField release];
|
||||
|
||||
_uikit_keyboard_init();
|
||||
}
|
||||
|
||||
/* reveal onscreen virtual keyboard */
|
||||
- (void)showKeyboard
|
||||
{
|
||||
keyboardVisible = YES;
|
||||
[textField becomeFirstResponder];
|
||||
}
|
||||
|
||||
/* hide onscreen virtual keyboard */
|
||||
- (void)hideKeyboard
|
||||
{
|
||||
keyboardVisible = NO;
|
||||
[textField resignFirstResponder];
|
||||
}
|
||||
|
||||
/* UITextFieldDelegate method. Invoked when user types something. */
|
||||
- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
|
||||
{
|
||||
if ([string length] == 0) {
|
||||
/* it wants to replace text with nothing, ie a delete */
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
|
||||
}
|
||||
else {
|
||||
/* go through all the characters in the string we've been sent
|
||||
and convert them to key presses */
|
||||
int i;
|
||||
for (i = 0; i < [string length]; i++) {
|
||||
|
||||
unichar c = [string characterAtIndex: i];
|
||||
|
||||
Uint16 mod = 0;
|
||||
SDL_Scancode code;
|
||||
|
||||
if (c < 127) {
|
||||
/* figure out the SDL_Scancode and SDL_keymod for this unichar */
|
||||
code = unicharToUIKeyInfoTable[c].code;
|
||||
mod = unicharToUIKeyInfoTable[c].mod;
|
||||
}
|
||||
else {
|
||||
/* we only deal with ASCII right now */
|
||||
code = SDL_SCANCODE_UNKNOWN;
|
||||
mod = 0;
|
||||
}
|
||||
|
||||
if (mod & KMOD_SHIFT) {
|
||||
/* If character uses shift, press shift down */
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
|
||||
}
|
||||
/* send a keydown and keyup even for the character */
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, code);
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, code);
|
||||
if (mod & KMOD_SHIFT) {
|
||||
/* If character uses shift, press shift back up */
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
|
||||
}
|
||||
}
|
||||
SDL_SendKeyboardText([string UTF8String]);
|
||||
}
|
||||
return NO; /* don't allow the edit! (keep placeholder text there) */
|
||||
}
|
||||
|
||||
/* Terminates the editing session */
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)_textField
|
||||
{
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
|
||||
SDL_StopTextInput();
|
||||
return YES;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
/* iPhone keyboard addition functions */
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
|
||||
static SDL_uikitview * getWindowView(SDL_Window * window)
|
||||
{
|
||||
if (window == NULL) {
|
||||
SDL_SetError("Window does not exist");
|
||||
return nil;
|
||||
}
|
||||
|
||||
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
|
||||
SDL_uikitview *view = data != NULL ? data->view : nil;
|
||||
|
||||
if (view == nil) {
|
||||
SDL_SetError("Window has no view");
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
SDL_bool UIKit_HasScreenKeyboardSupport(_THIS)
|
||||
{
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
|
||||
{
|
||||
SDL_uikitview *view = getWindowView(window);
|
||||
if (view != nil) {
|
||||
[view showKeyboard];
|
||||
}
|
||||
}
|
||||
|
||||
void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
|
||||
{
|
||||
SDL_uikitview *view = getWindowView(window);
|
||||
if (view != nil) {
|
||||
[view hideKeyboard];
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
|
||||
{
|
||||
SDL_uikitview *view = getWindowView(window);
|
||||
if (view == nil) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return view.keyboardVisible;
|
||||
}
|
||||
|
||||
|
||||
void _uikit_keyboard_update() {
|
||||
SDL_Window *window = SDL_GetFocusWindow();
|
||||
if (!window) { return; }
|
||||
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
|
||||
if (!data) { return; }
|
||||
SDL_uikitview *view = data->view;
|
||||
if (!view) { return; }
|
||||
|
||||
SDL_Rect r = view.textInputRect;
|
||||
int height = view.keyboardHeight;
|
||||
int offsetx = 0;
|
||||
int offsety = 0;
|
||||
float scale = [UIScreen mainScreen].scale;
|
||||
if (height) {
|
||||
int sw,sh;
|
||||
SDL_GetWindowSize(window,&sw,&sh);
|
||||
int bottom = (r.y + r.h);
|
||||
int kbottom = sh - height;
|
||||
if (kbottom < bottom) {
|
||||
offsety = kbottom-bottom;
|
||||
}
|
||||
}
|
||||
UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
|
||||
if (ui_orient == UIInterfaceOrientationLandscapeLeft) {
|
||||
int tmp = offsetx; offsetx = offsety; offsety = tmp;
|
||||
}
|
||||
if (ui_orient == UIInterfaceOrientationLandscapeRight) {
|
||||
offsety = -offsety;
|
||||
int tmp = offsetx; offsetx = offsety; offsety = tmp;
|
||||
}
|
||||
if (ui_orient == UIInterfaceOrientationPortraitUpsideDown) {
|
||||
offsety = -offsety;
|
||||
}
|
||||
|
||||
offsetx /= scale;
|
||||
offsety /= scale;
|
||||
|
||||
view.frame = CGRectMake(offsetx,offsety,view.frame.size.width,view.frame.size.height);
|
||||
}
|
||||
|
||||
void _uikit_keyboard_set_height(int height) {
|
||||
SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
|
||||
if (view == nil) {
|
||||
return ;
|
||||
}
|
||||
|
||||
view.keyboardHeight = height;
|
||||
_uikit_keyboard_update();
|
||||
}
|
||||
|
||||
void _uikit_keyboard_init() {
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
NSOperationQueue *queue = [NSOperationQueue mainQueue];
|
||||
[center addObserverForName:UIKeyboardWillShowNotification
|
||||
object:nil
|
||||
queue:queue
|
||||
usingBlock:^(NSNotification *notification) {
|
||||
int height = 0;
|
||||
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
|
||||
height = keyboardSize.height;
|
||||
UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
|
||||
if (ui_orient == UIInterfaceOrientationLandscapeRight || ui_orient == UIInterfaceOrientationLandscapeLeft) {
|
||||
height = keyboardSize.width;
|
||||
}
|
||||
height *= [UIScreen mainScreen].scale;
|
||||
_uikit_keyboard_set_height(height);
|
||||
}
|
||||
];
|
||||
[center addObserverForName:UIKeyboardDidHideNotification
|
||||
object:nil
|
||||
queue:queue
|
||||
usingBlock:^(NSNotification *notification) {
|
||||
_uikit_keyboard_set_height(0);
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
|
||||
{
|
||||
if (!rect) {
|
||||
SDL_InvalidParamError("rect");
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
|
||||
if (view == nil) {
|
||||
return ;
|
||||
}
|
||||
|
||||
view.textInputRect = *rect;
|
||||
}
|
||||
|
||||
|
||||
#endif /* SDL_IPHONE_KEYBOARD */
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_UIKIT */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -23,18 +23,56 @@
|
|||
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
@interface SDL_uikitviewcontroller : UIViewController {
|
||||
@private
|
||||
SDL_Window *window;
|
||||
}
|
||||
#include "SDL_touch.h"
|
||||
|
||||
@property (readwrite) SDL_Window *window;
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
@interface SDL_uikitviewcontroller : UIViewController <UITextFieldDelegate>
|
||||
#else
|
||||
@interface SDL_uikitviewcontroller : UIViewController
|
||||
#endif
|
||||
|
||||
@property (nonatomic, assign) SDL_Window *window;
|
||||
|
||||
- (instancetype)initWithSDLWindow:(SDL_Window *)_window;
|
||||
|
||||
- (void)setAnimationCallback:(int)interval
|
||||
callback:(void (*)(void*))callback
|
||||
callbackParam:(void*)callbackParam;
|
||||
|
||||
- (void)startAnimation;
|
||||
- (void)stopAnimation;
|
||||
|
||||
- (void)doLoop:(CADisplayLink*)sender;
|
||||
|
||||
- (id)initWithSDLWindow:(SDL_Window *)_window;
|
||||
- (void)loadView;
|
||||
- (void)viewDidLayoutSubviews;
|
||||
- (NSUInteger)supportedInterfaceOrientations;
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient;
|
||||
- (BOOL)prefersStatusBarHidden;
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle;
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
- (void)showKeyboard;
|
||||
- (void)hideKeyboard;
|
||||
- (void)initKeyboard;
|
||||
- (void)deinitKeyboard;
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification;
|
||||
- (void)keyboardWillHide:(NSNotification *)notification;
|
||||
|
||||
- (void)updateKeyboard;
|
||||
|
||||
@property (nonatomic, assign, getter=isKeyboardVisible) BOOL keyboardVisible;
|
||||
@property (nonatomic, assign) SDL_Rect textInputRect;
|
||||
@property (nonatomic, assign) int keyboardHeight;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
SDL_bool UIKit_HasScreenKeyboardSupport(_THIS);
|
||||
void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window);
|
||||
void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window);
|
||||
SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window);
|
||||
void UIKit_SetTextInputRect(_THIS, SDL_Rect *rect);
|
||||
#endif
|
||||
|
|
|
@ -28,108 +28,389 @@
|
|||
#include "../SDL_sysvideo.h"
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
#include "SDL_uikitviewcontroller.h"
|
||||
#import "SDL_uikitviewcontroller.h"
|
||||
#import "SDL_uikitmessagebox.h"
|
||||
#include "SDL_uikitvideo.h"
|
||||
#include "SDL_uikitmodes.h"
|
||||
#include "SDL_uikitwindow.h"
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
#include "keyinfotable.h"
|
||||
#endif
|
||||
|
||||
@implementation SDL_uikitviewcontroller
|
||||
@implementation SDL_uikitviewcontroller {
|
||||
CADisplayLink *displayLink;
|
||||
int animationInterval;
|
||||
void (*animationCallback)(void*);
|
||||
void *animationCallbackParam;
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
UITextField *textField;
|
||||
#endif
|
||||
}
|
||||
|
||||
@synthesize window;
|
||||
|
||||
- (id)initWithSDLWindow:(SDL_Window *)_window
|
||||
- (instancetype)initWithSDLWindow:(SDL_Window *)_window
|
||||
{
|
||||
self = [self init];
|
||||
if (self == nil) {
|
||||
return nil;
|
||||
}
|
||||
self.window = _window;
|
||||
if (self = [super initWithNibName:nil bundle:nil]) {
|
||||
self.window = _window;
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
[self initKeyboard];
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
[self deinitKeyboard];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)setAnimationCallback:(int)interval
|
||||
callback:(void (*)(void*))callback
|
||||
callbackParam:(void*)callbackParam
|
||||
{
|
||||
[self stopAnimation];
|
||||
|
||||
animationInterval = interval;
|
||||
animationCallback = callback;
|
||||
animationCallbackParam = callbackParam;
|
||||
|
||||
if (animationCallback) {
|
||||
[self startAnimation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)startAnimation
|
||||
{
|
||||
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
|
||||
[displayLink setFrameInterval:animationInterval];
|
||||
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
- (void)stopAnimation
|
||||
{
|
||||
[displayLink invalidate];
|
||||
displayLink = nil;
|
||||
}
|
||||
|
||||
- (void)doLoop:(CADisplayLink*)sender
|
||||
{
|
||||
/* Don't run the game loop while a messagebox is up */
|
||||
if (!UIKit_ShowingMessageBox()) {
|
||||
animationCallback(animationCallbackParam);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
/* do nothing. */
|
||||
/* Do nothing. */
|
||||
}
|
||||
|
||||
- (void)viewDidLayoutSubviews
|
||||
{
|
||||
if (self->window->flags & SDL_WINDOW_RESIZABLE) {
|
||||
SDL_WindowData *data = self->window->driverdata;
|
||||
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(self->window);
|
||||
SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
|
||||
const CGSize size = data->view.bounds.size;
|
||||
int w, h;
|
||||
const CGSize size = self.view.bounds.size;
|
||||
int w = (int) size.width;
|
||||
int h = (int) size.height;
|
||||
|
||||
w = (int)(size.width * displaymodedata->scale);
|
||||
h = (int)(size.height * displaymodedata->scale);
|
||||
|
||||
SDL_SendWindowEvent(self->window, SDL_WINDOWEVENT_RESIZED, w, h);
|
||||
}
|
||||
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h);
|
||||
}
|
||||
|
||||
- (NSUInteger)supportedInterfaceOrientations
|
||||
{
|
||||
NSUInteger orientationMask = 0;
|
||||
|
||||
const char *orientationsCString;
|
||||
if ((orientationsCString = SDL_GetHint(SDL_HINT_ORIENTATIONS)) != NULL) {
|
||||
BOOL rotate = NO;
|
||||
NSString *orientationsNSString = [NSString stringWithCString:orientationsCString
|
||||
encoding:NSUTF8StringEncoding];
|
||||
NSArray *orientations = [orientationsNSString componentsSeparatedByCharactersInSet:
|
||||
[NSCharacterSet characterSetWithCharactersInString:@" "]];
|
||||
|
||||
if ([orientations containsObject:@"LandscapeLeft"]) {
|
||||
orientationMask |= UIInterfaceOrientationMaskLandscapeLeft;
|
||||
}
|
||||
if ([orientations containsObject:@"LandscapeRight"]) {
|
||||
orientationMask |= UIInterfaceOrientationMaskLandscapeRight;
|
||||
}
|
||||
if ([orientations containsObject:@"Portrait"]) {
|
||||
orientationMask |= UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
if ([orientations containsObject:@"PortraitUpsideDown"]) {
|
||||
orientationMask |= UIInterfaceOrientationMaskPortraitUpsideDown;
|
||||
}
|
||||
|
||||
} else if (self->window->flags & SDL_WINDOW_RESIZABLE) {
|
||||
orientationMask = UIInterfaceOrientationMaskAll; /* any orientation is okay. */
|
||||
} else {
|
||||
if (self->window->w >= self->window->h) {
|
||||
orientationMask |= UIInterfaceOrientationMaskLandscape;
|
||||
}
|
||||
if (self->window->h >= self->window->w) {
|
||||
orientationMask |= (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
|
||||
orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
|
||||
}
|
||||
return orientationMask;
|
||||
return UIKit_GetSupportedOrientations(window);
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
|
||||
{
|
||||
NSUInteger orientationMask = [self supportedInterfaceOrientations];
|
||||
return (orientationMask & (1 << orient));
|
||||
return ([self supportedInterfaceOrientations] & (1 << orient)) != 0;
|
||||
}
|
||||
|
||||
- (BOOL)prefersStatusBarHidden
|
||||
{
|
||||
if (self->window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
|
||||
return YES;
|
||||
} else {
|
||||
return NO;
|
||||
return (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0;
|
||||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle
|
||||
{
|
||||
/* We assume most SDL apps don't have a bright white background. */
|
||||
return UIStatusBarStyleLightContent;
|
||||
}
|
||||
|
||||
/*
|
||||
---- Keyboard related functionality below this line ----
|
||||
*/
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
|
||||
@synthesize textInputRect;
|
||||
@synthesize keyboardHeight;
|
||||
@synthesize keyboardVisible;
|
||||
|
||||
/* Set ourselves up as a UITextFieldDelegate */
|
||||
- (void)initKeyboard
|
||||
{
|
||||
textField = [[UITextField alloc] initWithFrame:CGRectZero];
|
||||
textField.delegate = self;
|
||||
/* placeholder so there is something to delete! */
|
||||
textField.text = @" ";
|
||||
|
||||
/* set UITextInputTrait properties, mostly to defaults */
|
||||
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
textField.autocorrectionType = UITextAutocorrectionTypeNo;
|
||||
textField.enablesReturnKeyAutomatically = NO;
|
||||
textField.keyboardAppearance = UIKeyboardAppearanceDefault;
|
||||
textField.keyboardType = UIKeyboardTypeDefault;
|
||||
textField.returnKeyType = UIReturnKeyDefault;
|
||||
textField.secureTextEntry = NO;
|
||||
|
||||
textField.hidden = YES;
|
||||
keyboardVisible = NO;
|
||||
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
[center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
[center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)setView:(UIView *)view
|
||||
{
|
||||
[super setView:view];
|
||||
|
||||
[view addSubview:textField];
|
||||
|
||||
if (keyboardVisible) {
|
||||
[self showKeyboard];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)deinitKeyboard
|
||||
{
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
[center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
|
||||
[center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
|
||||
}
|
||||
|
||||
/* reveal onscreen virtual keyboard */
|
||||
- (void)showKeyboard
|
||||
{
|
||||
keyboardVisible = YES;
|
||||
if (textField.window) {
|
||||
[textField becomeFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
/* hide onscreen virtual keyboard */
|
||||
- (void)hideKeyboard
|
||||
{
|
||||
keyboardVisible = NO;
|
||||
[textField resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification
|
||||
{
|
||||
CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue];
|
||||
UIView *view = self.view;
|
||||
int height = 0;
|
||||
|
||||
/* The keyboard rect is in the coordinate space of the screen, but we want
|
||||
* its height in the view's coordinate space. */
|
||||
#ifdef __IPHONE_8_0
|
||||
if ([view respondsToSelector:@selector(convertRect:fromCoordinateSpace:)]) {
|
||||
UIScreen *screen = view.window.screen;
|
||||
kbrect = [view convertRect:kbrect fromCoordinateSpace:screen.coordinateSpace];
|
||||
height = kbrect.size.height;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* In iOS 7 and below, the screen's coordinate space is never rotated. */
|
||||
if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
|
||||
height = kbrect.size.width;
|
||||
} else {
|
||||
height = kbrect.size.height;
|
||||
}
|
||||
}
|
||||
|
||||
[self setKeyboardHeight:height];
|
||||
}
|
||||
|
||||
- (void)keyboardWillHide:(NSNotification *)notification
|
||||
{
|
||||
[self setKeyboardHeight:0];
|
||||
}
|
||||
|
||||
- (void)updateKeyboard
|
||||
{
|
||||
SDL_Rect textrect = self.textInputRect;
|
||||
CGAffineTransform t = self.view.transform;
|
||||
CGPoint offset = CGPointMake(0.0, 0.0);
|
||||
|
||||
if (self.keyboardHeight) {
|
||||
int rectbottom = textrect.y + textrect.h;
|
||||
int kbottom = self.view.bounds.size.height - self.keyboardHeight;
|
||||
if (kbottom < rectbottom) {
|
||||
offset.y = kbottom - rectbottom;
|
||||
}
|
||||
}
|
||||
|
||||
/* Put the offset into the this view transform's coordinate space. */
|
||||
t.tx = 0.0;
|
||||
t.ty = 0.0;
|
||||
offset = CGPointApplyAffineTransform(offset, t);
|
||||
|
||||
t.tx = offset.x;
|
||||
t.ty = offset.y;
|
||||
|
||||
/* Move the view by applying the updated transform. */
|
||||
self.view.transform = t;
|
||||
}
|
||||
|
||||
- (void)setKeyboardHeight:(int)height
|
||||
{
|
||||
keyboardVisible = height > 0;
|
||||
keyboardHeight = height;
|
||||
[self updateKeyboard];
|
||||
}
|
||||
|
||||
/* UITextFieldDelegate method. Invoked when user types something. */
|
||||
- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
|
||||
{
|
||||
NSUInteger len = string.length;
|
||||
|
||||
if (len == 0) {
|
||||
/* it wants to replace text with nothing, ie a delete */
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
|
||||
} else {
|
||||
/* go through all the characters in the string we've been sent and
|
||||
* convert them to key presses */
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
unichar c = [string characterAtIndex:i];
|
||||
Uint16 mod = 0;
|
||||
SDL_Scancode code;
|
||||
|
||||
if (c < 127) {
|
||||
/* figure out the SDL_Scancode and SDL_keymod for this unichar */
|
||||
code = unicharToUIKeyInfoTable[c].code;
|
||||
mod = unicharToUIKeyInfoTable[c].mod;
|
||||
} else {
|
||||
/* we only deal with ASCII right now */
|
||||
code = SDL_SCANCODE_UNKNOWN;
|
||||
mod = 0;
|
||||
}
|
||||
|
||||
if (mod & KMOD_SHIFT) {
|
||||
/* If character uses shift, press shift down */
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
|
||||
}
|
||||
|
||||
/* send a keydown and keyup even for the character */
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, code);
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, code);
|
||||
|
||||
if (mod & KMOD_SHIFT) {
|
||||
/* If character uses shift, press shift back up */
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SendKeyboardText([string UTF8String]);
|
||||
}
|
||||
|
||||
return NO; /* don't allow the edit! (keep placeholder text there) */
|
||||
}
|
||||
|
||||
/* Terminates the editing session */
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)_textField
|
||||
{
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
|
||||
SDL_StopTextInput();
|
||||
return YES;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
/* iPhone keyboard addition functions */
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
|
||||
static SDL_uikitviewcontroller *
|
||||
GetWindowViewController(SDL_Window * window)
|
||||
{
|
||||
if (!window || !window->driverdata) {
|
||||
SDL_SetError("Invalid window");
|
||||
return nil;
|
||||
}
|
||||
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
|
||||
|
||||
return data.viewcontroller;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
UIKit_HasScreenKeyboardSupport(_THIS)
|
||||
{
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_uikitviewcontroller *vc = GetWindowViewController(window);
|
||||
[vc showKeyboard];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_uikitviewcontroller *vc = GetWindowViewController(window);
|
||||
[vc hideKeyboard];
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_uikitviewcontroller *vc = GetWindowViewController(window);
|
||||
if (vc != nil) {
|
||||
return vc.isKeyboardVisible;
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
|
||||
{
|
||||
if (!rect) {
|
||||
SDL_InvalidParamError("rect");
|
||||
return;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
SDL_uikitviewcontroller *vc = GetWindowViewController(SDL_GetFocusWindow());
|
||||
if (vc != nil) {
|
||||
vc.textInputRect = *rect;
|
||||
|
||||
if (vc.keyboardVisible) {
|
||||
[vc updateKeyboard];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* SDL_IPHONE_KEYBOARD */
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_UIKIT */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -23,28 +23,33 @@
|
|||
|
||||
#include "../SDL_sysvideo.h"
|
||||
#import "SDL_uikitvideo.h"
|
||||
#import "SDL_uikitopenglview.h"
|
||||
#import "SDL_uikitview.h"
|
||||
#import "SDL_uikitviewcontroller.h"
|
||||
|
||||
typedef struct SDL_WindowData SDL_WindowData;
|
||||
|
||||
extern int UIKit_CreateWindow(_THIS, SDL_Window * window);
|
||||
extern void UIKit_SetWindowTitle(_THIS, SDL_Window * window);
|
||||
extern void UIKit_ShowWindow(_THIS, SDL_Window * window);
|
||||
extern void UIKit_HideWindow(_THIS, SDL_Window * window);
|
||||
extern void UIKit_RaiseWindow(_THIS, SDL_Window * window);
|
||||
extern void UIKit_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered);
|
||||
extern void UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
|
||||
extern void UIKit_DestroyWindow(_THIS, SDL_Window * window);
|
||||
extern SDL_bool UIKit_GetWindowWMInfo(_THIS, SDL_Window * window,
|
||||
struct SDL_SysWMinfo * info);
|
||||
|
||||
extern NSUInteger UIKit_GetSupportedOrientations(SDL_Window * window);
|
||||
|
||||
@class UIWindow;
|
||||
|
||||
struct SDL_WindowData
|
||||
{
|
||||
UIWindow *uiwindow;
|
||||
SDL_uikitopenglview *view;
|
||||
SDL_uikitviewcontroller *viewcontroller;
|
||||
};
|
||||
@interface SDL_WindowData : NSObject
|
||||
|
||||
@property (nonatomic, strong) UIWindow *uiwindow;
|
||||
@property (nonatomic, strong) SDL_uikitviewcontroller *viewcontroller;
|
||||
|
||||
/* Array of SDL_uikitviews owned by this window. */
|
||||
@property (nonatomic, copy) NSMutableArray *views;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* _SDL_uikitwindow_h */
|
||||
|
||||
|
|
|
@ -37,89 +37,110 @@
|
|||
#include "SDL_uikitwindow.h"
|
||||
#import "SDL_uikitappdelegate.h"
|
||||
|
||||
#import "SDL_uikitopenglview.h"
|
||||
#import "SDL_uikitview.h"
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
@implementation SDL_WindowData
|
||||
|
||||
@synthesize uiwindow;
|
||||
@synthesize viewcontroller;
|
||||
@synthesize views;
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
views = [NSMutableArray new];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface SDL_uikitwindow : UIWindow
|
||||
|
||||
- (void)layoutSubviews;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDL_uikitwindow
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
/* Workaround to fix window orientation issues in iOS 8+. */
|
||||
self.frame = self.screen.bounds;
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created)
|
||||
{
|
||||
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
|
||||
SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
|
||||
SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
|
||||
SDL_WindowData *data;
|
||||
SDL_DisplayData *displaydata = (__bridge SDL_DisplayData *) display->driverdata;
|
||||
SDL_uikitview *view;
|
||||
|
||||
/* Allocate the window data */
|
||||
data = (SDL_WindowData *)SDL_malloc(sizeof(*data));
|
||||
CGRect frame = UIKit_ComputeViewFrame(window, displaydata.uiscreen);
|
||||
int width = (int) frame.size.width;
|
||||
int height = (int) frame.size.height;
|
||||
|
||||
SDL_WindowData *data = [[SDL_WindowData alloc] init];
|
||||
if (!data) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
data->uiwindow = uiwindow;
|
||||
data->viewcontroller = nil;
|
||||
data->view = nil;
|
||||
|
||||
/* Fill in the SDL window with the window data */
|
||||
{
|
||||
window->x = 0;
|
||||
window->y = 0;
|
||||
window->driverdata = (void *) CFBridgingRetain(data);
|
||||
|
||||
CGRect bounds;
|
||||
if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
|
||||
bounds = [displaydata->uiscreen bounds];
|
||||
} else {
|
||||
bounds = [displaydata->uiscreen applicationFrame];
|
||||
}
|
||||
|
||||
/* Get frame dimensions in pixels */
|
||||
int width = (int)(bounds.size.width * displaymodedata->scale);
|
||||
int height = (int)(bounds.size.height * displaymodedata->scale);
|
||||
|
||||
/* Make sure the width/height are oriented correctly */
|
||||
if (UIKit_IsDisplayLandscape(displaydata->uiscreen) != (width > height)) {
|
||||
int temp = width;
|
||||
width = height;
|
||||
height = temp;
|
||||
}
|
||||
|
||||
window->w = width;
|
||||
window->h = height;
|
||||
}
|
||||
|
||||
window->driverdata = data;
|
||||
data.uiwindow = uiwindow;
|
||||
|
||||
/* only one window on iOS, always shown */
|
||||
window->flags &= ~SDL_WINDOW_HIDDEN;
|
||||
|
||||
/* 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 (displaydata->uiscreen == [UIScreen mainScreen]) {
|
||||
if (displaydata.uiscreen == [UIScreen mainScreen]) {
|
||||
window->flags |= SDL_WINDOW_INPUT_FOCUS; /* always has input focus */
|
||||
|
||||
/* This was setup earlier for our window, and in iOS 7 is controlled by the view, not the application
|
||||
if ([UIApplication sharedApplication].statusBarHidden) {
|
||||
window->flags |= SDL_WINDOW_BORDERLESS;
|
||||
} else {
|
||||
window->flags &= ~SDL_WINDOW_BORDERLESS;
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
window->flags &= ~SDL_WINDOW_RESIZABLE; /* window is NEVER resizeable */
|
||||
window->flags &= ~SDL_WINDOW_RESIZABLE; /* window is NEVER resizable */
|
||||
window->flags &= ~SDL_WINDOW_INPUT_FOCUS; /* never has input focus */
|
||||
window->flags |= SDL_WINDOW_BORDERLESS; /* never has a status bar. */
|
||||
}
|
||||
|
||||
/* The View Controller will handle rotating the view when the
|
||||
* device orientation changes. This will trigger resize events, if
|
||||
* appropriate.
|
||||
*/
|
||||
SDL_uikitviewcontroller *controller;
|
||||
controller = [SDL_uikitviewcontroller alloc];
|
||||
data->viewcontroller = [controller initWithSDLWindow:window];
|
||||
[data->viewcontroller setTitle:@"SDL App"]; /* !!! FIXME: hook up SDL_SetWindowTitle() */
|
||||
if (displaydata.uiscreen == [UIScreen mainScreen]) {
|
||||
NSUInteger orients = UIKit_GetSupportedOrientations(window);
|
||||
BOOL supportsLandscape = (orients & UIInterfaceOrientationMaskLandscape) != 0;
|
||||
BOOL supportsPortrait = (orients & (UIInterfaceOrientationMaskPortrait|UIInterfaceOrientationMaskPortraitUpsideDown)) != 0;
|
||||
|
||||
/* Make sure the width/height are oriented correctly */
|
||||
if ((width > height && !supportsLandscape) || (height > width && !supportsPortrait)) {
|
||||
int temp = width;
|
||||
width = height;
|
||||
height = temp;
|
||||
}
|
||||
}
|
||||
|
||||
window->x = 0;
|
||||
window->y = 0;
|
||||
window->w = width;
|
||||
window->h = height;
|
||||
|
||||
/* The View Controller will handle rotating the view when the device
|
||||
* orientation changes. This will trigger resize events, if appropriate. */
|
||||
data.viewcontroller = [[SDL_uikitviewcontroller alloc] initWithSDLWindow:window];
|
||||
|
||||
/* The window will initially contain a generic view so resizes, touch events,
|
||||
* etc. can be handled without an active OpenGL view/context. */
|
||||
view = [[SDL_uikitview alloc] initWithFrame:frame];
|
||||
|
||||
/* Sets this view as the controller's view, and adds the view to the window
|
||||
* heirarchy. */
|
||||
[view setSDLWindow:window];
|
||||
|
||||
/* Make this window the current mouse focus for touch input */
|
||||
if (displaydata.uiscreen == [UIScreen mainScreen]) {
|
||||
SDL_SetMouseFocus(window);
|
||||
SDL_SetKeyboardFocus(window);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -127,173 +148,165 @@ static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bo
|
|||
int
|
||||
UIKit_CreateWindow(_THIS, SDL_Window *window)
|
||||
{
|
||||
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
|
||||
SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
|
||||
const BOOL external = ([UIScreen mainScreen] != data->uiscreen);
|
||||
const CGSize origsize = [[data->uiscreen currentMode] size];
|
||||
@autoreleasepool {
|
||||
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
|
||||
SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
|
||||
const CGSize origsize = data.uiscreen.currentMode.size;
|
||||
|
||||
/* SDL currently puts this window at the start of display's linked list. We rely on this. */
|
||||
SDL_assert(_this->windows == window);
|
||||
/* 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 iOS */
|
||||
if (window->next != NULL) {
|
||||
return SDL_SetError("Only one window allowed per display.");
|
||||
}
|
||||
|
||||
/* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
|
||||
* user, so it's in standby), try to force the display to a resolution
|
||||
* that most closely matches the desired window size.
|
||||
*/
|
||||
if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
|
||||
if (display->num_display_modes == 0) {
|
||||
_this->GetDisplayModes(_this, display);
|
||||
/* We currently only handle a single window per display on iOS */
|
||||
if (window->next != NULL) {
|
||||
return SDL_SetError("Only one window allowed per display.");
|
||||
}
|
||||
|
||||
int i;
|
||||
const SDL_DisplayMode *bestmode = NULL;
|
||||
for (i = display->num_display_modes; i >= 0; i--) {
|
||||
const SDL_DisplayMode *mode = &display->display_modes[i];
|
||||
if ((mode->w >= window->w) && (mode->h >= window->h))
|
||||
bestmode = mode;
|
||||
}
|
||||
|
||||
if (bestmode) {
|
||||
SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)bestmode->driverdata;
|
||||
[data->uiscreen setCurrentMode:modedata->uiscreenmode];
|
||||
|
||||
/* desktop_mode doesn't change here (the higher level will
|
||||
* use it to set all the screens back to their defaults
|
||||
* upon window destruction, SDL_Quit(), etc.
|
||||
*/
|
||||
display->current_mode = *bestmode;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->uiscreen == [UIScreen mainScreen]) {
|
||||
if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
|
||||
[UIApplication sharedApplication].statusBarHidden = YES;
|
||||
} else {
|
||||
[UIApplication sharedApplication].statusBarHidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
|
||||
if (window->w > window->h) {
|
||||
if (!UIKit_IsDisplayLandscape(data->uiscreen)) {
|
||||
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
|
||||
/* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
|
||||
* user, so it's in standby), try to force the display to a resolution
|
||||
* that most closely matches the desired window size. */
|
||||
if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
|
||||
if (display->num_display_modes == 0) {
|
||||
_this->GetDisplayModes(_this, display);
|
||||
}
|
||||
} else if (window->w < window->h) {
|
||||
if (UIKit_IsDisplayLandscape(data->uiscreen)) {
|
||||
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
|
||||
|
||||
int i;
|
||||
const SDL_DisplayMode *bestmode = NULL;
|
||||
for (i = display->num_display_modes; i >= 0; i--) {
|
||||
const SDL_DisplayMode *mode = &display->display_modes[i];
|
||||
if ((mode->w >= window->w) && (mode->h >= window->h)) {
|
||||
bestmode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestmode) {
|
||||
SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)bestmode->driverdata;
|
||||
[data.uiscreen setCurrentMode:modedata.uiscreenmode];
|
||||
|
||||
/* desktop_mode doesn't change here (the higher level will
|
||||
* use it to set all the screens back to their defaults
|
||||
* upon window destruction, SDL_Quit(), etc. */
|
||||
display->current_mode = *bestmode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ignore the size user requested, and make a fullscreen window */
|
||||
/* !!! FIXME: can we have a smaller view? */
|
||||
UIWindow *uiwindow = [UIWindow alloc];
|
||||
uiwindow = [uiwindow initWithFrame:[data->uiscreen bounds]];
|
||||
if (data.uiscreen == [UIScreen mainScreen]) {
|
||||
NSUInteger orientations = UIKit_GetSupportedOrientations(window);
|
||||
UIApplication *app = [UIApplication sharedApplication];
|
||||
|
||||
/* 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:data->uiscreen];
|
||||
}
|
||||
if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
|
||||
app.statusBarHidden = YES;
|
||||
} else {
|
||||
app.statusBarHidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
|
||||
[uiwindow release];
|
||||
return -1;
|
||||
/* ignore the size user requested, and make a fullscreen window */
|
||||
/* !!! FIXME: can we have a smaller view? */
|
||||
UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds];
|
||||
|
||||
/* put the window on an external display if appropriate. */
|
||||
if (data.uiscreen != [UIScreen mainScreen]) {
|
||||
[uiwindow setScreen:data.uiscreen];
|
||||
}
|
||||
|
||||
if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_SetWindowTitle(_THIS, SDL_Window * window)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
|
||||
if (window->title) {
|
||||
data.viewcontroller.title = @(window->title);
|
||||
} else {
|
||||
data.viewcontroller.title = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_ShowWindow(_THIS, SDL_Window * window)
|
||||
{
|
||||
UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
|
||||
|
||||
[uiwindow makeKeyAndVisible];
|
||||
@autoreleasepool {
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
|
||||
[data.uiwindow makeKeyAndVisible];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_HideWindow(_THIS, SDL_Window * window)
|
||||
{
|
||||
UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
|
||||
|
||||
uiwindow.hidden = YES;
|
||||
@autoreleasepool {
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
|
||||
data.uiwindow.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_RaiseWindow(_THIS, SDL_Window * window)
|
||||
{
|
||||
/* We don't currently offer a concept of "raising" the SDL window, since
|
||||
* we only allow one per display, in the iOS fashion.
|
||||
* we only allow one per display, in the iOS fashion.
|
||||
* However, we use this entry point to rebind the context to the view
|
||||
* during OnWindowRestored processing.
|
||||
*/
|
||||
* during OnWindowRestored processing. */
|
||||
_this->GL_MakeCurrent(_this, _this->current_glwin, _this->current_glctx);
|
||||
}
|
||||
|
||||
static void
|
||||
UIKit_UpdateWindowBorder(_THIS, SDL_Window * window)
|
||||
{
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
|
||||
SDL_uikitviewcontroller *viewcontroller = data.viewcontroller;
|
||||
|
||||
if (data.uiwindow.screen == [UIScreen mainScreen]) {
|
||||
if (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS)) {
|
||||
[UIApplication sharedApplication].statusBarHidden = YES;
|
||||
} else {
|
||||
[UIApplication sharedApplication].statusBarHidden = NO;
|
||||
}
|
||||
|
||||
/* iOS 7+ won't update the status bar until we tell it to. */
|
||||
if ([viewcontroller respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
|
||||
[viewcontroller setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the view's frame to account for the status bar change. */
|
||||
viewcontroller.view.frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen);
|
||||
[viewcontroller.view setNeedsLayout];
|
||||
[viewcontroller.view layoutIfNeeded];
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
|
||||
{
|
||||
@autoreleasepool {
|
||||
UIKit_UpdateWindowBorder(_this, window);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
|
||||
{
|
||||
SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
|
||||
SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
|
||||
UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
|
||||
|
||||
if (fullscreen) {
|
||||
[UIApplication sharedApplication].statusBarHidden = YES;
|
||||
} else {
|
||||
[UIApplication sharedApplication].statusBarHidden = NO;
|
||||
}
|
||||
|
||||
CGRect bounds;
|
||||
if (fullscreen) {
|
||||
bounds = [displaydata->uiscreen bounds];
|
||||
} else {
|
||||
bounds = [displaydata->uiscreen applicationFrame];
|
||||
}
|
||||
|
||||
/* Get frame dimensions in pixels */
|
||||
int width = (int)(bounds.size.width * displaymodedata->scale);
|
||||
int height = (int)(bounds.size.height * displaymodedata->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 (width > height) {
|
||||
window->w = width;
|
||||
window->h = height;
|
||||
} else {
|
||||
window->w = height;
|
||||
window->h = width;
|
||||
}
|
||||
} else {
|
||||
if (width > height) {
|
||||
window->w = height;
|
||||
window->h = width;
|
||||
} else {
|
||||
window->w = width;
|
||||
window->h = height;
|
||||
}
|
||||
@autoreleasepool {
|
||||
UIKit_UpdateWindowBorder(_this, window);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UIKit_DestroyWindow(_THIS, SDL_Window * window)
|
||||
{
|
||||
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
|
||||
|
||||
if (data) {
|
||||
[data->viewcontroller release];
|
||||
[data->uiwindow release];
|
||||
SDL_free(data);
|
||||
@autoreleasepool {
|
||||
if (window->driverdata != NULL) {
|
||||
SDL_WindowData *data = (SDL_WindowData *) CFBridgingRelease(window->driverdata);
|
||||
[data.viewcontroller stopAnimation];
|
||||
}
|
||||
}
|
||||
window->driverdata = NULL;
|
||||
}
|
||||
|
@ -301,29 +314,82 @@ UIKit_DestroyWindow(_THIS, SDL_Window * window)
|
|||
SDL_bool
|
||||
UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
|
||||
{
|
||||
UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
|
||||
@autoreleasepool {
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
|
||||
|
||||
if (info->version.major <= SDL_MAJOR_VERSION) {
|
||||
info->subsystem = SDL_SYSWM_UIKIT;
|
||||
info->info.uikit.window = uiwindow;
|
||||
return SDL_TRUE;
|
||||
} else {
|
||||
SDL_SetError("Application not compiled with SDL %d.%d\n",
|
||||
SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
|
||||
return SDL_FALSE;
|
||||
if (info->version.major <= SDL_MAJOR_VERSION) {
|
||||
info->subsystem = SDL_SYSWM_UIKIT;
|
||||
info->info.uikit.window = data.uiwindow;
|
||||
return SDL_TRUE;
|
||||
} else {
|
||||
SDL_SetError("Application not compiled with SDL %d.%d\n",
|
||||
SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSUInteger
|
||||
UIKit_GetSupportedOrientations(SDL_Window * window)
|
||||
{
|
||||
const char *hint = SDL_GetHint(SDL_HINT_ORIENTATIONS);
|
||||
NSUInteger orientationMask = 0;
|
||||
|
||||
@autoreleasepool {
|
||||
if (hint != NULL) {
|
||||
NSArray *orientations = [@(hint) componentsSeparatedByString:@" "];
|
||||
|
||||
if ([orientations containsObject:@"LandscapeLeft"]) {
|
||||
orientationMask |= UIInterfaceOrientationMaskLandscapeLeft;
|
||||
}
|
||||
if ([orientations containsObject:@"LandscapeRight"]) {
|
||||
orientationMask |= UIInterfaceOrientationMaskLandscapeRight;
|
||||
}
|
||||
if ([orientations containsObject:@"Portrait"]) {
|
||||
orientationMask |= UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
if ([orientations containsObject:@"PortraitUpsideDown"]) {
|
||||
orientationMask |= UIInterfaceOrientationMaskPortraitUpsideDown;
|
||||
}
|
||||
}
|
||||
|
||||
if (orientationMask == 0 && (window->flags & SDL_WINDOW_RESIZABLE)) {
|
||||
/* any orientation is okay. */
|
||||
orientationMask = UIInterfaceOrientationMaskAll;
|
||||
}
|
||||
|
||||
if (orientationMask == 0) {
|
||||
if (window->w >= window->h) {
|
||||
orientationMask |= UIInterfaceOrientationMaskLandscape;
|
||||
}
|
||||
if (window->h >= window->w) {
|
||||
orientationMask |= (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
|
||||
orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
|
||||
}
|
||||
}
|
||||
|
||||
return orientationMask;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam)
|
||||
{
|
||||
SDL_WindowData *data = window ? (SDL_WindowData *)window->driverdata : NULL;
|
||||
|
||||
if (!data || !data->view) {
|
||||
return SDL_SetError("Invalid window or view not set");
|
||||
if (!window || !window->driverdata) {
|
||||
return SDL_SetError("Invalid window");
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
|
||||
[data.viewcontroller setAnimationCallback:interval
|
||||
callback:callback
|
||||
callbackParam:callbackParam];
|
||||
}
|
||||
|
||||
[data->view setAnimationCallback:interval callback:callback callbackParam:callbackParam];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue