doomAppDelegate.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. /*
  2. Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company.
  3. Copyright (C) 2009 Id Software, Inc.
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. */
  16. #import "doomAppDelegate.h"
  17. #import "EAGLView.h"
  18. #import <AudioToolbox/AudioServices.h>
  19. #include "../doomiphone.h"
  20. #import <QuartzCore/CADisplayLink.h>
  21. #import "SettingsMenuView.h"
  22. #import "ControlsMenuView.h"
  23. #include "IBGlue.h"
  24. #import "MapMenuView.h"
  25. @interface UIApplication (Private)
  26. - (void)setSystemVolumeHUDEnabled:(BOOL)enabled forAudioCategory:(NSString *)category;
  27. - (void)setSystemVolumeHUDEnabled:(BOOL)enabled;
  28. - (void)runFrame;
  29. - (void)asyncTic;
  30. @end
  31. char iphoneDocDirectory[1024];
  32. char iphoneAppDirectory[1024];
  33. @implementation gameAppDelegate
  34. @synthesize window;
  35. @synthesize glView;
  36. @synthesize displayLink;
  37. extern EAGLContext *context;
  38. gameAppDelegate * gAppDelegate = NULL;
  39. NSTimer *animationTimer;
  40. bool inBackgroundProcess = false;
  41. touch_t sysTouches[MAX_TOUCHES];
  42. touch_t gameTouches[MAX_TOUCHES];
  43. pthread_mutex_t eventMutex; // used to sync between game and event threads
  44. bool firstRun = true;
  45. pthread_t gameThreadHandle;
  46. volatile boolean startupCompleted;
  47. void *GameThread( void *args ) {
  48. if ( ![EAGLContext setCurrentContext:context]) {
  49. printf( "Couldn't setCurrentContext for game thread\n" );
  50. exit( 1 );
  51. }
  52. while( inBackgroundProcess ) {
  53. usleep( 1000 );
  54. }
  55. printf( "original game thread priority: %f\n", (float)[NSThread threadPriority] );
  56. [NSThread setThreadPriority: 0.5];
  57. printf( "new game thread priority: %f\n", (float)[NSThread threadPriority] );
  58. iphoneStartup();
  59. // make sure one frame has been run before setting
  60. // startupCompleted, so we don't get one grey frame
  61. iphoneFrame();
  62. startupCompleted = TRUE; // OK to start touch / accel callbacks
  63. while( 1 ) {
  64. // we are in the background.. dont do anything.
  65. if( inBackgroundProcess ) {
  66. usleep( 1000 );
  67. }
  68. iphoneFrame();
  69. }
  70. }
  71. - (void)asyncTic {
  72. iphoneAsyncTic();
  73. [ self restartAccelerometerIfNeeded];
  74. }
  75. - (void)runFrame {
  76. iphoneAsyncTic();
  77. iphoneFrame();
  78. }
  79. - (void)applicationDidFinishLaunching:(UIApplication *)application {
  80. inBackgroundProcess = false;
  81. application.statusBarHidden = YES;
  82. application.statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
  83. gAppDelegate = self;
  84. // get the documents directory, where we will write configs and save games
  85. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  86. NSString *documentsDirectory = [paths objectAtIndex:0];
  87. [documentsDirectory getCString: iphoneDocDirectory
  88. maxLength: sizeof( iphoneDocDirectory ) - 1
  89. encoding: NSASCIIStringEncoding ];
  90. // get the app directory, where our data files live
  91. // this gives something like:
  92. // /var/mobile/Applications/71355F9F-6400-4267-B07D-E7980764F5A8/Applications
  93. // when what we want is:
  94. // /var/mobile/Applications/71355F9F-6400-4267-B07D-E7980764F5A8/doom.app
  95. // so we get that in main() from argv[0]
  96. #if 0
  97. paths = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES);
  98. NSString *appDirectory = [paths objectAtIndex:0];
  99. static char iphoneAppDirectoryFromAPI[1024];
  100. [appDirectory getCString: iphoneAppDirectoryFromAPI
  101. maxLength: sizeof( iphoneAppDirectoryFromAPI ) - 1
  102. encoding: NSASCIIStringEncoding ];
  103. #endif
  104. // disable screen dimming
  105. [UIApplication sharedApplication].idleTimerDisabled = YES;
  106. // Add the Main Menu as the SubView
  107. [self MainMenu];
  108. // start the flow of accelerometer events
  109. UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
  110. accelerometer.delegate = self;
  111. accelerometer.updateInterval = 1.0f / 30.0f;
  112. // use this mutex for coordinating touch handling between
  113. // the run loop thread and the game thread
  114. if ( pthread_mutex_init( &eventMutex, NULL ) == -1 ) {
  115. perror( "pthread_mutex_init" );
  116. }
  117. // use this semaphore for signaling from the async cmd generation thread that
  118. // the game / draw thread can wake up
  119. // sem_init is unimplemented on iPhone
  120. //if ( sem_init( &ticSemaphore, 0, 0 ) == -1 ) {
  121. // perror( "sem_init" );
  122. //}
  123. ticSemaphore = sem_open( "ticSemaphore", O_CREAT, S_IRWXU, 0 );
  124. if ( ticSemaphore == SEM_FAILED ) {
  125. perror( "sem_open" );
  126. }
  127. // we want the main (event/async) thread to be as high a priority as possible
  128. // so the game/render thread will be interrupted immediately.
  129. // It looks like the default scheduling on iPhone is already what we want --
  130. // the main thread is at 1.0, and new threads are at 0.5.
  131. printf( "original event thread priority: %f\n", (float)[NSThread threadPriority] );
  132. [NSThread setThreadPriority: 1.0];
  133. printf( "new event thread priority: %f\n", (float)[NSThread threadPriority] );
  134. // do all the game startup work
  135. iphoneStartup();
  136. int animationFrameInterval = 2;
  137. CADisplayLink *aDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(runFrame)];
  138. [aDisplayLink setFrameInterval:animationFrameInterval];
  139. [aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  140. self.displayLink = aDisplayLink;
  141. aDisplayLink.paused = YES;
  142. startupCompleted = TRUE; // OK to start touch / accel callbacks
  143. }
  144. - (void)applicationWillResignActive:(UIApplication *)application {
  145. displayLink.paused = YES;
  146. inBackgroundProcess = YES;
  147. iphonePauseMusic();
  148. iphoneShutdown();
  149. }
  150. - (void)applicationDidBecomeActive:(UIApplication *)application {
  151. displayLink.paused = NO;
  152. inBackgroundProcess = NO;
  153. if( IBMenuVisible && !firstRun ) {
  154. iphonePlayMusic( "intro" );
  155. }
  156. firstRun = false;
  157. }
  158. - (void)applicationWillTerminate:(UIApplication *)application {
  159. iphoneStopMusic();
  160. iphoneShutdown();
  161. }
  162. - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
  163. Com_Printf( "applicationDidReceiveMemoryWarning\n" );
  164. }
  165. - (void)dealloc {
  166. [window release];
  167. [glView release];
  168. [super dealloc];
  169. }
  170. - (void)restartAccelerometerIfNeeded {
  171. // I have no idea why this seems to happen sometimes...
  172. if ( SysIphoneMilliseconds() - lastAccelUpdateMsec > 1000 ) {
  173. static int count;
  174. if ( ++count < 100 ) {
  175. printf( "Restarting accelerometer updates.\n" );
  176. }
  177. UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
  178. accelerometer.delegate = self;
  179. accelerometer.updateInterval = 0.01;
  180. }
  181. }
  182. - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
  183. {
  184. float acc[4];
  185. acc[0] = acceleration.x;
  186. acc[1] = acceleration.y;
  187. acc[2] = acceleration.z;
  188. acc[3] = acceleration.timestamp;
  189. iphoneTiltEvent( acc );
  190. lastAccelUpdateMsec = SysIphoneMilliseconds();
  191. }
  192. - (void) PrepareForViewSwap {
  193. [ mainMenuViewController.view removeFromSuperview ];
  194. [ mapMenuViewController.view removeFromSuperview ];
  195. [ creditsMenuViewController.view removeFromSuperview ];
  196. [ legalMenuViewController.view removeFromSuperview ];
  197. [ settingsMenuViewController.view removeFromSuperview ];
  198. [ controlsMenuViewController.view removeFromSuperview ];
  199. [ episodeMenuViewController.view removeFromSuperview ];
  200. }
  201. - (void) ResumeGame {
  202. ResumeGame();
  203. // Switch to the Game View.
  204. [window addSubview:glView];
  205. [window makeKeyAndVisible];
  206. displayLink.paused = NO;
  207. IBMenuVisible = NO;
  208. }
  209. - (void) MainMenu {
  210. [self PrepareForViewSwap];
  211. // Switch to the Game View.
  212. [window addSubview: mainMenuViewController.view];
  213. [window makeKeyAndVisible];
  214. iphonePauseMusic();
  215. displayLink.paused = YES;
  216. IBMenuVisible = YES;
  217. }
  218. - (void) DemoGame {
  219. StartDemoGame( false );
  220. // Switch to the Game View.
  221. [window addSubview:glView];
  222. [window makeKeyAndVisible];
  223. displayLink.paused = NO;
  224. IBMenuVisible = NO;
  225. }
  226. - (void) NewGame {
  227. [self PrepareForViewSwap];
  228. // Switch to the Game View.
  229. [window addSubview: episodeMenuViewController.view];
  230. [window makeKeyAndVisible];
  231. displayLink.paused = YES;
  232. IBMenuVisible = YES;
  233. }
  234. - (void) playMap: (int) dataset: (int) episode: (int) map: (int) skill {
  235. mapStart_t startmap;
  236. startmap.map = map;
  237. startmap.episode = episode;
  238. startmap.dataset = dataset;
  239. startmap.skill = skill;
  240. StartSinglePlayerGame( startmap );
  241. [self HideIB];
  242. }
  243. - (void) CreditsMenu {
  244. [self PrepareForViewSwap];
  245. // Switch to the Game View.
  246. [window addSubview: creditsMenuViewController.view];
  247. [window makeKeyAndVisible];
  248. displayLink.paused = YES;
  249. IBMenuVisible = YES;
  250. }
  251. - (void) LegalMenu {
  252. [self PrepareForViewSwap];
  253. // Switch to the Game View.
  254. [window addSubview: legalMenuViewController.view];
  255. [window makeKeyAndVisible];
  256. displayLink.paused = YES;
  257. IBMenuVisible = YES;
  258. }
  259. - (void) GotoSupport {
  260. SysIPhoneOpenURL("http://www.idsoftware.com/doom-classic/index.html");
  261. }
  262. - (void) idSoftwareApps {
  263. SysIPhoneOpenURL("http://itunes.com/apps/idsoftware");
  264. }
  265. - (void) ControlsMenu {
  266. [self PrepareForViewSwap];
  267. ControlsMenuView * menu = controlsMenuViewController.view;
  268. [ menu SetOptions];
  269. // Switch to the Game View.
  270. [window addSubview: controlsMenuViewController.view];
  271. [window makeKeyAndVisible];
  272. displayLink.paused = YES;
  273. IBMenuVisible = YES;
  274. }
  275. - (void) SettingsMenu {
  276. [self PrepareForViewSwap];
  277. SettingsMenuView * menu = settingsMenuViewController.view;
  278. [ menu resetSwitches];
  279. // Switch to the Game View.
  280. [window addSubview: settingsMenuViewController.view];
  281. [window makeKeyAndVisible];
  282. displayLink.paused = YES;
  283. IBMenuVisible = YES;
  284. }
  285. - (void) HUDLayout {
  286. menuState = IPM_HUDEDIT;
  287. [self HideIB];
  288. }
  289. - (void) HideIB {
  290. [self PrepareForViewSwap];
  291. // Switch to the Game View.
  292. [window addSubview:glView];
  293. [window makeKeyAndVisible];
  294. displayLink.paused = NO;
  295. IBMenuVisible = NO;
  296. }
  297. - (void) SelectEpisode: (int) episode {
  298. [self PrepareForViewSwap];
  299. [ (MapMenuView*)mapMenuViewController.view setEpisode: episode ];
  300. // Switch to the Game View.
  301. [window addSubview: mapMenuViewController.view];
  302. [window makeKeyAndVisible];
  303. displayLink.paused = YES;
  304. IBMenuVisible = YES;
  305. }
  306. @end