macosx_glimp.mm 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878
  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. #ifndef USE_SDL
  21. // -*- mode: objc -*-
  22. #import "../../idlib/precompiled.h"
  23. #import "../../renderer/tr_local.h"
  24. #import "macosx_glimp.h"
  25. #import "macosx_local.h"
  26. #import "macosx_sys.h"
  27. #import "macosx_display.h"
  28. #import <AppKit/AppKit.h>
  29. #import <Foundation/Foundation.h>
  30. #import <mach-o/dyld.h>
  31. #import <mach/mach.h>
  32. #import <mach/mach_error.h>
  33. static idCVar r_minDisplayRefresh( "r_minDisplayRefresh", "0", CVAR_ARCHIVE | CVAR_INTEGER, "" );
  34. static idCVar r_maxDisplayRefresh( "r_maxDisplayRefresh", "0", CVAR_ARCHIVE | CVAR_INTEGER, "" );
  35. static idCVar r_screen( "r_screen", "-1", CVAR_ARCHIVE | CVAR_INTEGER, "which display to use" );
  36. static void GLW_InitExtensions( void );
  37. static bool CreateGameWindow( glimpParms_t parms );
  38. static unsigned long Sys_QueryVideoMemory();
  39. CGDisplayErr Sys_CaptureActiveDisplays(void);
  40. glwstate_t glw_state;
  41. static bool isHidden = false;
  42. @interface NSOpenGLContext (CGLContextAccess)
  43. - (CGLContextObj) cglContext;
  44. @end
  45. @implementation NSOpenGLContext (CGLContextAccess)
  46. - (CGLContextObj) cglContext;
  47. {
  48. return _contextAuxiliary;
  49. }
  50. @end
  51. /*
  52. ============
  53. CheckErrors
  54. ============
  55. */
  56. void CheckErrors( void ) {
  57. GLenum err;
  58. err = qglGetError();
  59. if ( err != GL_NO_ERROR ) {
  60. common->Error( "glGetError: %s\n", qglGetString( err ) );
  61. }
  62. }
  63. #if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS)
  64. unsigned int QGLBeginStarted = 0;
  65. void QGLErrorBreak(void) { }
  66. void QGLCheckError( const char *message ) {
  67. GLenum error;
  68. static unsigned int errorCount = 0;
  69. error = _glGetError();
  70. if (error != GL_NO_ERROR) {
  71. if (errorCount == 100) {
  72. common->Printf("100 GL errors printed ... disabling further error reporting.\n");
  73. } else if (errorCount < 100) {
  74. if (errorCount == 0) {
  75. common->Warning("BREAK ON QGLErrorBreak to stop at the GL errors\n");
  76. }
  77. common->Warning("OpenGL Error(%s): 0x%04x -- %s\n", message, (int)error, gluErrorString(error));
  78. QGLErrorBreak();
  79. }
  80. errorCount++;
  81. }
  82. }
  83. #endif
  84. /*
  85. ** GLimp_SetMode
  86. */
  87. bool GLimp_SetMode( glimpParms_t parms ) {
  88. if ( !CreateGameWindow( parms ) ) {
  89. common->Printf( "GLimp_SetMode: window could not be created!\n" );
  90. return false;
  91. }
  92. glConfig.vidWidth = parms.width;
  93. glConfig.vidHeight = parms.height;
  94. // TODO: proper fullscreen support.
  95. glConfig.isFullscreen = false;//parms.fullScreen;
  96. // draw something to show that GL is alive
  97. qglClearColor( 0.5, 0.5, 0.7, 0 );
  98. qglClear( GL_COLOR_BUFFER_BIT );
  99. GLimp_SwapBuffers();
  100. qglClearColor( 0.5, 0.5, 0.7, 0 );
  101. qglClear( GL_COLOR_BUFFER_BIT );
  102. GLimp_SwapBuffers();
  103. Sys_UnfadeScreen( Sys_DisplayToUse(), NULL );
  104. CheckErrors();
  105. return true;
  106. }
  107. /*
  108. =================
  109. GetPixelAttributes
  110. =================
  111. */
  112. #define ADD_ATTR(x) \
  113. do { \
  114. if (attributeIndex >= attributeSize) { \
  115. attributeSize *= 2; \
  116. pixelAttributes = (NSOpenGLPixelFormatAttribute *)NSZoneRealloc(NULL, pixelAttributes, sizeof(*pixelAttributes) * attributeSize); \
  117. } \
  118. pixelAttributes[attributeIndex] = (NSOpenGLPixelFormatAttribute)x; \
  119. attributeIndex++; \
  120. if ( verbose ) { \
  121. common->Printf( "Adding pixel attribute: %d (%s)\n", x, #x); \
  122. } \
  123. } while(0)
  124. static NSOpenGLPixelFormatAttribute *GetPixelAttributes( unsigned int multisamples ) {
  125. NSOpenGLPixelFormatAttribute *pixelAttributes;
  126. unsigned int attributeIndex = 0;
  127. unsigned int attributeSize = 128;
  128. int verbose;
  129. unsigned int colorDepth;
  130. unsigned int desktopColorDepth;
  131. unsigned int depthBits;
  132. unsigned int stencilBits;
  133. unsigned int buffers;
  134. // TODO fix fullscreen.
  135. bool fullScreenEnabled = false;//cvarSystem->GetCVarBool( "r_fullscreen" );
  136. verbose = 0;
  137. pixelAttributes = (NSOpenGLPixelFormatAttribute *)NSZoneMalloc(NULL, sizeof(*pixelAttributes) * attributeSize);
  138. // only greater or equal attributes will be selected
  139. ADD_ATTR( NSOpenGLPFAMinimumPolicy );
  140. ADD_ATTR( 1 );
  141. if ( fullScreenEnabled ) {
  142. ADD_ATTR(NSOpenGLPFAFullScreen);
  143. }
  144. ADD_ATTR(NSOpenGLPFAScreenMask);
  145. ADD_ATTR(CGDisplayIDToOpenGLDisplayMask(Sys_DisplayToUse()));
  146. // Require hardware acceleration
  147. ADD_ATTR(NSOpenGLPFAAccelerated);
  148. // Require double-buffer
  149. ADD_ATTR(NSOpenGLPFADoubleBuffer);
  150. // color bits
  151. ADD_ATTR(NSOpenGLPFAColorSize);
  152. colorDepth = 32;
  153. if ( !fullScreenEnabled ) {
  154. desktopColorDepth = [[glw_state.desktopMode objectForKey: (id)kCGDisplayBitsPerPixel] intValue];
  155. if ( desktopColorDepth != 32 ) {
  156. common->Warning( "Desktop display colors should be 32 bits for window rendering" );
  157. }
  158. }
  159. ADD_ATTR(colorDepth);
  160. // Specify the number of depth bits
  161. ADD_ATTR( NSOpenGLPFADepthSize );
  162. depthBits = 24;
  163. ADD_ATTR( depthBits );
  164. // Specify the number of stencil bits
  165. stencilBits = 8;
  166. ADD_ATTR( NSOpenGLPFAStencilSize );
  167. ADD_ATTR( stencilBits );
  168. // Specify destination alpha
  169. ADD_ATTR( NSOpenGLPFAAlphaSize );
  170. ADD_ATTR( 8 );
  171. if ( multisamples ) {
  172. buffers = 1;
  173. ADD_ATTR( NSOpenGLPFASampleBuffers );
  174. ADD_ATTR( buffers );
  175. ADD_ATTR( NSOpenGLPFASamples );
  176. ADD_ATTR( multisamples );
  177. }
  178. // Terminate the list
  179. ADD_ATTR(0);
  180. return pixelAttributes;
  181. }
  182. void Sys_UpdateWindowMouseInputRect(void) {
  183. NSRect windowRect, screenRect;
  184. NSScreen *screen;
  185. /*
  186. // TTimo - I guess glw_state.window is bogus .. getting crappy data out of this
  187. // It appears we need to flip the coordinate system here. This means we need
  188. // to know the size of the screen.
  189. screen = [glw_state.window screen];
  190. screenRect = [screen frame];
  191. windowRect = [glw_state.window frame];
  192. windowRect.origin.y = screenRect.size.height - (windowRect.origin.y + windowRect.size.height);
  193. Sys_SetMouseInputRect( CGRectMake( windowRect.origin.x, windowRect.origin.y, windowRect.size.width, windowRect.size.height ) );
  194. */
  195. Sys_SetMouseInputRect( CGDisplayBounds( glw_state.display ) );
  196. }
  197. // This is needed since CGReleaseAllDisplays() restores the gamma on the displays and we want to fade it up rather than just flickering all the displays
  198. static void ReleaseAllDisplays() {
  199. CGDisplayCount displayIndex;
  200. common->Printf("Releasing displays\n");
  201. for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
  202. CGDisplayRelease(glw_state.originalDisplayGammaTables[displayIndex].display);
  203. }
  204. }
  205. /*
  206. =================
  207. CreateGameWindow
  208. =================
  209. */
  210. static bool CreateGameWindow( glimpParms_t parms ) {
  211. const char *windowed[] = { "Windowed", "Fullscreen" };
  212. NSOpenGLPixelFormatAttribute *pixelAttributes;
  213. NSOpenGLPixelFormat *pixelFormat;
  214. CGDisplayErr err;
  215. unsigned int multisamples;
  216. const long swap_limit = false;
  217. int nsOpenGLCPSwapLimit = 203;
  218. glw_state.display = Sys_DisplayToUse();
  219. glw_state.desktopMode = (NSDictionary *)CGDisplayCurrentMode( glw_state.display );
  220. if ( !glw_state.desktopMode ) {
  221. common->Error( "Could not get current graphics mode for display 0x%08x\n", glw_state.display );
  222. }
  223. // TODO: proper fullscreen support.
  224. parms.fullScreen = false;
  225. common->Printf( " %d %d %s\n", parms.width, parms.height, windowed[ parms.fullScreen ] );
  226. if (parms.fullScreen) {
  227. // We'll set up the screen resolution first in case that effects the list of pixel
  228. // formats that are available (for example, a smaller frame buffer might mean more
  229. // bits for depth/stencil buffers). Allow stretched video modes if we are in fallback mode.
  230. glw_state.gameMode = Sys_GetMatchingDisplayMode(parms);
  231. if (!glw_state.gameMode) {
  232. common->Printf( "Unable to find requested display mode.\n");
  233. return false;
  234. }
  235. // Fade all screens to black
  236. // Sys_FadeScreens();
  237. err = Sys_CaptureActiveDisplays();
  238. if ( err != CGDisplayNoErr ) {
  239. CGDisplayRestoreColorSyncSettings();
  240. common->Printf( " Unable to capture displays err = %d\n", err );
  241. return false;
  242. }
  243. err = CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.gameMode);
  244. if ( err != CGDisplayNoErr ) {
  245. CGDisplayRestoreColorSyncSettings();
  246. ReleaseAllDisplays();
  247. common->Printf( " Unable to set display mode, err = %d\n", err );
  248. return false;
  249. }
  250. } else {
  251. glw_state.gameMode = glw_state.desktopMode;
  252. }
  253. // Get the GL pixel format
  254. pixelFormat = nil;
  255. multisamples = cvarSystem->GetCVarInteger( "r_multiSamples" );
  256. while ( !pixelFormat ) {
  257. pixelAttributes = GetPixelAttributes( multisamples );
  258. pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes: pixelAttributes] autorelease];
  259. NSZoneFree(NULL, pixelAttributes);
  260. if ( pixelFormat || multisamples == 0 )
  261. break;
  262. multisamples >>= 1;
  263. }
  264. cvarSystem->SetCVarInteger( "r_multiSamples", multisamples );
  265. if (!pixelFormat) {
  266. CGDisplayRestoreColorSyncSettings();
  267. CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.desktopMode);
  268. ReleaseAllDisplays();
  269. common->Printf( " No pixel format found\n");
  270. return false;
  271. }
  272. // Create a context with the desired pixel attributes
  273. OSX_SetGLContext([[NSOpenGLContext alloc] initWithFormat: pixelFormat shareContext: nil]);
  274. if ( !OSX_GetNSGLContext() ) {
  275. CGDisplayRestoreColorSyncSettings();
  276. CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.desktopMode);
  277. ReleaseAllDisplays();
  278. common->Printf( "... +[NSOpenGLContext createWithFormat:share:] failed.\n" );
  279. return false;
  280. }
  281. #ifdef __ppc__
  282. long system_version = 0;
  283. Gestalt( gestaltSystemVersion, &system_version );
  284. if ( parms.width <= 1024 && parms.height <= 768 && system_version <= 0x1045 ) {
  285. [ OSX_GetNSGLContext() setValues: &swap_limit forParameter: (NSOpenGLContextParameter)nsOpenGLCPSwapLimit ];
  286. }
  287. #endif
  288. if ( !parms.fullScreen ) {
  289. NSScreen* screen;
  290. NSRect windowRect;
  291. int displayIndex;
  292. int displayCount;
  293. displayIndex = r_screen.GetInteger();
  294. displayCount = [[NSScreen screens] count];
  295. if ( displayIndex < 0 || displayIndex >= displayCount ) {
  296. screen = [NSScreen mainScreen];
  297. } else {
  298. screen = [[NSScreen screens] objectAtIndex:displayIndex];
  299. }
  300. NSRect r = [screen frame];
  301. windowRect.origin.x = ((short)r.size.width - parms.width) / 2;
  302. windowRect.origin.y = ((short)r.size.height - parms.height) / 2;
  303. windowRect.size.width = parms.width;
  304. windowRect.size.height = parms.height;
  305. glw_state.window = [NSWindow alloc];
  306. [glw_state.window initWithContentRect:windowRect styleMask:NSTitledWindowMask backing:NSBackingStoreRetained defer:NO screen:screen];
  307. [glw_state.window setTitle: @GAME_NAME];
  308. [glw_state.window orderFront: nil];
  309. // Always get mouse moved events (if mouse support is turned off (rare)
  310. // the event system will filter them out.
  311. [glw_state.window setAcceptsMouseMovedEvents: YES];
  312. // Direct the context to draw in this window
  313. [OSX_GetNSGLContext() setView: [glw_state.window contentView]];
  314. // Sync input rect with where the window actually is...
  315. Sys_UpdateWindowMouseInputRect();
  316. } else {
  317. CGLError err;
  318. glw_state.window = NULL;
  319. err = CGLSetFullScreen(OSX_GetCGLContext());
  320. if (err) {
  321. CGDisplayRestoreColorSyncSettings();
  322. CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.desktopMode);
  323. ReleaseAllDisplays();
  324. common->Printf("CGLSetFullScreen -> %d (%s)\n", err, CGLErrorString(err));
  325. return false;
  326. }
  327. Sys_SetMouseInputRect( CGDisplayBounds( glw_state.display ) );
  328. }
  329. #ifndef USE_CGLMACROS
  330. // Make this the current context
  331. OSX_GLContextSetCurrent();
  332. #endif
  333. // Store off the pixel format attributes that we actually got
  334. [pixelFormat getValues: (int *) &glConfig.colorBits forAttribute: NSOpenGLPFAColorSize forVirtualScreen: 0];
  335. [pixelFormat getValues: (int *) &glConfig.depthBits forAttribute: NSOpenGLPFADepthSize forVirtualScreen: 0];
  336. [pixelFormat getValues: (int *) &glConfig.stencilBits forAttribute: NSOpenGLPFAStencilSize forVirtualScreen: 0];
  337. glConfig.displayFrequency = [[glw_state.gameMode objectForKey: (id)kCGDisplayRefreshRate] intValue];
  338. common->Printf( "ok\n" );
  339. return true;
  340. }
  341. // This can be used to temporarily disassociate the GL context from the screen so that CoreGraphics can be used to draw to the screen.
  342. void Sys_PauseGL () {
  343. if (!glw_state.glPauseCount) {
  344. qglFinish (); // must do this to ensure the queue is complete
  345. // Have to call both to actually deallocate kernel resources and free the NSSurface
  346. CGLClearDrawable(OSX_GetCGLContext());
  347. [OSX_GetNSGLContext() clearDrawable];
  348. }
  349. glw_state.glPauseCount++;
  350. }
  351. // This can be used to reverse the pausing caused by Sys_PauseGL()
  352. void Sys_ResumeGL () {
  353. if (glw_state.glPauseCount) {
  354. glw_state.glPauseCount--;
  355. if (!glw_state.glPauseCount) {
  356. if (!glConfig.isFullscreen) {
  357. [OSX_GetNSGLContext() setView: [glw_state.window contentView]];
  358. } else {
  359. CGLError err;
  360. err = CGLSetFullScreen(OSX_GetCGLContext());
  361. if (err)
  362. common->Printf("CGLSetFullScreen -> %d (%s)\n", err, CGLErrorString(err));
  363. }
  364. }
  365. }
  366. }
  367. /*
  368. ===================
  369. GLimp_Init
  370. Don't return unless OpenGL has been properly initialized
  371. ===================
  372. */
  373. #ifdef OMNI_TIMER
  374. static void GLImp_Dump_Stamp_List_f(void) {
  375. OTStampListDumpToFile(glThreadStampList, "/tmp/gl_stamps");
  376. }
  377. #endif
  378. bool GLimp_Init( glimpParms_t parms ) {
  379. char *buf;
  380. common->Printf( "Initializing OpenGL subsystem\n" );
  381. common->Printf( " fullscreen: %s\n", cvarSystem->GetCVarBool( "r_fullscreen" ) ? "yes" : "no" );
  382. Sys_StoreGammaTables();
  383. if ( !Sys_QueryVideoMemory() ) {
  384. common->Error( "Could not initialize OpenGL. There does not appear to be an OpenGL-supported video card in your system.\n" );
  385. }
  386. if ( !GLimp_SetMode( parms ) ) {
  387. common->Warning( "Could not initialize OpenGL\n" );
  388. return false;
  389. }
  390. common->Printf( "------------------\n" );
  391. // get our config strings
  392. glConfig.vendor_string = (const char *)qglGetString( GL_VENDOR );
  393. glConfig.renderer_string = (const char *)qglGetString( GL_RENDERER );
  394. glConfig.version_string = (const char *)qglGetString( GL_VERSION );
  395. glConfig.extensions_string = (const char *)qglGetString( GL_EXTENSIONS );
  396. //
  397. // chipset specific configuration
  398. //
  399. buf = (char *)malloc(strlen(glConfig.renderer_string) + 1);
  400. strcpy( buf, glConfig.renderer_string );
  401. // Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string );
  402. free(buf);
  403. GLW_InitExtensions();
  404. /*
  405. #ifndef USE_CGLMACROS
  406. if (!r_enablerender->integer)
  407. OSX_GLContextClearCurrent();
  408. #endif
  409. */
  410. return true;
  411. }
  412. /*
  413. ** GLimp_SwapBuffers
  414. **
  415. ** Responsible for doing a swapbuffers and possibly for other stuff
  416. ** as yet to be determined. Probably better not to make this a GLimp
  417. ** function and instead do a call to GLimp_SwapBuffers.
  418. */
  419. void GLimp_SwapBuffers( void ) {
  420. if ( r_swapInterval.IsModified() ) {
  421. r_swapInterval.ClearModified();
  422. }
  423. #if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS)
  424. QGLCheckError("GLimp_EndFrame");
  425. #endif
  426. if (!glw_state.glPauseCount && !isHidden) {
  427. glw_state.bufferSwapCount++;
  428. [OSX_GetNSGLContext() flushBuffer];
  429. }
  430. /*
  431. // Enable turning off GL at any point for performance testing
  432. if (OSX_GLContextIsCurrent() != r_enablerender->integer) {
  433. if (r_enablerender->integer) {
  434. common->Printf("--- Enabling Renderer ---\n");
  435. OSX_GLContextSetCurrent();
  436. } else {
  437. common->Printf("--- Disabling Renderer ---\n");
  438. OSX_GLContextClearCurrent();
  439. }
  440. }
  441. */
  442. }
  443. /*
  444. ** GLimp_Shutdown
  445. **
  446. ** This routine does all OS specific shutdown procedures for the OpenGL
  447. ** subsystem. Under OpenGL this means NULLing out the current DC and
  448. ** HGLRC, deleting the rendering context, and releasing the DC acquired
  449. ** for the window. The state structure is also nulled out.
  450. **
  451. */
  452. static void _GLimp_RestoreOriginalVideoSettings() {
  453. CGDisplayErr err;
  454. // CGDisplayCurrentMode lies because we've captured the display and thus we won't
  455. // get any notifications about what the current display mode really is. For now,
  456. // we just always force it back to what mode we remember the desktop being in.
  457. if (glConfig.isFullscreen) {
  458. err = CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.desktopMode);
  459. if ( err != CGDisplayNoErr )
  460. common->Printf( " Unable to restore display mode!\n" );
  461. ReleaseAllDisplays();
  462. }
  463. }
  464. void GLimp_Shutdown( void ) {
  465. CGDisplayCount displayIndex;
  466. common->Printf("----- Shutting down GL -----\n");
  467. Sys_FadeScreen(Sys_DisplayToUse());
  468. if (OSX_GetNSGLContext()) {
  469. #ifndef USE_CGLMACROS
  470. OSX_GLContextClearCurrent();
  471. #endif
  472. // Have to call both to actually deallocate kernel resources and free the NSSurface
  473. CGLClearDrawable(OSX_GetCGLContext());
  474. [OSX_GetNSGLContext() clearDrawable];
  475. [OSX_GetNSGLContext() release];
  476. OSX_SetGLContext((id)nil);
  477. }
  478. _GLimp_RestoreOriginalVideoSettings();
  479. Sys_UnfadeScreens();
  480. // Restore the original gamma if needed.
  481. // if (glConfig.deviceSupportsGamma) {
  482. // common->Printf("Restoring ColorSync settings\n");
  483. // CGDisplayRestoreColorSyncSettings();
  484. // }
  485. if (glw_state.window) {
  486. [glw_state.window release];
  487. glw_state.window = nil;
  488. }
  489. if (glw_state.log_fp) {
  490. fclose(glw_state.log_fp);
  491. glw_state.log_fp = 0;
  492. }
  493. for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
  494. free(glw_state.originalDisplayGammaTables[displayIndex].red);
  495. free(glw_state.originalDisplayGammaTables[displayIndex].blue);
  496. free(glw_state.originalDisplayGammaTables[displayIndex].green);
  497. }
  498. free(glw_state.originalDisplayGammaTables);
  499. if (glw_state.tempTable.red) {
  500. free(glw_state.tempTable.red);
  501. free(glw_state.tempTable.blue);
  502. free(glw_state.tempTable.green);
  503. }
  504. if (glw_state.inGameTable.red) {
  505. free(glw_state.inGameTable.red);
  506. free(glw_state.inGameTable.blue);
  507. free(glw_state.inGameTable.green);
  508. }
  509. memset(&glConfig, 0, sizeof(glConfig));
  510. // memset(&glState, 0, sizeof(glState));
  511. memset(&glw_state, 0, sizeof(glw_state));
  512. common->Printf("----- Done shutting down GL -----\n");
  513. }
  514. /*
  515. ===============
  516. GLimp_LogComment
  517. ===============
  518. */
  519. void GLimp_LogComment( char *comment ) { }
  520. /*
  521. ===============
  522. GLimp_SetGamma
  523. ===============
  524. */
  525. void GLimp_SetGamma(unsigned short red[256],
  526. unsigned short green[256],
  527. unsigned short blue[256]) {
  528. CGGammaValue redGamma[256], greenGamma[256], blueGamma[256];
  529. CGTableCount i;
  530. CGDisplayErr err;
  531. for (i = 0; i < 256; i++) {
  532. redGamma[i] = red[i] / 65535.0;
  533. greenGamma[i] = green[i] / 65535.0;
  534. blueGamma[i] = blue[i] / 65535.0;
  535. }
  536. err = CGSetDisplayTransferByTable(glw_state.display, 256, redGamma, greenGamma, blueGamma);
  537. if (err != CGDisplayNoErr) {
  538. common->Printf("GLimp_SetGamma: CGSetDisplayTransferByByteTable returned %d.\n", err);
  539. }
  540. // Store the gamma table that we ended up using so we can reapply it later when unhiding or to work around the bug where if you leave the game sitting and the monitor sleeps, when it wakes, the gamma isn't reset.
  541. glw_state.inGameTable.display = glw_state.display;
  542. Sys_GetGammaTable(&glw_state.inGameTable);
  543. }
  544. /*****************************************************************************/
  545. #pragma mark -
  546. #pragma mark ¥ ATI_fragment_shader
  547. static GLuint sGeneratingProgram = 0;
  548. static int sCurrentPass;
  549. static char sConstString[4096];
  550. static char sPassString[2][4096];
  551. static int sOpUsed;
  552. static int sConstUsed;
  553. static int sConst[8];
  554. static GLfloat sConstVal[8][4];
  555. static void _endPass (void) {
  556. if (!sOpUsed) return;
  557. sOpUsed = 0;
  558. sCurrentPass ++;
  559. }
  560. GLuint glGenFragmentShadersATI (GLuint ID) {
  561. qglGenProgramsARB(1, &ID);
  562. return ID;
  563. }
  564. void glBindFragmentShaderATI (GLuint ID) {
  565. qglBindProgramARB(GL_TEXT_FRAGMENT_SHADER_ATI, ID);
  566. }
  567. void glDeleteFragmentShaderATI (GLuint ID) {
  568. // qglDeleteProgramsARB(1, &ID);
  569. }
  570. void glBeginFragmentShaderATI (void) {
  571. int i;
  572. sConstString[0] = 0;
  573. for (i = 0; i < 8; i ++)
  574. sConst[i] = 0;
  575. sOpUsed = 0;
  576. sPassString[0][0] = 0;
  577. sPassString[1][0] = 0;
  578. sCurrentPass = 0;
  579. sGeneratingProgram = 1;
  580. }
  581. void glEndFragmentShaderATI (void) {
  582. GLint errPos;
  583. int i;
  584. char fragString[4096];
  585. sGeneratingProgram = 0;
  586. // header
  587. strcpy(fragString, "!!ATIfs1.0\n");
  588. // constants
  589. if (sConstString[0] || sConstUsed) {
  590. strcat (fragString, "StartConstants;\n");
  591. if (sConstUsed) {
  592. for (i = 0; i < 8; i ++) {
  593. if (sConst[i] == 1) {
  594. char str[128];
  595. sprintf (str, " CONSTANT c%d = program.env[%d];\n", i, i);
  596. strcat (fragString, str);
  597. }
  598. }
  599. }
  600. if (sConstString[0]) {
  601. strcat (fragString, sConstString);
  602. }
  603. strcat (fragString, "EndConstants;\n\n");
  604. }
  605. if (sCurrentPass == 0) {
  606. strcat(fragString, "StartOutputPass;\n");
  607. strcat(fragString, sPassString[0]);
  608. strcat(fragString, "EndPass;\n");
  609. } else {
  610. strcat(fragString, "StartPrelimPass;\n");
  611. strcat(fragString, sPassString[0]);
  612. strcat(fragString, "EndPass;\n\n");
  613. strcat(fragString, "StartOutputPass;\n");
  614. strcat(fragString, sPassString[1]);
  615. strcat(fragString, "EndPass;\n");
  616. }
  617. qglProgramStringARB(GL_TEXT_FRAGMENT_SHADER_ATI, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(fragString), fragString);
  618. qglGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
  619. if(errPos != -1) {
  620. const GLubyte *errString = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
  621. common->Warning("WARNING: glError at %d:%s when compiling atiFragmentShader %s", errPos, errString, fragString);
  622. }
  623. }
  624. void glSetFragmentShaderConstantATI (GLuint num, const GLfloat *val) {
  625. int constNum = num-GL_CON_0_ATI;
  626. if (sGeneratingProgram) {
  627. char str[128];
  628. sprintf (str, " CONSTANT c%d = { %f, %f, %f, %f };\n", constNum, val[0], val[1], val[2], val[3]);
  629. strcat (sConstString, str);
  630. sConst[constNum] = 2;
  631. }
  632. else {
  633. // According to Duane, frequent setting of fragment shader constants, even if they contain
  634. // the same value, will cause a performance hit.
  635. // According to Chris Bentley at ATI, this performance hit appears if you are using
  636. // many different fragment shaders in each scene.
  637. // So, we cache those values and only set the constants if they are different.
  638. if (memcmp (val, sConstVal[constNum], sizeof(GLfloat)*8*4) != 0)
  639. {
  640. qglProgramEnvParameter4fvARB (GL_TEXT_FRAGMENT_SHADER_ATI, num-GL_CON_0_ATI, val);
  641. memcpy (sConstVal[constNum], val, sizeof(GLfloat)*8*4);
  642. }
  643. }
  644. }
  645. char *makeArgStr(GLuint arg) {
  646. // Since we return "str", it needs to be static to ensure that it retains
  647. // its value outside this routine.
  648. static char str[128];
  649. strcpy (str, "");
  650. if ( arg >= GL_REG_0_ATI && arg <= GL_REG_5_ATI ) {
  651. sprintf(str, "r%d", arg - GL_REG_0_ATI);
  652. } else if(arg >= GL_CON_0_ATI && arg <= GL_CON_7_ATI) {
  653. if(!sConst[arg - GL_CON_0_ATI]) {
  654. sConstUsed = 1;
  655. sConst[arg - GL_CON_0_ATI] = 1;
  656. }
  657. sprintf(str, "c%d", arg - GL_CON_0_ATI);
  658. } else if( arg >= GL_TEXTURE0_ARB && arg <= GL_TEXTURE31_ARB ) {
  659. sprintf(str, "t%d", arg - GL_TEXTURE0_ARB);
  660. } else if( arg == GL_PRIMARY_COLOR_ARB ) {
  661. strcpy(str, "color0");
  662. } else if(arg == GL_SECONDARY_INTERPOLATOR_ATI) {
  663. strcpy(str, "color1");
  664. } else if (arg == GL_ZERO) {
  665. strcpy(str, "0");
  666. } else if (arg == GL_ONE) {
  667. strcpy(str, "1");
  668. } else {
  669. common->Warning("makeArgStr: bad arg value\n");
  670. }
  671. return str;
  672. }
  673. void glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle) {
  674. char str[128] = "\0";
  675. _endPass();
  676. switch(swizzle) {
  677. case GL_SWIZZLE_STR_ATI:
  678. sprintf(str, " PassTexCoord r%d, %s.str;\n", dst - GL_REG_0_ATI, makeArgStr(coord));
  679. break;
  680. case GL_SWIZZLE_STQ_ATI:
  681. sprintf(str, " PassTexCoord r%d, %s.stq;\n", dst - GL_REG_0_ATI, makeArgStr(coord));
  682. break;
  683. case GL_SWIZZLE_STR_DR_ATI:
  684. sprintf(str, " PassTexCoord r%d, %s.str_dr;\n", dst - GL_REG_0_ATI, makeArgStr(coord));
  685. break;
  686. case GL_SWIZZLE_STQ_DQ_ATI:
  687. sprintf(str, " PassTexCoord r%d, %s.stq_dq;\n", dst - GL_REG_0_ATI, makeArgStr(coord));
  688. break;
  689. default:
  690. common->Warning("glPassTexCoordATI invalid swizzle;");
  691. break;
  692. }
  693. strcat(sPassString[sCurrentPass], str);
  694. }
  695. void glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle) {
  696. char str[128] = "\0";
  697. _endPass();
  698. switch(swizzle) {
  699. case GL_SWIZZLE_STR_ATI:
  700. sprintf(str, " SampleMap r%d, %s.str;\n", dst - GL_REG_0_ATI, makeArgStr(interp));
  701. break;
  702. case GL_SWIZZLE_STQ_ATI:
  703. sprintf(str, " SampleMap r%d, %s.stq;\n", dst - GL_REG_0_ATI, makeArgStr(interp));
  704. break;
  705. case GL_SWIZZLE_STR_DR_ATI:
  706. sprintf(str, " SampleMap r%d, %s.str_dr;\n", dst - GL_REG_0_ATI, makeArgStr(interp));
  707. break;
  708. case GL_SWIZZLE_STQ_DQ_ATI:
  709. sprintf(str, " SampleMap r%d, %s.stq_dq;\n", dst - GL_REG_0_ATI, makeArgStr(interp));
  710. break;
  711. default:
  712. common->Warning("glSampleMapATI invalid swizzle;");
  713. break;
  714. }
  715. strcat(sPassString[sCurrentPass], str);
  716. }
  717. char *makeMaskStr(GLuint mask) {
  718. // Since we return "str", it needs to be static to ensure that it retains
  719. // its value outside this routine.
  720. static char str[128];
  721. strcpy (str, "");
  722. switch (mask) {
  723. case GL_NONE:
  724. str[0] = '\0';
  725. break;
  726. case GL_RGBA:
  727. strcpy(str, ".rgba");
  728. break;
  729. case GL_RGB:
  730. strcpy(str, ".rgb");
  731. break;
  732. case GL_RED:
  733. strcpy(str, ".r");
  734. break;
  735. case GL_GREEN:
  736. strcpy(str, ".g");
  737. break;
  738. case GL_BLUE:
  739. strcpy(str, ".b");
  740. break;
  741. case GL_ALPHA:
  742. strcpy(str, ".a");
  743. break;
  744. default:
  745. strcpy(str, ".");
  746. if( mask & GL_RED_BIT_ATI )
  747. strcat(str, "r");
  748. if( mask & GL_GREEN_BIT_ATI )
  749. strcat(str, "g");
  750. if( mask & GL_BLUE_BIT_ATI )
  751. strcat(str, "b");
  752. break;
  753. }
  754. return str;
  755. }
  756. char *makeDstModStr(GLuint mod) {
  757. // Since we return "str", it needs to be static to ensure that it retains
  758. // its value outside this routine.
  759. static char str[128];
  760. strcpy (str, "");
  761. if( mod == GL_NONE) {
  762. str[0] = '\0';
  763. return str;
  764. }
  765. if( mod & GL_2X_BIT_ATI) {
  766. strcat(str, ".2x");
  767. }
  768. if( mod & GL_4X_BIT_ATI) {
  769. strcat(str, ".4x");
  770. }
  771. if( mod & GL_8X_BIT_ATI) {
  772. strcat(str, ".8x");
  773. }
  774. if( mod & GL_SATURATE_BIT_ATI) {
  775. strcat(str, ".sat");
  776. }
  777. if( mod & GL_HALF_BIT_ATI) {
  778. strcat(str, ".half");
  779. }
  780. if( mod & GL_QUARTER_BIT_ATI) {
  781. strcat(str, ".quarter");
  782. }
  783. if( mod & GL_EIGHTH_BIT_ATI) {
  784. strcat(str, ".eighth");
  785. }
  786. return str;
  787. }
  788. char *makeArgModStr(GLuint mod) {
  789. // Since we return "str", it needs to be static to ensure that it retains
  790. // its value outside this routine.
  791. static char str[128];
  792. strcpy (str, "");
  793. if( mod == GL_NONE) {
  794. str[0] = '\0';
  795. return str;
  796. }
  797. if( mod & GL_NEGATE_BIT_ATI) {
  798. strcat(str, ".neg");
  799. }
  800. if( mod & GL_2X_BIT_ATI) {
  801. strcat(str, ".2x");
  802. }
  803. if( mod & GL_BIAS_BIT_ATI) {
  804. strcat(str, ".bias");
  805. }
  806. if( mod & GL_COMP_BIT_ATI) {
  807. strcat(str, ".comp");
  808. }
  809. return str;
  810. }
  811. void glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) {
  812. char str[128] = "\0";
  813. sOpUsed = 1;
  814. switch(op) {
  815. // Unary operators
  816. case GL_MOV_ATI:
  817. sprintf(str, " MOV r%d", dst - GL_REG_0_ATI);
  818. break;
  819. default:
  820. common->Warning("glColorFragmentOp1ATI invalid op;\n");
  821. break;
  822. }
  823. if(dstMask != GL_NONE) {
  824. strcat(str, makeMaskStr(dstMask));
  825. }
  826. else {
  827. strcat(str, ".rgb" );
  828. }
  829. if(dstMod != GL_NONE) {
  830. strcat(str, makeDstModStr(dstMod));
  831. }
  832. strcat(str, ", ");
  833. strcat(str, makeArgStr(arg1));
  834. if(arg1Rep != GL_NONE) {
  835. strcat(str, makeMaskStr(arg1Rep));
  836. }
  837. if(arg1Mod != GL_NONE) {
  838. strcat(str, makeArgModStr(arg1Mod));
  839. }
  840. strcat(str, ";\n");
  841. strcat(sPassString[sCurrentPass], str);
  842. }
  843. void glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) {
  844. char str[128] = "\0";
  845. if (!sOpUsed)
  846. sprintf(str,"\n");
  847. sOpUsed = 1;
  848. switch(op) {
  849. // Unary operators - fall back to Op1 routine.
  850. case GL_MOV_ATI:
  851. glColorFragmentOp1ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod);
  852. return;
  853. // Binary operators
  854. case GL_ADD_ATI:
  855. sprintf(str, " ADD r%d", dst - GL_REG_0_ATI);
  856. break;
  857. case GL_MUL_ATI:
  858. sprintf(str, " MUL r%d", dst - GL_REG_0_ATI);
  859. break;
  860. case GL_SUB_ATI:
  861. sprintf(str, " SUB r%d", dst - GL_REG_0_ATI);
  862. break;
  863. case GL_DOT3_ATI:
  864. sprintf(str, " DOT3 r%d", dst - GL_REG_0_ATI);
  865. break;
  866. case GL_DOT4_ATI:
  867. sprintf(str, " DOT4 r%d", dst - GL_REG_0_ATI);
  868. break;
  869. default:
  870. common->Warning("glColorFragmentOp2ATI invalid op;");
  871. break;
  872. }
  873. if(dstMask != GL_NONE) {
  874. strcat(str, makeMaskStr(dstMask));
  875. }
  876. else {
  877. strcat(str, ".rgb" );
  878. }
  879. if(dstMod != GL_NONE) {
  880. strcat(str, makeDstModStr(dstMod));
  881. }
  882. strcat(str, ", ");
  883. strcat(str, makeArgStr(arg1));
  884. // if(arg1Rep != GL_NONE)
  885. strcat(str, makeMaskStr(arg1Rep));
  886. if(arg1Mod != GL_NONE) {
  887. strcat(str, makeArgModStr(arg1Mod));
  888. }
  889. strcat(str, ", ");
  890. strcat(str, makeArgStr(arg2));
  891. // if(arg2Rep != GL_NONE)
  892. strcat(str, makeMaskStr(arg2Rep));
  893. if(arg2Mod != GL_NONE) {
  894. strcat(str, makeArgModStr(arg2Mod));
  895. }
  896. strcat(str, ";\n");
  897. strcat(sPassString[sCurrentPass], str);
  898. }
  899. void glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod) {
  900. char str[128] = "\0";
  901. sOpUsed = 1;
  902. switch(op) {
  903. // Unary operators - fall back to Op1 routine.
  904. case GL_MOV_ATI:
  905. glColorFragmentOp1ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod);
  906. return;
  907. // Binary operators - fall back to Op2 routine.
  908. case GL_ADD_ATI:
  909. case GL_MUL_ATI:
  910. case GL_SUB_ATI:
  911. case GL_DOT3_ATI:
  912. case GL_DOT4_ATI:
  913. glColorFragmentOp2ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod);
  914. break;
  915. // Ternary operators
  916. case GL_MAD_ATI:
  917. sprintf(str, " MAD r%d", dst - GL_REG_0_ATI);
  918. break;
  919. case GL_LERP_ATI:
  920. sprintf(str, " LERP r%d", dst - GL_REG_0_ATI);
  921. break;
  922. case GL_CND_ATI:
  923. sprintf(str, " CND r%d", dst - GL_REG_0_ATI);
  924. break;
  925. case GL_CND0_ATI:
  926. sprintf(str, " CND0 r%d", dst - GL_REG_0_ATI);
  927. break;
  928. case GL_DOT2_ADD_ATI:
  929. sprintf(str, " DOT2ADD r%d", dst - GL_REG_0_ATI);
  930. break;
  931. default:
  932. common->Warning("glColorFragmentOp3ATI invalid op;");
  933. break;
  934. }
  935. if(dstMask != GL_NONE) {
  936. strcat(str, makeMaskStr(dstMask));
  937. }
  938. else {
  939. strcat(str, ".rgb" );
  940. }
  941. if(dstMod != GL_NONE) {
  942. strcat(str, makeDstModStr(dstMod));
  943. }
  944. strcat(str, ", ");
  945. strcat(str, makeArgStr(arg1));
  946. if(arg1Rep != GL_NONE) {
  947. strcat(str, makeMaskStr(arg1Rep));
  948. }
  949. if(arg1Mod != GL_NONE) {
  950. strcat(str, makeArgModStr(arg1Mod));
  951. }
  952. strcat(str, ", ");
  953. strcat(str, makeArgStr(arg2));
  954. if(arg2Rep != GL_NONE) {
  955. strcat(str, makeMaskStr(arg2Rep));
  956. }
  957. if(arg2Mod != GL_NONE) {
  958. strcat(str, makeArgModStr(arg2Mod));
  959. }
  960. strcat(str, ", ");
  961. strcat(str, makeArgStr(arg3));
  962. if(arg3Rep != GL_NONE) {
  963. strcat(str, makeMaskStr(arg3Rep));
  964. }
  965. if(arg3Mod != GL_NONE) {
  966. strcat(str, makeArgModStr(arg3Mod));
  967. }
  968. strcat(str, ";\n");
  969. strcat(sPassString[sCurrentPass], str);
  970. }
  971. void glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) {
  972. glColorFragmentOp1ATI ( op, dst, GL_ALPHA, dstMod, arg1, arg1Rep, arg1Mod);
  973. }
  974. void glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) {
  975. glColorFragmentOp2ATI ( op, dst, GL_ALPHA, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod);
  976. }
  977. void glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod) {
  978. glColorFragmentOp3ATI ( op, dst, GL_ALPHA, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod);
  979. }
  980. #pragma mark -
  981. GLExtension_t GLimp_ExtensionPointer(const char *name) {
  982. NSSymbol symbol;
  983. char *symbolName;
  984. // special case for ATI_fragment_shader calls to map to ATI_text_fragment_shader routines
  985. if (!strcmp(name, "glGenFragmentShadersATI")) {
  986. return (GLExtension_t)glGenFragmentShadersATI;
  987. }
  988. if (!strcmp(name, "glBindFragmentShaderATI")) {
  989. return (GLExtension_t)glBindFragmentShaderATI;
  990. }
  991. if (!strcmp(name, "glDeleteFragmentShaderATI")) {
  992. return (GLExtension_t)glDeleteFragmentShaderATI;
  993. }
  994. if (!strcmp(name, "glBeginFragmentShaderATI")) {
  995. return (GLExtension_t)glBeginFragmentShaderATI;
  996. }
  997. if (!strcmp(name, "glEndFragmentShaderATI")) {
  998. return (GLExtension_t)glEndFragmentShaderATI;
  999. }
  1000. if (!strcmp(name, "glPassTexCoordATI")) {
  1001. return (GLExtension_t)glPassTexCoordATI;
  1002. }
  1003. if (!strcmp(name, "glSampleMapATI")) {
  1004. return (GLExtension_t)glSampleMapATI;
  1005. }
  1006. if (!strcmp(name, "glColorFragmentOp1ATI")) {
  1007. return (GLExtension_t)glColorFragmentOp1ATI;
  1008. }
  1009. if (!strcmp(name, "glColorFragmentOp2ATI")) {
  1010. return (GLExtension_t)glColorFragmentOp2ATI;
  1011. }
  1012. if (!strcmp(name, "glColorFragmentOp3ATI")) {
  1013. return (GLExtension_t)glColorFragmentOp3ATI;
  1014. }
  1015. if (!strcmp(name, "glAlphaFragmentOp1ATI")) {
  1016. return (GLExtension_t)glAlphaFragmentOp1ATI;
  1017. }
  1018. if (!strcmp(name, "glAlphaFragmentOp2ATI")) {
  1019. return (GLExtension_t)glAlphaFragmentOp2ATI;
  1020. }
  1021. if (!strcmp(name, "glAlphaFragmentOp3ATI")) {
  1022. return (GLExtension_t)glAlphaFragmentOp3ATI;
  1023. }
  1024. if (!strcmp(name, "glSetFragmentShaderConstantATI")) {
  1025. return (GLExtension_t)glSetFragmentShaderConstantATI;
  1026. }
  1027. // Prepend a '_' for the Unix C symbol mangling convention
  1028. symbolName = (char *)alloca(strlen(name) + 2);
  1029. strcpy(symbolName + 1, name);
  1030. symbolName[0] = '_';
  1031. if ( !NSIsSymbolNameDefined( symbolName ) ) {
  1032. return NULL;
  1033. }
  1034. symbol = NSLookupAndBindSymbol(symbolName);
  1035. if ( !symbol ) {
  1036. // shouldn't happen ...
  1037. return NULL;
  1038. }
  1039. return (GLExtension_t)(NSAddressOfSymbol(symbol));
  1040. }
  1041. void * wglGetProcAddress(const char *name) {
  1042. return (void *)GLimp_ExtensionPointer( name );
  1043. }
  1044. /*
  1045. ** GLW_InitExtensions
  1046. */
  1047. void GLW_InitExtensions( void ) { }
  1048. #define MAX_RENDERER_INFO_COUNT 128
  1049. // Returns zero if there are no hardware renderers. Otherwise, returns the max memory across all renderers (on the presumption that the screen that we'll use has the most memory).
  1050. unsigned long Sys_QueryVideoMemory() {
  1051. CGLError err;
  1052. CGLRendererInfoObj rendererInfo, rendererInfos[MAX_RENDERER_INFO_COUNT];
  1053. long rendererInfoIndex;
  1054. GLint rendererInfoCount = MAX_RENDERER_INFO_COUNT;
  1055. long rendererIndex;
  1056. GLint rendererCount;
  1057. long maxVRAM = 0;
  1058. GLint vram = 0;
  1059. GLint accelerated;
  1060. GLint rendererID;
  1061. long totalRenderers = 0;
  1062. err = CGLQueryRendererInfo(CGDisplayIDToOpenGLDisplayMask(Sys_DisplayToUse()), rendererInfos, &rendererInfoCount);
  1063. if (err) {
  1064. common->Printf("CGLQueryRendererInfo -> %d\n", err);
  1065. return vram;
  1066. }
  1067. //common->Printf("rendererInfoCount = %d\n", rendererInfoCount);
  1068. for (rendererInfoIndex = 0; rendererInfoIndex < rendererInfoCount && totalRenderers < rendererInfoCount; rendererInfoIndex++) {
  1069. rendererInfo = rendererInfos[rendererInfoIndex];
  1070. //common->Printf("rendererInfo: 0x%08x\n", rendererInfo);
  1071. err = CGLDescribeRenderer(rendererInfo, 0, kCGLRPRendererCount, &rendererCount);
  1072. if (err) {
  1073. common->Printf("CGLDescribeRenderer(kCGLRPRendererID) -> %d\n", err);
  1074. continue;
  1075. }
  1076. //common->Printf(" rendererCount: %d\n", rendererCount);
  1077. for (rendererIndex = 0; rendererIndex < rendererCount; rendererIndex++) {
  1078. totalRenderers++;
  1079. //common->Printf(" rendererIndex: %d\n", rendererIndex);
  1080. rendererID = 0xffffffff;
  1081. err = CGLDescribeRenderer(rendererInfo, rendererIndex, kCGLRPRendererID, &rendererID);
  1082. if (err) {
  1083. common->Printf("CGLDescribeRenderer(kCGLRPRendererID) -> %d\n", err);
  1084. continue;
  1085. }
  1086. //common->Printf(" rendererID: 0x%08x\n", rendererID);
  1087. accelerated = 0;
  1088. err = CGLDescribeRenderer(rendererInfo, rendererIndex, kCGLRPAccelerated, &accelerated);
  1089. if (err) {
  1090. common->Printf("CGLDescribeRenderer(kCGLRPAccelerated) -> %d\n", err);
  1091. continue;
  1092. }
  1093. //common->Printf(" accelerated: %d\n", accelerated);
  1094. if (!accelerated)
  1095. continue;
  1096. vram = 0;
  1097. err = CGLDescribeRenderer(rendererInfo, rendererIndex, kCGLRPVideoMemory, &vram);
  1098. if (err) {
  1099. common->Printf("CGLDescribeRenderer -> %d\n", err);
  1100. continue;
  1101. }
  1102. //common->Printf(" vram: 0x%08x\n", vram);
  1103. // presumably we'll be running on the best card, so we'll take the max of the vrams
  1104. if (vram > maxVRAM)
  1105. maxVRAM = vram;
  1106. }
  1107. #if 0
  1108. err = CGLDestroyRendererInfo(rendererInfo);
  1109. if (err) {
  1110. common->Printf("CGLDestroyRendererInfo -> %d\n", err);
  1111. }
  1112. #endif
  1113. }
  1114. return maxVRAM;
  1115. }
  1116. // We will set the Sys_IsHidden global to cause input to be handle differently (we'll just let NSApp handle events in this case). We also will unbind the GL context and restore the video mode.
  1117. bool Sys_Hide() {
  1118. if ( isHidden ) {
  1119. // Eh?
  1120. return false;
  1121. }
  1122. if ( !r_fullscreen.GetBool() ) {
  1123. // We only support hiding in fullscreen mode right now
  1124. return false;
  1125. }
  1126. isHidden = true;
  1127. // Don't need to store the current gamma since we always keep it around in glw_state.inGameTable.
  1128. Sys_FadeScreen(Sys_DisplayToUse());
  1129. // Disassociate the GL context from the screen
  1130. // Have to call both to actually deallocate kernel resources and free the NSSurface
  1131. CGLClearDrawable(OSX_GetCGLContext());
  1132. [OSX_GetNSGLContext() clearDrawable];
  1133. // Restore the original video mode
  1134. _GLimp_RestoreOriginalVideoSettings();
  1135. // Restore the original gamma if needed.
  1136. // if (glConfig.deviceSupportsGamma) {
  1137. // CGDisplayRestoreColorSyncSettings();
  1138. // }
  1139. // Release the screen(s)
  1140. ReleaseAllDisplays();
  1141. Sys_UnfadeScreens();
  1142. // Shut down the input system so the mouse and keyboard settings are restore to normal
  1143. Sys_ShutdownInput();
  1144. // Hide the application so that when the user clicks on our app icon, we'll get an unhide notification
  1145. [NSApp hide: nil];
  1146. return true;
  1147. }
  1148. CGDisplayErr Sys_CaptureActiveDisplays(void) {
  1149. CGDisplayErr err;
  1150. CGDisplayCount displayIndex;
  1151. for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
  1152. const glwgamma_t *table;
  1153. table = &glw_state.originalDisplayGammaTables[displayIndex];
  1154. err = CGDisplayCapture(table->display);
  1155. if (err != CGDisplayNoErr)
  1156. return err;
  1157. }
  1158. return CGDisplayNoErr;
  1159. }
  1160. bool Sys_Unhide() {
  1161. CGDisplayErr err;
  1162. CGLError glErr;
  1163. if ( !isHidden) {
  1164. // Eh?
  1165. return false;
  1166. }
  1167. Sys_FadeScreens();
  1168. // Capture the screen(s)
  1169. err = Sys_CaptureActiveDisplays();
  1170. if (err != CGDisplayNoErr) {
  1171. Sys_UnfadeScreens();
  1172. common->Printf( "Unhide failed -- cannot capture the display again.\n" );
  1173. return false;
  1174. }
  1175. // Restore the game mode
  1176. err = CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.gameMode);
  1177. if ( err != CGDisplayNoErr ) {
  1178. ReleaseAllDisplays();
  1179. Sys_UnfadeScreens();
  1180. common->Printf( "Unhide failed -- Unable to set display mode\n" );
  1181. return false;
  1182. }
  1183. // Reassociate the GL context and the screen
  1184. glErr = CGLSetFullScreen(OSX_GetCGLContext());
  1185. if (glErr) {
  1186. ReleaseAllDisplays();
  1187. Sys_UnfadeScreens();
  1188. common->Printf( "Unhide failed: CGLSetFullScreen -> %d (%s)\n", err, CGLErrorString(glErr));
  1189. return false;
  1190. }
  1191. // Restore the current context
  1192. [OSX_GetNSGLContext() makeCurrentContext];
  1193. // Restore the gamma that the game had set
  1194. Sys_UnfadeScreen(Sys_DisplayToUse(), &glw_state.inGameTable);
  1195. // Restore the input system (last so if something goes wrong we don't eat the mouse)
  1196. Sys_InitInput();
  1197. isHidden = false;
  1198. return true;
  1199. }
  1200. bool GLimp_SpawnRenderThread( void (*function)( void ) ) {
  1201. return false;
  1202. }
  1203. void *GLimp_RendererSleep(void) {
  1204. return NULL;
  1205. }
  1206. void GLimp_FrontEndSleep(void) { }
  1207. void GLimp_WakeRenderer( void *data ) { }
  1208. void *GLimp_BackEndSleep( void ) {
  1209. return NULL;
  1210. }
  1211. void GLimp_WakeBackEnd( void *data ) {
  1212. }
  1213. // enable / disable context is just for the r_skipRenderContext debug option
  1214. void GLimp_DeactivateContext( void ) {
  1215. [NSOpenGLContext clearCurrentContext];
  1216. }
  1217. void GLimp_ActivateContext( void ) {
  1218. [OSX_GetNSGLContext() makeCurrentContext];
  1219. }
  1220. void GLimp_EnableLogging(bool stat) { }
  1221. NSDictionary *Sys_GetMatchingDisplayMode( glimpParms_t parms ) {
  1222. NSArray *displayModes;
  1223. NSDictionary *mode;
  1224. unsigned int modeIndex, modeCount, bestModeIndex;
  1225. int verbose;
  1226. // cvar_t *cMinFreq, *cMaxFreq;
  1227. int minFreq, maxFreq;
  1228. unsigned int colorDepth;
  1229. verbose = 0;
  1230. colorDepth = 32;
  1231. minFreq = r_minDisplayRefresh.GetInteger();
  1232. maxFreq = r_maxDisplayRefresh.GetInteger();
  1233. if ( minFreq > maxFreq ) {
  1234. common->Error( "r_minDisplayRefresh must be less than or equal to r_maxDisplayRefresh" );
  1235. }
  1236. displayModes = (NSArray *)CGDisplayAvailableModes(glw_state.display);
  1237. if (!displayModes) {
  1238. common->Error( "CGDisplayAvailableModes returned NULL -- 0x%0x is an invalid display", glw_state.display);
  1239. }
  1240. modeCount = [displayModes count];
  1241. if (verbose) {
  1242. common->Printf( "%d modes avaliable\n", modeCount);
  1243. common->Printf( "Current mode is %s\n", [[(id)CGDisplayCurrentMode(glw_state.display) description] cString]);
  1244. }
  1245. // Default to the current desktop mode
  1246. bestModeIndex = 0xFFFFFFFF;
  1247. for ( modeIndex = 0; modeIndex < modeCount; ++modeIndex ) {
  1248. id object;
  1249. int refresh;
  1250. mode = [displayModes objectAtIndex: modeIndex];
  1251. if (verbose) {
  1252. common->Printf( " mode %d -- %s\n", modeIndex, [[mode description] cString]);
  1253. }
  1254. // Make sure we get the right size
  1255. if ([[mode objectForKey: (id)kCGDisplayWidth] intValue] != parms.width ||
  1256. [[mode objectForKey: (id)kCGDisplayHeight] intValue] != parms.height) {
  1257. if (verbose)
  1258. common->Printf( " -- bad size\n");
  1259. continue;
  1260. }
  1261. // Make sure that our frequency restrictions are observed
  1262. refresh = [[mode objectForKey: (id)kCGDisplayRefreshRate] intValue];
  1263. if (minFreq && refresh < minFreq) {
  1264. if (verbose)
  1265. common->Printf( " -- refresh too low\n");
  1266. continue;
  1267. }
  1268. if (maxFreq && refresh > maxFreq) {
  1269. if (verbose)
  1270. common->Printf( " -- refresh too high\n");
  1271. continue;
  1272. }
  1273. if ([[mode objectForKey: (id)kCGDisplayBitsPerPixel] intValue] != colorDepth) {
  1274. if (verbose)
  1275. common->Printf( " -- bad depth\n");
  1276. continue;
  1277. }
  1278. object = [mode objectForKey: (id)kCGDisplayModeIsStretched];
  1279. if ( object ) {
  1280. if ( [object boolValue] != cvarSystem->GetCVarBool( "r_stretched" ) ) {
  1281. if (verbose)
  1282. common->Printf( " -- bad stretch setting\n");
  1283. continue;
  1284. }
  1285. }
  1286. else {
  1287. if ( cvarSystem->GetCVarBool( "r_stretched" ) ) {
  1288. if (verbose)
  1289. common->Printf( " -- stretch requested, stretch property not available\n");
  1290. continue;
  1291. }
  1292. }
  1293. bestModeIndex = modeIndex;
  1294. if (verbose)
  1295. common->Printf( " -- OK\n", bestModeIndex);
  1296. }
  1297. if (verbose)
  1298. common->Printf( " bestModeIndex = %d\n", bestModeIndex);
  1299. if (bestModeIndex == 0xFFFFFFFF) {
  1300. common->Printf( "No suitable display mode available.\n");
  1301. return nil;
  1302. }
  1303. return [displayModes objectAtIndex: bestModeIndex];
  1304. }
  1305. #define MAX_DISPLAYS 128
  1306. void Sys_GetGammaTable(glwgamma_t *table) {
  1307. CGTableCount tableSize = 512;
  1308. CGDisplayErr err;
  1309. table->tableSize = tableSize;
  1310. if (table->red)
  1311. free(table->red);
  1312. table->red = (float *)malloc(tableSize * sizeof(*table->red));
  1313. if (table->green)
  1314. free(table->green);
  1315. table->green = (float *)malloc(tableSize * sizeof(*table->green));
  1316. if (table->blue)
  1317. free(table->blue);
  1318. table->blue = (float *)malloc(tableSize * sizeof(*table->blue));
  1319. // TJW: We _could_ loop here if we get back the same size as our table, increasing the table size.
  1320. err = CGGetDisplayTransferByTable(table->display, tableSize, table->red, table->green, table->blue,
  1321. &table->tableSize);
  1322. if (err != CGDisplayNoErr) {
  1323. common->Printf("GLimp_Init: CGGetDisplayTransferByTable returned %d.\n", err);
  1324. table->tableSize = 0;
  1325. }
  1326. }
  1327. void Sys_SetGammaTable(glwgamma_t *table) { }
  1328. void Sys_StoreGammaTables() {
  1329. // Store the original gamma for all monitors so that we can fade and unfade them all
  1330. CGDirectDisplayID displays[MAX_DISPLAYS];
  1331. CGDisplayCount displayIndex;
  1332. CGDisplayErr err;
  1333. err = CGGetActiveDisplayList(MAX_DISPLAYS, displays, &glw_state.displayCount);
  1334. if (err != CGDisplayNoErr)
  1335. Sys_Error("Cannot get display list -- CGGetActiveDisplayList returned %d.\n", err);
  1336. glw_state.originalDisplayGammaTables = (glwgamma_t *)calloc(glw_state.displayCount, sizeof(*glw_state.originalDisplayGammaTables));
  1337. for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
  1338. glwgamma_t *table;
  1339. table = &glw_state.originalDisplayGammaTables[displayIndex];
  1340. table->display = displays[displayIndex];
  1341. Sys_GetGammaTable(table);
  1342. }
  1343. }
  1344. // This isn't a mathematically correct fade, but we don't care that much.
  1345. void Sys_SetScreenFade(glwgamma_t *table, float fraction) {
  1346. CGTableCount tableSize;
  1347. CGGammaValue *red, *blue, *green;
  1348. CGTableCount gammaIndex;
  1349. // if (!glConfig.deviceSupportsGamma)
  1350. // return;
  1351. if (!(tableSize = table->tableSize))
  1352. // we couldn't get the table for this display for some reason
  1353. return;
  1354. // common->Printf("0x%08x %f\n", table->display, fraction);
  1355. red = glw_state.tempTable.red;
  1356. green = glw_state.tempTable.green;
  1357. blue = glw_state.tempTable.blue;
  1358. if (glw_state.tempTable.tableSize < tableSize) {
  1359. glw_state.tempTable.tableSize = tableSize;
  1360. red = (float *)realloc(red, sizeof(*red) * tableSize);
  1361. green = (float *)realloc(green, sizeof(*green) * tableSize);
  1362. blue = (float *)realloc(blue, sizeof(*blue) * tableSize);
  1363. glw_state.tempTable.red = red;
  1364. glw_state.tempTable.green = green;
  1365. glw_state.tempTable.blue = blue;
  1366. }
  1367. for (gammaIndex = 0; gammaIndex < table->tableSize; gammaIndex++) {
  1368. red[gammaIndex] = table->red[gammaIndex] * fraction;
  1369. blue[gammaIndex] = table->blue[gammaIndex] * fraction;
  1370. green[gammaIndex] = table->green[gammaIndex] * fraction;
  1371. }
  1372. CGSetDisplayTransferByTable(table->display, table->tableSize, red, green, blue);
  1373. }
  1374. // Fades all the active displays at the same time.
  1375. #define FADE_DURATION 0.5
  1376. void Sys_FadeScreens() {
  1377. CGDisplayCount displayIndex;
  1378. int stepIndex;
  1379. glwgamma_t *table;
  1380. NSTimeInterval start, current;
  1381. float time;
  1382. // if (!glConfig.deviceSupportsGamma)
  1383. // return;
  1384. common->Printf("Fading all displays\n");
  1385. start = [NSDate timeIntervalSinceReferenceDate];
  1386. time = 0.0;
  1387. while (time != FADE_DURATION) {
  1388. current = [NSDate timeIntervalSinceReferenceDate];
  1389. time = current - start;
  1390. if (time > FADE_DURATION)
  1391. time = FADE_DURATION;
  1392. for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
  1393. table = &glw_state.originalDisplayGammaTables[displayIndex];
  1394. Sys_SetScreenFade(table, 1.0 - time / FADE_DURATION);
  1395. }
  1396. }
  1397. }
  1398. void Sys_FadeScreen(CGDirectDisplayID display) {
  1399. CGDisplayCount displayIndex;
  1400. glwgamma_t *table;
  1401. int stepIndex;
  1402. common->Printf( "FIXME: Sys_FadeScreen\n" );
  1403. return;
  1404. // if (!glConfig.deviceSupportsGamma)
  1405. // return;
  1406. common->Printf("Fading display 0x%08x\n", display);
  1407. for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
  1408. if (display == glw_state.originalDisplayGammaTables[displayIndex].display) {
  1409. NSTimeInterval start, current;
  1410. float time;
  1411. start = [NSDate timeIntervalSinceReferenceDate];
  1412. time = 0.0;
  1413. table = &glw_state.originalDisplayGammaTables[displayIndex];
  1414. while (time != FADE_DURATION) {
  1415. current = [NSDate timeIntervalSinceReferenceDate];
  1416. time = current - start;
  1417. if (time > FADE_DURATION)
  1418. time = FADE_DURATION;
  1419. Sys_SetScreenFade(table, 1.0 - time / FADE_DURATION);
  1420. }
  1421. return;
  1422. }
  1423. }
  1424. common->Printf("Unable to find display to fade it\n");
  1425. }
  1426. void Sys_UnfadeScreens() {
  1427. CGDisplayCount displayIndex;
  1428. int stepIndex;
  1429. glwgamma_t *table;
  1430. NSTimeInterval start, current;
  1431. float time;
  1432. common->Printf( "FIXME: Sys_UnfadeScreens\n" );
  1433. return;
  1434. // if (!glConfig.deviceSupportsGamma)
  1435. // return;
  1436. common->Printf("Unfading all displays\n");
  1437. start = [NSDate timeIntervalSinceReferenceDate];
  1438. time = 0.0;
  1439. while (time != FADE_DURATION) {
  1440. current = [NSDate timeIntervalSinceReferenceDate];
  1441. time = current - start;
  1442. if (time > FADE_DURATION)
  1443. time = FADE_DURATION;
  1444. for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
  1445. table = &glw_state.originalDisplayGammaTables[displayIndex];
  1446. Sys_SetScreenFade(table, time / FADE_DURATION);
  1447. }
  1448. }
  1449. }
  1450. void Sys_UnfadeScreen(CGDirectDisplayID display, glwgamma_t *table) {
  1451. CGDisplayCount displayIndex;
  1452. int stepIndex;
  1453. common->Printf( "FIXME: Sys_UnfadeScreen\n" );
  1454. return;
  1455. // if (!glConfig.deviceSupportsGamma)
  1456. // return;
  1457. common->Printf("Unfading display 0x%08x\n", display);
  1458. if (table) {
  1459. CGTableCount i;
  1460. common->Printf("Given table:\n");
  1461. for (i = 0; i < table->tableSize; i++) {
  1462. common->Printf(" %f %f %f\n", table->red[i], table->blue[i], table->green[i]);
  1463. }
  1464. }
  1465. // Search for the original gamma table for the display
  1466. if (!table) {
  1467. for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
  1468. if (display == glw_state.originalDisplayGammaTables[displayIndex].display) {
  1469. table = &glw_state.originalDisplayGammaTables[displayIndex];
  1470. break;
  1471. }
  1472. }
  1473. }
  1474. if (table) {
  1475. NSTimeInterval start, current;
  1476. float time;
  1477. start = [NSDate timeIntervalSinceReferenceDate];
  1478. time = 0.0;
  1479. while (time != FADE_DURATION) {
  1480. current = [NSDate timeIntervalSinceReferenceDate];
  1481. time = current - start;
  1482. if (time > FADE_DURATION)
  1483. time = FADE_DURATION;
  1484. Sys_SetScreenFade(table, time / FADE_DURATION);
  1485. }
  1486. return;
  1487. }
  1488. common->Printf("Unable to find display to unfade it\n");
  1489. }
  1490. #define MAX_DISPLAYS 128
  1491. CGDirectDisplayID Sys_DisplayToUse(void) {
  1492. static bool gotDisplay = NO;
  1493. static CGDirectDisplayID displayToUse;
  1494. CGDisplayErr err;
  1495. CGDirectDisplayID displays[MAX_DISPLAYS];
  1496. CGDisplayCount displayCount;
  1497. int displayIndex;
  1498. if ( gotDisplay ) {
  1499. return displayToUse;
  1500. }
  1501. gotDisplay = YES;
  1502. err = CGGetActiveDisplayList( MAX_DISPLAYS, displays, &displayCount );
  1503. if ( err != CGDisplayNoErr ) {
  1504. common->Error("Cannot get display list -- CGGetActiveDisplayList returned %d.\n", err );
  1505. }
  1506. // -1, the default, means to use the main screen
  1507. displayIndex = r_screen.GetInteger();
  1508. if ( displayIndex < 0 || displayIndex >= displayCount ) {
  1509. // This is documented (in CGDirectDisplay.h) to be the main display. We want to
  1510. // return this instead of kCGDirectMainDisplay since this will allow us to compare
  1511. // display IDs.
  1512. displayToUse = displays[ 0 ];
  1513. } else {
  1514. displayToUse = displays[ displayIndex ];
  1515. }
  1516. return displayToUse;
  1517. }
  1518. /*
  1519. ===================
  1520. GLimp_SetScreenParms
  1521. ===================
  1522. */
  1523. bool GLimp_SetScreenParms( glimpParms_t parms ) {
  1524. return true;
  1525. }
  1526. /*
  1527. ===================
  1528. Sys_GrabMouseCursor
  1529. ===================
  1530. */
  1531. void Sys_GrabMouseCursor( bool grabIt ) { }
  1532. #endif