diff --git a/ios/ViewController.h b/ios/ViewController.h index 0b97209924..911c011b31 100644 --- a/ios/ViewController.h +++ b/ios/ViewController.h @@ -2,14 +2,13 @@ #import #import -#import #import "iCade/iCadeReaderView.h" #import "LocationHelper.h" #import "ViewControllerCommon.h" -@interface PPSSPPViewControllerGL : PPSSPPBaseViewController +@interface PPSSPPViewControllerGL : PPSSPPBaseViewController // Public-ish control similar to GLKViewController @property (nonatomic, assign) NSInteger preferredFramesPerSecond; // default 60 diff --git a/ios/ViewController.mm b/ios/ViewController.mm index d6db80a5b7..3650fd7cb9 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -9,10 +9,8 @@ #import "ViewController.h" #import "DisplayManager.h" #import "iOSCoreAudio.h" -#import "IAPManager.h" #import -#import "Controls.h" #import #include @@ -97,8 +95,6 @@ static std::thread g_renderLoopThread; PPSSPPBaseViewController *sharedViewController; @interface PPSSPPViewControllerGL () { - ICadeTracker g_iCadeTracker; - IOSGLESContext *graphicsContext; int imageRequestId; @@ -112,10 +108,6 @@ PPSSPPBaseViewController *sharedViewController; @property (nonatomic, strong) EAGLContext* context; -@property (nonatomic) GCController *gameController __attribute__((weak_import)); -@property (strong, nonatomic) CMMotionManager *motionManager; -@property (strong, nonatomic) NSOperationQueue *accelerometerQueue; - @end @implementation PPSSPPViewControllerGL {} @@ -124,27 +116,10 @@ PPSSPPBaseViewController *sharedViewController; self = [super init]; if (self) { _preferredFramesPerSecond = 60; // default - sharedViewController = self; - g_iCadeTracker.InitKeyMap(); - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidConnect:) name:GCControllerDidConnectNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidDisconnect:) name:GCControllerDidDisconnectNotification object:nil]; } - self.accelerometerQueue = [[NSOperationQueue alloc] init]; - self.accelerometerQueue.name = @"AccelerometerQueue"; - self.accelerometerQueue.maxConcurrentOperationCount = 1; return self; } -- (BOOL)prefersHomeIndicatorAutoHidden { - if (g_Config.iAppSwitchMode == (int)AppSwitchMode::DOUBLE_SWIPE_INDICATOR) { - return NO; - } else { - return YES; - } -} - // The actual rendering is NOT on this thread, this is the emu thread // that runs game logic. void GLRenderLoop(IOSGLESContext *graphicsContext) { @@ -264,19 +239,12 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) { [self hideKeyboard]; // Initialize the motion manager for accelerometer control. - self.motionManager = [[CMMotionManager alloc] init]; INFO_LOG(Log::G3D, "Done with viewDidLoad."); } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; self.glView.frame = self.view.bounds; - /* - // if you need to update viewport: - CGSize s = self.glView.bounds.size; - [EAGLContext setCurrentContext:self.glContext]; - glViewport(0, 0, (GLsizei)round(s.width), (GLsizei)round(s.height)); - */ } - (void)viewWillAppear:(BOOL)animated { @@ -340,39 +308,11 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) { } } -- (void)handleSwipeFrom:(UIScreenEdgePanGestureRecognizer *)recognizer { - if (recognizer.state == UIGestureRecognizerStateEnded) { - KeyInput key; - key.flags = KEY_DOWN | KEY_UP; - key.keyCode = NKCODE_BACK; - key.deviceId = DEVICE_ID_TOUCH; - NativeKey(key); - INFO_LOG(Log::System, "Detected back swipe"); - } -} - -- (void)appWillTerminate:(NSNotification *)notification -{ - [self shutdown]; -} - - (void)didBecomeActive { - INFO_LOG(Log::System, "didBecomeActive begin"); - if (self.motionManager.accelerometerAvailable) { - self.motionManager.accelerometerUpdateInterval = 1.0 / 60.0; - INFO_LOG(Log::G3D, "Starting accelerometer updates."); + [super didBecomeActive]; + + INFO_LOG(Log::System, "didBecomeActive begin"); - [self.motionManager startAccelerometerUpdatesToQueue:self.accelerometerQueue - withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) { - if (error) { - NSLog(@"Accelerometer error: %@", error); - return; - } - ProcessAccelerometerData(accelerometerData); - }]; - } else { - INFO_LOG(Log::G3D, "No accelerometer available, not starting updates."); - } [self runGLRenderLoop]; [[DisplayManager shared] updateResolution:[UIScreen mainScreen]]; @@ -382,29 +322,26 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) { } - (void)willResignActive { - INFO_LOG(Log::System, "willResignActive begin"); + INFO_LOG(Log::System, "willResignActive GL"); [self requestExitGLRenderLoop]; - // Stop accelerometer updates - if (self.motionManager.accelerometerActive) { - INFO_LOG(Log::G3D, "Stopping accelerometer updates"); - [self.motionManager stopAccelerometerUpdates]; - } - INFO_LOG(Log::System, "willResignActive end"); - self.displayLink.paused = YES; + + [super willResignActive]; } -- (void)shutdown -{ +- (void)shutdown { + [super shutdown]; + INFO_LOG(Log::System, "shutdown GL"); g_Config.Save("shutdown GL"); - _dbg_assert_(graphicsContext); _dbg_assert_(sharedViewController != nil); sharedViewController = nil; + _dbg_assert_(graphicsContext); + if (self.context) { if ([EAGLContext currentContext] == self.context) { [EAGLContext setCurrentContext:nil]; @@ -414,8 +351,6 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) { [[NSNotificationCenter defaultCenter] removeObserver:self]; - self.gameController = nil; - graphicsContext->BeginShutdown(); // Skipping GL calls here because the old context is lost. graphicsContext->ThreadFrameUntilCondition([]() -> bool { @@ -429,75 +364,16 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) { INFO_LOG(Log::System, "Done shutting down GL"); } -- (UIInterfaceOrientationMask)supportedInterfaceOrientations -{ - return UIInterfaceOrientationMaskAll; -} - - (void)bindDefaultFBO { [(GLKView*)self.glView bindDrawable]; } -- (void)buttonDown:(iCadeState)button -{ - g_iCadeTracker.ButtonDown(button); -} - -- (void)buttonUp:(iCadeState)button -{ - g_iCadeTracker.ButtonUp(button); -} - -- (void)controllerDidConnect:(NSNotification *)note -{ - if (![[GCController controllers] containsObject:self.gameController]) self.gameController = nil; - - if (self.gameController != nil) return; // already have a connected controller - - [self setupController:(GCController *)note.object]; -} - -- (void)controllerDidDisconnect:(NSNotification *)note -{ - if (self.gameController == note.object) { - self.gameController = nil; - - if ([[GCController controllers] count] > 0) { - [self setupController:[[GCController controllers] firstObject]]; - } - } -} - - (UIView *)getView { return [self view]; } -- (void)setupController:(GCController *)controller -{ - self.gameController = controller; - if (!InitController(controller)) { - self.gameController = nil; - } -} - -// See PPSSPPUIApplication.mm for the other method -#if PPSSPP_PLATFORM(IOS_APP_STORE) - -- (void)pressesBegan:(NSSet *)presses withEvent:(UIPressesEvent *)event { - KeyboardPressesBegan(presses, event); -} - -- (void)pressesEnded:(NSSet *)presses withEvent:(UIPressesEvent *)event { - KeyboardPressesEnded(presses, event); -} - -- (void)pressesCancelled:(NSSet *)presses withEvent:(UIPressesEvent *)event { - KeyboardPressesEnded(presses, event); -} - -#endif - +// Can't consolidate this yet. - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; diff --git a/ios/ViewControllerCommon.h b/ios/ViewControllerCommon.h index da9460d49a..6307ea0244 100644 --- a/ios/ViewControllerCommon.h +++ b/ios/ViewControllerCommon.h @@ -2,13 +2,16 @@ #import +#import + #import "CameraHelper.h" #import "LocationHelper.h" +#import "iCade/iCadeReaderView.h" @interface PPSSPPBaseViewController : UIViewController< UIImagePickerControllerDelegate, UINavigationControllerDelegate, CameraFrameDelegate, LocationHandlerDelegate, UIKeyInput, - UIGestureRecognizerDelegate> + UIGestureRecognizerDelegate, iCadeEventDelegate> - (void)hideKeyboard; - (void)showKeyboard; @@ -21,6 +24,7 @@ - (void)startVideo:(int)width height:(int)height; - (void)stopVideo; - (void)appSwitchModeChanged; +- (void)setupController:(GCController *)controller; // Forwarded from the AppDelegate - (void)didBecomeActive; diff --git a/ios/ViewControllerCommon.mm b/ios/ViewControllerCommon.mm index 5f503d3850..9787883ec5 100644 --- a/ios/ViewControllerCommon.mm +++ b/ios/ViewControllerCommon.mm @@ -16,15 +16,84 @@ NSString *imageFilename; CameraHelper *cameraHelper; LocationHelper *locationHelper; + ICadeTracker g_iCadeTracker; TouchTracker g_touchTracker; } +@property (strong, nonatomic) NSOperationQueue *accelerometerQueue; +@property (nonatomic) GCController *gameController __attribute__((weak_import)); +@property (strong, nonatomic) CMMotionManager *motionManager; + @end @implementation PPSSPPBaseViewController { UIScreenEdgePanGestureRecognizer *mBackGestureRecognizer; } +- (id)init { + self = [super init]; + if (self) { + sharedViewController = self; + + g_iCadeTracker.InitKeyMap(); + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidConnect:) name:GCControllerDidConnectNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidDisconnect:) name:GCControllerDidDisconnectNotification object:nil]; + } + self.accelerometerQueue = [[NSOperationQueue alloc] init]; + self.accelerometerQueue.name = @"AccelerometerQueue"; + self.accelerometerQueue.maxConcurrentOperationCount = 1; + + return self; +} + +- (void)shutdown { + self.gameController = nil; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + _dbg_assert_(sharedViewController != nil); + sharedViewController = nil; +} + +- (BOOL)prefersHomeIndicatorAutoHidden { + if (g_Config.iAppSwitchMode == (int)AppSwitchMode::DOUBLE_SWIPE_INDICATOR) { + return NO; + } else { + return YES; + } +} + +- (void)didBecomeActive { + if (self.motionManager.accelerometerAvailable) { + self.motionManager.accelerometerUpdateInterval = 1.0 / 60.0; + INFO_LOG(Log::G3D, "Starting accelerometer updates."); + + [self.motionManager startAccelerometerUpdatesToQueue:self.accelerometerQueue + withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) { + if (error) { + NSLog(@"Accelerometer error: %@", error); + return; + } + ProcessAccelerometerData(accelerometerData); + }]; + } else { + INFO_LOG(Log::G3D, "No accelerometer available, not starting updates."); + } +} + +- (void)willResignActive { + // Stop accelerometer updates + if (self.motionManager.accelerometerActive) { + INFO_LOG(Log::G3D, "Stopping accelerometer updates"); + [self.motionManager stopAccelerometerUpdates]; + } +} + +- (void)appWillTerminate:(NSNotification *)notification { + [self shutdown]; +} + - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; INFO_LOG(Log::G3D, "viewDidAppear"); @@ -57,6 +126,33 @@ } } +- (void)controllerDidConnect:(NSNotification *)note +{ + if (![[GCController controllers] containsObject:self.gameController]) self.gameController = nil; + + if (self.gameController != nil) return; // already have a connected controller + + [self setupController:(GCController *)note.object]; +} + +- (void)controllerDidDisconnect:(NSNotification *)note +{ + if (self.gameController == note.object) { + self.gameController = nil; + + if ([[GCController controllers] count] > 0) { + [self setupController:[[GCController controllers] firstObject]]; + } + } +} + +- (void)setupController:(GCController *)controller { + self.gameController = controller; + if (!InitController(controller)) { + self.gameController = nil; + } +} + - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { g_touchTracker.Began(touches, self.view); @@ -189,6 +285,8 @@ locationHelper = [[LocationHelper alloc] init]; [locationHelper setDelegate:self]; + + self.motionManager = [[CMMotionManager alloc] init]; } extern float g_safeInsetLeft; @@ -271,4 +369,31 @@ static float BoostInset(float inset) { return YES; } +- (void)buttonDown:(iCadeState)button +{ + g_iCadeTracker.ButtonDown(button); +} + +- (void)buttonUp:(iCadeState)button +{ + g_iCadeTracker.ButtonUp(button); +} + +// See PPSSPPUIApplication.mm for the other method +#if PPSSPP_PLATFORM(IOS_APP_STORE) + +- (void)pressesBegan:(NSSet *)presses withEvent:(UIPressesEvent *)event { + KeyboardPressesBegan(presses, event); +} + +- (void)pressesEnded:(NSSet *)presses withEvent:(UIPressesEvent *)event { + KeyboardPressesEnded(presses, event); +} + +- (void)pressesCancelled:(NSSet *)presses withEvent:(UIPressesEvent *)event { + KeyboardPressesEnded(presses, event); +} + +#endif + @end diff --git a/ios/ViewControllerMetal.h b/ios/ViewControllerMetal.h index d4fcb7bf6f..33bc1d757a 100644 --- a/ios/ViewControllerMetal.h +++ b/ios/ViewControllerMetal.h @@ -6,7 +6,7 @@ #import "ViewControllerCommon.h" #import "iCade/iCadeReaderView.h" -@interface PPSSPPViewControllerMetal : PPSSPPBaseViewController +@interface PPSSPPViewControllerMetal : PPSSPPBaseViewController @end /** The Metal-compatibile view. */ diff --git a/ios/ViewControllerMetal.mm b/ios/ViewControllerMetal.mm index 63ede0e11a..2996fd418b 100644 --- a/ios/ViewControllerMetal.mm +++ b/ios/ViewControllerMetal.mm @@ -1,9 +1,7 @@ #import "AppDelegate.h" #import "ViewControllerMetal.h" #import "DisplayManager.h" -#include "Controls.h" #import "iOSCoreAudio.h" -#import "IAPManager.h" #include "Common/Log.h" @@ -178,41 +176,18 @@ static std::atomic renderLoopRunning; static std::thread g_renderLoopThread; @interface PPSSPPViewControllerMetal () { - ICadeTracker g_iCadeTracker; - IOSVulkanContext *graphicsContext; - CameraHelper *cameraHelper; } -@property (nonatomic) GCController *gameController __attribute__((weak_import)); -@property (strong, nonatomic) CMMotionManager *motionManager; -@property (strong, nonatomic) NSOperationQueue *accelerometerQueue; - @end // @interface @implementation PPSSPPViewControllerMetal {} - (id)init { self = [super init]; - if (self) { - sharedViewController = self; - g_iCadeTracker.InitKeyMap(); - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidConnect:) name:GCControllerDidConnectNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidDisconnect:) name:GCControllerDidDisconnectNotification object:nil]; - } - self.accelerometerQueue = [[NSOperationQueue alloc] init]; - self.accelerometerQueue.name = @"AccelerometerQueue"; - self.accelerometerQueue.maxConcurrentOperationCount = 1; return self; } -- (void)appWillTerminate:(NSNotification *)notification -{ - [self shutdown]; -} - // Should be very similar to the Android one, probably mergeable. // This is the EmuThread for iOS. void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLayer) { @@ -315,22 +290,9 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye // These two are forwarded from the appDelegate - (void)didBecomeActive { - INFO_LOG(Log::G3D, "didBecomeActive GL"); - if (self.motionManager.accelerometerAvailable) { - self.motionManager.accelerometerUpdateInterval = 1.0 / 60.0; - INFO_LOG(Log::G3D, "Starting accelerometer updates."); - - [self.motionManager startAccelerometerUpdatesToQueue:self.accelerometerQueue - withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) { - if (error) { - NSLog(@"Accelerometer error: %@", error); - return; - } - ProcessAccelerometerData(accelerometerData); - }]; - } else { - INFO_LOG(Log::G3D, "No accelerometer available, not starting updates."); - } + [super didBecomeActive]; + INFO_LOG(Log::G3D, "didBecomeActive Metal"); + // Spin up the emu thread. It will in turn spin up the Vulkan render thread // on its own. [self runVulkanRenderLoop]; @@ -338,29 +300,19 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye } - (void)willResignActive { - INFO_LOG(Log::G3D, "willResignActive GL"); + INFO_LOG(Log::G3D, "willResignActive Metal"); [self requestExitVulkanRenderLoop]; - // Stop accelerometer updates - if (self.motionManager.accelerometerActive) { - INFO_LOG(Log::G3D, "Stopping accelerometer updates"); - [self.motionManager stopAccelerometerUpdates]; - } + [super willResignActive]; } -- (void)shutdown -{ - INFO_LOG(Log::System, "shutdown VK"); +- (void)shutdown { + [super shutdown]; + + INFO_LOG(Log::System, "shutdown"); g_Config.Save("shutdown vk"); - _dbg_assert_(sharedViewController != nil); - sharedViewController = nil; - - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - self.gameController = nil; - if (graphicsContext) { graphicsContext->Shutdown(); delete graphicsContext; @@ -408,9 +360,6 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye } INFO_LOG(Log::G3D, "Detected size: %dx%d", g_display.pixel_xres, g_display.pixel_yres); - - // Initialize the motion manager for accelerometer control. - self.motionManager = [[CMMotionManager alloc] init]; } - (UIView *)getView { @@ -433,74 +382,11 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye INFO_LOG(Log::G3D, "viewWillDisappear"); } -- (BOOL)prefersHomeIndicatorAutoHidden { - if (g_Config.iAppSwitchMode == (int)AppSwitchMode::DOUBLE_SWIPE_INDICATOR) { - return NO; - } else { - return YES; - } -} - - (void)bindDefaultFBO { // Do nothing } -- (void)buttonDown:(iCadeState)button -{ - g_iCadeTracker.ButtonDown(button); -} - -- (void)buttonUp:(iCadeState)button -{ - g_iCadeTracker.ButtonUp(button); -} - -// See PPSSPPUIApplication.mm for the other method -#if PPSSPP_PLATFORM(IOS_APP_STORE) - -- (void)pressesBegan:(NSSet *)presses withEvent:(UIPressesEvent *)event { - KeyboardPressesBegan(presses, event); -} - -- (void)pressesEnded:(NSSet *)presses withEvent:(UIPressesEvent *)event { - KeyboardPressesEnded(presses, event); -} - -- (void)pressesCancelled:(NSSet *)presses withEvent:(UIPressesEvent *)event { - KeyboardPressesEnded(presses, event); -} - -#endif - -- (void)controllerDidConnect:(NSNotification *)note -{ - if (![[GCController controllers] containsObject:self.gameController]) self.gameController = nil; - - if (self.gameController != nil) return; // already have a connected controller - - [self setupController:(GCController *)note.object]; -} - -- (void)controllerDidDisconnect:(NSNotification *)note -{ - if (self.gameController == note.object) { - self.gameController = nil; - - if ([[GCController controllers] count] > 0) { - [self setupController:[[GCController controllers] firstObject]]; - } - } -} - -- (void)setupController:(GCController *)controller -{ - self.gameController = controller; - if (!InitController(controller)) { - self.gameController = nil; - } -} - - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];