iOSMotionManager.mm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #import "iOSMotionManager.h"
  23. #include "platformiOS.h"
  24. #include "string/stringBuffer.h"
  25. #include "sim/simBase.h"
  26. #include "game/gameInterface.h"
  27. extern iOSPlatState platState;
  28. static const double kFilterConst = 0.1;
  29. static const double kUpdateInterval = 0.2;
  30. @implementation iOSMotionManager
  31. @synthesize referenceAttitude;
  32. @synthesize accelerometerEnabled;
  33. @synthesize gyroscopeEnabled;
  34. - (id)init
  35. {
  36. if (!(self = [super init])) return nil;
  37. if(self != NULL)
  38. {
  39. accelerometerEnabled = NO;
  40. gyroscopeEnabled = NO;
  41. motionManager = [[CMMotionManager alloc] init];
  42. if(motionManager.deviceMotionAvailable)
  43. {
  44. [motionManager setDeviceMotionUpdateInterval:kUpdateInterval];
  45. }
  46. else
  47. {
  48. [motionManager setAccelerometerUpdateInterval:kUpdateInterval];
  49. }
  50. }
  51. else
  52. {
  53. Con::printf("Could not initialized iOSMotionManager!");
  54. return 0;
  55. }
  56. return self;
  57. }
  58. double accelAxes[6];
  59. - (void)enableAccelerometer
  60. {
  61. accelerometerEnabled = YES;
  62. }
  63. - (void)disableAccelerometer
  64. {
  65. accelerometerEnabled = NO;
  66. }
  67. - (bool)isAccelerometerActive
  68. {
  69. return motionManager.accelerometerActive;
  70. }
  71. - (bool)enableGyroscope
  72. {
  73. if(motionManager.gyroAvailable)
  74. gyroscopeEnabled = YES;
  75. else
  76. {
  77. Con::errorf("Gyroscope not supported on this device");
  78. return false;
  79. }
  80. return true;
  81. }
  82. - (bool)disableGyroscope
  83. {
  84. if(motionManager.gyroAvailable)
  85. gyroscopeEnabled = NO;
  86. else
  87. {
  88. Con::errorf("Gyroscope not supported on this device");
  89. return false;
  90. }
  91. return true;
  92. }
  93. - (bool)isGyroAvailable
  94. {
  95. return motionManager.gyroAvailable;
  96. }
  97. - (bool)isGyroActive
  98. {
  99. return motionManager.gyroActive;
  100. }
  101. static double filteredAccel[3] = {0, 0, 0};
  102. void (^accelerometerHandler)(CMAccelerometerData*, NSError*) = ^(CMAccelerometerData *accelData, NSError *)
  103. {
  104. if(gMotionManager.accelerometerEnabled)
  105. {
  106. U32 accelAxes[6] = { SI_ACCELX, SI_ACCELY, SI_ACCELZ, SI_GRAVX, SI_GRAVY, SI_GRAVZ };
  107. double userAcc[6];
  108. if(platState.portrait)
  109. {
  110. filteredAccel[0] = (accelData.acceleration.x * kFilterConst) + (filteredAccel[0] * (1.0 - kFilterConst));
  111. filteredAccel[1] = (accelData.acceleration.y * kFilterConst) + (filteredAccel[1] * (1.0 - kFilterConst));
  112. filteredAccel[2] = (accelData.acceleration.z * kFilterConst) + (filteredAccel[2] * (1.0 - kFilterConst));
  113. userAcc[0] = accelData.acceleration.x - filteredAccel[0];
  114. userAcc[1] = accelData.acceleration.y - filteredAccel[1];
  115. userAcc[2] = accelData.acceleration.z - filteredAccel[2];
  116. // Assign the non-filtered data to gravity
  117. userAcc[3] = accelData.acceleration.x;
  118. userAcc[4] = accelData.acceleration.y;
  119. userAcc[5] = accelData.acceleration.z;
  120. }
  121. else
  122. {
  123. filteredAccel[0] = (accelData.acceleration.y * kFilterConst) + (filteredAccel[0] * (1.0 - kFilterConst));
  124. filteredAccel[1] = (accelData.acceleration.x * kFilterConst) + (filteredAccel[1] * (1.0 - kFilterConst));
  125. filteredAccel[2] = (accelData.acceleration.z * kFilterConst) + (filteredAccel[2] * (1.0 - kFilterConst));
  126. userAcc[0] = accelData.acceleration.y - filteredAccel[0];
  127. userAcc[1] = accelData.acceleration.x - filteredAccel[1];
  128. userAcc[2] = accelData.acceleration.z - filteredAccel[2];
  129. // Assign the non-filtered data to gravity
  130. userAcc[3] = accelData.acceleration.y;
  131. userAcc[4] = accelData.acceleration.x;
  132. userAcc[5] = accelData.acceleration.z;
  133. }
  134. for( int i = 0; i < 6; i++)
  135. {
  136. InputEvent event;
  137. event.deviceInst = 0;
  138. event.fValues[0] = userAcc[i];
  139. event.deviceType = AccelerometerDeviceType;
  140. event.objType = accelAxes[i];
  141. event.objInst = i;
  142. event.action = SI_MOTION;
  143. event.modifier = 0;
  144. Game->postEvent(event);
  145. }
  146. }
  147. };
  148. void (^motionHandler)(CMDeviceMotion*, NSError*) = ^(CMDeviceMotion *motionData, NSError *error)
  149. {
  150. if(gMotionManager.referenceAttitude == NULL)
  151. [gMotionManager resetDeviceMotionReference];
  152. CMAttitude* currentAttitude = motionData.attitude;
  153. [currentAttitude multiplyByInverseOfAttitude:gMotionManager.referenceAttitude];
  154. if(gMotionManager.accelerometerEnabled)
  155. {
  156. U32 accelAxes[6] = { SI_ACCELX, SI_ACCELY, SI_ACCELZ, SI_GRAVX, SI_GRAVY, SI_GRAVZ };
  157. double userAcc[6];
  158. if(platState.portrait)
  159. {
  160. userAcc[0] = motionData.userAcceleration.x;
  161. userAcc[1] = motionData.userAcceleration.y;
  162. userAcc[2] = motionData.userAcceleration.z;
  163. userAcc[3] = motionData.gravity.x;
  164. userAcc[4] = motionData.gravity.y;
  165. userAcc[5] = motionData.gravity.z;
  166. }
  167. else
  168. {
  169. userAcc[0] = motionData.userAcceleration.y;
  170. userAcc[1] = motionData.userAcceleration.x;
  171. userAcc[2] = motionData.userAcceleration.z;
  172. userAcc[3] = motionData.gravity.y;
  173. userAcc[4] = motionData.gravity.x;
  174. userAcc[5] = motionData.gravity.z;
  175. }
  176. for( int i = 0; i < 6; i++)
  177. {
  178. InputEvent event;
  179. event.deviceInst = 0;
  180. event.fValues[0] = userAcc[i];
  181. event.deviceType = AccelerometerDeviceType;
  182. event.objType = accelAxes[i];
  183. event.objInst = i;
  184. event.action = SI_MOTION;
  185. event.modifier = 0;
  186. Game->postEvent(event);
  187. }
  188. }
  189. if(gMotionManager.gyroscopeEnabled)
  190. {
  191. double gyroData[6] = { currentAttitude.pitch,
  192. currentAttitude.yaw,
  193. currentAttitude.roll,
  194. motionData.rotationRate.x,
  195. motionData.rotationRate.y,
  196. motionData.rotationRate.z };
  197. U32 gyroAxes[6] = { SI_PITCH, SI_YAW, SI_ROLL, SI_GYROX, SI_GYROY, SI_GYROZ };
  198. for( int i = 0; i < 6; i++)
  199. {
  200. InputEvent event;
  201. event.deviceInst = 0;
  202. event.fValues[0] = gyroData[i];
  203. event.deviceType = GyroscopeDeviceType;
  204. event.objType = gyroAxes[i];
  205. event.objInst = i;
  206. event.action = SI_MOTION;
  207. event.modifier = 0;
  208. Game->postEvent(event);
  209. }
  210. }
  211. };
  212. - (bool)startDeviceMotion
  213. {
  214. if(motionManager.deviceMotionAvailable)
  215. {
  216. if(referenceAttitude == NULL)
  217. referenceAttitude = motionManager.deviceMotion.attitude;
  218. [motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:motionHandler];
  219. }
  220. else
  221. {
  222. [motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:accelerometerHandler];
  223. }
  224. return true;
  225. }
  226. - (bool)stopDeviceMotion
  227. {
  228. if(motionManager.deviceMotionAvailable)
  229. [motionManager stopDeviceMotionUpdates];
  230. else
  231. {
  232. [motionManager stopAccelerometerUpdates];
  233. }
  234. return true;
  235. }
  236. - (bool)resetDeviceMotionReference
  237. {
  238. if(motionManager.deviceMotionAvailable)
  239. {
  240. referenceAttitude = motionManager.deviceMotion.attitude;
  241. return true;
  242. }
  243. Con::errorf("Device Motion not supported on this device (check OS)");
  244. return false;
  245. }
  246. - (bool)isDeviceMotionAvailable
  247. {
  248. return motionManager.deviceMotionAvailable;
  249. }
  250. - (bool)isDeviceMotionActive
  251. {
  252. return motionManager.deviceMotionActive;
  253. }
  254. @end
  255. ConsoleFunction(initMotionManager, void, 1, 1, "() Initialize the iOSMotionManager")
  256. {
  257. if(gMotionManager != NULL)
  258. {
  259. Con::printf("Motion Manager already initialized");
  260. }
  261. else
  262. gMotionManager = [[iOSMotionManager alloc] init];
  263. }
  264. ConsoleFunction(enableAccelerometer, void, 1, 1, "() Allow accelerometer tracking during device motion updates")
  265. {
  266. if(gMotionManager == NULL)
  267. gMotionManager = [[iOSMotionManager alloc] init];
  268. gMotionManager.accelerometerEnabled = YES;
  269. [gMotionManager startDeviceMotion];
  270. }
  271. ConsoleFunction(disableAccelerometer, void, 1, 1, "() Stop accelerometer tracking")
  272. {
  273. if(gMotionManager != NULL)
  274. gMotionManager.accelerometerEnabled = NO;
  275. else
  276. {
  277. Con::warnf("Motion Manager was not initialized. Initializing now");
  278. gMotionManager = [[iOSMotionManager alloc] init];
  279. }
  280. }
  281. ConsoleFunction(isAccelerometerActive, bool, 1, 1, "() Check to see if Accelerometer is being polled\n"
  282. "@return True if accelerometer is on, false otherwise")
  283. {
  284. if(gMotionManager != NULL)
  285. return [gMotionManager isAccelerometerActive];
  286. else
  287. {
  288. Con::warnf("Motion Manager was not initialized. Initializing now");
  289. gMotionManager = [[iOSMotionManager alloc] init];
  290. return [gMotionManager isAccelerometerActive];
  291. }
  292. }
  293. ConsoleFunction(isGyroAvailable, bool, 1, 1, "() Check to see if this iOS device has a gyroscope\n"
  294. "@return True if gyro is on the device, false otherwise")
  295. {
  296. if(gMotionManager != NULL)
  297. return [gMotionManager isGyroAvailable];
  298. else
  299. {
  300. Con::warnf("Motion Manager was not initialized. Initializing now");
  301. gMotionManager = [[iOSMotionManager alloc] init];
  302. return [gMotionManager isGyroAvailable];
  303. }
  304. }
  305. ConsoleFunction(isGyroActive, bool, 1, 1, "() Check to see if this iOS device has a gyroscope\n"
  306. "@return True if gyro is on the device, false otherwise")
  307. {
  308. if(gMotionManager != NULL)
  309. return [gMotionManager isGyroActive];
  310. else
  311. {
  312. Con::warnf("Motion Manager was not initialized. Initializing now");
  313. gMotionManager = [[iOSMotionManager alloc] init];
  314. return [gMotionManager isGyroActive];
  315. }
  316. }
  317. ConsoleFunction(enableGyroscope, void, 1, 1, "() Start the gyroscope tracking\n"
  318. "@return True if gyroscope is supported, false otherwise")
  319. {
  320. if(gMotionManager != NULL)
  321. gMotionManager.gyroscopeEnabled = YES;
  322. else
  323. {
  324. Con::warnf("Motion Manager was not initialized. Initializing now");
  325. gMotionManager = [[iOSMotionManager alloc] init];
  326. gMotionManager.gyroscopeEnabled = YES;
  327. [gMotionManager startDeviceMotion];
  328. }
  329. }
  330. ConsoleFunction(stopGyroscope, void, 1, 1, "() Stop gyroscope tracking\n"
  331. "@return True if gyroscope is supported, false otherwise")
  332. {
  333. if(gMotionManager != NULL)
  334. gMotionManager.gyroscopeEnabled = NO;
  335. else
  336. {
  337. Con::warnf("Motion Manager was not initialized. Initializing now");
  338. gMotionManager = [[iOSMotionManager alloc] init];
  339. }
  340. }
  341. ConsoleFunction(isDeviceMotionAvailable, bool, 1, 1, "() Check to see if this iOS device supports advanced device motion (requires gyroscope\n"
  342. "@return True if Device Motion is supported, false otherwise")
  343. {
  344. if(gMotionManager != NULL)
  345. return [gMotionManager isDeviceMotionAvailable];
  346. else
  347. {
  348. Con::warnf("Motion Manager was not initialized. Initializing now");
  349. gMotionManager = [[iOSMotionManager alloc] init];
  350. return [gMotionManager isDeviceMotionAvailable];
  351. }
  352. }
  353. ConsoleFunction(isDeviceMotionActive, bool, 1, 1, "() Check to see if the device motion is running\n"
  354. "@return True if device motion is being tracked, false otherwise")
  355. {
  356. if(gMotionManager != NULL)
  357. return [gMotionManager isDeviceMotionActive];
  358. Con::warnf("Motion Manager was not initialized. Initializing now");
  359. gMotionManager = [[iOSMotionManager alloc] init];
  360. return [gMotionManager isDeviceMotionActive];
  361. }
  362. ConsoleFunction(startDeviceMotion, bool, 1, 1, "() Start Device motion tracking\n"
  363. "@return True if device motion is supported, false otherwise")
  364. {
  365. if(gMotionManager != NULL)
  366. return [gMotionManager startDeviceMotion];
  367. else
  368. {
  369. Con::warnf("Motion Manager was not initialized. Initializing now");
  370. gMotionManager = [[iOSMotionManager alloc] init];
  371. return [gMotionManager startDeviceMotion];
  372. }
  373. }
  374. ConsoleFunction(stopDeviceMotion, bool, 1, 1, "() Stop Device Motion tracking\n"
  375. "@return True if device motion is supported, false otherwise")
  376. {
  377. if(gMotionManager != NULL)
  378. return [gMotionManager stopDeviceMotion];
  379. else
  380. {
  381. Con::warnf("Motion Manager was not initialized. Initializing now");
  382. gMotionManager = [[iOSMotionManager alloc] init];
  383. return [gMotionManager stopDeviceMotion];
  384. }
  385. }