2104 lines
69 KiB
Objective-C
2104 lines
69 KiB
Objective-C
//___________________________________________________________________________________________________________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 <AppKit/AppKit.h>
|
|
#import <IOKit/graphics/IOGraphicsTypes.h>
|
|
#import <mach-o/dyld.h>
|
|
#import <OpenGL/OpenGL.h>
|
|
#import <OpenGL/gl.h>
|
|
#import <OpenGL/glu.h>
|
|
#import <OpenGL/glext.h>
|
|
|
|
#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
|