From 7b3f0aeab2030d4f2a0ff478856f21c2214c0f65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 4 Jun 2024 11:51:09 +0200 Subject: [PATCH] iOS: Implement accelerometer support --- CMakeLists.txt | 2 +- ios/Controls.h | 4 ++++ ios/Controls.mm | 8 ++++++++ ios/ViewController.mm | 30 +++++++++++++++++++++++++++++- ios/ViewControllerMetal.mm | 31 ++++++++++++++++++++++++++++++- 5 files changed, 72 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4220504f4fd2..021cf8b3e8ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1325,7 +1325,7 @@ elseif(IOS AND NOT LIBRETRO) Common/Battery/AppleBatteryClient.m ) - set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation -framework CoreLocation -framework CoreText -framework CoreVideo -framework CoreMedia -framework CoreServices -framework Metal -framework IOSurface" ) + set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework CoreMotion -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation -framework CoreLocation -framework CoreText -framework CoreVideo -framework CoreMedia -framework CoreServices -framework Metal -framework IOSurface" ) if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework") set(nativeExtraLibs ${nativeExtraLibs} "-weak_framework GameController") endif() diff --git a/ios/Controls.h b/ios/Controls.h index cf4112f9d282..8c5707f28c02 100644 --- a/ios/Controls.h +++ b/ios/Controls.h @@ -3,6 +3,8 @@ #include #import +#import + #include "iCade/iCadeState.h" #include "Common/Input/InputState.h" @@ -38,3 +40,5 @@ struct ICadeTracker { double lastSelectPress = 0.0f; double lastStartPress = 0.0f; }; + +void ProcessAccelerometerData(CMAccelerometerData *accData); \ No newline at end of file diff --git a/ios/Controls.mm b/ios/Controls.mm index 6fcbd90521db..fc28499f5f93 100644 --- a/ios/Controls.mm +++ b/ios/Controls.mm @@ -358,3 +358,11 @@ bool SetupController(GCController *controller) { NativeKey(key); } } + +void ProcessAccelerometerData(CMAccelerometerData *accData) { + CMAcceleration acc = accData.acceleration; + // INFO_LOG(SYSTEM, "%f %f %f", acc.x, acc.y, acc.z); + + // Might need to change these for portrait or inverse landscape + NativeAccelerometer(-acc.x, -acc.y, -acc.z); +} diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 8870b99fe596..e713e5ecf3a3 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -109,6 +109,8 @@ @interface PPSSPPViewControllerGL () { //@property (nonatomic) iCadeReaderView* iCadeView; @property (nonatomic) GCController *gameController __attribute__((weak_import)); +@property (strong, nonatomic) CMMotionManager *motionManager; +@property (strong, nonatomic) NSOperationQueue *accelerometerQueue; @end @@ -124,6 +126,9 @@ -(id) init { [[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; } @@ -269,7 +274,9 @@ - (void)viewDidLoad { [mBackGestureRecognizer setEdges:UIRectEdgeLeft]; [[self view] addGestureRecognizer:mBackGestureRecognizer]; - INFO_LOG(G3D, "Done with viewDidLoad. Next up, OpenGL"); + // Initialize the motion manager for accelerometer control. + self.motionManager = [[CMMotionManager alloc] init]; + INFO_LOG(G3D, "Done with viewDidLoad."); } - (void)handleSwipeFrom:(UIScreenEdgePanGestureRecognizer *)recognizer @@ -291,6 +298,21 @@ - (void)appWillTerminate:(NSNotification *)notification - (void)didBecomeActive { INFO_LOG(SYSTEM, "didBecomeActive begin"); + if (self.motionManager.accelerometerAvailable) { + self.motionManager.accelerometerUpdateInterval = 1.0 / 60.0; + INFO_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(G3D, "No accelerometer available, not starting updates."); + } [self runGLRenderLoop]; INFO_LOG(SYSTEM, "didBecomeActive end"); } @@ -298,6 +320,12 @@ - (void)didBecomeActive { - (void)willResignActive { INFO_LOG(SYSTEM, "willResignActive begin"); [self requestExitGLRenderLoop]; + + // Stop accelerometer updates + if (self.motionManager.accelerometerActive) { + INFO_LOG(G3D, "Stopping accelerometer updates"); + [self.motionManager stopAccelerometerUpdates]; + } INFO_LOG(SYSTEM, "willResignActive end"); } diff --git a/ios/ViewControllerMetal.mm b/ios/ViewControllerMetal.mm index 2a5976cf4646..8e0a138bda0b 100644 --- a/ios/ViewControllerMetal.mm +++ b/ios/ViewControllerMetal.mm @@ -213,6 +213,8 @@ @interface PPSSPPViewControllerMetal () { } @property (nonatomic) GCController *gameController __attribute__((weak_import)); +@property (strong, nonatomic) CMMotionManager *motionManager; +@property (strong, nonatomic) NSOperationQueue *accelerometerQueue; @end // @interface @@ -228,6 +230,9 @@ - (id)init { [[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; } @@ -338,7 +343,21 @@ - (void)requestExitVulkanRenderLoop { // These two are forwarded from the appDelegate - (void)didBecomeActive { INFO_LOG(G3D, "didBecomeActive GL"); - + if (self.motionManager.accelerometerAvailable) { + self.motionManager.accelerometerUpdateInterval = 1.0 / 60.0; + INFO_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(G3D, "No accelerometer available, not starting updates."); + } // Spin up the emu thread. It will in turn spin up the Vulkan render thread // on its own. [self runVulkanRenderLoop]; @@ -347,6 +366,12 @@ - (void)didBecomeActive { - (void)willResignActive { INFO_LOG(G3D, "willResignActive GL"); [self requestExitVulkanRenderLoop]; + + // Stop accelerometer updates + if (self.motionManager.accelerometerActive) { + INFO_LOG(G3D, "Stopping accelerometer updates"); + [self.motionManager stopAccelerometerUpdates]; + } } - (void)shutdown @@ -419,6 +444,9 @@ - (void)viewDidLoad { UIScreenEdgePanGestureRecognizer *mBackGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFrom:) ]; [mBackGestureRecognizer setEdges:UIRectEdgeLeft]; [[self view] addGestureRecognizer:mBackGestureRecognizer]; + + // Initialize the motion manager for accelerometer control. + self.motionManager = [[CMMotionManager alloc] init]; } // Allow device rotation to resize the swapchain @@ -444,6 +472,7 @@ - (void)viewWillDisappear:(BOOL)animated { - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear: animated]; + INFO_LOG(G3D, "viewWillDisappear"); } - (void)viewDidAppear:(BOOL)animated {