diff --git a/ios/RetroArch/RADirectoryFilterList.m b/ios/RetroArch/RADirectoryFilterList.m index d4838f4dad..02fb61dde5 100644 --- a/ios/RetroArch/RADirectoryFilterList.m +++ b/ios/RetroArch/RADirectoryFilterList.m @@ -69,7 +69,7 @@ NSRegularExpression* expr = [NSRegularExpression regularExpressionWithPattern:regex options:0 error:nil]; - [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListWithPath:_path filter:expr]]; + [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListWithPath:_path filter:expr] isGame:NO]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section diff --git a/ios/RetroArch/RADirectoryGrid.m b/ios/RetroArch/RADirectoryGrid.m index b2d45767da..d48d9efa2c 100644 --- a/ios/RetroArch/RADirectoryGrid.m +++ b/ios/RetroArch/RADirectoryGrid.m @@ -60,7 +60,7 @@ RADirectoryItem* path = [_list objectAtIndex: indexPath.row]; if(path.isDirectory) - [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListWithPath:path.path]]; + [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListWithPath:path.path] isGame:NO]; else [[RetroArch_iOS get] runGame:path.path]; } diff --git a/ios/RetroArch/RADirectoryList.m b/ios/RetroArch/RADirectoryList.m index b4b78bca81..a27a86c636 100644 --- a/ios/RetroArch/RADirectoryList.m +++ b/ios/RetroArch/RADirectoryList.m @@ -74,7 +74,7 @@ static NSString* check_path(NSString* path) RADirectoryItem* path = [_list objectAtIndex: indexPath.row]; if(path.isDirectory) - [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListWithPath:path.path]]; + [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListWithPath:path.path] isGame:NO]; else [[RetroArch_iOS get] runGame:path.path]; } diff --git a/ios/RetroArch/RAGameView.m b/ios/RetroArch/RAGameView.m index 1605a48736..5fdc1e9581 100644 --- a/ios/RetroArch/RAGameView.m +++ b/ios/RetroArch/RAGameView.m @@ -16,9 +16,6 @@ #include "general.h" #include "rarch_wrapper.h" -static bool _isRunning; -static bool _isPaused; - static float screen_scale; static int frame_skips = 4; static bool is_syncing = true; @@ -88,22 +85,6 @@ static bool is_syncing = true; _notifyLabel.alpha = 0.0f; } -- (void)iterate -{ - while (_isRunning && !_isPaused) - { - _isRunning = rarch_main_iterate(); - - if (!_isRunning) - { - ios_close_game(); - return; - } - else - while(!_isPaused && _isRunning && CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource); - } -} - - (void)needsToDie { glFinish(); @@ -114,94 +95,16 @@ static bool is_syncing = true; [EAGLContext setCurrentContext:nil]; } -- (void)pause -{ - _isPaused = true; -} - -- (void)resume -{ - if (_isPaused) - { - _isPaused = false; - [self performSelector:@selector(iterate) withObject:nil afterDelay:.02f]; - } -} - @end static RAGameView* gameViewer; -bool ios_load_game(const char* path) -{ - [RASettingsList refreshConfigFile]; - - const char* const sd = [[RetroArch_iOS get].system_directory UTF8String]; - const char* const cf =[[RetroArch_iOS get].configFilePath UTF8String]; - const char* const libretro = [[RetroArch_iOS get].module_path UTF8String]; - - struct rarch_main_wrap main_wrapper = {path, sd, sd, cf, libretro}; - if (rarch_main_init_wrap(&main_wrapper) == 0) - { - rarch_init_msg_queue(); - _isRunning = true; - } - else - _isRunning = false; - - return _isRunning; -} - -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]; -} - -void ios_pause_emulator() -{ - if (_isRunning) - [gameViewer pause]; -} - -void ios_resume_emulator() -{ - if (_isRunning) - [gameViewer resume]; -} - -void ios_suspend_emulator() -{ - if (_isRunning) - uninit_drivers(); -} - -void ios_activate_emulator() -{ - if (_isRunning) - init_drivers(); -} - bool ios_init_game_view() { if (!gameViewer) { gameViewer = [RAGameView new]; - [[RetroArch_iOS get] setViewer:gameViewer]; - [gameViewer performSelector:@selector(iterate) withObject:nil afterDelay:.02f]; + [[RetroArch_iOS get] pushViewController:gameViewer isGame:YES]; } return true; @@ -212,7 +115,7 @@ void ios_destroy_game_view() if (gameViewer) { [gameViewer needsToDie]; - [[RetroArch_iOS get] setViewer:nil]; + [[RetroArch_iOS get] popViewController]; gameViewer = nil; } } diff --git a/ios/RetroArch/RAModuleList.m b/ios/RetroArch/RAModuleList.m index 7b36bef162..be37cf1e3e 100644 --- a/ios/RetroArch/RAModuleList.m +++ b/ios/RetroArch/RAModuleList.m @@ -59,13 +59,13 @@ RAModuleInfo* info = (RAModuleInfo*)[_modules objectAtIndex:indexPath.row]; [RetroArch_iOS get].module_path = info.path; - [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListWithPath:nil]]; + [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListWithPath:nil] isGame:NO]; } - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { RAModuleInfo* info = (RAModuleInfo*)[_modules objectAtIndex:indexPath.row]; - [[RetroArch_iOS get] pushViewController:[[RAModuleInfoList alloc] initWithModuleInfo:info]]; + [[RetroArch_iOS get] pushViewController:[[RAModuleInfoList alloc] initWithModuleInfo:info] isGame:NO]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section diff --git a/ios/RetroArch/RetroArch_iOS.h b/ios/RetroArch/RetroArch_iOS.h index eec5fcedf5..67a9d8f410 100644 --- a/ios/RetroArch/RetroArch_iOS.h +++ b/ios/RetroArch/RetroArch_iOS.h @@ -24,13 +24,10 @@ extern NSString* const GSEventKeyUpNotification; + (RetroArch_iOS*)get; - (void)runGame:(NSString*)path; -- (void)gameHasExited; -- (void)pushViewController:(UIViewController*)theView; +- (void)pushViewController:(UIViewController*)theView isGame:(BOOL)game; - (void)popViewController; -- (void)setViewer:(UIViewController*)theView; - - (NSString*)configFilePath; @property (strong, nonatomic) NSString* system_directory; diff --git a/ios/RetroArch/RetroArch_iOS.m b/ios/RetroArch/RetroArch_iOS.m index 4e45931752..43c7101896 100644 --- a/ios/RetroArch/RetroArch_iOS.m +++ b/ios/RetroArch/RetroArch_iOS.m @@ -15,6 +15,7 @@ #include #include "rarch_wrapper.h" +#include "general.h" #define MAX_TOUCH 16 extern struct @@ -29,10 +30,49 @@ extern bool ios_keys[256]; extern uint32_t ios_current_touch_count; +@interface RANavigator : UINavigationController +// 0 if no RAGameView is in the navigator +// 1 if a RAGameView is the top +// 2+ if there are views pushed ontop of the RAGameView +@property unsigned gameAndAbove; + +- (void)pushViewController:(UIViewController*)theView isGame:(BOOL)game; +@end + +@implementation RANavigator +- (void)pushViewController:(UIViewController*)theView isGame:(BOOL)game +{ + assert(!game || self.gameAndAbove == 0); + + if (game || self.gameAndAbove) self.gameAndAbove ++; + + [[UIApplication sharedApplication] setStatusBarHidden:game withAnimation:UIStatusBarAnimationNone]; + self.navigationBarHidden = game; + [self pushViewController:theView animated:!(self.gameAndAbove == 1 || self.gameAndAbove == 2)]; +} + +- (UIViewController *)popViewControllerAnimated:(BOOL)animated +{ + const bool poppingFromGame = self.gameAndAbove == 1; + const bool poppingToGame = self.gameAndAbove == 2; + if (self.gameAndAbove) self.gameAndAbove --; + + if (self.gameAndAbove == 1) + [[RetroArch_iOS get] performSelector:@selector(startTimer)]; + + [[UIApplication sharedApplication] setStatusBarHidden:poppingToGame withAnimation:UIStatusBarAnimationNone]; + self.navigationBarHidden = poppingToGame; + return [super popViewControllerAnimated:!poppingToGame && !poppingFromGame]; +} +@end + @implementation RetroArch_iOS { UIWindow* _window; - UINavigationController* _navigator; + RANavigator* _navigator; + NSTimer* _gameTimer; + + bool _isRunning; } + (void)displayErrorMessage:(NSString*)message @@ -50,36 +90,9 @@ extern uint32_t ios_current_touch_count; return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate]; } -- (void)runGame:(NSString*)path +- (void)showSettings { - ios_load_game([path UTF8String]); -} - -- (void)gameHasExited -{ - _navigator = [[UINavigationController alloc] init]; - [_navigator pushViewController: [[RAModuleList alloc] init] animated:YES]; - - _window.rootViewController = _navigator; -} - -- (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; - [[UIApplication sharedApplication] setStatusBarHidden:theView ? YES : NO withAnimation:UIStatusBarAnimationNone]; - _window.rootViewController = theView; + [self pushViewController:[RASettingsList new] isGame:NO]; } - (NSString*)configFilePath @@ -108,13 +121,13 @@ extern uint32_t ios_current_touch_count; style:UIBarButtonItemStyleBordered target:nil action:nil]; self.settings_button.target = self; - self.settings_button.action = @selector(show_settings); + self.settings_button.action = @selector(showSettings); [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone]; // Setup window - _navigator = [[UINavigationController alloc] init]; - [_navigator pushViewController: [[RAModuleList alloc] init] animated:YES]; + _navigator = [RANavigator new]; + [_navigator pushViewController: [RAModuleList new] animated:YES]; _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; _window.rootViewController = _navigator; @@ -125,26 +138,106 @@ extern uint32_t ios_current_touch_count; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(keyReleased:) name: GSEventKeyUpNotification object: nil]; } +#pragma mark VIEW MANAGEMENT +- (void)pushViewController:(UIViewController*)theView isGame:(BOOL)game +{ + [_navigator pushViewController:theView isGame:game]; + [self startTimer]; +} + +- (void)popViewController +{ + [_navigator popViewControllerAnimated:YES]; + [self startTimer]; +} + +#pragma mark EMULATION +- (void)runGame:(NSString*)path +{ + [RASettingsList refreshConfigFile]; + + const char* const sd = [[RetroArch_iOS get].system_directory UTF8String]; + const char* const cf =[[RetroArch_iOS get].configFilePath UTF8String]; + const char* const libretro = [[RetroArch_iOS get].module_path UTF8String]; + + struct rarch_main_wrap main_wrapper = {[path UTF8String], sd, sd, cf, libretro}; + if (rarch_main_init_wrap(&main_wrapper) == 0) + { + _isRunning = true; + rarch_init_msg_queue(); + [self startTimer]; + } + else + { + _isRunning = false; + [RetroArch_iOS displayErrorMessage:@"Failed to load game."]; + } +} + +- (void)closeGame +{ + if (_isRunning) + { + rarch_main_deinit(); + rarch_deinit_msg_queue(); + +#ifdef PERF_TEST + rarch_perf_log(); +#endif + + rarch_main_clear_state(); + } + + [self stopTimer]; + _isRunning = false; +} + +- (void)iterate +{ + if (!_isRunning || _navigator.gameAndAbove != 1) + [self stopTimer]; + else if (_isRunning && !rarch_main_iterate()) + [self closeGame]; +} + +- (void)startTimer +{ + if (!_gameTimer) + _gameTimer = [NSTimer scheduledTimerWithTimeInterval:0.001f target:self selector:@selector(iterate) userInfo:nil repeats:YES]; +} + +- (void)stopTimer +{ + if (_gameTimer) + [_gameTimer invalidate]; + + _gameTimer = nil; +} + +#pragma mark LIFE CYCLE - (void)applicationDidBecomeActive:(UIApplication*)application { - ios_resume_emulator(); + [self startTimer]; } - (void)applicationWillResignActive:(UIApplication*)application { - ios_pause_emulator(); + [self stopTimer]; } - (void)applicationWillEnterForeground:(UIApplication *)application { - ios_activate_emulator(); + if (_isRunning) + init_drivers(); } - (void)applicationDidEnterBackground:(UIApplication *)application { - ios_suspend_emulator(); + if (_isRunning) + uninit_drivers(); } +#pragma mark INPUT -(void) keyPressed: (NSNotification*) notification { int keycode = [[notification.userInfo objectForKey:@"keycode"] intValue]; @@ -157,11 +250,6 @@ extern uint32_t ios_current_touch_count; if (keycode < 256) ios_keys[keycode] = false; } -- (void)show_settings -{ - [self pushViewController:[RASettingsList new]]; -} - - (void)processTouches:(NSArray*)touches { ios_current_touch_count = [touches count]; @@ -180,9 +268,10 @@ extern uint32_t ios_current_touch_count; if (coord.y < view.bounds.size.height / 10.0f) { float tenpct = view.bounds.size.width / 10.0f; + if (_navigator.gameAndAbove == 1) if (coord.x >= tenpct * 4 && coord.x <= tenpct * 6) { - ios_close_game(); + [self closeGame]; } } } diff --git a/ios/RetroArch/ios_input.c b/ios/RetroArch/ios_input.c index 4fba92d606..2a29ddd4bc 100644 --- a/ios/RetroArch/ios_input.c +++ b/ios/RetroArch/ios_input.c @@ -244,6 +244,7 @@ static void *ios_input_init(void) { input_init_keyboard_lut(rarch_key_map_hidusage); + ios_current_touch_count = 0; memset(ios_touches, 0, sizeof(ios_touches)); memset(ios_keys, 0, sizeof(ios_keys)); return (void*)-1; diff --git a/ios/RetroArch/rarch_wrapper.h b/ios/RetroArch/rarch_wrapper.h index ed2a31b571..b53bb0a340 100644 --- a/ios/RetroArch/rarch_wrapper.h +++ b/ios/RetroArch/rarch_wrapper.h @@ -16,12 +16,8 @@ #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(); +// These functions must only be called in gfx/context/ioseagl_ctx.c + bool ios_init_game_view(); void ios_destroy_game_view(); void ios_flip_game_view(); diff --git a/ios/RetroArch/settings/RASettingsList.m b/ios/RetroArch/settings/RASettingsList.m index 1b7595fb3d..bd3588c331 100644 --- a/ios/RetroArch/settings/RASettingsList.m +++ b/ios/RetroArch/settings/RASettingsList.m @@ -93,7 +93,7 @@ static RASettingData* subpath_setting(RAConfig* config, NSString* name, NSString NSArray* settings = [NSArray arrayWithObjects: [NSArray arrayWithObjects:@"Video", boolean_setting(config, @"video_smooth", @"Smooth Video", @"true"), - boolean_setting(config, @"video_crop_overscan", @"Crop Overscan", @"false"), + boolean_setting(config, @"video_crop_overscan", @"Crop Overscan", @"true"), subpath_setting(config, @"video_bsnes_shader", @"Shader", @"", shader_path, @"shader"), nil], diff --git a/ios/RetroArch/settings/RASettingsSubList.m b/ios/RetroArch/settings/RASettingsSubList.m index 2ba3baf9ff..b6b6ac0341 100644 --- a/ios/RetroArch/settings/RASettingsSubList.m +++ b/ios/RetroArch/settings/RASettingsSubList.m @@ -73,7 +73,7 @@ static const char* const SETTINGID = "SETTING"; { case EnumerationSetting: case FileListSetting: - [[RetroArch_iOS get] pushViewController:[[RASettingEnumerationList alloc] initWithSetting:setting fromTable:(UITableView*)self.view]]; + [[RetroArch_iOS get] pushViewController:[[RASettingEnumerationList alloc] initWithSetting:setting fromTable:(UITableView*)self.view] isGame:NO]; break; case ButtonSetting: @@ -81,7 +81,7 @@ static const char* const SETTINGID = "SETTING"; break; case GroupSetting: - [[RetroArch_iOS get] pushViewController:[[RASettingsSubList alloc] initWithSettings:setting.subValues title:setting.label]]; + [[RetroArch_iOS get] pushViewController:[[RASettingsSubList alloc] initWithSettings:setting.subValues title:setting.label] isGame:NO]; break; default: