DOOMController.mm 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. // -*- mode: objc -*-
  21. #import "../../idlib/precompiled.h"
  22. #import "DOOMController.h"
  23. #import <unistd.h>
  24. #import <pthread.h>
  25. #import <Foundation/Foundation.h>
  26. #import <Carbon/Carbon.h>
  27. #import <AppKit/AppKit.h>
  28. #import <OpenGL/gl.h>
  29. #import "macosx_common.h"
  30. #import "macosx_local.h"
  31. #import "macosx_sys.h"
  32. #import <fenv.h>
  33. #import <mach/thread_status.h>
  34. #define MAX_KEYS 256
  35. static idStr savepath;
  36. extern bool key_overstrikeMode;
  37. #define TEST_FPU_EXCEPTIONS \
  38. FPU_EXCEPTION_INVALID_OPERATION | \
  39. FPU_EXCEPTION_DENORMALIZED_OPERAND | \
  40. FPU_EXCEPTION_DIVIDE_BY_ZERO | \
  41. /* FPU_EXCEPTION_NUMERIC_OVERFLOW | */ \
  42. /* FPU_EXCEPTION_NUMERIC_UNDERFLOW | */ \
  43. /* FPU_EXCEPTION_INEXACT_RESULT | */ \
  44. 0
  45. #define kRegKey @"RegCode"
  46. static const ControlID kRegCode1EditText = { 'RegC', 1 };
  47. struct RegCodeInfo
  48. {
  49. char prefRegCode1[256];
  50. bool okPressed;
  51. WindowRef window;
  52. ControlRef regCode1EditText;
  53. };
  54. static OSErr DoRegCodeDialog( char* ioRegCode1 );
  55. @interface DOOMController (Private)
  56. - (void)quakeMain;
  57. - (BOOL)checkRegCodes;
  58. - (BOOL)checkOS;
  59. @end
  60. @implementation DOOMController
  61. /*
  62. + (void)initialize;
  63. {
  64. static bool initialized = NO;
  65. [super initialize];
  66. if ( initialized ) {
  67. return;
  68. }
  69. initialized = YES;
  70. }
  71. */
  72. #define MAX_ARGC 1024
  73. - (void)applicationDidFinishLaunching:(NSNotification *)notification;
  74. {
  75. NS_DURING {
  76. NSAssert(sizeof(bool) == 1, @"sizeof(bool) should equal 1 byte");
  77. [self quakeMain];
  78. } NS_HANDLER {
  79. Sys_Error( (const char *)[ [ localException reason ] cString ] );
  80. } NS_ENDHANDLER;
  81. Sys_Quit();
  82. }
  83. - (void)applicationWillHide:(NSNotification *)notification;
  84. {
  85. Sys_ShutdownInput();
  86. }
  87. - (void)applicationWillUnhide:(NSNotification *)notification;
  88. {
  89. Sys_InitInput();
  90. }
  91. - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
  92. {
  93. common->Quit();
  94. return NSTerminateLater; // we never reach this
  95. }
  96. #if 0
  97. // Actions
  98. - (IBAction)paste:(id)sender;
  99. {
  100. int shiftWasDown, insertWasDown;
  101. unsigned int currentTime;
  102. currentTime = Sys_Milliseconds();
  103. // Save the original keyboard state
  104. shiftWasDown = keys[K_SHIFT].down;
  105. insertWasDown = keys[K_INS].down;
  106. // Fake a Shift-Insert keyboard event
  107. keys[K_SHIFT].down = true;
  108. Posix_QueEvent(currentTime, SE_KEY, K_INS, true, 0, NULL);
  109. Posix_QueEvent(currentTime, SE_KEY, K_INS, false, 0, NULL);
  110. // Restore the original keyboard state
  111. keys[K_SHIFT].down = shiftWasDown;
  112. keys[K_INS].down = insertWasDown;
  113. }
  114. extern void CL_Quit_f(void);
  115. //extern void SetProgramPath(const char *path);
  116. - (IBAction)requestTerminate:(id)sender;
  117. {
  118. //osxQuit();
  119. common->Quit();
  120. }
  121. - (void)showBanner;
  122. {
  123. static bool hasShownBanner = NO;
  124. if (!hasShownBanner) {
  125. //cvar_t *showBanner;
  126. hasShownBanner = YES;
  127. //showBanner = Cvar_Get("cl_showBanner", "1", 0);
  128. //if ( showBanner->integer != 0 ) {
  129. if ( true ) {
  130. NSPanel *splashPanel;
  131. NSImage *bannerImage;
  132. NSRect bannerRect;
  133. NSImageView *bannerImageView;
  134. bannerImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:@"banner.jpg"]];
  135. bannerRect = NSMakeRect(0.0, 0.0, [bannerImage size].width, [bannerImage size].height);
  136. splashPanel = [[NSPanel alloc] initWithContentRect:bannerRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
  137. bannerImageView = [[NSImageView alloc] initWithFrame:bannerRect];
  138. [bannerImageView setImage:bannerImage];
  139. [splashPanel setContentView:bannerImageView];
  140. [bannerImageView release];
  141. [splashPanel center];
  142. [splashPanel setHasShadow:YES];
  143. [splashPanel orderFront: nil];
  144. [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.5]];
  145. [splashPanel close];
  146. [bannerImage release];
  147. }
  148. }
  149. }
  150. // Services
  151. - (void)connectToServer:(NSPasteboard *)pasteboard userData:(NSString *)data error:(NSString **)error;
  152. {
  153. NSArray *pasteboardTypes;
  154. pasteboardTypes = [pasteboard types];
  155. if ([pasteboardTypes containsObject:NSStringPboardType]) {
  156. NSString *requestedServer;
  157. requestedServer = [pasteboard stringForType:NSStringPboardType];
  158. if (requestedServer) {
  159. Cbuf_AddText( va( "connect %s\n", [requestedServer cString]));
  160. return;
  161. }
  162. }
  163. *error = @"Unable to connect to server: could not find string on pasteboard";
  164. }
  165. - (void)performCommand:(NSPasteboard *)pasteboard userData:(NSString *)data error:(NSString **)error;
  166. {
  167. NSArray *pasteboardTypes;
  168. pasteboardTypes = [pasteboard types];
  169. if ([pasteboardTypes containsObject:NSStringPboardType]) {
  170. NSString *requestedCommand;
  171. requestedCommand = [pasteboard stringForType:NSStringPboardType];
  172. if (requestedCommand) {
  173. Cbuf_AddText(va("%s\n", [requestedCommand cString]));
  174. return;
  175. }
  176. }
  177. *error = @"Unable to perform command: could not find string on pasteboard";
  178. }
  179. #endif // commented out all the banners and actions
  180. @end
  181. @implementation DOOMController (Private)
  182. - (void)quakeMain
  183. {
  184. NSAutoreleasePool *pool;
  185. int argc = 0;
  186. const char *argv[MAX_ARGC];
  187. NSProcessInfo *processInfo;
  188. NSArray *arguments;
  189. unsigned int argumentIndex, argumentCount;
  190. //const char *cddir;
  191. //NSFileManager *defaultManager;
  192. //bool tryAgain;
  193. pool = [[NSAutoreleasePool alloc] init];
  194. [NSApp setServicesProvider:self];
  195. processInfo = [NSProcessInfo processInfo];
  196. arguments = [processInfo arguments];
  197. argumentCount = [arguments count];
  198. for (argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++) {
  199. argv[argc++] = strdup([[arguments objectAtIndex:argumentIndex] cString]);
  200. }
  201. if (![[NSFileManager defaultManager] changeCurrentDirectoryPath:[[NSBundle mainBundle] resourcePath]]) {
  202. Sys_Error("Could not access application resources");
  203. }
  204. //cddir = macosx_scanForLibraryDirectory();
  205. /*
  206. do {
  207. tryAgain = NO;
  208. defaultManager = [NSFileManager defaultManager];
  209. if (![defaultManager fileExistsAtPath:@"./base/default.cfg"] && (!cddir || *cddir == '\0' || ![defaultManager fileExistsAtPath:[NSString stringWithFormat:@"%s/baseq3/pak0.pk3", cddir]])) {
  210. NSString *message;
  211. if (!cddir || *cddir == '\0') {
  212. message = [NSString stringWithFormat:@"Could not find DOOM levels."];
  213. } else if (![defaultManager fileExistsAtPath:[NSString stringWithFormat:@"%s", cddir]]) {
  214. message = [NSString stringWithFormat:@"Could not find DOOM levels: '%s' does not exist.", cddir];
  215. } else {
  216. message = [NSString stringWithFormat:@"Could not find DOOM levels: '%s' is not a complete DOOM installation.", cddir];
  217. }
  218. switch (NSRunAlertPanel(@"DOOM", @"%@", @"Quit", @"Find...", nil, message)) {
  219. case NSAlertDefaultReturn:
  220. default:
  221. Sys_Quit();
  222. break;
  223. case NSAlertAlternateReturn:
  224. tryAgain = YES;
  225. break;
  226. }
  227. if (tryAgain) {
  228. NSOpenPanel *openPanel;
  229. int result;
  230. openPanel = [NSOpenPanel openPanel];
  231. [openPanel setAllowsMultipleSelection:NO];
  232. [openPanel setCanChooseDirectories:YES];
  233. [openPanel setCanChooseFiles:NO];
  234. result = [openPanel runModalForDirectory:nil file:nil];
  235. if (result == NSOKButton) {
  236. NSArray *filenames;
  237. filenames = [openPanel filenames];
  238. if ([filenames count] == 1) {
  239. NSString *cdPath;
  240. cdPath = [filenames objectAtIndex:0];
  241. [[NSUserDefaults standardUserDefaults] setObject:cdPath forKey:@"CDPath"];
  242. cddir = strdup([cdPath cString]);
  243. }
  244. }
  245. }
  246. }
  247. } while (tryAgain);
  248. */
  249. /*
  250. if (cddir && *cddir != '\0') {
  251. SetProgramPath([[[NSString stringWithCString:cddir] stringByAppendingPathComponent:@"/x"] cString]);
  252. }
  253. */
  254. //Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS );
  255. Posix_EarlyInit( );
  256. #ifndef _DEBUG
  257. if ( [self checkOS] == FALSE) {
  258. common->Quit();
  259. }
  260. if ( [self checkDVD] == FALSE) {
  261. common->Quit();
  262. }
  263. #endif
  264. // need strncmp, can't use idlib before init
  265. #undef strncmp
  266. // Finder passes the process serial number as only argument after the program path
  267. // nuke it if we see it
  268. // TODO: clean out all the misc. osx arguments the engine doesn't understand.
  269. if ( false ) {//argc > 1 && strncmp( argv[ 1 ], "-psn", 4 ) ) {
  270. common->Init( argc-1, &argv[1], NULL );
  271. } else {
  272. common->Init( 0, NULL, NULL );
  273. }
  274. Posix_LateInit( );
  275. [NSApp activateIgnoringOtherApps:YES];
  276. while (1) {
  277. #ifdef OMNI_TIMER
  278. OTPeriodicTimerReset();
  279. OTNodeStart(RootNode);
  280. #endif
  281. // maintain exceptions in case system calls are turning them off (is that needed)
  282. //Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS );
  283. common->Frame();
  284. // We should think about doing this less frequently than every frame
  285. [pool release];
  286. pool = [[NSAutoreleasePool alloc] init];
  287. #ifdef OMNI_TIMER
  288. OTNodeStop(RootNode);
  289. #endif
  290. }
  291. [pool release];
  292. }
  293. - (BOOL)checkRegCodes
  294. {
  295. BOOL retval;
  296. NSString *cdKey;
  297. NSUserDefaults *userDefaults;
  298. userDefaults = [NSUserDefaults standardUserDefaults];
  299. cdKey = [userDefaults stringForKey:kRegKey];
  300. retval = TRUE;
  301. if ( cdKey == nil || [cdKey length] == 0 ) {
  302. char regCode[256];
  303. if ( DoRegCodeDialog( regCode ) != noErr ) {
  304. retval = FALSE;
  305. }
  306. else {
  307. [userDefaults setObject:[NSString stringWithCString: regCode] forKey:kRegKey];
  308. [userDefaults synchronize];
  309. }
  310. }
  311. return retval;
  312. }
  313. - (BOOL)checkOS
  314. {
  315. OSErr err;
  316. long gestaltOSVersion;
  317. err = Gestalt(gestaltSystemVersion, &gestaltOSVersion);
  318. if ( err || gestaltOSVersion < 0x1038 ) {
  319. NSBundle *thisBundle = [ NSBundle mainBundle ];
  320. NSString *messsage = [ thisBundle localizedStringForKey:@"InsufficientOS" value:@"No translation" table:nil ];
  321. NSRunAlertPanel(@GAME_NAME, messsage, nil, nil, nil);
  322. return FALSE;
  323. }
  324. return TRUE;
  325. }
  326. - (BOOL)checkDVD
  327. {
  328. return TRUE;
  329. }
  330. @end
  331. /*
  332. ==============
  333. Sys_EXEPath
  334. ==============
  335. */
  336. const char *Sys_EXEPath( void ) {
  337. static char exepath[ 1024 ];
  338. strncpy( exepath, [ [ [ NSBundle mainBundle ] executablePath ] cString ], 1024 );
  339. return exepath;
  340. }
  341. /*
  342. ==========
  343. Sys_DefaultSavePath
  344. ==========
  345. */
  346. const char *Sys_DefaultSavePath(void) {
  347. #if defined( ID_DEMO_BUILD )
  348. sprintf( savepath, "%s/Library/Application Support/BlendoGames/Quadrilateral Cowboy Demo", [NSHomeDirectory() cString] );
  349. #else
  350. sprintf( savepath, "%s/Library/Application Support/BlendoGames/Quadrilateral Cowboy", [NSHomeDirectory() cString] );
  351. #endif
  352. return savepath.c_str();
  353. }
  354. /*
  355. ==========
  356. Sys_DefaultBasePath
  357. ==========
  358. */
  359. const char *Sys_DefaultBasePath(void) {
  360. static char basepath[ 1024 ];
  361. strncpy( basepath, [ [ [ NSBundle mainBundle ] pathForResource:@"base" ofType:nil ] cString ], 1024 );
  362. char *snap = strrchr( basepath, '/' );
  363. if ( snap ) {
  364. *snap = '\0';
  365. }
  366. return basepath;
  367. }
  368. /*
  369. ===============
  370. Sys_Shutdown
  371. ===============
  372. */
  373. void Sys_Shutdown( void ) {
  374. savepath.Clear();
  375. Posix_Shutdown();
  376. }
  377. /*
  378. ===============
  379. Sys_GetProcessorId
  380. ===============
  381. */
  382. cpuid_t Sys_GetProcessorId( void ) {
  383. cpuid_t cpuid = CPUID_GENERIC;
  384. #if defined(__ppc__)
  385. cpuid |= CPUID_ALTIVEC;
  386. #elif defined(__i386__)
  387. // cpuid |= CPUID_INTEL | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_SSE3 | CPUID_HTT | CPUID_CMOV | CPUID_FTZ | CPUID_DAZ;
  388. #endif
  389. return cpuid;
  390. }
  391. /*
  392. ===============
  393. Sys_GetProcessorString
  394. ===============
  395. */
  396. const char *Sys_GetProcessorString( void ) {
  397. #if defined(__ppc__)
  398. return "ppc CPU with AltiVec extensions";
  399. #elif defined(__i386__)
  400. return "x86 CPU with MMX/SSE/SSE2/SSE3 extensions";
  401. #else
  402. #error
  403. return NULL;
  404. #endif
  405. }
  406. /*
  407. ===============
  408. Sys_FPU_EnableExceptions
  409. http://developer.apple.com/documentation/mac/PPCNumerics/PPCNumerics-154.html
  410. http://developer.apple.com/documentation/Performance/Conceptual/Mac_OSX_Numerics/Mac_OSX_Numerics.pdf
  411. ===============
  412. */
  413. #define fegetenvd(x) asm volatile( "mffs %0" : "=f" (x) );
  414. #define fesetenvd(x) asm volatile( "mtfsf 255,%0" : : "f" (x) );
  415. enum {
  416. FE_ENABLE_INEXACT = 0x8,
  417. FE_ENABLE_DIVBYZERO = 0x10,
  418. FE_ENABLE_UNDERFLOW = 0x20,
  419. FE_ENABLE_OVERFLOW = 0x40,
  420. FE_ENABLE_INVALID = 0x80,
  421. FE_ENABLE_ALL_EXCEPT = 0xF8
  422. };
  423. typedef union {
  424. struct {
  425. unsigned long hi;
  426. unsigned long lo;
  427. } i;
  428. double d;
  429. } hexdouble;
  430. static int exception_mask = 0;
  431. void Sys_FPU_EnableExceptions( int exceptions ) {
  432. #if 0
  433. if ( exceptions & ( FPU_EXCEPTION_INVALID_OPERATION | FPU_EXCEPTION_DENORMALIZED_OPERAND ) ) {
  434. // clear the flag before enabling the exception
  435. asm( "mtfsb0 2" );
  436. asm( "mtfsb0 7" );
  437. asm( "mtfsb0 8" );
  438. asm( "mtfsb0 9" );
  439. asm( "mtfsb0 10" );
  440. asm( "mtfsb0 11" );
  441. asm( "mtfsb0 12" );
  442. asm( "mtfsb0 21" );
  443. asm( "mtfsb0 22" );
  444. asm( "mtfsb0 23" );
  445. // enable
  446. asm( "mtfsb1 24" );
  447. } else {
  448. asm( "mtfsb0 24" );
  449. }
  450. if ( exceptions & FPU_EXCEPTION_DIVIDE_BY_ZERO ) {
  451. asm( "mtfsb0 5" );
  452. asm( "mtfsb1 27" );
  453. } else {
  454. asm( "mtfsb0 27" );
  455. }
  456. if ( exceptions & FPU_EXCEPTION_NUMERIC_OVERFLOW ) {
  457. asm( "mtfsb0 3" );
  458. asm( "mtfsb1 25" );
  459. } else {
  460. asm( "mtfsb0 25" );
  461. }
  462. if ( exceptions & FPU_EXCEPTION_NUMERIC_UNDERFLOW ) {
  463. asm( "mtfsb0 4" );
  464. asm( "mtfsb1 26" );
  465. } else {
  466. asm( "mtfsb0 26" );
  467. }
  468. if ( exceptions & FPU_EXCEPTION_INEXACT_RESULT ) {
  469. asm( "mtfsb0 6" );
  470. asm( "mtfsb0 13" );
  471. asm( "mtfsb0 14" );
  472. asm( "mtfsb1 28" );
  473. } else {
  474. asm( "mtfsb0 28" );
  475. }
  476. #elif defined(__ppc__)
  477. hexdouble t;
  478. exception_mask = 0;
  479. if ( exceptions & ( FPU_EXCEPTION_INVALID_OPERATION | FPU_EXCEPTION_DENORMALIZED_OPERAND ) ) {
  480. exception_mask |= FE_ENABLE_INVALID;
  481. }
  482. if ( exceptions & FPU_EXCEPTION_DIVIDE_BY_ZERO ) {
  483. exception_mask |= FE_ENABLE_DIVBYZERO;
  484. }
  485. if ( exceptions & FPU_EXCEPTION_NUMERIC_OVERFLOW ) {
  486. exception_mask |= FE_ENABLE_OVERFLOW;
  487. }
  488. if ( exceptions & FPU_EXCEPTION_NUMERIC_UNDERFLOW ) {
  489. exception_mask |= FE_ENABLE_UNDERFLOW;
  490. }
  491. if ( exceptions & FPU_EXCEPTION_INEXACT_RESULT ) {
  492. exception_mask |= FE_ENABLE_INVALID;
  493. }
  494. Sys_Printf( "Sys_FPUEnableExceptions: 0x%x\n", exception_mask );
  495. // clear the exception flags
  496. feclearexcept( FE_ALL_EXCEPT );
  497. // set the enable flags on the exceptions we want
  498. fegetenvd( t.d );
  499. t.i.lo &= ~FE_ENABLE_ALL_EXCEPT;
  500. t.i.lo |= exception_mask;
  501. fesetenvd( t.d );
  502. Sys_Printf( "done\n" );
  503. #endif
  504. }
  505. /*
  506. ===============
  507. Sys_FPE_handler
  508. ===============
  509. */
  510. void Sys_FPE_handler( int signum, siginfo_t *info, void *context ) {
  511. #if defined(__ppc__)
  512. int ret;
  513. ppc_float_state_t *fs;
  514. ppc_thread_state_t *ss;
  515. fs = &( (struct ucontext *)context )->uc_mcontext->fs;
  516. ss = &( (struct ucontext *)context )->uc_mcontext->ss;
  517. Sys_Printf( "FPE at 0x%x:\n", info->si_addr );
  518. ret = fetestexcept( FE_ALL_EXCEPT );
  519. if ( ret & FE_INEXACT ) {
  520. Sys_Printf( "FE_INEXACT " );
  521. }
  522. if ( ret & FE_DIVBYZERO ) {
  523. Sys_Printf( "FE_DIVBYZERO " );
  524. }
  525. if ( ret & FE_UNDERFLOW ) {
  526. Sys_Printf( "FE_UNDERFLOW " );
  527. }
  528. if ( ret & FE_OVERFLOW ) {
  529. Sys_Printf( "FE_OVERFLOW " );
  530. }
  531. if ( ret & FE_INVALID ) {
  532. Sys_Printf( "FE_INVALID " );
  533. }
  534. Sys_Printf( "\n" );
  535. // clear the exception flags
  536. feclearexcept( FE_ALL_EXCEPT );
  537. // re-arm
  538. fs->fpscr &= exception_mask;
  539. ss->srr0 += 4;
  540. #endif
  541. }
  542. /*
  543. ===============
  544. Sys_GetClockTicks
  545. ===============
  546. */
  547. double Sys_GetClockTicks( void ) {
  548. // NOTE that this only affects idTimer atm, which is only used for performance timing during developement
  549. #warning FIXME: implement Sys_GetClockTicks
  550. return 0.0;
  551. }
  552. /*
  553. ===============
  554. Sys_ClockTicksPerSecond
  555. ===============
  556. */
  557. double Sys_ClockTicksPerSecond(void) {
  558. // Our strategy is to query both Gestalt & IOKit and then take the larger of the two values.
  559. long gestaltSpeed, ioKitSpeed = -1;
  560. // GESTALT
  561. // gestaltProcClkSpeedMHz available in 10.3 needs to be used because CPU speeds have now
  562. // exceeded the signed long that Gestalt returns.
  563. long osVers;
  564. OSErr err;
  565. Gestalt(gestaltSystemVersion, &osVers);
  566. if (osVers >= 0x1030)
  567. err = Gestalt(gestaltProcClkSpeedMHz, &gestaltSpeed);
  568. else
  569. {
  570. err = Gestalt(gestaltProcClkSpeed, &gestaltSpeed);
  571. if (err == noErr)
  572. gestaltSpeed = gestaltSpeed / 1000000;
  573. }
  574. // IO KIT
  575. mach_port_t masterPort;
  576. CFMutableDictionaryRef matchDict = nil;
  577. io_iterator_t itThis;
  578. io_service_t service = nil;
  579. if (IOMasterPort(MACH_PORT_NULL, &masterPort))
  580. goto bail;
  581. matchDict = IOServiceNameMatching("cpus");
  582. if (IOServiceGetMatchingServices(masterPort, matchDict, &itThis))
  583. goto bail;
  584. service = IOIteratorNext(itThis);
  585. while(service)
  586. {
  587. io_service_t ioCpu = NULL;
  588. if (IORegistryEntryGetChildEntry(service, kIODeviceTreePlane, &ioCpu))
  589. goto bail;
  590. if (ioCpu)
  591. {
  592. CFDataRef data = (CFDataRef)IORegistryEntryCreateCFProperty(ioCpu, CFSTR("clock-frequency"),kCFAllocatorDefault,0);
  593. if (data)
  594. ioKitSpeed = *((unsigned long*)CFDataGetBytePtr(data)) / 1000000;
  595. }
  596. service = IOIteratorNext(itThis);
  597. }
  598. // Return the larger value
  599. bail:
  600. return ( ioKitSpeed > gestaltSpeed ? ioKitSpeed : gestaltSpeed ) * 1000000.f;
  601. }
  602. /*
  603. ================
  604. Sys_GetSystemRam
  605. returns in megabytes
  606. ================
  607. */
  608. int Sys_GetSystemRam( void ) {
  609. long ramSize;
  610. if ( Gestalt( gestaltPhysicalRAMSize, &ramSize ) == noErr ) {
  611. return ramSize / (1024*1024);
  612. }
  613. else
  614. return 1024;
  615. }
  616. /*
  617. ================
  618. Sys_GetVideoRam
  619. returns in megabytes
  620. ================
  621. */
  622. int Sys_GetVideoRam( void ) {
  623. unsigned int i;
  624. CFTypeRef typeCode;
  625. long vramStorage = 64;
  626. const short MAXDISPLAYS = 8;
  627. CGDisplayCount displayCount;
  628. io_service_t dspPorts[MAXDISPLAYS];
  629. CGDirectDisplayID displays[MAXDISPLAYS];
  630. CGGetOnlineDisplayList( MAXDISPLAYS, displays, &displayCount );
  631. for ( i = 0; i < displayCount; i++ ) {
  632. #ifdef USE_SDL
  633. if ( 0 == displays[i] ) {
  634. #else
  635. if ( Sys_DisplayToUse() == displays[i] ) {
  636. #endif
  637. dspPorts[i] = CGDisplayIOServicePort(displays[i]);
  638. typeCode = IORegistryEntryCreateCFProperty( dspPorts[i], CFSTR("IOFBMemorySize"), kCFAllocatorDefault, kNilOptions );
  639. if( typeCode && CFGetTypeID( typeCode ) == CFNumberGetTypeID() ) {
  640. CFNumberGetValue( ( CFNumberRef )typeCode, kCFNumberSInt32Type, &vramStorage );
  641. vramStorage /= (1024*1024);
  642. }
  643. }
  644. }
  645. return vramStorage;
  646. }
  647. bool OSX_GetCPUIdentification( int& cpuId, bool& oldArchitecture )
  648. {
  649. long cpu;
  650. Gestalt(gestaltNativeCPUtype, &cpu);
  651. cpuId = cpu;
  652. oldArchitecture = cpuId < gestaltCPU970;
  653. return true;
  654. }
  655. void OSX_GetVideoCard( int& outVendorId, int& outDeviceId )
  656. {
  657. kern_return_t err;
  658. mach_port_t masterPort;
  659. io_iterator_t itThis;
  660. io_service_t service;
  661. outVendorId = -1;
  662. outDeviceId = -1;
  663. // Get a mach port for us and check for errors
  664. err = IOMasterPort(MACH_PORT_NULL, &masterPort);
  665. if(err)
  666. return;
  667. // Grab all the PCI devices out of the registry
  668. err = IOServiceGetMatchingServices(masterPort, IOServiceMatching("IOPCIDevice"), &itThis);
  669. if(err)
  670. return;
  671. // Yank everything out of the iterator
  672. // We could walk through all devices and try to determine the best card. But for now,
  673. // we'll just look at the first card.
  674. while(1)
  675. {
  676. service = IOIteratorNext(itThis);
  677. io_name_t dName;
  678. // Make sure we have a valid service
  679. if(service)
  680. {
  681. // Get the classcode so we know what we're looking at
  682. CFDataRef classCode = (CFDataRef)IORegistryEntryCreateCFProperty(service,CFSTR("class-code"),kCFAllocatorDefault,0);
  683. // Only accept devices that are
  684. // PCI Spec - 0x00030000 is a display device
  685. if((*(UInt32*)CFDataGetBytePtr(classCode) & 0x00ff0000) == 0x00030000)
  686. {
  687. // Get the name of the service (hw)
  688. IORegistryEntryGetName(service, dName);
  689. CFDataRef vendorID, deviceID;
  690. // Get the information for the device we've selected from the list
  691. vendorID = (CFDataRef)IORegistryEntryCreateCFProperty(service, CFSTR("vendor-id"),kCFAllocatorDefault,0);
  692. deviceID = (CFDataRef)IORegistryEntryCreateCFProperty(service, CFSTR("device-id"),kCFAllocatorDefault,0);
  693. outVendorId = *((long*)CFDataGetBytePtr(vendorID));
  694. outDeviceId = *((long*)CFDataGetBytePtr(deviceID));
  695. CFRelease(vendorID);
  696. CFRelease(deviceID);
  697. }
  698. CFRelease(classCode);
  699. // Stop after finding the first device
  700. if (outVendorId != -1)
  701. break;
  702. }
  703. else
  704. break;
  705. }
  706. }
  707. /*
  708. ===============
  709. main
  710. ===============
  711. */
  712. int main( int argc, const char *argv[] ) {
  713. return NSApplicationMain( argc, argv );
  714. }
  715. #pragma mark -
  716. bool FormatRegCode(const char* inRegCode, char* outRegCode)
  717. {
  718. // Clean up the reg code. Remove spaces. Accept only numbers/letters.
  719. char* dst = outRegCode;
  720. const char* src = inRegCode;
  721. while (*src)
  722. {
  723. if (isalnum(*src))
  724. *dst++ = *src;
  725. else if (*src != ' ')
  726. return false;
  727. src++;
  728. }
  729. *dst = 0;
  730. // Reg codes are 18 characters in length
  731. return strlen(outRegCode) == 18;
  732. }
  733. /*
  734. ===============
  735. RegCodeHandler
  736. ===============
  737. */
  738. static pascal OSStatus RegCodeHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* inUserData )
  739. {
  740. #pragma unused( inHandler )
  741. #if 1
  742. // FIXME: the CD key API has changed for startup check support and expansion pack key support
  743. return noErr;
  744. #else
  745. HICommand cmd;
  746. OSStatus result = eventNotHandledErr;
  747. RegCodeInfo* regCodeInfo = (RegCodeInfo*)inUserData;
  748. GetEventParameter( inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof( cmd ), NULL, &cmd );
  749. switch ( cmd.commandID ) {
  750. case kHICommandOK:
  751. bool fValid;
  752. Size actualSize;
  753. char cntrl[256];
  754. char doomKey[256];
  755. char strippedKey[256];
  756. fValid = false;
  757. strippedKey[0] = doomKey[0] = NULL;
  758. GetControlData ( regCodeInfo->regCode1EditText, kControlEntireControl, kControlEditTextTextTag, 256, cntrl, &actualSize );
  759. cntrl[actualSize] = NULL;
  760. if ( FormatRegCode( cntrl, strippedKey ) ) {
  761. strncat( doomKey, strippedKey, 16 );
  762. strcat( doomKey, " " );
  763. strncat( doomKey, strippedKey + 16, 2 );
  764. fValid = session->CheckKey( doomKey );
  765. }
  766. if ( fValid ) {
  767. strcpy( regCodeInfo->prefRegCode1, doomKey );
  768. session->SetCDKey( doomKey );
  769. }
  770. else {
  771. unsigned char theError[512];
  772. unsigned char theExplanation[512];
  773. CFStringRef theErrorStr = CFCopyLocalizedString( CFSTR("DVD_KEY_ERROR"), "" );
  774. CFStringRef theExplanationStr = CFCopyLocalizedString( CFSTR("DVD_KEY_EXPLANATION"), "" );
  775. c2pstrcpy( theError, CFStringGetCStringPtr( theErrorStr, kCFStringEncodingMacRoman ) );
  776. c2pstrcpy( theExplanation, CFStringGetCStringPtr( theExplanationStr, kCFStringEncodingMacRoman ) );
  777. StandardAlert(kAlertStopAlert, theError, theExplanation, NULL, NULL);
  778. // Highlight the invalid reg code
  779. ClearKeyboardFocus(regCodeInfo->window);
  780. SetKeyboardFocus( regCodeInfo->window, regCodeInfo->regCode1EditText, kControlEditTextPart );
  781. ControlEditTextSelectionRec sel = {0, 32000};
  782. SetControlData (regCodeInfo->regCode1EditText, kControlEntireControl, kControlEditTextSelectionTag, sizeof(sel), &sel);
  783. break;
  784. }
  785. regCodeInfo->okPressed = true;
  786. QuitAppModalLoopForWindow( regCodeInfo->window );
  787. result = noErr;
  788. break;
  789. case kHICommandCancel:
  790. regCodeInfo->okPressed = false;
  791. QuitAppModalLoopForWindow( regCodeInfo->window );
  792. result = noErr;
  793. break;
  794. }
  795. return result;
  796. #endif
  797. }
  798. /*
  799. ===============
  800. DoRegCodeDialog
  801. ===============
  802. */
  803. static OSErr DoRegCodeDialog( char* ioRegCode1 )
  804. {
  805. OSErr err;
  806. RegCodeInfo regCodeInfo;
  807. memset(&regCodeInfo, 0, sizeof(regCodeInfo));
  808. IBNibRef aslNib;
  809. CFBundleRef theBundle = CFBundleGetMainBundle();
  810. err = CreateNibReferenceWithCFBundle( theBundle, CFSTR("ASLCore"), &aslNib );
  811. err = ::CreateWindowFromNib( aslNib, CFSTR("Reg Code Sheet"), &regCodeInfo.window );
  812. if (err != noErr)
  813. return err;
  814. GetControlByID( regCodeInfo.window, &kRegCode1EditText, &regCodeInfo.regCode1EditText );
  815. assert( regCodeInfo.regCode1EditText );
  816. SetKeyboardFocus( regCodeInfo.window, regCodeInfo.regCode1EditText, kControlEditTextPart );
  817. ControlEditTextSelectionRec sel = {0, 32000};
  818. SetControlData (regCodeInfo.regCode1EditText, kControlEntireControl, kControlEditTextSelectionTag, sizeof(sel), &sel);
  819. EventTypeSpec cmdEvent = { kEventClassCommand, kEventCommandProcess };
  820. EventHandlerUPP handler = NewEventHandlerUPP( RegCodeHandler );
  821. InstallWindowEventHandler( regCodeInfo.window, handler, 1, &cmdEvent, &regCodeInfo, NULL );
  822. RepositionWindow( regCodeInfo.window, NULL, kWindowAlertPositionOnMainScreen );
  823. ShowWindow( regCodeInfo.window );
  824. RunAppModalLoopForWindow( regCodeInfo.window );
  825. DisposeWindow( regCodeInfo.window );
  826. if (regCodeInfo.okPressed) {
  827. strcpy(ioRegCode1, regCodeInfo.prefRegCode1);
  828. }
  829. return regCodeInfo.okPressed ? (OSErr)noErr : (OSErr)userCanceledErr;
  830. }
  831. /*
  832. =================
  833. Sys_AsyncThread
  834. =================
  835. */
  836. void Sys_AsyncThread( void ) {
  837. while ( 1 ) {
  838. usleep( 16666 );
  839. common->Async();
  840. Sys_TriggerEvent( TRIGGER_EVENT_ONE );
  841. pthread_testcancel();
  842. }
  843. }
  844. #if defined(__ppc__)
  845. /*
  846. ================
  847. Sys_FPU_SetDAZ
  848. ================
  849. */
  850. void Sys_FPU_SetDAZ( bool enable ) {
  851. }
  852. /*
  853. ================
  854. Sys_FPU_SetFTZ
  855. ================
  856. */
  857. void Sys_FPU_SetFTZ( bool enable ) {
  858. }
  859. #elif defined(__i386__)
  860. #include <xmmintrin.h>
  861. /*
  862. ================
  863. Sys_FPU_SetDAZ
  864. ================
  865. */
  866. void Sys_FPU_SetDAZ( bool enable ) {
  867. uint32_t dwData;
  868. uint32_t enable_l = (uint32_t) enable;
  869. enable_l = enable_l & 1;
  870. enable_l = enable_l << 6;
  871. dwData = _mm_getcsr(); // store MXCSR to dwData
  872. dwData = dwData & 0xffbf;
  873. dwData = dwData | enable_l;
  874. _mm_setcsr(dwData); // load MXCSR with dwData
  875. }
  876. /*
  877. ================
  878. Sys_FPU_SetFTZ
  879. ================
  880. */
  881. void Sys_FPU_SetFTZ( bool enable ) {
  882. uint32_t dwData;
  883. uint32_t enable_l = (uint32_t) enable;
  884. enable_l = enable_l & 1;
  885. enable_l = enable_l << 15;
  886. dwData = _mm_getcsr(); // store MXCSR to dwData
  887. dwData = dwData & 0x7fff;
  888. dwData = dwData | enable_l;
  889. _mm_setcsr(dwData); // load MXCSR with dwData
  890. }
  891. #endif