//___________________________________________________________________________________________________________nFO // "gl_vidosx.m" - MacOS X OpenGL Video driver // // Written by: Axel "awe" Wefers [mailto:awe@fruitz-of-dojo.de]. // (C)2001-2002 Fruitz Of Dojo [http://www.fruitz-of-dojo.de]. // // QuakeŞ is copyrighted by id software [http://www.idsoftware.com]. // // Version History: // // TenebraeQuake: // v1.0.0: Initial release. // // Standard Quake branch [pre-TenebraeQuake]: // v1.0.8: Fixed an issue with the console aspect, if apspect ratio was not 4:3. // Added support for gl_arb_multisample. // v1.0.7: Brings back the video options menu. // "vid_wait" now availavle via video options. // ATI Radeon only: // Added support for FSAA, via variable "gl_fsaa" or video options. // Added support for Truform, via variable "gl_truform" or video options. // Added support for anisotropic texture filtering, via variable "gl_anisotropic" or options. // v1.0.5: Added "minimized in Dock" mode. // Displays are now catured manually due to a bug with CGReleaseAllDisplays(). // Reduced the fade duration to 1.0s. // v1.0.4: Fixed continuous console output, if gamma setting fails. // Fixed a multi-monitor issue. // v1.0.3: Enables setting the gamma via the brightness slider at the options dialog. // Enable/Disable VBL syncing via "vid_wait". // v1.0.2: GLQuake/GLQuakeWorld: // Fixed a performance issue [see "gl_rsurf.c"]. // Default value of "gl_keeptjunctions" is now "1" [see "gl_rmain.c"]. // Added "DrawSprocket" style gamma fading at game start/end. // Some internal changes. // GLQuakeWorld: // Fixed console width/height bug with resolutions other than 640x480 [was always 640x480]. // v1.0.1: Initial release. //______________________________________________________________________________________________________iNCLUDES #pragma mark =Includes= #include "quakedef.h" #import #import #import #import #import #import #import #pragma mark - //_______________________________________________________________________________________________________dEFINES #pragma mark =Defines= #define HWA_OPENGL_ONLY // allow only systems with HWA OpenGL. #define USE_BUFFERED_WINDOW // the appearance of buffered windows is nicer. #define ALLOW_MULTITEXTURE_EXTENSION // doesn't seem to work with current MacOS X [10.1]. #define FADE_DURATION 1.0f #define MAX_DISPLAYS 100 // max displays for gamma fading. #define WARP_WIDTH 320 #define WARP_HEIGHT 200 #define CONSOLE_MIN_WIDTH 320 #define CONSOLE_MIN_HEIGHT 200 #define ATI_FSAA_LEVEL 510 // required for CGLSetParamter () to enable FSAA. #define FONT_WIDTH 8 #define FONT_HEIGHT 8 #define FIRST_MENU_LINE 40 #pragma mark - //________________________________________________________________________________________________________mACROS #pragma mark =Macros= #define SQUARE(A) ((A) * (A)) #pragma mark - //_________________________________________________________________________________________________________eNUMS #pragma mark =Enums= enum { VIDEO_WAIT, VIDEO_FSAA, VIDEO_ANISOTROPIC, VIDEO_TRUFORM }; #pragma mark - //__________________________________________________________________________________________________________mISC #pragma mark =TypeDefs= typedef unsigned int UInt; typedef signed int SInt; typedef struct { CGDirectDisplayID displayID; CGGammaValue component[9]; } osxCGGammaStruct; typedef struct { UInt16 Width; UInt16 Height; float Refresh; char Desc[32]; } osxCGModeListStruct; #pragma mark - //____________________________________________________________________________________________________iNTERFACES #pragma mark =ObjC Interfaces= @interface NSOpenGLContext (CGLContextAccess) - (CGLContextObj) cglContext; @end @interface QuakeView : NSView @end #pragma mark - //_____________________________________________________________________________________________________vARIABLES #pragma mark =Variables= const char *gl_renderer, *gl_vendor, *gl_version, *gl_extensions; extern qboolean gMouseEnabled; cvar_t vid_mode = { "vid_mode", "0", 0 }; cvar_t vid_redrawfull = { "vid_redrawfull", "0", 0 }; cvar_t vid_wait = { "vid_wait", "1", 1 }; cvar_t _vid_default_mode = { "_vid_default_mode", "0", 1 }; cvar_t _vid_default_blit_mode = { "_vid_default_blit_mode", "0", 1 }; cvar_t _windowed_mouse = { "_windowed_mouse","0", 0 }; cvar_t gl_anisotropic = { "gl_anisotropic", "0", 1 }; cvar_t gl_fsaa = { "gl_fsaa", "1", 0 }; cvar_t gl_truform = { "gl_truform", "-1", 1 }; cvar_t gl_ztrick = { "gl_ztrick", "1" }; unsigned d_8to24table[256]; unsigned char d_15to8table[65536]; unsigned char d_8to8graytable[256]; NSDictionary *gDisplayMode; CGDirectDisplayID gDisplayList[MAX_DISPLAYS]; CGDisplayCount gDisplayCount; NSWindow *gWindow; qboolean gDisplayFullscreen, isPermedia = NO, gl_palettedtex = NO, gl_nvcombiner = NO, gl_geforce3 = NO, gl_radeon = NO, gl_var = NO, gl_fsaaavailable = NO, gl_mtexable = NO, gl_pntriangles = NO, gl_texturefilteranisotropic = NO; Boolean gFadeAllDisplays, gWindowedMouse = NO, gIsMinimized = NO; UInt gDisplay; SInt texture_extension_number = 1, texture_mode = GL_LINEAR, gARBMultiSamples = 0; float gWindowPosX, gWindowPosY; GLfloat gldepthmin, gldepthmax, gl_texureanisotropylevel = 1.0f; void * AGP_Buffer = NULL; static const float gGLTruformAmbient[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; static CGDirectDisplayID gCapturedDisplayList[MAX_DISPLAYS]; static CGDisplayCount gCapturedDisplayCount = 0; static NSDictionary *gOriginalMode; static NSOpenGLContext *gGLContext; static osxCGGammaStruct *gOriginalGamma = NULL; static QuakeView *gWindowView = NULL; static NSImage *gMiniWindow = NULL, *gOldIcon = NULL; static Boolean gDisplayIs8Bit, gGLAnisotropic = NO; static UInt gDisplayWidth, gDisplayHeight, gDisplayDepth; static UInt32 *gMiniBuffer = NULL; static float vid_gamma = 1.0f, gVidWait = 0.0f, gFSAALevel = 1.0f, gPNTriangleLevel = -1.0f; static SInt8 gMenuMaxLine, gMenuLine = FIRST_MENU_LINE, gMenuItem = VIDEO_WAIT; #pragma mark - //___________________________________________________________________________________________fUNCTION_pROTOTYPES #pragma mark =Function ProtoTypes = extern void M_Menu_Options_f (void); extern void M_Print (int cx, int cy, char *str); extern void M_DrawCharacter (int cx, int line, int num); extern void M_DrawPic (int x, int y, qpic_t *pic); extern void IN_ShowCursor (Boolean); extern double Sys_FloatTime (void); extern void GL_CreateShadersRadeon (void); extern qboolean GL_LookupRadeonSymbols (void); static void VID_CheckGamma (unsigned char *); static Boolean VID_CaptureDisplays (Boolean); static Boolean VID_ReleaseDisplays (Boolean); static Boolean VID_FadeGammaInit (Boolean); static void VID_FadeGammaOut (Boolean, float); static void VID_FadeGammaIn (Boolean, float); static void VID_SetWait (UInt32); static Boolean VID_SetDisplayMode (void); static void VID_RestoreOldIcon (void); static void VID_MenuDraw (void); static void VID_MenuKey (int theKey); Boolean GL_CheckARBMultisampleExtension (CGDirectDisplayID theDisplay); void * GL_GetProcAddress (const char *theName, qboolean theSafeMode); static void GL_CheckPalettedTexture (void); static void GL_CheckMultiTextureExtensions (void); static void GL_CheckDiffuseBumpMappingExtensions (void); static void GL_CheckSpecularBumpMappingExtensions (void); static void GL_CheckGeforce3Extensions (void); static void GL_CheckRadeonExtensions (void); static void GL_CheckVertexArrayRange (void); static void GL_CheckPNTrianglesExtensions (void); static void GL_CheckSwitchFSAAOnTheFly (void); static void GL_CheckTextureFilterAnisotropic (void); static void GL_Init (void); static void GL_SetFSAA (UInt32 theFSAALevel); static void GL_RenderInsideDock (void); #pragma mark - //______________________________________________________________________________________________VID_LockBuffer() #ifdef QUAKE_WORLD void VID_LockBuffer (void) { } #endif /* QUAKE_WORLD */ //____________________________________________________________________________________________VID_UnlockBuffer() #ifdef QUAKE_WORLD void VID_UnlockBuffer (void) { } #endif /* QUAKE_WORLD */ //__________________________________________________________________________________________________VID_Is8bit() qboolean VID_Is8bit (void) { return (gDisplayIs8Bit); } //______________________________________________________________________________________________VID_CheckGamma() void VID_CheckGamma (unsigned char *thePalette) { float myNewValue; unsigned char myPalette[768]; SInt i; if ((i = COM_CheckParm ("-gamma")) == 0) { if ((gl_renderer && strstr (gl_renderer, "Voodoo")) || (gl_vendor && strstr (gl_vendor, "3Dfx"))) { vid_gamma = 1.0f; } else { vid_gamma = 0.6f; } } else { vid_gamma = Q_atof (com_argv[i+1]); } for (i = 0 ; i < 768 ; i++) { myNewValue = pow ((thePalette[i] + 1) / 256.0f, vid_gamma) * 255 + 0.5f; if (myNewValue < 0.0f) myNewValue = 0.0f; if (myNewValue > 255.0f) myNewValue = 255.0f; myPalette[i] = (unsigned char) myNewValue; } memcpy (thePalette, myPalette, sizeof (myPalette)); } //______________________________________________________________________________________________VID_SetPalette() void VID_SetPalette (UInt8 *thePalette) { UInt myRedComp, myGreenComp, myBlueComp, myColorValue, myBestValue, *myColorTable; SInt myNewRedComp, myNewGreenComp, myNewBlueComp, myCurDistance, myBestDistance; UInt16 i; UInt8 *myPalette, *myShadeTable; myPalette = thePalette; myShadeTable = d_8to8graytable; myColorTable = d_8to24table; for (i = 0; i < 256; i++) { myRedComp = myPalette[0]; myGreenComp = myPalette[1]; myBlueComp = myPalette[2]; myColorValue = (myRedComp << 24) + (myGreenComp << 16) + (myBlueComp << 8) + (0xFF << 0); *myColorTable++ = myColorValue; *myShadeTable++ = (myRedComp + myGreenComp + myBlueComp) / 3; myPalette += 3; } d_8to24table[255] &= 0xffffff00; for (i = 0; i < (1 << 15); i++) { myRedComp = ((i & 0x001F) << 3) + 4; myGreenComp = ((i & 0x03E0) >> 2) + 4; myBlueComp = ((i & 0x7C00) >> 7) + 4; myPalette = (UInt8 *) d_8to24table; for (myColorValue = 0 , myBestValue = 0, myBestDistance = SQUARE(10000); myColorValue < 256; myColorValue++, myPalette += 4) { myNewRedComp = (SInt) myRedComp - (SInt) myPalette[0]; myNewGreenComp = (SInt) myGreenComp - (SInt) myPalette[1]; myNewBlueComp = (SInt) myBlueComp - (SInt) myPalette[2]; myCurDistance = SQUARE(myNewRedComp) + SQUARE(myNewGreenComp) + SQUARE(myNewBlueComp); if (myCurDistance < myBestDistance) { myBestValue = myColorValue; myBestDistance = myCurDistance; } } d_15to8table[i] = myBestValue; } } //____________________________________________________________________________________________VID_ShiftPalette() void VID_ShiftPalette (UInt8 *thePalette) { // nothing to do here... } //_________________________________________________________________________________________________VID_SetMode() SInt VID_SetMode (SInt modenum, UInt8 *thePalette) { return (1); } //_________________________________________________________________________________________VID_CaptureDisplays() Boolean VID_CaptureDisplays (Boolean theCaptureAllDisplays) { CGDisplayErr myError; SInt16 i; if (theCaptureAllDisplays == NO) { if (CGDisplayIsCaptured (gDisplayList[gDisplay]) == NO) { myError = CGDisplayCapture (gDisplayList[gDisplay]); if (myError != CGDisplayNoErr) { return (NO); } } return (YES); } // are the displays already captured? if (gCapturedDisplayCount != 0) { return (YES); } // we have to loop manually thru each display, since there is a bug with CGReleaseAllDisplays(). // [only active displays will be released and not all captured!] // get the active display list: myError = CGGetActiveDisplayList (MAX_DISPLAYS, gCapturedDisplayList, &gCapturedDisplayCount); if (myError != CGDisplayNoErr || gCapturedDisplayCount == 0) { gCapturedDisplayCount = 0; return (NO); } // capture each active display: for (i = 0; i < gCapturedDisplayCount; i++) { myError = CGDisplayCapture (gCapturedDisplayList[i]); if (myError != CGDisplayNoErr) { for (; i >= 0; i--) { CGDisplayRelease (gCapturedDisplayList[i]); } gCapturedDisplayCount = 0; return (NO); } } return (YES); } //_________________________________________________________________________________________VID_ReleaseDisplays() Boolean VID_ReleaseDisplays (Boolean theCaptureAllDisplays) { CGDisplayErr myError; SInt16 i; if (theCaptureAllDisplays == NO) { if (CGDisplayIsCaptured (gDisplayList[gDisplay]) == YES) { myError = CGDisplayRelease (gDisplayList[gDisplay]); if (myError != CGDisplayNoErr) { return (NO); } } return (YES); } // are the displays already released? if (gCapturedDisplayCount == 0) { return (YES); } // release each captured display: for (i = 0; i < gCapturedDisplayCount; i++) { CGDisplayRelease (gCapturedDisplayList[i]); } gCapturedDisplayCount = 0; return (YES); } //___________________________________________________________________________________________VID_FadeGammaInit() Boolean VID_FadeGammaInit (Boolean theFadeOnAllDisplays) { static Boolean myFadeOnAllDisplays; CGDisplayErr myError; UInt32 i; // if init fails, no gamma fading will be used! if (gOriginalGamma != NULL) { // initialized, but did we change the number of displays? if (theFadeOnAllDisplays == myFadeOnAllDisplays) { return (YES); } free (gOriginalGamma); gOriginalGamma = NULL; } // get the list of displays, in case something bad is going on: if (gDisplayList == NULL || gDisplayCount == 0) { return (NO); } if (gDisplay > gDisplayCount) { gDisplay = 0; } if (theFadeOnAllDisplays == NO) { gDisplayList[0] = gDisplayList[gDisplay]; gDisplayCount = 1; gDisplay = 0; } // get memory for our original gamma table(s): gOriginalGamma = malloc (sizeof (osxCGGammaStruct) * gDisplayCount); if (gOriginalGamma == NULL) { return (NO); } // store the original gamma values within this table(s): for (i = 0; i < gDisplayCount; i++) { if (gDisplayCount == 1) { gOriginalGamma[i].displayID = gDisplayList[gDisplay]; } else { gOriginalGamma[i].displayID = gDisplayList[i]; } myError = CGGetDisplayTransferByFormula (gOriginalGamma[i].displayID, &gOriginalGamma[i].component[0], &gOriginalGamma[i].component[1], &gOriginalGamma[i].component[2], &gOriginalGamma[i].component[3], &gOriginalGamma[i].component[4], &gOriginalGamma[i].component[5], &gOriginalGamma[i].component[6], &gOriginalGamma[i].component[7], &gOriginalGamma[i].component[8]); if (myError != CGDisplayNoErr) { free (gOriginalGamma); gOriginalGamma = NULL; return (NO); } } myFadeOnAllDisplays = theFadeOnAllDisplays; return (YES); } //____________________________________________________________________________________________VID_FadeGammaOut() void VID_FadeGammaOut (Boolean theFadeOnAllDisplays, float theDuration) { osxCGGammaStruct myCurGamma; float myStartTime = 0.0f, myCurScale = 0.0f; UInt32 i, j; // check if initialized: if (VID_FadeGammaInit (theFadeOnAllDisplays) == NO) { return; } // get the time of the fade start: myStartTime = Sys_FloatTime (); // fade for the choosen duration: while (1) { // calculate the current scale and clamp it: if (theDuration > 0.0f) { myCurScale = 1.0f - (Sys_FloatTime () - myStartTime) / theDuration; if (myCurScale < 0.0f) { myCurScale = 0.0f; } } // fade the gamma for each display: for (i = 0; i < gDisplayCount; i++) { // calculate the current intensity for each color component: for (j = 1; j < 9; j += 3) { myCurGamma.component[j] = myCurScale * gOriginalGamma[i].component[j]; } // set the current gamma: CGSetDisplayTransferByFormula (gOriginalGamma[i].displayID, gOriginalGamma[i].component[0], myCurGamma.component[1], gOriginalGamma[i].component[2], gOriginalGamma[i].component[3], myCurGamma.component[4], gOriginalGamma[i].component[5], gOriginalGamma[i].component[6], myCurGamma.component[7], gOriginalGamma[i].component[8]); } // are we finished? if(myCurScale <= 0.0f) { break; } } } //_____________________________________________________________________________________________VID_FadeGammaIn() void VID_FadeGammaIn (Boolean theFadeOnAllDisplays, float theDuration) { osxCGGammaStruct myCurGamma; float myStartTime = 0.0f, myCurScale = 1.0f; UInt32 i, j; // check if initialized: if (gOriginalGamma == NULL) { return; } // get the time of the fade start: myStartTime = Sys_FloatTime (); // fade for the choosen duration: while (1) { // calculate the current scale and clamp it: if (theDuration > 0.0f) { myCurScale = (Sys_FloatTime () - myStartTime) / theDuration; if (myCurScale > 1.0f) { myCurScale = 1.0f; } } // fade the gamma for each display: for (i = 0; i < gDisplayCount; i++) { // calculate the current intensity for each gamma component: for (j = 1; j < 9; j += 3) { myCurGamma.component[j] = myCurScale * gOriginalGamma[i].component[j]; } // set the current gamma: CGSetDisplayTransferByFormula (gOriginalGamma[i].displayID, gOriginalGamma[i].component[0], myCurGamma.component[1], gOriginalGamma[i].component[2], gOriginalGamma[i].component[3], myCurGamma.component[4], gOriginalGamma[i].component[5], gOriginalGamma[i].component[6], myCurGamma.component[7], gOriginalGamma[i].component[8]); } // are we finished? if(myCurScale >= 1.0f) { break; } } } //_____________________________________________________________________________________VID_CreateGLPixelFormat() NSOpenGLPixelFormat * VID_CreateGLPixelFormat (void) { NSOpenGLPixelFormat *myPixelFormat; NSOpenGLPixelFormatAttribute myAttributeList[32]; UInt i = 0; if (gARBMultiSamples > 0) { if (gARBMultiSamples > 8) gARBMultiSamples = 8; myAttributeList[i++] = NSOpenGLPFASampleBuffers; myAttributeList[i++] = 1; myAttributeList[i++] = NSOpenGLPFASamples; myAttributeList[i++] = gARBMultiSamples; } myAttributeList[i++] = NSOpenGLPFANoRecovery; myAttributeList[i++] = NSOpenGLPFAClosestPolicy; myAttributeList[i++] = NSOpenGLPFAAccelerated; myAttributeList[i++] = NSOpenGLPFADoubleBuffer; myAttributeList[i++] = NSOpenGLPFAColorSize; myAttributeList[i++] = gDisplayDepth; myAttributeList[i++] = NSOpenGLPFADepthSize; myAttributeList[i++] = 24; myAttributeList[i++] = NSOpenGLPFAAlphaSize; myAttributeList[i++] = 8; myAttributeList[i++] = NSOpenGLPFAStencilSize; myAttributeList[i++] = 8; myAttributeList[i++] = NSOpenGLPFAAccumSize; myAttributeList[i++] = 0; if (gDisplayFullscreen == YES) { myAttributeList[i++] = NSOpenGLPFAFullScreen; myAttributeList[i++] = NSOpenGLPFAScreenMask; myAttributeList[i++] = CGDisplayIDToOpenGLDisplayMask (gDisplayList[gDisplay]); } else { myAttributeList[i++] = NSOpenGLPFAWindow; } myAttributeList[i++] = 0; myPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes: myAttributeList]; return (myPixelFormat); } //_________________________________________________________________________________________________VID_SetWait() void VID_SetWait (UInt32 theState) { // set theState to 1 to enable, to 0 to disable VBL syncing. [gGLContext makeCurrentContext]; if(CGLSetParameter (CGLGetCurrentContext (), kCGLCPSwapInterval, &theState) == CGDisplayNoErr) { gVidWait = vid_wait.value; if (theState == 0) { Con_Printf ("video wait successfully disabled!\n"); } else { Con_Printf ("video wait successfully enabled!\n"); } } else { vid_wait.value = gVidWait; Con_Printf ("Error while trying to change video wait!\n"); } } //_________________________________________________________________________________________________VID_SetMode() Boolean VID_SetDisplayMode (void) { NSOpenGLPixelFormat *myPixelFormat; // just for security: if (gDisplayList == NULL || gDisplayCount == 0) { Sys_Error ("Invalid list of active displays!"); } // save the old display mode: gOriginalMode = (NSDictionary *) CGDisplayCurrentMode (gDisplayList[gDisplay]); if (gDisplayFullscreen) { // hide cursor: IN_ShowCursor (NO); // fade the display(s) to black: VID_FadeGammaOut (gFadeAllDisplays, FADE_DURATION); // capture display(s); if (VID_CaptureDisplays (gFadeAllDisplays) == NO) Sys_Error ("Unable to capture display(s)!"); // switch the display mode: if (CGDisplaySwitchToMode (gDisplayList[gDisplay], (CFDictionaryRef) gDisplayMode) != CGDisplayNoErr) { Sys_Error ("Unable to switch the displaymode!"); } gDisplayDepth = [[gDisplayMode objectForKey: (id)kCGDisplayBitsPerPixel] intValue]; } else { gDisplayDepth = [[gOriginalMode objectForKey: (id)kCGDisplayBitsPerPixel] intValue]; } // 8 bit display depth is possible with windowed modes: if (gDisplayDepth == 8) gDisplayIs8Bit = YES; else gDisplayIs8Bit = NO; // get the pixel format: if ((myPixelFormat = VID_CreateGLPixelFormat ()) == NULL) { if (gARBMultiSamples > 0) Sys_Error ("Unable to find a matching pixelformat. Set FSAA samples to zero and try again."); else Sys_Error ("Unable to find a matching pixelformat. Probably your graphics board is not supported."); } // initialize the OpenGL context: if (!(gGLContext = [[NSOpenGLContext alloc] initWithFormat: myPixelFormat shareContext: nil])) { if (gARBMultiSamples > 0) Sys_Error ("Unable to create an OpenGL context. Set FSAA samples to zero and try again."); else Sys_Error ("Unable to create an OpenGL context. Probably your graphics board is not supported."); } // get rid of the pixel format: [myPixelFormat release]; if (gDisplayFullscreen) { // attach the OpenGL context to fullscreen: if (CGLSetFullScreen ([gGLContext cglContext]) != CGDisplayNoErr) Sys_Error ("Unable to use the selected displaymode for fullscreen OpenGL."); // fade the gamma back: VID_FadeGammaIn (gFadeAllDisplays, 0.0f); } else { NSRect myContentRect; // setup the window according to our settings: myContentRect = NSMakeRect (0, 0, gDisplayWidth, gDisplayHeight); gWindow = [[NSWindow alloc] initWithContentRect: myContentRect styleMask: NSTitledWindowMask | NSMiniaturizableWindowMask #ifdef USE_BUFFERED_WINDOW backing: NSBackingStoreBuffered #else backing: NSBackingStoreRetained #endif /* USE_BUFFERED_WINDOW */ defer: NO]; [gWindow setTitle: @"TenebraeQuake"]; gWindowView = [[QuakeView alloc] initWithFrame: myContentRect]; if (gWindowView == NULL) { Sys_Error ("Unable to create content view!\n"); } // setup the view for tracking the window location: [gWindow setContentView: gWindowView]; [gWindow makeFirstResponder: gWindowView]; [gWindow setDelegate: gWindowView]; // attach the OpenGL context to the window: [gGLContext setView: [gWindow contentView]]; // finally show the window: [gWindow center]; [gWindow setAcceptsMouseMovedEvents: YES]; [gWindow makeKeyAndOrderFront: nil]; [gWindow makeMainWindow]; [gWindow flushWindow]; // setup the miniwindow [if one alloc fails, the miniwindow will not be drawn]: gMiniWindow = [[NSImage alloc] initWithSize: NSMakeSize (128, 128)]; gOldIcon = [NSImage imageNamed: @"NSApplicationIcon"]; gMiniBuffer = malloc (gDisplayWidth * gDisplayHeight * 4); } // Lock the OpenGL context to the refresh rate of the display [for clean rendering], if desired: VID_SetWait((UInt32) vid_wait.value); return (YES); } //____________________________________________________________________________________________________VID_Init() void VID_Init (unsigned char *thePalette) { char myGLDir[MAX_OSPATH]; UInt i; // register miscelanous vars: Cvar_RegisterVariable (&vid_mode); Cvar_RegisterVariable (&_vid_default_mode); Cvar_RegisterVariable (&_vid_default_blit_mode); Cvar_RegisterVariable (&vid_wait); Cvar_RegisterVariable (&vid_redrawfull); Cvar_RegisterVariable (&_windowed_mouse); Cvar_RegisterVariable (&gl_anisotropic); Cvar_RegisterVariable (&gl_fsaa); Cvar_RegisterVariable (&gl_truform); Cvar_RegisterVariable (&gl_ztrick); // setup basic width/height: vid.maxwarpwidth = WARP_WIDTH; vid.maxwarpheight = WARP_HEIGHT; vid.colormap = host_colormap; vid.fullbright = 256 - LittleLong (*((SInt *)vid.colormap + 2048)); gDisplayWidth = [[gDisplayMode objectForKey: (id)kCGDisplayWidth] intValue]; gDisplayHeight = [[gDisplayMode objectForKey: (id)kCGDisplayHeight] intValue]; // get width from command line parameters [only for windowed mode]: if ((i = COM_CheckParm("-width"))) gDisplayWidth = atoi (com_argv[i+1]); vid.width = gDisplayWidth; // get height from command line parameters [only for windowed mode]: if ((i = COM_CheckParm("-height"))) gDisplayHeight = atoi (com_argv[i+1]); vid.height = gDisplayHeight; vid.aspect = ((float) vid.height / (float) vid.width) * (320.0f / 240.0f); vid.numpages = 2; // switch the video mode: if (!VID_SetDisplayMode()) Sys_Error ("Can\'t initialize video!"); // setup console width according to display width: if ((i = COM_CheckParm("-conwidth"))) vid.conwidth = Q_atoi (com_argv[i+1]); else vid.conwidth = vid.width; vid.conwidth &= 0xfff8; // setup console height according to display height: if ((i = COM_CheckParm ("-conheight"))) vid.conheight = Q_atoi (com_argv[i+1]); else vid.conheight = vid.height; // check the console size: if (vid.conwidth > gDisplayWidth) vid.conwidth = gDisplayWidth; if (vid.conheight > gDisplayHeight) vid.conheight = gDisplayHeight; if (vid.conwidth < CONSOLE_MIN_WIDTH) vid.conwidth = CONSOLE_MIN_WIDTH; if (vid.conheight < CONSOLE_MIN_HEIGHT) vid.conheight = CONSOLE_MIN_HEIGHT; // setup OpenGL: GL_Init (); // setup the "glquake" folder within the "id1" folder: sprintf (myGLDir, "%s/glquake", com_gamedir); Sys_mkdir (myGLDir); // enable the video options menu: vid_menudrawfn = VID_MenuDraw; vid_menukeyfn = VID_MenuKey; // finish up initialization: VID_CheckGamma (thePalette); VID_SetPalette (thePalette); Con_SafePrintf ("Video mode %dx%d initialized.\n", gDisplayWidth, gDisplayHeight); vid.recalc_refdef = 1; } //________________________________________________________________________________________________VID_Shutdown() void VID_Shutdown (void) { // restore old application icon, if changed: VID_RestoreOldIcon (); // release the buffer of the mini window: if (gMiniBuffer != NULL) { free (gMiniBuffer); gMiniBuffer = NULL; } // release the miniwindow: if (gMiniWindow != NULL) { [gMiniWindow release]; gMiniWindow = NULL; } // release the old icon: if (gOldIcon != NULL) { [gOldIcon release]; gOldIcon = NULL; } // close the old window: if (gWindow != NULL) { [gWindow close]; [gWindow release]; gWindow = NULL; } // close the content view: if (gWindowView != NULL) { [gWindowView release]; gWindowView = NULL; } // fade gamma out, to avoid splash: if (gDisplayFullscreen == YES && gOriginalMode != NULL) { VID_FadeGammaOut (gFadeAllDisplays, 0.0f); } // clean up the OpenGL context: if (gGLContext != NULL) { [NSOpenGLContext clearCurrentContext]; [gGLContext clearDrawable]; [gGLContext release]; gGLContext = NULL; } // free the vertexarray buffer: if (gl_var == YES && AGP_Buffer != NULL) { free (AGP_Buffer); AGP_Buffer = NULL; } // restore the old display mode: if (gDisplayFullscreen == YES) { if (gOriginalMode != NULL) { CGDisplaySwitchToMode (gDisplayList[gDisplay], (CFDictionaryRef) gOriginalMode); VID_ReleaseDisplays (gFadeAllDisplays); VID_FadeGammaIn (gFadeAllDisplays, FADE_DURATION); // clean up the gamma fading: if (gOriginalGamma != NULL) { free (gOriginalGamma); gOriginalGamma = NULL; } } } else { if (gWindow != NULL) { [gWindow release]; } } } //__________________________________________________________________________________________VID_RestoreOldIcon() void VID_RestoreOldIcon (void) { if (gIsMinimized == YES) { if (gOldIcon != NULL) { [NSApp setApplicationIconImage: gOldIcon]; } gIsMinimized = NO; } } //________________________________________________________________________________________________VID_MenuDraw() void VID_MenuDraw (void) { qpic_t *myPicture; UInt8 myRow = FIRST_MENU_LINE, myString[16]; myPicture = Draw_CachePic ("gfx/vidmodes.lmp"); M_DrawPic ((320 - myPicture->width) / 2, 4, myPicture); // draw vid_wait option: M_Print (FONT_WIDTH, myRow, "Video Sync:"); if (vid_wait.value) M_Print ((39 - 2) * FONT_WIDTH, myRow, "On"); else M_Print ((39 - 3) * FONT_WIDTH, myRow, "Off"); if (gMenuLine == myRow) gMenuItem = VIDEO_WAIT; // draw FSAA option: if (gl_fsaaavailable == YES) { myRow += FONT_HEIGHT; M_Print (FONT_WIDTH, myRow, "FSAA:"); if (gl_fsaa.value == 1.0f) { M_Print ((39 - 3) * FONT_WIDTH, myRow, "Off"); } else { snprintf (myString, 16, "%dx", (int) gl_fsaa.value); M_Print ((39 - strlen (myString)) * FONT_WIDTH, myRow, myString); } if (gMenuLine == myRow) gMenuItem = VIDEO_FSAA; } // draw anisotropic option: if (gl_texturefilteranisotropic == YES) { myRow += FONT_HEIGHT; M_Print (FONT_WIDTH, myRow, "Anisotropic Texture Filtering:"); if (gl_anisotropic.value) M_Print ((39 - 2) * FONT_WIDTH, myRow, "On"); else M_Print ((39 - 3) * FONT_WIDTH, myRow, "Off"); if (gMenuLine == myRow) gMenuItem = VIDEO_ANISOTROPIC; } // draw truform option: if (gl_pntriangles == YES) { myRow += FONT_HEIGHT; M_Print (FONT_WIDTH, myRow, "ATI Truform Tesselation Level:"); if (gl_truform.value < 0) { M_Print ((39 - 3) * FONT_WIDTH, myRow, "Off"); } else { snprintf (myString, 16, "%dx", (int) gl_truform.value); M_Print ((39 - strlen (myString)) * FONT_WIDTH, myRow, myString); } if (gMenuLine == myRow) gMenuItem = VIDEO_TRUFORM; } M_Print (4 * FONT_WIDTH + 4, 36 + 23 * FONT_HEIGHT, "Video modes must be set at the"); M_Print (11 * FONT_WIDTH + 4, 36 + 24 * FONT_HEIGHT, "startup dialog!"); M_DrawCharacter (0, gMenuLine, 12 + ((int)(realtime * 4) & 1)); gMenuMaxLine = myRow; } //_________________________________________________________________________________________________VID_MenuKey() void VID_MenuKey (int theKey) { switch (theKey) { case K_ESCAPE: S_LocalSound ("misc/menu1.wav"); M_Menu_Options_f (); break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); gMenuLine -= FONT_HEIGHT; if (gMenuLine < FIRST_MENU_LINE) gMenuLine = gMenuMaxLine; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); gMenuLine += FONT_HEIGHT; if (gMenuLine > gMenuMaxLine) gMenuLine = FIRST_MENU_LINE; break; case K_LEFTARROW: S_LocalSound ("misc/menu1.wav"); switch (gMenuItem) { case VIDEO_WAIT: Cvar_SetValue ("vid_wait", (vid_wait.value == 0.0f) ? 1.0f : 0.0f); break; case VIDEO_FSAA: Cvar_SetValue ("gl_fsaa", (gl_fsaa.value <= 1.0f) ? 4.0f : gl_fsaa.value / 2.0f); break; case VIDEO_ANISOTROPIC: Cvar_SetValue ("gl_anisotropic", (gl_anisotropic.value == 0.0f) ? 1.0f : 0.0f); break; case VIDEO_TRUFORM: Cvar_SetValue ("gl_truform", (gl_truform.value <= -1.0f) ? 7.0f : gl_truform.value - 1.0f); break; } break; case K_RIGHTARROW: case K_ENTER: S_LocalSound ("misc/menu1.wav"); switch (gMenuItem) { case VIDEO_WAIT: Cvar_SetValue ("vid_wait", (vid_wait.value == 0.0f) ? 1.0f : 0.0f); break; case VIDEO_FSAA: Cvar_SetValue ("gl_fsaa", (gl_fsaa.value >= 4.0f) ? 1.0f : gl_fsaa.value * 2.0f); break; case VIDEO_ANISOTROPIC: Cvar_SetValue ("gl_anisotropic", (gl_anisotropic.value == 0.0f) ? 1.0f : 0.0f); break; case VIDEO_TRUFORM: Cvar_SetValue ("gl_truform", (gl_truform.value >= 7.0f) ? -1.0f : gl_truform.value + 1.0f); break; } break; default: break; } } //___________________________________________________________________________________________GL_GetProcAddress() void * GL_GetProcAddress (const char *theName, qboolean theSafeMode) { NSSymbol mySymbol = NULL; char * mySymbolName = malloc (strlen (theName) + 2); if (mySymbolName != NULL) { strcpy (mySymbolName + 1, theName); mySymbolName[0] = '_'; mySymbol = NULL; if (NSIsSymbolNameDefined (mySymbolName)) mySymbol = NSLookupAndBindSymbol (mySymbolName); free (mySymbolName); } if (theSafeMode == YES && mySymbol == NULL) { Sys_Error ("Failed to import a required OpenGL function!\n"); } return ((mySymbol != NULL) ? NSAddressOfSymbol (mySymbol) : NULL); } //_____________________________________________________________________________________________GL_CheckVersion() Boolean GL_CheckVersion (UInt8 theMajor, UInt8 theMinor) { UInt8 myMajor, myMinor; // just security: if (gl_version == NULL) { return (NO); } // get the major version number: myMajor = atoi (gl_version); if (myMajor < theMajor) { return (NO); } // compare minor version numbers only if the majors are equal: if (myMajor == theMajor) { const char * myGLVersion = gl_version; while (*myGLVersion != 0x00 && *myGLVersion++ != '.'); myMinor = atoi (myGLVersion); if (myMinor < theMinor) { return (NO); } } return (YES); } //_____________________________________________________________________________________GL_CheckPalettedTexture() void GL_CheckPalettedTexture (void) { if (strstr (gl_extensions, "GL_EXT_paletted_texture")) { gl_palettedtex = YES; Con_Printf ("Found GL_EXT_paletted_texture...\n"); } } //______________________________________________________________________________GL_CheckMultiTextureExtensions() void GL_CheckMultiTextureExtensions (void) { // look for the extension: if (!strstr (gl_extensions, "GL_ARB_multitexture ")) { Sys_Error ("\"GL_ARB_multitexture\" not found.\nYour 3D board is not supported by TenebraeQuake.\n"); } qglActiveTextureARB = GL_GetProcAddress ("glActiveTextureARB", YES); qglClientActiveTextureARB = GL_GetProcAddress ("glClientActiveTextureARB", YES); qglMultiTexCoord1fARB = GL_GetProcAddress ("glMultiTexCoord1fARB", YES); qglMultiTexCoord2fARB = GL_GetProcAddress ("glMultiTexCoord2fARB", YES); qglMultiTexCoord2fvARB = GL_GetProcAddress ("glMultiTexCoord2fvARB", YES); qglMultiTexCoord3fARB = GL_GetProcAddress ("glMultiTexCoord3fARB", YES); qglMultiTexCoord3fvARB = GL_GetProcAddress ("glMultiTexCoord3fvARB", YES); Con_Printf ("Found GL_ARB_multitexture...\n"); gl_mtexable = YES; } //________________________________________________________________________GL_CheckDiffuseBumpMappingExtensions() void GL_CheckDiffuseBumpMappingExtensions (void) { if (!strstr(gl_extensions, "GL_ARB_texture_env_combine")) { Sys_Error ("\"GL_ARB_texture_env_combine\" not found.\n" "Your 3D board is not supported by TenebraeQuake.\n"); } Con_Printf ("Found GL_ARB_texture_env_combine...\n"); if (!strstr(gl_extensions, "GL_ARB_texture_env_dot3")) { Sys_Error ("\"GL_ARB_texture_env_dot3\" not found.\n" "Your 3D board is not supported by TenebraeQuake.\n"); } Con_Printf ("Found GL_ARB_texture_env_dot3...\n"); if (!strstr(gl_extensions, "GL_ARB_texture_cube_map")) { Sys_Error ("\"GL_ARB_texture_cube_map\" not found.\n" "Your 3D board is not supported by TenebraeQuake.\n"); } Con_Printf ("Found GL_ARB_texture_cube_map...\n"); if (GL_CheckVersion (1, 2) == NO && !strstr(gl_extensions, "GL_SGI_texture_edge_clamp") && !strstr(gl_extensions, "GL_EXT_texture_edge_clamp")) { Con_Printf("Warning no edge_clamp extension found..."); } } //_______________________________________________________________________GL_CheckSpecularBumpMappingExtensions() void GL_CheckSpecularBumpMappingExtensions (void) { gl_nvcombiner = NO; if ((strstr(gl_extensions, "GL_NV_register_combiners")) && (!COM_CheckParm ("-forcenonv"))) { qglCombinerParameterfvNV = GL_GetProcAddress ("glCombinerParameterfvNV", NO); qglCombinerParameterivNV = GL_GetProcAddress ("glCombinerParameterivNV", NO); qglCombinerParameterfNV = GL_GetProcAddress ("glCombinerParameterfNV", NO); qglCombinerParameteriNV = GL_GetProcAddress ("glCombinerParameteriNV", NO); qglCombinerInputNV = GL_GetProcAddress ("glCombinerInputNV", NO); qglCombinerOutputNV = GL_GetProcAddress ("glCombinerOutputNV", NO); qglFinalCombinerInputNV = GL_GetProcAddress ("glFinalCombinerInputNV", NO); qglGetCombinerInputParameterfvNV = GL_GetProcAddress ("glGetCombinerInputParameterfvNV", NO); qglGetCombinerInputParameterivNV = GL_GetProcAddress ("glGetCombinerInputParameterivNV", NO); qglGetCombinerOutputParameterfvNV = GL_GetProcAddress ("glGetCombinerOutputParameterfvNV", NO); qglGetCombinerOutputParameterivNV = GL_GetProcAddress ("glGetCombinerOutputParameterivNV", NO); qglGetFinalCombinerInputParameterfvNV = GL_GetProcAddress ("glGetFinalCombinerInputParameterfvNV", NO); qglGetFinalCombinerInputParameterivNV = GL_GetProcAddress ("glGetFinalCombinerInputParameterivNV", NO); if (qglCombinerParameterfvNV != NULL && qglCombinerParameterivNV != NULL && qglCombinerParameterfNV != NULL && qglCombinerParameteriNV != NULL && qglCombinerInputNV != NULL && qglCombinerOutputNV != NULL && qglFinalCombinerInputNV != NULL && qglGetCombinerInputParameterfvNV != NULL && qglGetCombinerInputParameterivNV != NULL && qglGetCombinerOutputParameterfvNV != NULL && qglGetCombinerOutputParameterivNV != NULL && qglGetFinalCombinerInputParameterfvNV != NULL && qglGetFinalCombinerInputParameterivNV != NULL) { gl_nvcombiner = YES; Con_Printf ("Found GL_NV_register_combiners...\n"); } } } //__________________________________________________________________________________GL_CheckGeforce3Extensions() // TODO: Replace GL_NV_vertex_program with GL_ARB_vertex_program since it will probably never be supported under // MacOS X. void GL_CheckGeforce3Extensions (void) { GLint mySupportedTextureUnits; glGetIntegerv (GL_MAX_TEXTURE_UNITS_ARB, &mySupportedTextureUnits); Con_Printf ("%d texture units\n", mySupportedTextureUnits); gl_geforce3 = NO; if (strstr (gl_extensions, "GL_NV_vertex_program") && (mySupportedTextureUnits >= 4) && (!COM_CheckParm ("-forcegf2")) && (gl_nvcombiner == YES)) { if (GL_CheckVersion (1, 2) == YES) { qglTexImage3DEXT = GL_GetProcAddress ("glTexImage3D", NO); Con_Printf ("Found OpenGL v1.2 or later. Using \"glTexImage3D ()\"\n"); } else { if (strstr (gl_extensions, "GL_EXT_texture3D")) { qglTexImage3DEXT = GL_GetProcAddress ("glTexImage3DEXT", NO); Con_Printf ("Found GL_EXT_texture3D...\n"); } } if (qglTexImage3DEXT != NULL) { qglAreProgramsResidentNV = GL_GetProcAddress ("glAreProgramsResidentNV", NO); qglBindProgramNV = GL_GetProcAddress ("glBindProgramNV", NO); qglDeleteProgramsNV = GL_GetProcAddress ("glDeleteProgramsNV", NO); qglExecuteProgramNV = GL_GetProcAddress ("glExecuteProgramNV", NO); qglGenProgramsNV = GL_GetProcAddress ("glGenProgramsNV", NO); qglGetProgramParameterdvNV = GL_GetProcAddress ("glGetProgramParameterdvNV", NO); qglGetProgramParameterfvNV = GL_GetProcAddress ("glGetProgramParameterfvNV", NO); qglGetProgramivNV = GL_GetProcAddress ("glGetProgramivNV", NO); qglGetProgramStringNV = GL_GetProcAddress ("glGetProgramStringNV", NO); qglGetTrackMatrixivNV = GL_GetProcAddress ("glGetTrackMatrixivNV", NO); qglGetVertexAttribdvNV = GL_GetProcAddress ("glGetVertexAttribdvNV", NO); qglGetVertexAttribfvNV = GL_GetProcAddress ("glGetVertexAttribfvNV", NO); qglGetVertexAttribivNV = GL_GetProcAddress ("glGetVertexAttribivNV", NO); qglGetVertexAttribPointervNV = GL_GetProcAddress ("glGetVertexAttribPointervNV", NO); qglIsProgramNV = GL_GetProcAddress ("glIsProgramNV", NO); qglLoadProgramNV = GL_GetProcAddress ("glLoadProgramNV", NO); qglProgramParameter4dNV = GL_GetProcAddress ("glProgramParameter4dNV", NO); qglProgramParameter4dvNV = GL_GetProcAddress ("glProgramParameter4dvNV", NO); qglProgramParameter4fNV = GL_GetProcAddress ("glProgramParameter4fNV", NO); qglProgramParameter4fvNV = GL_GetProcAddress ("glProgramParameter4fvNV", NO); qglProgramParameters4dvNV = GL_GetProcAddress ("glProgramParameters4dvNV", NO); qglProgramParameters4fvNV = GL_GetProcAddress ("glProgramParameters4fvNV", NO); qglRequestResidentProgramsNV = GL_GetProcAddress ("glRequestResidentProgramsNV", NO); qglTrackMatrixNV = GL_GetProcAddress ("glTrackMatrixNV", NO); /* qglBindProgramARB = GL_GetProcAddress ("glBindProgramARB", NO); qglDeleteProgramsARB = GL_GetProcAddress ("glDeleteProgramsNV", NO); qglGenProgramsARB = GL_GetProcAddress ("glGenProgramsNV", NO); qglGetProgramivARB = GL_GetProcAddress ("glGetProgramivNV", NO); qglGetProgramStringARB = GL_GetProcAddress ("glGetProgramStringNV", NO); qglGetVertexAttribdvARB = GL_GetProcAddress ("glGetVertexAttribdvNV", NO); qglGetVertexAttribfvARB = GL_GetProcAddress ("glGetVertexAttribfvNV", NO); qglGetVertexAttribivARB = GL_GetProcAddress ("glGetVertexAttribivNV", NO); qglGetVertexAttribPointervARB = GL_GetProcAddress ("glGetVertexAttribPointervNV", NO); qglIsProgramARB = GL_GetProcAddress ("glIsProgramNV", NO); qglProgramStringARB = GL_GetProcAddress ("glLoadProgramNV", NO); if (qglBindProgramARB != NULL && qglDeleteProgramsARB != NULL && qglGenProgramsARB != NULL && qglGetProgramivARB != NULL && qglGetVertexAttribdvARB != NULL && qglGetVertexAttribfvARB != NULL && qglGetVertexAttribivARB != NULL && qglGetVertexAttribPointervARB != NULL && qglIsProgramARB != NULL && qglProgramStringARB != NULL && glTrackMatrixNV != NULL)*/ if (qglAreProgramsResidentNV != NULL && qglBindProgramNV != NULL && qglDeleteProgramsNV != NULL && qglExecuteProgramNV != NULL && qglGenProgramsNV != NULL && qglGetProgramParameterdvNV != NULL && qglGetProgramParameterfvNV != NULL && qglGetProgramivNV != NULL && qglGetProgramStringNV != NULL && qglGetTrackMatrixivNV != NULL && qglGetVertexAttribdvNV != NULL && qglGetVertexAttribfvNV != NULL && qglGetVertexAttribivNV != NULL && qglGetVertexAttribPointervNV != NULL && qglIsProgramNV != NULL && qglLoadProgramNV != NULL && qglProgramParameter4dNV != NULL && qglProgramParameter4dvNV != NULL && qglProgramParameter4fNV != NULL && qglProgramParameter4fvNV != NULL && qglProgramParameters4dvNV != NULL && qglProgramParameters4fvNV != NULL && qglRequestResidentProgramsNV != NULL && qglTrackMatrixNV != NULL) { Con_Printf ("Using NVidia Geforce 3 or 4Ti path.\n"); gl_geforce3 = YES; gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; gl_filter_max = GL_LINEAR; } } } } //____________________________________________________________________________________GL_CheckRadeonExtensions() void GL_CheckRadeonExtensions (void) { GLint mySupportedTextureUnits; Boolean myOpenGL12 = NO, myExtTexImage3D = NO; glGetIntegerv (GL_MAX_TEXTURE_UNITS_ARB, &mySupportedTextureUnits); gl_radeon = NO; myOpenGL12 = GL_CheckVersion (1, 2); myExtTexImage3D = strstr (gl_extensions, "GL_EXT_vertex_shader") ? YES : NO; if ((myOpenGL12 == YES || myExtTexImage3D == YES) && (mySupportedTextureUnits >= 4) && (!COM_CheckParm ("-forcegeneric")) && strstr (gl_extensions, "GL_ATI_fragment_shader") && strstr (gl_extensions, "GL_EXT_vertex_shader")) { if (myOpenGL12 == YES) { qglTexImage3DEXT = GL_GetProcAddress ("glTexImage3D", NO); Con_Printf ("Found OpenGL v1.2 or later. Using \"glTexImage3D ()\"\n"); } else { if (myExtTexImage3D = YES) { qglTexImage3DEXT = GL_GetProcAddress ("glTexImage3DEXT", NO); Con_Printf ("Found GL_EXT_texture3D...\n"); } } if (qglTexImage3DEXT != NULL) { if (GL_LookupRadeonSymbols () == YES) { gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; gl_filter_max = GL_LINEAR; GL_CreateShadersRadeon(); gl_radeon = YES; Con_Printf("Using ATI Radeon 8500 path.\n"); } } } if (gl_radeon == NO) { if (gl_geforce3 == YES) { Con_Printf("Using Geforce3 or Geforce4Ti path\n"); } else { if (gl_nvcombiner == YES) { Con_Printf("Using Geforce2MX or Geforce4MX path\n"); } else { Con_Printf("Using generic path.\n"); } } } } //____________________________________________________________________________________GL_CheckVertexArrayRange() void GL_CheckVertexArrayRange (void) { gl_var = NO; /* // Don't use it yet. There seems to be something up. if (strstr(gl_extensions, "GL_APPLE_vertex_array_range")) { qglFlushVertexArrayRangeAPPLE = GL_GetProcAddress ("glFlushVertexArrayRangeAPPLE", NO); qglVertexArrayRangeAPPLE = GL_GetProcAddress ("glVertexArrayRangeAPPLE", NO); //qglVertexArrayParameteriAPPLE = GL_GetProcAddress ("glVertexArrayParameteriAPPLE", NO); if (qglFlushVertexArrayRangeAPPLE != NULL && qglVertexArrayRangeAPPLE != NULL) { AGP_Buffer = malloc (AGP_BUFFER_SIZE); if (AGP_Buffer != NULL) { gl_var = YES; Con_Printf ("Found GL_APPLE_vertex_array_range...\nAllocated %dkb.\n", AGP_BUFFER_SIZE / 1024); } } } */ } //_______________________________________________________________________________GL_CheckPNTrianglesExtensions() void GL_CheckPNTrianglesExtensions (void) { if (strstr (gl_extensions, "GL_ATIX_pn_triangles")) { // symbols present? if (glPNTrianglesiATIX != NULL) { Con_Printf ("Found GL_ATIX_pn_triangles...\n"); gl_pntriangles = YES; } else { gl_pntriangles = NO; } } else { gl_pntriangles = NO; } } //_____________________________________________________________________________GL_CheckARBMultisampleExtension() Boolean GL_CheckARBMultisampleExtension (CGDirectDisplayID theDisplay) { CGLRendererInfoObj myRendererInfo; CGLError myError; UInt64 myDisplayMask; long myCount, myIndex, mySampleBuffers, mySamples, myMaxSampleBuffers = 0, myMaxSamples = 0; // retrieve the renderer info for the selected display: myDisplayMask = CGDisplayIDToOpenGLDisplayMask (theDisplay); myError = CGLQueryRendererInfo (myDisplayMask, &myRendererInfo, &myCount); if (myError == kCGErrorSuccess) { // loop through all renderers: for (myIndex = 0; myIndex < myCount; myIndex++) { // check if the current renderer supports sample buffers: myError = CGLDescribeRenderer (myRendererInfo, myIndex, kCGLRPMaxSampleBuffers, &mySampleBuffers); if (myError == kCGErrorSuccess && mySampleBuffers > 0) { // retrieve the number of samples supported by the current renderer: myError = CGLDescribeRenderer (myRendererInfo, myIndex, kCGLRPMaxSamples, &mySamples); if (myError == kCGErrorSuccess && mySamples > myMaxSamples) { myMaxSampleBuffers = mySampleBuffers; myMaxSamples = mySamples; } } } // get rid of the renderer info: CGLDestroyRendererInfo (myRendererInfo); } // NOTE: we could return the max number of samples at this point, but unfortunately there is a bug // with the ATI Radeon/PCI drivers: We would return 4 instead of 8. So we assume that the // max samples are always 8 if we have sample buffers and max samples is greater than 1. if (myMaxSampleBuffers > 0 && myMaxSamples > 1) return (YES); return (NO); } //__________________________________________________________________________________GL_CheckSwitchFSAAOnTheFly() void GL_CheckSwitchFSAAOnTheFly (void) { // Changing the FSAA samples is only available for Radeon boards // [a sample buffer is not required at the pixelformat]. // // We don't want to support FSAA under 10.1.x because the current driver will crash the WindowServer. // Thus we check for the Radeon string AND the GL_ARB_multisample extension, which is only available for // Radeon boards under 10.2 or later. if (strstr (gl_renderer, "ATI Radeon") && strstr (gl_extensions, "GL_ARB_multisample")) { Con_Printf ("Graphics board is capable to switch FSAA samples on the fly...\n"); gl_fsaaavailable = YES; switch (gARBMultiSamples) { case 4: gFSAALevel = 2.0f; break; case 8: gFSAALevel = 4.0f; break; case 0: default: gFSAALevel = 1.0f; break; } gl_fsaa.value = gFSAALevel; return; } gl_fsaaavailable = NO; } //____________________________________________________________________________GL_CheckTextureFilterAnisotropic() void GL_CheckTextureFilterAnisotropic (void) { if (strstr (gl_extensions, "GL_EXT_texture_filter_anisotropic")) { Con_Printf ("Found GL_EXT_texture_filter_anisotropic...\n"); gl_texturefilteranisotropic = YES; } else { gl_texturefilteranisotropic = NO; } } //_____________________________________________________________________________________________________GL_Init() void GL_Init (void) { // show OpenGL stats at the console: gl_vendor = glGetString (GL_VENDOR); Con_Printf ("GL_VENDOR: %s\n", gl_vendor); gl_renderer = glGetString (GL_RENDERER); Con_Printf ("GL_RENDERER: %s\n", gl_renderer); gl_version = glGetString (GL_VERSION); Con_Printf ("GL_VERSION: %s\n", gl_version); gl_extensions = glGetString (GL_EXTENSIONS); Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions); // not required for MacOS X, but nevertheless: if (!strncasecmp ((char*) gl_renderer, "Permedia", 8)) isPermedia = YES; // check for paletted texture extension (GL_Upload8_EXT ()): GL_CheckPalettedTexture (); // check for multitexture extensions: GL_CheckMultiTextureExtensions (); // check for extensions required for bump-mapping: GL_CheckDiffuseBumpMappingExtensions (); GL_CheckSpecularBumpMappingExtensions (); GL_CheckGeforce3Extensions (); GL_CheckRadeonExtensions (); GL_CheckVertexArrayRange (); // check for pn_triangles extension: GL_CheckPNTrianglesExtensions (); // check if FSAA is available: GL_CheckSwitchFSAAOnTheFly (); // check for texture filter anisotropic extension: GL_CheckTextureFilterAnisotropic (); // setup OpenGL: if (gARBMultiSamples > 0) glEnable (GL_MULTISAMPLE_ARB); glClearColor (0,0,0,0); glCullFace (GL_FRONT); glEnable (GL_TEXTURE_2D); glEnable (GL_ALPHA_TEST); glAlphaFunc (GL_GREATER, 0.666f); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); glShadeModel (GL_FLAT); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } //________________________________________________________________________________________GL_RenderInnsideDock() void GL_RenderInsideDock (void) { if ([gWindow isMiniaturized] == YES) { UInt8 *myPlanes[5]; UInt32 myStore, *myTop, *myBottom, myRow = vid.width, mySize = myRow * gDisplayHeight, j; if (gMiniBuffer == NULL || gMiniWindow == NULL) { return; } // get the current OpenGL rendering: glReadPixels (0, 0, gDisplayWidth, gDisplayHeight, GL_RGBA, GL_UNSIGNED_BYTE, gMiniBuffer); // mirror the buffer [only vertical]: myTop = gMiniBuffer; myBottom = myTop + mySize - myRow; while (myTop < myBottom) { for (j = 0; j < myRow; j++) { myStore = myTop[j]; myTop[j] = myBottom[j]; myBottom[j] = myStore; } myTop += myRow; myBottom -= myRow; } myPlanes[0] = (UInt8 *) gMiniBuffer; [gMiniWindow lockFocus]; NSDrawBitmap (NSMakeRect (0, 0, 128, 128), gDisplayWidth, gDisplayHeight, 8, 3, 32, gDisplayWidth * 4, NO, NO, @"NSDeviceRGBColorSpace", (const UInt8 * const *) myPlanes); [gMiniWindow unlockFocus]; // doesn't seem to work: //[gWindow setMiniwindowImage: gMiniWindow]; // so use the app icon instead: [NSApp setApplicationIconImage: gMiniWindow]; gIsMinimized = YES; } else { VID_RestoreOldIcon (); } } //__________________________________________________________________________________________________GL_SetFSAA() void GL_SetFSAA (UInt32 theFSAALevel) { // check the level value: if (theFSAALevel != 1 && theFSAALevel != 2 && theFSAALevel != 4) { Cvar_SetValue (gl_fsaa.name, gFSAALevel); Con_Printf ("Invalid FSAA level, accepted values are 1, 2 or 4!\n"); return; } // check if FSAA is available: if (gl_fsaaavailable == NO) { gFSAALevel = gl_fsaa.value; if (theFSAALevel != 1) { Con_Printf ("FSAA not supported with the current graphics board!\n"); } return; } // set the level: [gGLContext makeCurrentContext]; if(CGLSetParameter (CGLGetCurrentContext (), ATI_FSAA_LEVEL, &theFSAALevel) == CGDisplayNoErr) { gFSAALevel = theFSAALevel; Con_Printf ("FSAA level set to: %d!\n", theFSAALevel); } else { Con_Printf ("Error while trying to set the new FSAA Level!\n"); Cvar_SetValue (gl_fsaa.name, gFSAALevel); } } //___________________________________________________________________________________________GL_SetPNTriangles() void GL_SetPNTriangles (SInt32 thePNTriangleLevel) { // check if the pntriangles extension is available: if (gl_pntriangles == NO) { if (thePNTriangleLevel != -1) { Con_Printf ("pntriangles not supported with the current graphics board!\n"); } gPNTriangleLevel = (gl_truform.value > 7.0f) ? 7.0f : gl_truform.value; if (gPNTriangleLevel < 0.0f) gPNTriangleLevel = -1.0f; Cvar_SetValue (gl_truform.name, gPNTriangleLevel); return; } if (thePNTriangleLevel >= 0) { if (thePNTriangleLevel > 7) { thePNTriangleLevel = 7; Con_Printf ("Clamping to max. pntriangle level 7!\n"); } // enable pn_triangles. lightning required due to a bug of OpenGL! glEnable (GL_PN_TRIANGLES_ATIX); glEnable (GL_LIGHTING); glLightModelfv (GL_LIGHT_MODEL_AMBIENT, gGLTruformAmbient); glEnable (GL_COLOR_MATERIAL); // point mode: glPNTrianglesiATIX (GL_PN_TRIANGLES_POINT_MODE_ATIX, GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATIX); // normal mode (no normals used at all by Quake): glPNTrianglesiATIX (GL_PN_TRIANGLES_NORMAL_MODE_ATIX, GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATIX); // tesselation level: glPNTrianglesiATIX (GL_PN_TRIANGLES_TESSELATION_LEVEL_ATIX, thePNTriangleLevel); Con_Printf ("Truform enabled, current tesselation level: %d!\n", thePNTriangleLevel); } else { thePNTriangleLevel = -1; glDisable (GL_PN_TRIANGLES_ATIX); glDisable (GL_LIGHTING); Con_Printf ("Truform disabled!\n"); } gPNTriangleLevel = thePNTriangleLevel; Cvar_SetValue (gl_truform.name, gPNTriangleLevel); } //______________________________________________________________________________GL_SetTextureFilterAnisotropic() void GL_SetTextureFilterAnisotropic (UInt32 theState) { // clamp the value to 1 [= enabled]: gGLAnisotropic = theState ? YES : NO; Cvar_SetValue (gl_anisotropic.name, gGLAnisotropic); // check if anisotropic filtering is available: if (gl_texturefilteranisotropic == NO) { gl_texureanisotropylevel = 1.0f; if (theState != 0) { Con_Printf ("Anisotropic tetxure filtering not supported with the current graphics board!\n"); } return; } // enable/disable anisotropic filtering: if (theState == 0) { gl_texureanisotropylevel = 1.0f; } else { glGetFloatv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_texureanisotropylevel); } } //___________________________________________________________________________________________GL_BeginRendering() void GL_BeginRendering (SInt *x, SInt *y, SInt *width, SInt *height) { *x = *y = 0; *width = gDisplayWidth; *height = gDisplayHeight; } //_____________________________________________________________________________________________GL_EndRendering() void GL_EndRendering (void) { // flush OpenGL buffers: glFlush (); CGLFlushDrawable ([gGLContext cglContext]);//CGLGetCurrentContext ()); // check if video_wait changed: if(vid_wait.value != gVidWait) { VID_SetWait ((UInt32) vid_wait.value); } // check if anisotropic texture filtering changed: if (gl_anisotropic.value != gGLAnisotropic) { GL_SetTextureFilterAnisotropic ((UInt32) gl_anisotropic.value); } // check if vid_fsaa changed: if (gl_fsaa.value != gFSAALevel) { GL_SetFSAA ((UInt32) gl_fsaa.value); } // check if truform changed: if (gl_truform.value != gPNTriangleLevel) { GL_SetPNTriangles ((SInt32) gl_truform.value); } // specials for windowed/fullscreen mode: if (gDisplayFullscreen == YES) { static float myOldGamma = 0.0f; // setting the gamma requires fullscreen mode... if (myOldGamma != v_gamma.value) { if (gOriginalGamma != NULL) { // set the current gamma: myOldGamma = 1.0f - v_gamma.value; if (myOldGamma < 0.0f) { myOldGamma = 0.0f; } else { if (myOldGamma >= 1.0f) { myOldGamma = 0.999f; } } CGSetDisplayTransferByFormula (gOriginalGamma[gDisplay].displayID, myOldGamma, 1.0f, gOriginalGamma[gDisplay].component[2], myOldGamma, 1.0f, gOriginalGamma[gDisplay].component[5], myOldGamma, 1.0f, gOriginalGamma[gDisplay].component[8]); } else { Con_Printf ("Can\'t set the requested gamma value!\n"); } myOldGamma = v_gamma.value; } } else { // if minimized, render inside the Dock! GL_RenderInsideDock (); } } #pragma mark - //________________________________________________________________________________iMPLEMENTATION_NSOpenGLContext @implementation NSOpenGLContext (CGLContextAccess) //___________________________________________________________________________________________________cglContext: - (CGLContextObj) cglContext; { return (_contextAuxiliary); } @end //______________________________________________________________________________________iMPLEMENTATION_QuakeView @implementation QuakeView //_________________________________________________________________________________________acceptsFirstResponder -(BOOL) acceptsFirstResponder { return YES; } //________________________________________________________________________________________________windowDidMove: - (void)windowDidMove: (NSNotification *)note { NSRect myRect; myRect = [gWindow frame]; gWindowPosX = myRect.origin.x + 1.0f; gWindowPosY = myRect.origin.y + 1.0f; } @end //___________________________________________________________________________________________________________eOF