typedef int sysEventType_t; // FIXME... #include "../renderer/tr_local.h" #include "mac_local.h" #include #include #include "MacGamma.h" #define MAX_DEVICES 32 typedef struct { GDHandle devices[MAX_DEVICES]; int numDevices; Ptr systemGammas; GDHandle device; AGLContext context; AGLDrawable drawable; AGLPixelFormat fmt; GLint textureMemory; GLint videoMemory; DSpContextReference DSpContext; } macGlInfo; cvar_t *r_device; cvar_t *r_ext_transform_hint; glHardwareType_t sys_hardwareType; macGlInfo sys_gl; void GLimp_EndFrame( void ); static void GLimp_Extensions( void ); void CToPStr(char *cs, Str255 ps) { GLint i, l; l = strlen(cs); if(l > 255) l = 255; ps[0] = l; for(i = 0; i < l; i++) ps[i + 1] = cs[i]; } /* ============ CheckErrors ============ */ void CheckErrors( void ) { GLenum err; err = aglGetError(); if( err != AGL_NO_ERROR ) { ri.Error( ERR_FATAL, "aglGetError: %s", aglErrorString( err ) ); } } //======================================================================= /* ===================== GLimp_ResetDisplay ===================== */ void GLimp_ResetDisplay( void ) { if ( !glConfig.isFullscreen ) { return; } glConfig.isFullscreen = qfalse; // put the context into the inactive state DSpContext_SetState( sys_gl.DSpContext, kDSpContextState_Inactive ); // release the context DSpContext_Release( sys_gl.DSpContext ); // shutdown draw sprockets DSpShutdown(); } /* ===================== GLimp_ChangeDisplay ===================== */ void GLimp_ChangeDisplay( int *actualWidth, int *actualHeight ) { OSStatus theError; DSpContextAttributes inAttributes; int colorBits; // startup DrawSprocket theError = DSpStartup(); if( theError ) { ri.Printf( PRINT_ALL, "DSpStartup() failed: %i\n", theError ); *actualWidth = 640; *actualHeight = 480; return; } if ( r_colorbits->integer == 24 || r_colorbits->integer == 32 ) { colorBits = kDSpDepthMask_32; } else { colorBits = kDSpDepthMask_16; } memset( &inAttributes, 0, sizeof( inAttributes ) ); inAttributes.frequency = 0; inAttributes.displayWidth = glConfig.vidWidth; inAttributes.displayHeight = glConfig.vidHeight; inAttributes.reserved1 = 0; inAttributes.reserved2 = 0; inAttributes.colorNeeds = kDSpColorNeeds_Require; inAttributes.colorTable = NULL; inAttributes.contextOptions = 0; inAttributes.backBufferDepthMask = colorBits; inAttributes.displayDepthMask = colorBits; inAttributes.backBufferBestDepth = colorBits; inAttributes.displayBestDepth = colorBits; inAttributes.pageCount = 1; inAttributes.gameMustConfirmSwitch = false; inAttributes.reserved3[0] = 0; inAttributes.reserved3[1] = 0; inAttributes.reserved3[2] = 0; inAttributes.reserved3[3] = 0; theError = DSpFindBestContext( &inAttributes, &sys_gl.DSpContext ); inAttributes.displayWidth = glConfig.vidWidth; inAttributes.displayHeight = glConfig.vidHeight; inAttributes.backBufferDepthMask = colorBits; inAttributes.displayDepthMask = colorBits; inAttributes.backBufferBestDepth = colorBits; inAttributes.displayBestDepth = colorBits; inAttributes.pageCount = 1; theError = DSpContext_Reserve( sys_gl.DSpContext, &inAttributes ); // find out what res we actually got theError = DSpContext_GetAttributes( sys_gl.DSpContext, &inAttributes ); *actualWidth = inAttributes.displayWidth; *actualHeight = inAttributes.displayHeight; // put the context into the active state theError = DSpContext_SetState( sys_gl.DSpContext, kDSpContextState_Active ); // fade back in theError = DSpContext_FadeGammaIn( NULL, NULL ); glConfig.isFullscreen = qtrue; } //======================================================================= /* =================== GLimp_AglDescribe_f =================== */ void GLimp_AglDescribe_f( void ) { long value; long r,g,b,a; long stencil, depth; ri.Printf( PRINT_ALL, "Selected pixel format 0x%x\n", (int)sys_gl.fmt ); ri.Printf( PRINT_ALL, "TEXTURE_MEMORY: %i\n", sys_gl.textureMemory ); ri.Printf( PRINT_ALL, "VIDEO_MEMORY: %i\n", sys_gl.videoMemory ); aglDescribePixelFormat(sys_gl.fmt, AGL_RED_SIZE, &r); aglDescribePixelFormat(sys_gl.fmt, AGL_GREEN_SIZE, &g); aglDescribePixelFormat(sys_gl.fmt, AGL_BLUE_SIZE, &b); aglDescribePixelFormat(sys_gl.fmt, AGL_ALPHA_SIZE, &a); aglDescribePixelFormat(sys_gl.fmt, AGL_STENCIL_SIZE, &stencil); aglDescribePixelFormat(sys_gl.fmt, AGL_DEPTH_SIZE, &depth); ri.Printf( PRINT_ALL, "red:%i green:%i blue:%i alpha:%i depth:%i stencil:%i\n", r, g, b, a, depth, stencil ); aglDescribePixelFormat(sys_gl.fmt, AGL_BUFFER_SIZE, &value); ri.Printf( PRINT_ALL, "BUFFER_SIZE: %i\n", value ); aglDescribePixelFormat(sys_gl.fmt, AGL_PIXEL_SIZE, &value); ri.Printf( PRINT_ALL, "PIXEL_SIZE: %i\n", value ); aglDescribePixelFormat(sys_gl.fmt, AGL_RENDERER_ID, &value); ri.Printf( PRINT_ALL, "RENDERER_ID: %i\n", value ); // memory functions value = glmGetInteger( GLM_PAGE_SIZE ); ri.Printf( PRINT_ALL, "GLM_PAGE_SIZE: %i\n", value ); value = glmGetInteger( GLM_NUMBER_PAGES ); ri.Printf( PRINT_ALL, "GLM_NUMBER_PAGES: %i\n", value ); value = glmGetInteger( GLM_CURRENT_MEMORY ); ri.Printf( PRINT_ALL, "GLM_CURRENT_MEMORY: %i\n", value ); value = glmGetInteger( GLM_MAXIMUM_MEMORY ); ri.Printf( PRINT_ALL, "GLM_MAXIMUM_MEMORY: %i\n", value ); } /* =================== GLimp_AglState_f =================== */ void GLimp_AglState_f( void ) { char *cmd; int state, value; if ( ri.Cmd_Argc() != 3 ) { ri.Printf( PRINT_ALL, "Usage: aglstate <0/1>\n" ); return; } cmd = ri.Cmd_Argv( 1 ); if ( !Q_stricmp( cmd, "rasterization" ) ) { state = AGL_RASTERIZATION; } else { ri.Printf( PRINT_ALL, "Unknown agl state: %s\n", cmd ); return; } cmd = ri.Cmd_Argv( 2 ); value = atoi( cmd ); if ( value ) { aglEnable( sys_gl.context, state ); } else { aglDisable( sys_gl.context, state ); } } /* =================== GLimp_Extensions =================== */ static void GLimp_Extensions( void ) { const char *extensions; // get our config strings Q_strncpyz( glConfig.vendor_string, (const char *)qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) ); Q_strncpyz( glConfig.renderer_string, (const char *)qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) ); Q_strncpyz( glConfig.version_string, (const char *)qglGetString (GL_VERSION), sizeof( glConfig.version_string ) ); Q_strncpyz( glConfig.extensions_string, (const char *)qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) ); extensions = glConfig.extensions_string; // GL_ARB_multitexture qglMultiTexCoord2fARB = NULL; qglActiveTextureARB = NULL; qglClientActiveTextureARB = NULL; if ( strstr( extensions, "GL_ARB_multitexture" ) ) { if ( r_ext_multitexture->integer && r_allowExtensions->integer ) { qglMultiTexCoord2fARB = glMultiTexCoord2fARB; qglActiveTextureARB = glActiveTextureARB; qglClientActiveTextureARB = glClientActiveTextureARB; ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); } else { ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); } } else { ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); } // GL_EXT_compiled_vertex_array qglLockArraysEXT = NULL; qglUnlockArraysEXT = NULL; if ( strstr( extensions, "GL_EXT_compiled_vertex_array" ) ) { if ( r_ext_compiled_vertex_array->integer && r_allowExtensions->integer ) { qglLockArraysEXT = glLockArraysEXT; qglUnlockArraysEXT = glUnlockArraysEXT; ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" ); } else { ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); } } else { ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); } // GL_EXT_texture_env_add glConfig.textureEnvAddAvailable = qfalse; if ( strstr( glConfig.extensions_string, "EXT_texture_env_add" ) ) { if ( r_ext_texture_env_add->integer ) { glConfig.textureEnvAddAvailable = qtrue; ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); } else { glConfig.textureEnvAddAvailable = qfalse; ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" ); } } else { ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" ); } // GL_EXT_texture_filter_anisotropic glConfig.textureFilterAnisotropicAvailable = qfalse; if ( strstr( glConfig.extensions_string, "EXT_texture_filter_anisotropic" ) ) { glConfig.textureFilterAnisotropicAvailable = qtrue; ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic available\n" ); if ( r_ext_texture_filter_anisotropic->integer ) { ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic\n" ); } else { ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" ); } ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "1" ); } else { ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" ); ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "0" ); } // apple transform hint if ( strstr( extensions, "GL_APPLE_transform_hint" ) ) { if ( r_ext_compiled_vertex_array->integer && r_allowExtensions->integer ) { glHint( GL_TRANSFORM_HINT_APPLE, GL_FASTEST ); ri.Printf( PRINT_ALL, "...using GL_APPLE_transform_hint\n" ); } else { ri.Printf( PRINT_ALL, "...ignoring GL_APPLE_transform_hint\n" ); } } else { ri.Printf( PRINT_ALL, "...GL_APPLE_transform_hint not found\n" ); } } /* ============================ GLimp_SufficientVideoMemory ============================ */ #if 0 qboolean GLimp_SufficientVideoMemory( void ) { AGLRendererInfo head_info, info; GLint accelerated; AGLDevice *device; GLint i, ndevs; device = aglDevicesOfPixelFormat( sys_gl.fmt, &ndevs); if (!device || ndevs < 1) { ri.Printf( PRINT_ALL, "aglDevicesOfPixelFormat failed.\n" ); return 0; } ri.Printf( PRINT_ALL, "%i rendering devices\n", ndevs ); head_info = aglQueryRendererInfo( device, 1 ); info = head_info; if (!info) { ri.Printf( PRINT_ALL, "aglQueryRendererInfo failed.\n" ); return 0; } for ( i = 0 ; i < ndevs ; i++ ) { // ignore the software renderer listing aglDescribeRenderer( info, AGL_ACCELERATED, &accelerated ); if ( accelerated ) { aglDescribeRenderer( info, AGL_TEXTURE_MEMORY, &sys_gl.textureMemory ); aglDescribeRenderer( info, AGL_VIDEO_MEMORY, &sys_gl.videoMemory ); } info = aglNextRendererInfo(info); } aglDestroyRendererInfo(head_info); #if 0 if ( sys_gl.videoMemory < 16000000 ) { glConfig.hardwareType = GLHW_RAGEPRO; // FIXME when voodoo is available } else { glConfig.isRagePro = GLHW_GENERIC; // FIXME when voodoo is available } #endif ri.Printf( PRINT_ALL, "%i texture memory, %i video memory\n", sys_gl.textureMemory, sys_gl.videoMemory ); return qtrue; } #endif /* ======================= CheckDeviceRenderers ======================== */ static void CheckDeviceRenderers( GDHandle device ) { AGLRendererInfo info, head_info; GLint inum; GLint accelerated; GLint textureMemory, videoMemory; head_info = aglQueryRendererInfo(&device, 1); if( !head_info ) { ri.Printf( PRINT_ALL, "aglQueryRendererInfo : Info Error\n"); return; } info = head_info; inum = 0; while( info ) { ri.Printf( PRINT_ALL, " Renderer : %d\n", inum); aglDescribeRenderer( info, AGL_ACCELERATED, &accelerated ); if ( accelerated ) { aglDescribeRenderer( info, AGL_TEXTURE_MEMORY, &textureMemory ); aglDescribeRenderer( info, AGL_VIDEO_MEMORY, &videoMemory ); ri.Printf( PRINT_ALL, " AGL_VIDEO_MEMORY: %i\n", textureMemory ); ri.Printf( PRINT_ALL, " AGL_TEXTURE_MEMORY: %i\n", videoMemory ); // save the device with the most texture memory if ( sys_gl.textureMemory < textureMemory ) { sys_gl.textureMemory = textureMemory; sys_gl.device = device; } } else { ri.Printf( PRINT_ALL, " Not accelerated.\n" ); } info = aglNextRendererInfo(info); inum++; } aglDestroyRendererInfo(head_info); } /* ======================= CheckDevices Make sure there is a device with enough video memory to play ======================= */ static void CheckDevices( void ) { GDHandle device; static qboolean checkedFullscreen; if ( checkedFullscreen ) { return; } if ( glConfig.isFullscreen ) { checkedFullscreen = qtrue; } device = GetDeviceList(); sys_gl.numDevices = 0; while( device && sys_gl.numDevices < MAX_DEVICES ) { sys_gl.devices[ sys_gl.numDevices ] = device; ri.Printf( PRINT_ALL, "Device : %d\n", sys_gl.numDevices); CheckDeviceRenderers(device); device = GetNextDevice(device); sys_gl.numDevices++; } CheckErrors(); if ( sys_gl.textureMemory < 4000000 ) { ri.Error( ERR_FATAL, "You must have at least four megs of video memory to play" ); } if ( sys_gl.textureMemory < 16000000 ) { sys_hardwareType = GLHW_RAGEPRO; // this will have to change with voodoo } else { sys_hardwareType = GLHW_GENERIC; } } /* ================= CreateGameWindow ================= */ static qboolean CreateGameWindow( void ) { cvar_t *vid_xpos; cvar_t *vid_ypos; int mode; int x, y; Str255 pstr; vid_xpos = ri.Cvar_Get( "vid_xpos", "30", 0 ); vid_ypos = ri.Cvar_Get( "vid_ypos", "30", 0 ); // get mode info mode = r_mode->integer; ri.Printf( PRINT_ALL, "...setting mode %d:", mode ); if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) ) { ri.Printf( PRINT_ALL, " invalid mode\n" ); return false; } ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight ); /* Create window */ if ( r_fullscreen->integer ) { int actualWidth, actualHeight; // change display resolution GLimp_ChangeDisplay( &actualWidth, &actualHeight ); x = ( actualWidth - glConfig.vidWidth ) / 2; y = ( actualHeight - glConfig.vidHeight ) / 2; sys_gl.drawable = (AGLDrawable) GetNewCWindow(kFullScreenWindow,nil,(WindowPtr)-1L); } else { x = vid_xpos->integer; y = vid_ypos->integer; sys_gl.drawable = (AGLDrawable) GetNewCWindow(kMainWindow,nil,(WindowPtr)-1L); } if( !sys_gl.drawable ) { return qfalse; } SizeWindow((GrafPort *) sys_gl.drawable, glConfig.vidWidth, glConfig.vidHeight,GL_FALSE); MoveWindow((GrafPort *) sys_gl.drawable,x, y, GL_FALSE); ShowWindow((GrafPort *) sys_gl.drawable); SetPort((GrafPort *) sys_gl.drawable); CToPStr("Quake3: Arena", pstr); SetWTitle((GrafPort *) sys_gl.drawable, pstr); HiliteWindow((GrafPort *) sys_gl.drawable, 1); return qtrue; } /* =================== GLimp_SetMode Returns false if the mode / fullscrenn / options combination failed, so another fallback can be tried =================== */ qboolean GLimp_SetMode( void ) { GLint value; GLint attrib[64]; int i; if ( !CreateGameWindow() ) { ri.Printf( PRINT_ALL, "GLimp_Init: window could not be created" ); return qfalse; } // check devices now that the game has set the display mode, // because RAVE devices don't get reported if in an 8 bit desktop CheckDevices(); // set up the attribute list i = 0; attrib[i++] = AGL_RGBA; attrib[i++] = AGL_DOUBLEBUFFER; attrib[i++] = AGL_NO_RECOVERY; attrib[i++] = AGL_ACCELERATED; if ( r_colorbits->integer >= 16 ) { attrib[i++] = AGL_RED_SIZE; attrib[i++] = 8; attrib[i++] = AGL_GREEN_SIZE; attrib[i++] = 8; attrib[i++] = AGL_BLUE_SIZE; attrib[i++] = 8; attrib[i++] = AGL_ALPHA_SIZE; attrib[i++] = 0; } else { attrib[i++] = AGL_RED_SIZE; attrib[i++] = 5; attrib[i++] = AGL_GREEN_SIZE; attrib[i++] = 5; attrib[i++] = AGL_BLUE_SIZE; attrib[i++] = 5; attrib[i++] = AGL_ALPHA_SIZE; attrib[i++] = 0; } attrib[i++] = AGL_STENCIL_SIZE; if ( r_stencilbits->integer ) { attrib[i++] = r_stencilbits->integer; } else { attrib[i++] = 0; } attrib[i++] = AGL_DEPTH_SIZE; if ( r_depthbits->integer ) { attrib[i++] = r_depthbits->integer; } else { attrib[i++] = 16; } attrib[i++] = 0; /* Choose pixel format */ ri.Printf( PRINT_ALL, "aglChoosePixelFormat\n" ); if ( r_device->integer < 0 || r_device->integer >= sys_gl.numDevices ) { ri.Cvar_Set( "r_device", "0" ); } sys_gl.fmt = aglChoosePixelFormat( &sys_gl.devices[ r_device->integer ], 1, attrib); if(!sys_gl.fmt) { ri.Printf( PRINT_ALL, "GLimp_Init: Pixel format could not be achieved\n"); return qfalse; } ri.Printf( PRINT_ALL, "Selected pixel format 0x%x\n", (int)sys_gl.fmt ); aglDescribePixelFormat(sys_gl.fmt, AGL_RED_SIZE, &value); glConfig.colorBits = value * 3; aglDescribePixelFormat(sys_gl.fmt, AGL_STENCIL_SIZE, &value); glConfig.stencilBits = value; aglDescribePixelFormat(sys_gl.fmt, AGL_DEPTH_SIZE, &value); glConfig.depthBits = value; CheckErrors(); /* Create context */ sys_gl.context = aglCreateContext(sys_gl.fmt, NULL); if(!sys_gl.context) { ri.Printf( PRINT_ALL, "GLimp_init: Context could not be created\n"); return qfalse; } CheckErrors(); /* Make context current */ if(!aglSetDrawable(sys_gl.context, sys_gl.drawable)) { ri.Printf( PRINT_ALL, "GLimp_Init: Could not attach to context\n" ); return qfalse; } CheckErrors(); if( !aglSetCurrentContext(sys_gl.context) ) { ri.Printf( PRINT_ALL, "GLimp_Init: Could not attach to context"); return qfalse; } CheckErrors(); // check video memory and determine ragePro status #if 0 if ( !GLimp_SufficientVideoMemory() ) { return qfalse; } #endif glConfig.hardwareType = sys_hardwareType; // FIXME: this isn't really right // draw something to show that GL is alive qglClearColor( 1, 0.5, 0.2, 0 ); qglClear( GL_COLOR_BUFFER_BIT ); GLimp_EndFrame(); CheckErrors(); // get the extensions GLimp_Extensions(); CheckErrors(); return qtrue; } /* =================== GLimp_Init Don't return unless OpenGL has been properly initialized =================== */ void GLimp_Init( void ) { GLint major, minor; static qboolean registered; ri.Printf( PRINT_ALL, "--- GLimp_Init ---\n" ); aglGetVersion( &major, &minor ); ri.Printf( PRINT_ALL, "aglVersion: %i.%i\n", (int)major, (int)minor ); r_device = ri.Cvar_Get( "r_device", "0", CVAR_LATCH | CVAR_ARCHIVE ); r_ext_transform_hint = ri.Cvar_Get( "r_ext_transform_hint", "1", CVAR_LATCH | CVAR_ARCHIVE ); if ( !registered ) { ri.Cmd_AddCommand( "aglDescribe", GLimp_AglDescribe_f ); ri.Cmd_AddCommand( "aglState", GLimp_AglState_f ); } memset( &glConfig, 0, sizeof( glConfig ) ); r_swapInterval->modified = qtrue; // force a set next frame glConfig.deviceSupportsGamma = qtrue; // FIXME: try for a voodoo first sys_gl.systemGammas = GetSystemGammas(); if ( GLimp_SetMode() ) { ri.Printf( PRINT_ALL, "------------------\n" ); return; } // fall back to the known-good mode ri.Cvar_Set( "r_fullscreen", "1" ); ri.Cvar_Set( "r_mode", "3" ); ri.Cvar_Set( "r_stereo", "0" ); ri.Cvar_Set( "r_depthBits", "16" ); ri.Cvar_Set( "r_colorBits", "16" ); ri.Cvar_Set( "r_stencilBits", "0" ); if ( GLimp_SetMode() ) { ri.Printf( PRINT_ALL, "------------------\n" ); return; } ri.Error( ERR_FATAL, "Could not initialize OpenGL" ); } /* =============== GLimp_EndFrame =============== */ void GLimp_EndFrame( void ) { // check for variable changes if ( r_swapInterval->modified ) { r_swapInterval->modified = qfalse; ri.Printf( PRINT_ALL, "Changing AGL_SWAP_INTERVAL\n" ); aglSetInteger( sys_gl.context, AGL_SWAP_INTERVAL, (long *)&r_swapInterval->integer ); } // make sure the event loop is pumped Sys_SendKeyEvents(); aglSwapBuffers( sys_gl.context ); } /* =============== GLimp_Shutdown =============== */ void GLimp_Shutdown( void ) { if ( sys_gl.systemGammas ) { RestoreSystemGammas( sys_gl.systemGammas ); DisposeSystemGammas( &sys_gl.systemGammas ); sys_gl.systemGammas = 0; } if ( sys_gl.context ) { aglDestroyContext(sys_gl.context); sys_gl.context = 0; } if ( sys_gl.fmt ) { aglDestroyPixelFormat(sys_gl.fmt); sys_gl.fmt = 0; } if ( sys_gl.drawable ) { DisposeWindow((GrafPort *) sys_gl.drawable); sys_gl.drawable = 0; } GLimp_ResetDisplay(); memset( &glConfig, 0, sizeof( glConfig ) ); } void GLimp_LogComment( char *comment ) { } qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) { } void *GLimp_RendererSleep( void ) { } void GLimp_FrontEndSleep( void ) { } void GLimp_WakeRenderer( void * data ) { } /* =============== GLimp_SetGamma =============== */ void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] ) { char color[3][256]; int i; for ( i = 0 ; i < 256 ; i++ ) { color[0][i] = red[i]; color[1][i] = green[i]; color[2][i] = blue[i]; } SetDeviceGammaRampGD( sys_gl.device, color[0] ); }