diff --git a/gfx/context/ioseagl_ctx.c b/gfx/context/ioseagl_ctx.c index 106eb3d242..9c70e3b01f 100644 --- a/gfx/context/ioseagl_ctx.c +++ b/gfx/context/ioseagl_ctx.c @@ -35,7 +35,8 @@ static void gfx_ctx_set_swap_interval(unsigned interval) static void gfx_ctx_destroy(void) { - RARCH_LOG("gfx_ctx_destroy().\n"); + extern void ios_destroy_game_view(); + ios_destroy_game_view(); } static void gfx_ctx_get_video_size(unsigned *width, unsigned *height) @@ -46,7 +47,8 @@ static void gfx_ctx_get_video_size(unsigned *width, unsigned *height) static bool gfx_ctx_init(void) { - return true; + extern bool ios_init_game_view(); + return ios_init_game_view(); } static void gfx_ctx_swap_buffers(void) diff --git a/ios/RetroArch.xcodeproj/project.pbxproj b/ios/RetroArch.xcodeproj/project.pbxproj index 26ae9501dd..68f3413caa 100644 --- a/ios/RetroArch.xcodeproj/project.pbxproj +++ b/ios/RetroArch.xcodeproj/project.pbxproj @@ -84,6 +84,7 @@ 96AFAFAD16C1EEE9009DE44C /* sinc.c in Sources */ = {isa = PBXBuildFile; fileRef = 96AFAEF716C1DC73009DE44C /* sinc.c */; }; 96AFAFD416C1FBC0009DE44C /* input_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 96AFAFC916C1FBC0009DE44C /* input_common.c */; }; 96AFAFD716C1FBC0009DE44C /* null.c in Sources */ = {isa = PBXBuildFile; fileRef = 96AFAFCD16C1FBC0009DE44C /* null.c */; }; + 96C6A5D216CDB384009E3280 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96C6A5D116CDB384009E3280 /* QuartzCore.framework */; }; 96CF015016C2C0B700ABF9C9 /* overlay.c in Sources */ = {isa = PBXBuildFile; fileRef = 96AFAFCE16C1FBC0009DE44C /* overlay.c */; }; 96CF015C16C2F72900ABF9C9 /* ios_input.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CF015B16C2F72900ABF9C9 /* ios_input.c */; }; /* End PBXBuildFile section */ @@ -290,6 +291,7 @@ 96AFAFD016C1FBC0009DE44C /* sdl_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sdl_input.c; sourceTree = ""; }; 96AFAFD116C1FBC0009DE44C /* sdl_joypad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sdl_joypad.c; sourceTree = ""; }; 96AFAFD216C1FBC0009DE44C /* x11_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x11_input.c; sourceTree = ""; }; + 96C6A5D116CDB384009E3280 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 96CF015B16C2F72900ABF9C9 /* ios_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ios_input.c; sourceTree = ""; }; /* End PBXFileReference section */ @@ -298,6 +300,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 96C6A5D216CDB384009E3280 /* QuartzCore.framework in Frameworks */, 96366C5916C9ACF500D64A22 /* AudioToolbox.framework in Frameworks */, 96366C5516C9AC3300D64A22 /* CoreAudio.framework in Frameworks */, 96AFAF2216C1DF88009DE44C /* libz.dylib in Frameworks */, @@ -351,6 +354,7 @@ 96AFAE2816C1D4EA009DE44C /* Frameworks */ = { isa = PBXGroup; children = ( + 96C6A5D116CDB384009E3280 /* QuartzCore.framework */, 96366C5816C9ACF500D64A22 /* AudioToolbox.framework */, 96366C5416C9AC3300D64A22 /* CoreAudio.framework */, 96AFAE2916C1D4EA009DE44C /* UIKit.framework */, @@ -981,7 +985,6 @@ "-DHAVE_GLSL", "-DINLINE=inline", "-DLSB_FIRST", - "-DHAVE_THREAD", "-D__LIBRETRO__", "-DRARCH_PERFORMANCE_MODE", "-DPACKAGE_VERSION=\\\"1.0\\\"", @@ -1019,7 +1022,6 @@ "-DHAVE_GLSL", "-DINLINE=inline", "-DLSB_FIRST", - "-DHAVE_THREAD", "-D__LIBRETRO__", "-DRARCH_PERFORMANCE_MODE", "-DPACKAGE_VERSION=\\\"1.0\\\"", diff --git a/ios/RetroArch/RAGameView.m b/ios/RetroArch/RAGameView.m index 65044267b5..a01f857b0e 100644 --- a/ios/RetroArch/RAGameView.m +++ b/ios/RetroArch/RAGameView.m @@ -14,77 +14,71 @@ * If not, see . */ +#import #include "general.h" -static GLKView *gl_view; +static bool _isRunning; + static float screen_scale; static int frame_skips = 4; static bool is_syncing = true; -static bool active_iterate() -{ - while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource); - return rarch_main_iterate(); -} - -static bool idle_iterate() -{ - CFRunLoopRunInMode(kCFRunLoopDefaultMode, .5, false); - return true; -} - @implementation RAGameView { - EAGLContext *gl_context; - NSString* game; - bool paused; - bool exiting; + EAGLContext* _glContext; + CADisplayLink* _timer; } -- (id)initWithGame:(NSString*)path +- (id)init { self = [super init]; - game = path; screen_scale = [[UIScreen mainScreen] scale]; + _glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + [EAGLContext setCurrentContext:_glContext]; + + self.view = [[GLKView alloc] initWithFrame:CGRectMake(0, 0, 640, 480) context:_glContext]; + self.view.multipleTouchEnabled = YES; + + _timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(iterate)]; + [_timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + return self; } +- (void)iterate +{ + if (_isRunning) rarch_main_iterate(); +} + +- (void)needsToDie +{ + [_timer invalidate]; + _timer = nil; + + glFinish(); + + GLKView* glview = (GLKView*)self.view; + glview.context = nil; + _glContext = nil; + [EAGLContext setCurrentContext:nil]; +} + - (void)pause { - paused = true; + _timer.paused = true; } - (void)resume { - paused = false; + if (_isRunning) _timer.paused = false; } -- (void)exit -{ - exiting = true; -} +@end -- (void)dealloc -{ - if ([EAGLContext currentContext] == gl_context) [EAGLContext setCurrentContext:nil]; - gl_context = nil; - gl_view = nil; -} +static RAGameView* gameViewer; -- (void)loadView -{ - gl_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - [EAGLContext setCurrentContext:gl_context]; - - gl_view = [[GLKView alloc] initWithFrame:CGRectMake(0, 0, 640, 480) context:gl_context]; - gl_view.multipleTouchEnabled = YES; - self.view = gl_view; - - [self performSelector:@selector(runGame) withObject:nil afterDelay:0.2f]; -} - -- (void)runGame +void ios_load_game(const char* path) { [RASettingsList refreshConfigFile]; @@ -92,30 +86,86 @@ static bool idle_iterate() const char* const cf =[[RetroArch_iOS get].config_file_path UTF8String]; const char* const libretro = [[RetroArch_iOS get].module_path UTF8String]; - struct rarch_main_wrap main_wrapper = {[game UTF8String], sd, sd, cf, libretro}; + struct rarch_main_wrap main_wrapper = {path, sd, sd, cf, libretro}; if (rarch_main_init_wrap(&main_wrapper) == 0) { rarch_init_msg_queue(); - while (!exiting && (paused ? idle_iterate() : active_iterate())); + _isRunning = true; + } + else + _isRunning = false; +} + +void ios_close_game() +{ + if (_isRunning) + { rarch_main_deinit(); rarch_deinit_msg_queue(); - + #ifdef PERF_TEST rarch_perf_log(); #endif - + rarch_main_clear_state(); + + _isRunning = false; } [[RetroArch_iOS get] gameHasExited]; } -@end +void ios_pause_emulator() +{ + if (gameViewer) + [gameViewer pause]; +} + +void ios_resume_emulator() +{ + if (gameViewer) + [gameViewer resume]; +} + +void ios_suspend_emulator() +{ + if (gameViewer) + uninit_drivers(); +} + +void ios_activate_emulator() +{ + if (!gameViewer) + init_drivers(); +} + +bool ios_init_game_view() +{ + if (!gameViewer) + { + gameViewer = [RAGameView new]; + [[RetroArch_iOS get] setViewer:gameViewer]; + } + + return true; +} + +void ios_destroy_game_view() +{ + if (gameViewer) + { + [gameViewer needsToDie]; + [[RetroArch_iOS get] setViewer:nil]; + gameViewer = nil; + } +} void ios_flip_game_view() { - if (gl_view) + if (gameViewer) { + GLKView* gl_view = (GLKView*)gameViewer.view; + if (--frame_skips < 0) { [gl_view setNeedsDisplay]; @@ -133,8 +183,10 @@ void ios_set_game_view_sync(bool on) void ios_get_game_view_size(unsigned *width, unsigned *height) { - if (gl_view) + if (gameViewer) { + GLKView* gl_view = (GLKView*)gameViewer.view; + *width = gl_view.bounds.size.width * screen_scale; *height = gl_view.bounds.size.height * screen_scale; } @@ -142,8 +194,9 @@ void ios_get_game_view_size(unsigned *width, unsigned *height) void ios_bind_game_view_fbo() { - if (gl_view) + if (gameViewer) { + GLKView* gl_view = (GLKView*)gameViewer.view; [gl_view bindDrawable]; } } diff --git a/ios/RetroArch/RetroArch_iOS.h b/ios/RetroArch/RetroArch_iOS.h index a185024c3d..369699a7e0 100644 --- a/ios/RetroArch/RetroArch_iOS.h +++ b/ios/RetroArch/RetroArch_iOS.h @@ -19,6 +19,8 @@ extern NSString* const GSEventKeyUpNotification; - (void)pushViewController:(UIViewController*)theView; - (void)popViewController; +- (void)setViewer:(UIViewController*)theView; + @property (strong, nonatomic) NSString* system_directory; @property (strong, nonatomic) NSString* config_file_path; diff --git a/ios/RetroArch/RetroArch_iOS.m b/ios/RetroArch/RetroArch_iOS.m index 9306dba10f..dcea6e6809 100644 --- a/ios/RetroArch/RetroArch_iOS.m +++ b/ios/RetroArch/RetroArch_iOS.m @@ -6,6 +6,7 @@ // #include +#include "rarch_wrapper.h" #define MAX_TOUCH 16 extern struct @@ -22,8 +23,6 @@ extern uint32_t ios_current_touch_count; @implementation RetroArch_iOS { - RAGameView* _game; - UIWindow* _window; UINavigationController* _navigator; } @@ -35,15 +34,11 @@ extern uint32_t ios_current_touch_count; - (void)runGame:(NSString*)path { - _game = [[RAGameView alloc] initWithGame:path]; - _window.rootViewController = _game; - _navigator = nil; + ios_load_game([path UTF8String]); } - (void)gameHasExited { - _game = nil; - _navigator = [[UINavigationController alloc] init]; [_navigator pushViewController: [[RAModuleList alloc] init] animated:YES]; @@ -53,17 +48,19 @@ extern uint32_t ios_current_touch_count; - (void)pushViewController:(UIViewController*)theView { if (_navigator != nil) - { [_navigator pushViewController:theView animated:YES]; - } } - (void)popViewController { if (_navigator != nil) - { [_navigator popViewControllerAnimated:YES]; - } +} + +- (void)setViewer:(UIViewController*)theView +{ + _navigator = nil; + _window.rootViewController = theView; } - (void)applicationDidFinishLaunching:(UIApplication *)application @@ -99,16 +96,24 @@ extern uint32_t ios_current_touch_count; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(keyReleased:) name: GSEventKeyUpNotification object: nil]; } +- (void)applicationDidBecomeActive:(UIApplication*)application +{ + ios_resume_emulator(); +} + +- (void)applicationWillResignActive:(UIApplication*)application +{ + ios_pause_emulator(); +} + - (void)applicationWillEnterForeground:(UIApplication *)application { - if (_game) - [_game resume]; + ios_activate_emulator(); } - (void)applicationDidEnterBackground:(UIApplication *)application { - if (_game) - [_game pause]; + ios_suspend_emulator(); } -(void) keyPressed: (NSNotification*) notification @@ -130,34 +135,32 @@ extern uint32_t ios_current_touch_count; - (void)processTouches:(NSArray*)touches { - if (_game) - { - ios_current_touch_count = [touches count]; + ios_current_touch_count = [touches count]; - for(int i = 0; i != [touches count]; i ++) - { - UITouch *touch = [touches objectAtIndex:i]; - CGPoint coord = [touch locationInView:_game.view]; - float scale = [[UIScreen mainScreen] scale]; + UIView* view = _window.rootViewController.view; + + for(int i = 0; i != [touches count]; i ++) + { + UITouch *touch = [touches objectAtIndex:i]; + CGPoint coord = [touch locationInView:view]; + float scale = [[UIScreen mainScreen] scale]; - // Exit hack! - if (touch.tapCount == 3) + // Exit hack! + if (touch.tapCount == 3) + { + if (coord.y < view.bounds.size.height / 10.0f) { - if (coord.y < _game.view.bounds.size.height / 10.0f) + float tenpct = view.bounds.size.width / 10.0f; + if (coord.x >= tenpct * 4 && coord.x <= tenpct * 6) { - float tenpct = _game.view.bounds.size.width / 10.0f; - if (coord.x >= tenpct * 4 && coord.x <= tenpct * 6) - { - [_game exit]; - } + ios_close_game(); } } - - ios_touches[i].is_down = (touch.phase != UITouchPhaseEnded) && (touch.phase != UITouchPhaseCancelled); - - ios_touches[i].screen_x = coord.x * scale; - ios_touches[i].screen_y = coord.y * scale; } + + ios_touches[i].is_down = (touch.phase != UITouchPhaseEnded) && (touch.phase != UITouchPhaseCancelled); + ios_touches[i].screen_x = coord.x * scale; + ios_touches[i].screen_y = coord.y * scale; } } diff --git a/ios/RetroArch/main.m b/ios/RetroArch/main.m index 1a80052609..8ecd7e8bdb 100644 --- a/ios/RetroArch/main.m +++ b/ios/RetroArch/main.m @@ -26,29 +26,31 @@ NSString *const GSEventKeyUpNotification = @"GSEventKeyUpHackNotification"; // Stolen from: http://nacho4d-nacho4d.blogspot.com/2012/01/catching-keyboard-events-in-ios.html - (void)sendEvent:(UIEvent *)event { - [super sendEvent:event]; + [super sendEvent:event]; - if ([event respondsToSelector:@selector(_gsEvent)]) - { - int* eventMem = (int *)(void*)CFBridgingRetain([event performSelector:@selector(_gsEvent)]); - int eventType = eventMem ? eventMem[GSEVENT_TYPE] : 0; + if ([event respondsToSelector:@selector(_gsEvent)]) + { + int* eventMem = (int *)(void*)CFBridgingRetain([event performSelector:@selector(_gsEvent)]); + int eventType = eventMem ? eventMem[GSEVENT_TYPE] : 0; - if (eventMem && (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)) - { - // Read keycode from GSEventKey - int tmp = eventMem[GSEVENTKEY_KEYCODE]; - UniChar *keycode = (UniChar *)&tmp; + if (eventMem && (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)) + { + // Read keycode from GSEventKey + int tmp = eventMem[GSEVENTKEY_KEYCODE]; + UniChar *keycode = (UniChar *)&tmp; - // Post notification - NSDictionary *inf = [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithShort:keycode[0]], @"keycode", - nil]; + // Post notification + NSDictionary *inf = [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithShort:keycode[0]], @"keycode", + nil]; - [[NSNotificationCenter defaultCenter] - postNotificationName:(eventType == GSEVENT_TYPE_KEYDOWN) ? GSEventKeyDownNotification : GSEventKeyUpNotification - object:nil userInfo:inf]; - } - } + [[NSNotificationCenter defaultCenter] + postNotificationName:(eventType == GSEVENT_TYPE_KEYDOWN) ? GSEventKeyDownNotification : GSEventKeyUpNotification + object:nil userInfo:inf]; + } + + CFBridgingRelease(eventMem); + } } #endif diff --git a/ios/RetroArch/rarch_wrapper.h b/ios/RetroArch/rarch_wrapper.h new file mode 100644 index 0000000000..195c4eca01 --- /dev/null +++ b/ios/RetroArch/rarch_wrapper.h @@ -0,0 +1,17 @@ +#ifndef __IOS_RARCH_WRAPPER_H__ +#define __IOS_RARCH_WRAPPER_H__ + +bool ios_load_game(const char* path); +void ios_close_game(); +void ios_pause_emulator(); +void ios_resume_emulator(); +void ios_suspend_emulator(); +void ios_activate_emulator(); +bool ios_init_game_view(); +void ios_destroy_game_view(); +void ios_flip_game_view(); +void ios_set_game_view_sync(bool on); +void ios_get_game_view_size(unsigned *width, unsigned *height); +void ios_bind_game_view_fbo(); + +#endif diff --git a/ios/RetroArch/views.h b/ios/RetroArch/views.h index 59d21b1a60..cdb31e9ae6 100644 --- a/ios/RetroArch/views.h +++ b/ios/RetroArch/views.h @@ -4,10 +4,6 @@ #include "conf/config_file.h" @interface RAGameView : UIViewController -- (id)initWithGame:(NSString*)path;\ -- (void)pause; -- (void)resume; -- (void)exit; @end @interface RAModuleList : UITableViewController