/* * sdl_glimp.c - SDL window creation, input handling * * Copyright (C) 1999-2005 Id Software, Inc. * Copyright (C) 2005 Damien Thebault * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ** GLW_IMP.C ** ** This file contains ALL Linux specific stuff having to do with the ** OpenGL refresh. When a port is being made the following functions ** must be implemented by the port: ** ** GLimp_EndFrame ** GLimp_Init ** GLimp_Shutdown ** GLimp_SwitchFullscreen ** GLimp_SetGamma ** */ #include "../renderer/tr_local.h" #include "../client/client.h" #include "sdl_local.h" #include "sdl_glw.h" #include "SDL.h" #include "SDL_loadso.h" /* SDL_LoadFunction */ typedef enum { RSERR_OK, RSERR_INVALID_FULLSCREEN, RSERR_INVALID_MODE, RSERR_UNKNOWN } rserr_t; glwstate_t glw_state; cvar_t *in_nograb; // this is strictly for developers cvar_t *in_joythreshold = NULL; cvar_t *r_allowSoftwareGL; // don't abort out if the pixelformat claims software cvar_t *r_previousglDriver; qboolean vidmode_ext = qfalse; /* * Find the first occurrence of find in s. */ // bk001130 - from cvs1.17 (mkv), const // bk001130 - made first argument const static const char *Q_stristr( const char *s, const char *find) { register char c, sc; register size_t len; if ((c = *find++) != 0) { if (c >= 'a' && c <= 'z') { c -= ('a' - 'A'); } len = strlen(find); do { do { if ((sc = *s++) == 0) return NULL; if (sc >= 'a' && sc <= 'z') { sc -= ('a' - 'A'); } } while (sc != c); } while (Q_stricmpn(s, find, len) != 0); s--; } return s; } /***************************************************************************** ** KEYBOARD ** Some special keys are mapped directly from SDL KeySym to Quake ones ** The others are translated from the keysym and the mods by SDL. ** you can turn on some debugging and verbose of the keyboard code with #define KBD_DBG ******************************************************************************/ //#define KBD_DBG char * SDLateKey( int *qkey, SDL_KeyboardEvent sdlke ) { int key; static char buf[2]; switch( sdlke.keysym.sym ) { case SDLK_PAGEUP: key = K_PGUP; break; case SDLK_PAGEDOWN: key = K_PGDN; break; case SDLK_HOME: key = K_HOME; break; case SDLK_END: key = K_END; break; case SDLK_UP: key = K_UPARROW; break; case SDLK_DOWN: key = K_DOWNARROW; break; case SDLK_LEFT: key = K_LEFTARROW; break; case SDLK_RIGHT: key = K_RIGHTARROW; break; case SDLK_ESCAPE: key = K_ESCAPE; break; case SDLK_RETURN: key = K_ENTER; break; case SDLK_KP_ENTER: key = K_KP_ENTER; break; case SDLK_TAB: key = K_TAB; break; case SDLK_F1: key = K_F1; break; case SDLK_F2: key = K_F2; break; case SDLK_F3: key = K_F3; break; case SDLK_F4: key = K_F4; break; case SDLK_F5: key = K_F5; break; case SDLK_F6: key = K_F6; break; case SDLK_F7: key = K_F7; break; case SDLK_F8: key = K_F8; break; case SDLK_F9: key = K_F9; break; case SDLK_F10: key = K_F10; break; case SDLK_F11: key = K_F11; break; case SDLK_F12: key = K_F12; break; case SDLK_BACKSPACE: key = 8; break; case SDLK_DELETE: key = K_DEL; break; case SDLK_PAUSE: key = K_PAUSE; break; case SDLK_RSHIFT: case SDLK_LSHIFT: key = K_SHIFT; break; case SDLK_RCTRL: case SDLK_LCTRL: key = K_CTRL; break; case SDLK_RALT: case SDLK_LALT: case SDLK_RMETA: case SDLK_LMETA: case SDLK_LSUPER: case SDLK_RSUPER: key = K_ALT; break; case SDLK_INSERT: key = K_INS; break; case SDLK_SPACE: key = K_SPACE; break; //French keyboard '²' case 178: key = '~'; break; default: if( sdlke.keysym.unicode < 256 ) { /* If the translated key is between 0 and 256, it's ok */ key = sdlke.keysym.unicode; } else { /* The key don't fit in the Quake3 keyboard array */ key = 0; } break; } #ifdef KBD_DBG printf( "Key '%c' (%d) -> '%c' (%d)\n", sdlke.keysym.sym, sdlke.keysym.sym, key, key ); #endif *qkey = key; if( sdlke.type == SDL_KEYDOWN ) { buf[0] = key; buf[1] = '\0'; } else { buf[0] = '\0'; } return buf; } static void HandleEvents(void) { int key; char *p; SDL_Event sdlevent; while( SDL_PollEvent( &sdlevent ) ) { switch( sdlevent.type ) { case SDL_KEYDOWN: case SDL_KEYUP: p = SDLateKey( &key, sdlevent.key ); Sys_QueEvent( 0, SE_KEY, key, sdlevent.key.state, 0, NULL ); while (*p) Sys_QueEvent( 0, SE_CHAR, *p++, 0, 0, NULL ); break; case SDL_MOUSEMOTION: Sys_QueEvent( 0, SE_MOUSE, sdlevent.motion.xrel, sdlevent.motion.yrel, 0, NULL ); break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: Sys_QueEvent( 0, SE_KEY, K_MOUSE1 + sdlevent.button.button - 1, sdlevent.button.state, 0, NULL ); break; case SDL_JOYAXISMOTION: case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: IN_JoyEvent( sdlevent ); break; } } } /*****************************************************************************/ /* ** GLimp_SetGamma ** ** This routine should only be called if glConfig.deviceSupportsGamma is TRUE */ void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] ) { float g = Cvar_Get("r_gamma", "1.0", 0)->value; SDL_SetGamma( g,g,g ); } /* ** GLimp_Shutdown ** ** This routine does all OS specific shutdown procedures for the OpenGL ** subsystem. Under OpenGL this means NULLing out the current DC and ** HGLRC, deleting the rendering context, and releasing the DC acquired ** for the window. The state structure is also nulled out. ** */ void GLimp_Shutdown( void ) { if (!in_nograb->value) { SDL_WM_GrabInput( SDL_GRAB_OFF ); SDL_ShowCursor( SDL_ENABLE ); } memset( &glConfig, 0, sizeof( glConfig ) ); memset( &glState, 0, sizeof( glState ) ); SDL_Quit(); QGL_Shutdown(); } /* ** GLimp_LogComment */ void GLimp_LogComment( char *comment ) { if ( glw_state.log_fp ) { fprintf( glw_state.log_fp, "%s", comment ); } } /* ** GLW_StartDriverAndSetMode */ // bk001204 - prototype needed int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen ); static qboolean GLW_StartDriverAndSetMode( const char *drivername, int mode, qboolean fullscreen ) { rserr_t err; // don't ever bother going into fullscreen with a voodoo card #if 1 // JDC: I reenabled this if ( Q_stristr( drivername, "Voodoo" ) ) { ri.Cvar_Set( "r_fullscreen", "0" ); r_fullscreen->modified = qfalse; fullscreen = qfalse; } #endif if (fullscreen && in_nograb->value) { ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n"); ri.Cvar_Set( "r_fullscreen", "0" ); r_fullscreen->modified = qfalse; fullscreen = qfalse; } err = GLW_SetMode( drivername, mode, fullscreen ); switch ( err ) { case RSERR_INVALID_FULLSCREEN: ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" ); return qfalse; case RSERR_INVALID_MODE: ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode ); return qfalse; default: break; } return qtrue; } /* ** GLW_SetMode */ int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen ) { const char* glstring; int colorbits,depthbits,stencilbits; int r=0,g=0,b=0,depth=0,stencil=0,doublebuffer=-1; // status ri.Printf( PRINT_ALL, "Initializing OpenGL display\n"); ri.Printf( PRINT_ALL, "SDL : initialization... "); if( SDL_Init( SDL_INIT_VIDEO ) != 0 ) { fprintf( stderr, "Error : %s\n", SDL_GetError() ); return RSERR_INVALID_MODE; } else { ri.Printf( PRINT_ALL, "OK\n" ); } ri.Printf( PRINT_ALL, "SDL : get video info... "); if( SDL_GetVideoInfo() == NULL ) { fprintf( stderr, "Error : %s\n", SDL_GetError() ); return RSERR_INVALID_MODE; } else { ri.Printf( PRINT_ALL, "OK\n" ); } if ( !r_depthbits->value ) depthbits = 24; else depthbits = r_depthbits->value; stencilbits = r_stencilbits->value; if (!r_colorbits->value) colorbits = 24; else colorbits = r_colorbits->value; if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) ) colorbits = 16; if( colorbits == 24 || colorbits == 32 ) { SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 ); r=g=b=8; } else if( colorbits == 16 ) { SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 4 ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 4 ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 4 ); r=g=b=4; } SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, depthbits ); // depth buffer SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, stencilbits ); // stencil buffer ri.Printf( PRINT_ALL, "getting info about mode %d... ", mode ); if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) ) { ri.Printf( PRINT_ALL, "invalid mode\n" ); return RSERR_INVALID_MODE; } else { ri.Printf( PRINT_ALL, "%dx%d\n", glConfig.vidWidth, glConfig.vidHeight); } ri.Printf( PRINT_ALL, "SDL : setting mode %d (%dx%d) %s... ", mode, glConfig.vidWidth, glConfig.vidHeight, fullscreen?"fullscreen":"windowed" ); if( SDL_SetVideoMode( glConfig.vidWidth, glConfig.vidHeight, 32, SDL_OPENGL | (fullscreen?SDL_FULLSCREEN:0) ) == 0 ) { ri.Printf( PRINT_ALL, "Failed\n" ); ri.Printf( PRINT_ALL, "Trying with minimal settings : 640x480 windowed... " ); SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 2 ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 2 ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 2 ); r=g=b=2; SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 8 ); depthbits = 8; SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 0 ); stencilbits = 0; R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, 3 ); if( SDL_SetVideoMode( glConfig.vidWidth, glConfig.vidHeight, 32, SDL_OPENGL ) == 0 ) { fprintf( stderr, "Error : \n%s\n", SDL_GetError() ); SDL_Quit(); return RSERR_INVALID_MODE; } else { ri.Cvar_Set( "r_colorbits", "8" ); ri.Cvar_Set( "r_depthbits", "8" ); ri.Cvar_Set( "r_stencilbits", "0" ); ri.Cvar_Get( "r_mode", "", CVAR_ROM ); // disable latched value ri.Cvar_Set( "r_mode", "3" ); ri.Cvar_Set( "r_fullscreen", "0" ); ri.Printf( PRINT_ALL, "OK\n" ); } } else { ri.Printf( PRINT_ALL, "OK\n" ); } ri.Printf( PRINT_ALL, "Configuration : Using %d/%d/%d Color bits, %d depth, %d stencil display.\n", r, g, b, depthbits, stencilbits); ri.Printf( PRINT_ALL, "SDL/GL status :\n" ); if( SDL_GL_GetAttribute( SDL_GL_RED_SIZE, &r ) != 0 ) ri.Printf( PRINT_ALL, "Error getting red size : %s\n", SDL_GetError() ); if( SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, &g ) != 0 ) ri.Printf( PRINT_ALL, "Error getting green size : %s\n", SDL_GetError() ); if( SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, &b ) != 0 ) ri.Printf( PRINT_ALL, "Error getting blue size : %s\n", SDL_GetError() ); if( r==g && r==b && r!=0) ri.Printf( PRINT_ALL, "- color depth : %d (%d/%d/%d)\n", r+g+b, r, g, b ); else ri.Printf( PRINT_ALL, "- color depth : unknown (r=%d, g=%d, b=%d)\n", r, g, b ); if( SDL_GL_GetAttribute( SDL_GL_DEPTH_SIZE, &depth ) == 0) ri.Printf( PRINT_ALL, "- depth buffer size : %d\n", depth ); else ri.Printf( PRINT_ALL, "- depth buffer size : Error : %s\n", SDL_GetError() ); if( SDL_GL_GetAttribute( SDL_GL_STENCIL_SIZE, &stencil ) == 0) ri.Printf( PRINT_ALL, "- stencil buffer size : %d\n", stencil ); else ri.Printf( PRINT_ALL, "- stencil buffer size : Error : %s\n", SDL_GetError() ); if( SDL_GL_GetAttribute( SDL_GL_DOUBLEBUFFER, &doublebuffer ) == 0) ri.Printf( PRINT_ALL, "- double buffering : %s\n", doublebuffer==1? "enabled" : "disabled" ); else ri.Printf( PRINT_ALL, "- double buffering : Error : %s\n", SDL_GetError() ); glConfig.colorBits = r+g+b; glConfig.depthBits = depth; glConfig.stencilBits = stencil; glstring = qglGetString (GL_RENDERER); if ( !Q_stricmp( glstring, "Mesa X11") || !Q_stricmp( glstring, "Mesa GLX Indirect") ) { if ( !r_allowSoftwareGL->integer ) { ri.Printf( PRINT_ALL, "\nGL_RENDERER: %s\n", glstring ); ri.Printf( PRINT_ALL, "***********************************************************\n" ); ri.Printf( PRINT_ALL, " You are using software Mesa (no hardware acceleration)! \n" ); ri.Printf( PRINT_ALL, " Driver DLL used: %s\n", drivername ); ri.Printf( PRINT_ALL, " If this is intentional, add\n" ); ri.Printf( PRINT_ALL, " \"+set r_allowSoftwareGL 1\"\n" ); ri.Printf( PRINT_ALL, " to the command line when starting the game.\n" ); ri.Printf( PRINT_ALL, "***********************************************************\n"); GLimp_Shutdown( ); return RSERR_INVALID_MODE; } else { ri.Printf( PRINT_ALL, "...using software Mesa (r_allowSoftwareGL==1).\n" ); } } if (!in_nograb->value) { SDL_ShowCursor( SDL_DISABLE ); SDL_WM_GrabInput( SDL_GRAB_ON ); } /* KeyRepeat enabled for console and textboxes This don't change anytihng for gameplay */ SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); /* Unicode enabled for console and textboxes This is good because any keyboard is supported */ SDL_EnableUNICODE( 1 ); /* Window title */ SDL_WM_SetCaption( "Quake III arena", "quake3" ); return RSERR_OK; } /* ** GLW_InitExtensions */ static void GLW_InitExtensions( void ) { if ( !r_allowExtensions->integer ) { ri.Printf( PRINT_ALL, "*** IGNORING OPENGL EXTENSIONS ***\n" ); return; } ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" ); // GL_S3_s3tc if ( Q_stristr( glConfig.extensions_string, "GL_S3_s3tc" ) ) { if ( r_ext_compressed_textures->value ) { glConfig.textureCompression = TC_S3TC; ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" ); } else { glConfig.textureCompression = TC_NONE; ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" ); } } else { glConfig.textureCompression = TC_NONE; ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" ); } // GL_EXT_texture_env_add glConfig.textureEnvAddAvailable = qfalse; if ( Q_stristr( 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_ARB_multitexture qglMultiTexCoord2fARB = NULL; qglActiveTextureARB = NULL; qglClientActiveTextureARB = NULL; if ( Q_stristr( glConfig.extensions_string, "GL_ARB_multitexture" ) ) { if ( r_ext_multitexture->value ) { qglMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) SDL_LoadFunction (glw_state.OpenGLLib, "glMultiTexCoord2fARB"); qglActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_LoadFunction (glw_state.OpenGLLib, "glActiveTextureARB"); qglClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC) SDL_LoadFunction (glw_state.OpenGLLib, "glClientActiveTextureARB"); if ( qglActiveTextureARB ) { qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glConfig.maxActiveTextures ); if ( glConfig.maxActiveTextures > 1 ) { ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); } else { qglMultiTexCoord2fARB = NULL; qglActiveTextureARB = NULL; qglClientActiveTextureARB = NULL; ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\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 if ( Q_stristr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) ) { if ( r_ext_compiled_vertex_array->value ) { ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" ); qglLockArraysEXT = (void (APIENTRY *)(int, int)) SDL_LoadFunction (glw_state.OpenGLLib, "glLockArraysEXT"); qglUnlockArraysEXT = (void (APIENTRY *)(void )) SDL_LoadFunction (glw_state.OpenGLLib, "glUnlockArraysEXT"); if (!qglLockArraysEXT || !qglUnlockArraysEXT) { ri.Error (ERR_FATAL, "bad getprocaddress"); } } 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" ); } } static void GLW_InitGamma() { // We have to try SDL_SetGamma... glConfig.deviceSupportsGamma = qtrue; } /* ** GLW_LoadOpenGL ** ** GLimp_win.c internal function that that attempts to load and use ** a specific OpenGL DLL. */ static qboolean GLW_LoadOpenGL( const char *name ) { ri.Printf( PRINT_ALL, "...loading %s: ", name ); // disable the 3Dfx splash screen and set gamma // we do this all the time, but it shouldn't hurt anything // on non-3Dfx stuff putenv("FX_GLIDE_NO_SPLASH=0"); // Mesa VooDoo hacks putenv("MESA_GLX_FX=fullscreen\n"); // load the QGL layer if ( QGL_Init( name ) ) { // create the window and set up the context if ( !GLW_StartDriverAndSetMode( name, r_mode->integer, r_fullscreen->integer ) ) { ri.Printf( PRINT_ALL, "failed\n" ); QGL_Shutdown(); return qfalse; } } return qtrue; } /* ** GLimp_Init ** ** This routine is responsible for initializing the OS specific portions ** of OpenGL. */ void GLimp_Init( void ) { qboolean attemptedlibGL = qfalse; qboolean attempted3Dfx = qfalse; qboolean success = qfalse; char buf[1024]; cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE ); // guarded, as this is only relevant to SMP renderer thread #ifdef SMP // TODO : what to do with SDL/OpenGL in SMP mode? #endif r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); r_previousglDriver = ri.Cvar_Get( "r_previousglDriver", "", CVAR_ROM ); InitSig(); // Hack here so that if the UI if ( *r_previousglDriver->string ) { // The UI changed it on us, hack it back // This means the renderer can't be changed on the fly ri.Cvar_Set( "r_glDriver", r_previousglDriver->string ); } // // load and initialize the specific OpenGL driver // if ( !GLW_LoadOpenGL( r_glDriver->string ) ) { if ( !Q_stricmp( r_glDriver->string, OPENGL_DRIVER_NAME ) ) { attemptedlibGL = qtrue; } else if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) ) { attempted3Dfx = qtrue; } #if 0 // TTimo // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=455 // old legacy load code, was confusing people who had a bad OpenGL setup if ( !attempted3Dfx && !success ) { attempted3Dfx = qtrue; if ( GLW_LoadOpenGL( _3DFX_DRIVER_NAME ) ) { ri.Cvar_Set( "r_glDriver", _3DFX_DRIVER_NAME ); r_glDriver->modified = qfalse; success = qtrue; } } #endif // try ICD before trying 3Dfx standalone driver if ( !attemptedlibGL && !success ) { attemptedlibGL = qtrue; if ( GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) ) { ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME ); r_glDriver->modified = qfalse; success = qtrue; } } if (!success) ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" ); } // Save it in case the UI stomps it ri.Cvar_Set( "r_previousglDriver", r_glDriver->string ); // This values force the UI to disable driver selection glConfig.driverType = GLDRV_ICD; glConfig.hardwareType = GLHW_GENERIC; // get our config strings Q_strncpyz( glConfig.vendor_string, qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) ); Q_strncpyz( glConfig.renderer_string, qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) ); if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n') glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0; Q_strncpyz( glConfig.version_string, qglGetString (GL_VERSION), sizeof( glConfig.version_string ) ); Q_strncpyz( glConfig.extensions_string, qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) ); // // chipset specific configuration // strcpy( buf, glConfig.renderer_string ); strlwr( buf ); // // NOTE: if changing cvars, do it within this block. This allows them // to be overridden when testing driver fixes, etc. but only sets // them to their default state when the hardware is first installed/run. // if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) ) { glConfig.hardwareType = GLHW_GENERIC; ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); // VOODOO GRAPHICS w/ 2MB if ( Q_stristr( buf, "voodoo graphics/1 tmu/2 mb" ) ) { ri.Cvar_Set( "r_picmip", "2" ); ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); } else { ri.Cvar_Set( "r_picmip", "1" ); if ( Q_stristr( buf, "rage 128" ) || Q_stristr( buf, "rage128" ) ) { ri.Cvar_Set( "r_finish", "0" ); } // Savage3D and Savage4 should always have trilinear enabled else if ( Q_stristr( buf, "savage3d" ) || Q_stristr( buf, "s3 savage4" ) ) { ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); } } } // // this is where hardware specific workarounds that should be // detected/initialized every startup should go. // if ( Q_stristr( buf, "banshee" ) || Q_stristr( buf, "Voodoo_Graphics" ) ) { glConfig.hardwareType = GLHW_3DFX_2D3D; } else if ( Q_stristr( buf, "rage pro" ) || Q_stristr( buf, "RagePro" ) ) { glConfig.hardwareType = GLHW_RAGEPRO; } else if ( Q_stristr( buf, "permedia2" ) ) { glConfig.hardwareType = GLHW_PERMEDIA2; } else if ( Q_stristr( buf, "riva 128" ) ) { glConfig.hardwareType = GLHW_RIVA128; } else if ( Q_stristr( buf, "riva tnt " ) ) { } ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string ); // initialize extensions GLW_InitExtensions(); GLW_InitGamma(); InitSig(); // not clear why this is at begin & end of function return; } /* ** GLimp_EndFrame ** ** Responsible for doing a swapbuffers and possibly for other stuff ** as yet to be determined. Probably better not to make this a GLimp ** function and instead do a call to GLimp_SwapBuffers. */ void GLimp_EndFrame (void) { // Just call GL_SwapBuffers() // This should work with single-buffer too SDL_GL_SwapBuffers(); // check logging QGL_EnableLogging( (qboolean)r_logFile->integer ); // bk001205 - was ->value } // TODO : handle SMP void GLimp_RenderThreadWrapper( void *stub ) {} qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) { ri.Printf( PRINT_WARNING, "ERROR: SMP support was disabled at compile time\n"); return qfalse; } void *GLimp_RendererSleep( void ) { return NULL; } void GLimp_FrontEndSleep( void ) {} void GLimp_WakeRenderer( void *data ) {} /*****************************************************************************/ /* Input */ /*****************************************************************************/ void IN_Init(void) { Com_Printf ("\n------- Input Initialization -------\n"); in_nograb = Cvar_Get ("in_nograb", "0", 0); in_joythreshold = Cvar_Get ("in_joythreshold", "0.15", CVAR_ARCHIVE); IN_StartupJoystick( ); Com_Printf ("------------------------------------\n"); } void IN_Frame (void) {} void IN_Shutdown(void) { IN_ShutdownJoystick(); } void Sys_SendKeyEvents (void) { HandleEvents(); }