From 8f7968cb9c59355f4cfbefbb5e7166f242e81f90 Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Tue, 30 Apr 2013 13:33:52 +1000 Subject: [PATCH 1/3] add sdl glimp/input from ioquake3 for SP --- code/CMakeLists.txt | 25 +- code/client/cl_main.cpp | 5 + code/client/client.h | 4 + code/game/q_shared.cpp | 38 + code/game/q_shared.h | 3 + code/renderer/qgl.h | 19 +- code/renderer/tr_init.cpp | 4 - code/sdl/sdl_gamma.cpp | 92 +++ code/sdl/sdl_glimp.cpp | 1225 +++++++++++++++++++++++++++++++ code/sdl/sdl_input.cpp | 1107 ++++++++++++++++++++++++++++ code/sdl/sdl_local.h | 11 + code/unix/unix_glimp_common.cpp | 82 +++ code/unix/unix_main.cpp | 2 +- 13 files changed, 2601 insertions(+), 16 deletions(-) create mode 100644 code/sdl/sdl_gamma.cpp create mode 100644 code/sdl/sdl_glimp.cpp create mode 100644 code/sdl/sdl_input.cpp create mode 100644 code/sdl/sdl_local.h create mode 100644 code/unix/unix_glimp_common.cpp diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index b8d152c..5a6fbff 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -33,12 +33,14 @@ add_definitions( -D_IMMERSION_DISABLE ) add_definitions( -DNDEBUG ) add_definitions( -DFINAL_BUILD ) -include_directories(/usr/X11R6/include/) -link_directories(/usr/X11R6/lib) +find_package (SDL REQUIRED) +include_directories(${SDL_INCLUDE_DIR}) -include_directories(/usr/local/include/) -link_directories(/usr/local/lib) +find_package(OpenGL REQUIRED) +include_directories(${OPENGL_INCLUDE_DIR}) +find_package(OpenAL REQUIRED) +include_directories(${OPENAL_INCLUDE_DIR}) set(src_main_rmg RMG/RM_Area.cpp @@ -272,11 +274,16 @@ set(src_main_zlib set(src_main_unix unix/unix_main.cpp unix/unix_shared.cpp - unix/linux_glimp.cpp - unix/linux_qgl.cpp + unix/unix_glimp_common.cpp null/null_snddma.cpp ) +set(src_sdl + sdl/sdl_gamma.cpp + sdl/sdl_glimp.cpp + sdl/sdl_input.cpp +) + set(src_starwars ${src_main_rmg} ${src_main_client} @@ -292,6 +299,7 @@ set(src_starwars ${src_main_ui} ${src_main_zlib} ${src_main_unix} + ${src_sdl} ) add_executable(jasp @@ -302,8 +310,9 @@ set_target_properties(jasp PROPERTIES COMPILE_DEFINITIONS "_JK2EXE;_FF_DISABLE") target_link_libraries(jasp m pthread - X11 Xxf86vm Xxf86dga - openal + ${SDL_LIBRARY} + ${OPENGL_gl_LIBRARY} + ${OPENAL_LIBRARY} ) if (CMAKE_SYSTEM_NAME MATCHES "Linux") diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index 01b786c..ff455e2 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -79,6 +79,8 @@ cvar_t *cl_ingameVideo; cvar_t *cl_thumbStickMode; +cvar_t *cl_consoleKeys; + clientActive_t cl; clientConnection_t clc; clientStatic_t cls; @@ -1265,6 +1267,9 @@ void CL_Init( void ) { cl_updateInfoString = Cvar_Get( "cl_updateInfoString", "", CVAR_ROM ); + // ~ and `, as keys and characters + cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60", CVAR_ARCHIVE); + // userinfo Cvar_Get ("name", "Jaden", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("snaps", "20", CVAR_USERINFO | CVAR_ARCHIVE ); diff --git a/code/client/client.h b/code/client/client.h index 5d513b6..bdadce6 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -305,6 +305,8 @@ extern cvar_t *cl_activeAction; extern cvar_t *cl_thumbStickMode; +extern cvar_t *cl_consoleKeys; + //================================================= // @@ -352,6 +354,7 @@ void CL_WritePacket( void ); void IN_CenterView (void); float CL_KeyState (kbutton_t *key); +int Key_StringToKeynum( char *str ); const char *Key_KeynumToString( int keynum/*, qboolean bTranslate*/ ); //note: translate is only called for menu display not configs // @@ -458,6 +461,7 @@ void CL_FirstSnapshot( void ); // void CL_InitUI( void ); void CL_ShutdownUI( void ); +int Key_GetCatcher( void ); void CL_GenericMenu_f(void); void CL_DataPad_f(void); void CL_EndScreenDissolve_f(void); diff --git a/code/game/q_shared.cpp b/code/game/q_shared.cpp index ca9cb5a..1cf3bcd 100644 --- a/code/game/q_shared.cpp +++ b/code/game/q_shared.cpp @@ -585,6 +585,44 @@ void Parse3DMatrix ( const char **buf_p, int z, int y, int x, float *m) { COM_MatchToken( buf_p, ")" ); } +/* +=================== +Com_HexStrToInt +=================== +*/ +int Com_HexStrToInt( const char *str ) +{ + if ( !str || !str[ 0 ] ) + return -1; + + // check for hex code + if( str[ 0 ] == '0' && str[ 1 ] == 'x' ) + { + int i, n = 0; + + for( i = 2; i < strlen( str ); i++ ) + { + char digit; + + n *= 16; + + digit = tolower( str[ i ] ); + + if( digit >= '0' && digit <= '9' ) + digit -= '0'; + else if( digit >= 'a' && digit <= 'f' ) + digit = digit - 'a' + 10; + else + return -1; + + n += digit; + } + + return n; + } + + return -1; +} /* ============================================================================ diff --git a/code/game/q_shared.h b/code/game/q_shared.h index e066ce5..759886f 100644 --- a/code/game/q_shared.h +++ b/code/game/q_shared.h @@ -226,6 +226,8 @@ typedef int clipHandle_t; #define MAX_QINT 0x7fffffff #define MIN_QINT (-MAX_QINT-1) +#define ARRAY_LEN(x) (sizeof(x) / sizeof(*(x))) +#define STRARRAY_LEN(x) (ARRAY_LEN(x) - 1) // angle indexes #define PITCH 0 // up / down @@ -1207,6 +1209,7 @@ void SkipRestOfLine ( const char **data ); void Parse1DMatrix (const char **buf_p, int x, float *m); void Parse2DMatrix (const char **buf_p, int y, int x, float *m); void Parse3DMatrix (const char **buf_p, int z, int y, int x, float *m); +int Com_HexStrToInt( const char *str ); void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...); diff --git a/code/renderer/qgl.h b/code/renderer/qgl.h index 15e42f6..e1d4781 100644 --- a/code/renderer/qgl.h +++ b/code/renderer/qgl.h @@ -5,7 +5,17 @@ #ifndef __QGL_H__ #define __QGL_H__ -#if defined( __LINT__ ) +#ifndef DYNAMIC_LINK_GL + +#ifdef USE_LOCAL_HEADERS +# include "SDL_opengl.h" +#else +# include +#endif + +#include "qgl_linked.h" + +#elif defined( __LINT__ ) #include @@ -29,7 +39,7 @@ #include #include -#endif +#endif // !DYNAMIC_LINK_GL #ifndef APIENTRY #define APIENTRY @@ -328,6 +338,8 @@ extern void ( APIENTRY * qglPointParameterfvEXT)( GLenum, GLfloat *); extern void ( APIENTRY * qglPointParameteriNV)( GLenum, GLint); extern void ( APIENTRY * qglPointParameterivNV)( GLenum, const GLint *); +#ifdef DYNAMIC_LINK_GL + //=========================================================================== // windows systems use a function pointer for each call so we can load minidrivers @@ -708,4 +720,5 @@ extern void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable ); #endif // _WIN32 -#endif +#endif // DYNAMIC_LINK_GL +#endif // __QGL_H__ diff --git a/code/renderer/tr_init.cpp b/code/renderer/tr_init.cpp index 4955d4e..ad31a0d 100644 --- a/code/renderer/tr_init.cpp +++ b/code/renderer/tr_init.cpp @@ -1144,11 +1144,7 @@ void R_Register( void ) r_texturebitslm = Cvar_Get( "r_texturebitslm", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_colorbits = Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_stereo = Cvar_Get( "r_stereo", "0", CVAR_ARCHIVE | CVAR_LATCH ); -#ifdef __linux__ - r_stencilbits = Cvar_Get( "r_stencilbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); -#else r_stencilbits = Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH ); -#endif r_depthbits = Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_overBrightBits = Cvar_Get ("r_overBrightBits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_ignorehwgamma = Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); diff --git a/code/sdl/sdl_gamma.cpp b/code/sdl/sdl_gamma.cpp new file mode 100644 index 0000000..ef2a520 --- /dev/null +++ b/code/sdl/sdl_gamma.cpp @@ -0,0 +1,92 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#ifdef USE_LOCAL_HEADERS +# include "SDL.h" +#else +# include +#endif + +#include "../game/q_shared.h" +#include "../renderer/tr_local.h" +#include "../qcommon/qcommon.h" + +/* +================= +GLimp_SetGamma +================= +*/ +void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] ) +{ + Uint16 table[3][256]; + int i, j; + + if( !glConfig.deviceSupportsGamma || r_ignorehwgamma->integer > 0 ) + return; + + for (i = 0; i < 256; i++) + { + table[0][i] = ( ( ( Uint16 ) red[i] ) << 8 ) | red[i]; + table[1][i] = ( ( ( Uint16 ) green[i] ) << 8 ) | green[i]; + table[2][i] = ( ( ( Uint16 ) blue[i] ) << 8 ) | blue[i]; + } + +#ifdef _WIN32 +#include + + // Win2K and newer put this odd restriction on gamma ramps... + { + OSVERSIONINFO vinfo; + + vinfo.dwOSVersionInfoSize = sizeof( vinfo ); + GetVersionEx( &vinfo ); + if( vinfo.dwMajorVersion >= 5 && vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) + { + ri.Printf( PRINT_DEVELOPER, "performing gamma clamp.\n" ); + for( j = 0 ; j < 3 ; j++ ) + { + for( i = 0 ; i < 128 ; i++ ) + { + if( table[ j ] [ i] > ( ( 128 + i ) << 8 ) ) + table[ j ][ i ] = ( 128 + i ) << 8; + } + + if( table[ j ] [127 ] > 254 << 8 ) + table[ j ][ 127 ] = 254 << 8; + } + } + } +#endif + + // enforce constantly increasing + for (j = 0; j < 3; j++) + { + for (i = 1; i < 256; i++) + { + if (table[j][i] < table[j][i-1]) + table[j][i] = table[j][i-1]; + } + } + + SDL_SetGammaRamp(table[0], table[1], table[2]); +} + diff --git a/code/sdl/sdl_glimp.cpp b/code/sdl/sdl_glimp.cpp new file mode 100644 index 0000000..b91626f --- /dev/null +++ b/code/sdl/sdl_glimp.cpp @@ -0,0 +1,1225 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#ifdef USE_LOCAL_HEADERS +# include "SDL.h" +#else +# include +#endif + +#include +#include +#include +#include + +#include "../renderer/tr_local.h" +#include "sdl_local.h" +#ifdef notyet +#include "sdl_icon.h" +#endif + +#define CLIENT_WINDOW_TITLE "Jedi Outcast" +#define CLIENT_WINDOW_MIN_TITLE "JO" + +/* Just hack it for now. */ +#ifdef MACOS_X +#include +typedef CGLContextObj QGLContext; +#define GLimp_GetCurrentContext() CGLGetCurrentContext() +#define GLimp_SetCurrentContext(ctx) CGLSetCurrentContext(ctx) +#else +typedef void *QGLContext; +#define GLimp_GetCurrentContext() (NULL) +#define GLimp_SetCurrentContext(ctx) +#endif + +static QGLContext opengl_context; +static float displayAspect; + +typedef enum +{ + RSERR_OK, + + RSERR_INVALID_FULLSCREEN, + RSERR_INVALID_MODE, + + RSERR_UNKNOWN +} rserr_t; + +static SDL_Surface *screen = NULL; +static const SDL_VideoInfo *videoInfo = NULL; + +cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obtained +cvar_t *r_allowResize; // make window resizable +cvar_t *r_centerWindow; +cvar_t *r_sdlDriver; +cvar_t *r_noborder; + +// Whether the current hardware supports dynamic glows/flares. +extern bool g_bDynamicGlowSupported; + +// Hack variable for deciding which kind of texture rectangle thing to do (for some +// reason it acts different on radeon! It's against the spec!). +bool g_bTextureRectangleHack = false; + +/* +=============== +GLimp_Shutdown +=============== +*/ +void GLimp_Shutdown( void ) +{ + IN_Shutdown(); + + SDL_QuitSubSystem( SDL_INIT_VIDEO ); + screen = NULL; +} + +/* +=============== +GLimp_Minimize + +Minimize the game so that user is back at the desktop +=============== +*/ +void GLimp_Minimize(void) +{ + SDL_WM_IconifyWindow(); +} + + +/* +=============== +GLimp_LogComment +=============== +*/ +void GLimp_LogComment( char *comment ) +{ +} + +/* +=============== +GLimp_CompareModes +=============== +*/ +static int GLimp_CompareModes( const void *a, const void *b ) +{ + const float ASPECT_EPSILON = 0.001f; + SDL_Rect *modeA = *(SDL_Rect **)a; + SDL_Rect *modeB = *(SDL_Rect **)b; + float aspectA = (float)modeA->w / (float)modeA->h; + float aspectB = (float)modeB->w / (float)modeB->h; + int areaA = modeA->w * modeA->h; + int areaB = modeB->w * modeB->h; + float aspectDiffA = fabs( aspectA - displayAspect ); + float aspectDiffB = fabs( aspectB - displayAspect ); + float aspectDiffsDiff = aspectDiffA - aspectDiffB; + + if( aspectDiffsDiff > ASPECT_EPSILON ) + return 1; + else if( aspectDiffsDiff < -ASPECT_EPSILON ) + return -1; + else + return areaA - areaB; +} + + +/* +=============== +GLimp_DetectAvailableModes +=============== +*/ +static void GLimp_DetectAvailableModes(void) +{ + char buf[ MAX_STRING_CHARS ] = { 0 }; + SDL_Rect **modes; + int numModes; + int i; + + modes = SDL_ListModes( videoInfo->vfmt, SDL_OPENGL | SDL_FULLSCREEN ); + + if( !modes ) + { + VID_Printf( PRINT_WARNING, "Can't get list of available modes\n" ); + return; + } + + if( modes == (SDL_Rect **)-1 ) + { + VID_Printf( PRINT_ALL, "Display supports any resolution\n" ); + return; // can set any resolution + } + + for( numModes = 0; modes[ numModes ]; numModes++ ); + + if( numModes > 1 ) + qsort( modes, numModes, sizeof( SDL_Rect* ), GLimp_CompareModes ); + + for( i = 0; i < numModes; i++ ) + { + const char *newModeString = va( "%ux%u ", modes[ i ]->w, modes[ i ]->h ); + + if( strlen( newModeString ) < (int)sizeof( buf ) - strlen( buf ) ) + Q_strcat( buf, sizeof( buf ), newModeString ); + else + VID_Printf( PRINT_WARNING, "Skipping mode %ux%x, buffer too small\n", modes[i]->w, modes[i]->h ); + } + + if( *buf ) + { + buf[ strlen( buf ) - 1 ] = 0; + VID_Printf( PRINT_ALL, "Available modes: '%s'\n", buf ); + Cvar_Set( "r_availableModes", buf ); + } +} + +/* +=============== +GLimp_SetMode +=============== +*/ +static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) +{ + const char* glstring; + int sdlcolorbits; + int colorbits, depthbits, stencilbits; + int tcolorbits, tdepthbits, tstencilbits; + int samples; + int i = 0; + SDL_Surface *vidscreen = NULL; + Uint32 flags = SDL_OPENGL; + + VID_Printf( PRINT_ALL, "Initializing OpenGL display\n"); + + if ( r_allowResize->integer ) + flags |= SDL_RESIZABLE; + + if( videoInfo == NULL ) + { + static SDL_VideoInfo sVideoInfo; + static SDL_PixelFormat sPixelFormat; + + videoInfo = SDL_GetVideoInfo( ); + + // Take a copy of the videoInfo + memcpy( &sPixelFormat, videoInfo->vfmt, sizeof( SDL_PixelFormat ) ); + sPixelFormat.palette = NULL; // Should already be the case + memcpy( &sVideoInfo, videoInfo, sizeof( SDL_VideoInfo ) ); + sVideoInfo.vfmt = &sPixelFormat; + videoInfo = &sVideoInfo; + + if( videoInfo->current_h > 0 ) + { + // Guess the display aspect ratio through the desktop resolution + // by assuming (relatively safely) that it is set at or close to + // the display's native aspect ratio + displayAspect = (float)videoInfo->current_w / (float)videoInfo->current_h; + + VID_Printf( PRINT_ALL, "Estimated display aspect: %.3f\n", displayAspect ); + } + else + { + VID_Printf( PRINT_ALL, + "Cannot estimate display aspect, assuming 1.333\n" ); + } + } + + VID_Printf (PRINT_ALL, "...setting mode %d:", mode ); + + if (mode == -2) + { + // use desktop video resolution + if( videoInfo->current_h > 0 ) + { + glConfig.vidWidth = videoInfo->current_w; + glConfig.vidHeight = videoInfo->current_h; + } + else + { + glConfig.vidWidth = 640; + glConfig.vidHeight = 480; + VID_Printf( PRINT_ALL, + "Cannot determine display resolution, assuming 640x480\n" ); + } + +#if 0 + glConfig.windowAspect = (float)glConfig.vidWidth / (float)glConfig.vidHeight; +#endif + } + else if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, mode ) ) + { + VID_Printf( PRINT_ALL, " invalid mode\n" ); + return RSERR_INVALID_MODE; + } + VID_Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight); + + if (fullscreen) + { + flags |= SDL_FULLSCREEN; + glConfig.isFullscreen = qtrue; + } + else + { + if (noborder) + flags |= SDL_NOFRAME; + + glConfig.isFullscreen = qfalse; + } + + colorbits = r_colorbits->value; + if ((!colorbits) || (colorbits >= 32)) + colorbits = 24; + + if (!r_depthbits->value) + depthbits = 24; + else + depthbits = r_depthbits->value; + stencilbits = r_stencilbits->value; +#ifdef notyet + samples = r_ext_multisample->value; +#else + samples = 0; +#endif + + for (i = 0; i < 16; i++) + { + // 0 - default + // 1 - minus colorbits + // 2 - minus depthbits + // 3 - minus stencil + if ((i % 4) == 0 && i) + { + // one pass, reduce + switch (i / 4) + { + case 2 : + if (colorbits == 24) + colorbits = 16; + break; + case 1 : + if (depthbits == 24) + depthbits = 16; + else if (depthbits == 16) + depthbits = 8; + case 3 : + if (stencilbits == 24) + stencilbits = 16; + else if (stencilbits == 16) + stencilbits = 8; + } + } + + tcolorbits = colorbits; + tdepthbits = depthbits; + tstencilbits = stencilbits; + + if ((i % 4) == 3) + { // reduce colorbits + if (tcolorbits == 24) + tcolorbits = 16; + } + + if ((i % 4) == 2) + { // reduce depthbits + if (tdepthbits == 24) + tdepthbits = 16; + else if (tdepthbits == 16) + tdepthbits = 8; + } + + if ((i % 4) == 1) + { // reduce stencilbits + if (tstencilbits == 24) + tstencilbits = 16; + else if (tstencilbits == 16) + tstencilbits = 8; + else + tstencilbits = 0; + } + + sdlcolorbits = 4; + if (tcolorbits == 24) + sdlcolorbits = 8; + +#ifdef __sgi /* Fix for SGIs grabbing too many bits of color */ + if (sdlcolorbits == 4) + sdlcolorbits = 0; /* Use minimum size for 16-bit color */ + + /* Need alpha or else SGIs choose 36+ bit RGB mode */ + SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 1); +#endif + + SDL_GL_SetAttribute( SDL_GL_RED_SIZE, sdlcolorbits ); + SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, sdlcolorbits ); + SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, sdlcolorbits ); + SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits ); + SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits ); + + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0 ); + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, samples ); + +#ifdef notyet + if(r_stereoEnabled->integer) + { + glConfig.stereoEnabled = qtrue; + SDL_GL_SetAttribute(SDL_GL_STEREO, 1); + } + else + { + glConfig.stereoEnabled = qfalse; + SDL_GL_SetAttribute(SDL_GL_STEREO, 0); + } +#endif + + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + +#if 0 // See http://bugzilla.icculus.org/show_bug.cgi?id=3526 + // If not allowing software GL, demand accelerated + if( !r_allowSoftwareGL->integer ) + { + if( SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 ) < 0 ) + { + VID_Printf( PRINT_ALL, "Unable to guarantee accelerated " + "visual with libSDL < 1.2.10\n" ); + } + } +#endif + + if( SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, r_swapInterval->integer ) < 0 ) + VID_Printf( PRINT_ALL, "r_swapInterval requires libSDL >= 1.2.10\n" ); + +#ifdef USE_ICON + { + SDL_Surface *icon = SDL_CreateRGBSurfaceFrom( + (void *)CLIENT_WINDOW_ICON.pixel_data, + CLIENT_WINDOW_ICON.width, + CLIENT_WINDOW_ICON.height, + CLIENT_WINDOW_ICON.bytes_per_pixel * 8, + CLIENT_WINDOW_ICON.bytes_per_pixel * CLIENT_WINDOW_ICON.width, +#ifdef Q3_LITTLE_ENDIAN + 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 +#else + 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF +#endif + ); + + SDL_WM_SetIcon( icon, NULL ); + SDL_FreeSurface( icon ); + } +#endif + + SDL_WM_SetCaption(CLIENT_WINDOW_TITLE, CLIENT_WINDOW_MIN_TITLE); + SDL_ShowCursor(0); + + if (!(vidscreen = SDL_SetVideoMode(glConfig.vidWidth, glConfig.vidHeight, colorbits, flags))) + { + VID_Printf( PRINT_DEVELOPER, "SDL_SetVideoMode failed: %s\n", SDL_GetError( ) ); + continue; + } + + opengl_context = GLimp_GetCurrentContext(); + + VID_Printf( PRINT_ALL, "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n", + sdlcolorbits, sdlcolorbits, sdlcolorbits, tdepthbits, tstencilbits); + + glConfig.colorBits = tcolorbits; + glConfig.depthBits = tdepthbits; + glConfig.stencilBits = tstencilbits; + break; + } + + GLimp_DetectAvailableModes(); + + if (!vidscreen) + { + VID_Printf( PRINT_ALL, "Couldn't get a visual\n" ); + return RSERR_INVALID_MODE; + } + + screen = vidscreen; + + glstring = (char *) qglGetString (GL_RENDERER); + VID_Printf( PRINT_ALL, "GL_RENDERER: %s\n", glstring ); + + return RSERR_OK; +} + +/* +=============== +GLimp_StartDriverAndSetMode +=============== +*/ +static qboolean GLimp_StartDriverAndSetMode(int mode, qboolean fullscreen, qboolean noborder) +{ + rserr_t err; + + if (!SDL_WasInit(SDL_INIT_VIDEO)) + { + char driverName[ 64 ]; + + if (SDL_Init(SDL_INIT_VIDEO) == -1) + { + VID_Printf( PRINT_ALL, "SDL_Init( SDL_INIT_VIDEO ) FAILED (%s)\n", + SDL_GetError()); + return qfalse; + } + + SDL_VideoDriverName( driverName, sizeof( driverName ) - 1 ); + VID_Printf( PRINT_ALL, "SDL using driver \"%s\"\n", driverName ); + Cvar_Set( "r_sdlDriver", driverName ); + } + + if (fullscreen && Cvar_VariableIntegerValue( "in_nograb" ) ) + { + VID_Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n"); + Cvar_Set( "r_fullscreen", "0" ); + r_fullscreen->modified = qfalse; + fullscreen = qfalse; + } + + err = (rserr_t) GLimp_SetMode(mode, fullscreen, noborder); + + switch ( err ) + { + case RSERR_INVALID_FULLSCREEN: + VID_Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" ); + return qfalse; + case RSERR_INVALID_MODE: + VID_Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode ); + return qfalse; + default: + break; + } + + return qtrue; +} + +//-------------------------------------------- +static void GLW_InitTextureCompression( void ) +{ + qboolean newer_tc, old_tc; + + // Check for available tc methods. + newer_tc = ( strstr( glConfig.extensions_string, "ARB_texture_compression" ) + && strstr( glConfig.extensions_string, "EXT_texture_compression_s3tc" )) ? qtrue : qfalse; + old_tc = ( strstr( glConfig.extensions_string, "GL_S3_s3tc" )) ? qtrue : qfalse; + + if ( old_tc ) + { + VID_Printf( PRINT_ALL, "...GL_S3_s3tc available\n" ); + } + + if ( newer_tc ) + { + VID_Printf( PRINT_ALL, "...GL_EXT_texture_compression_s3tc available\n" ); + } + + if ( !r_ext_compressed_textures->value ) + { + // Compressed textures are off + glConfig.textureCompression = TC_NONE; + VID_Printf( PRINT_ALL, "...ignoring texture compression\n" ); + } + else if ( !old_tc && !newer_tc ) + { + // Requesting texture compression, but no method found + glConfig.textureCompression = TC_NONE; + VID_Printf( PRINT_ALL, "...no supported texture compression method found\n" ); + VID_Printf( PRINT_ALL, ".....ignoring texture compression\n" ); + } + else + { + // some form of supported texture compression is avaiable, so see if the user has a preference + if ( r_ext_preferred_tc_method->integer == TC_NONE ) + { + // No preference, so pick the best + if ( newer_tc ) + { + VID_Printf( PRINT_ALL, "...no tc preference specified\n" ); + VID_Printf( PRINT_ALL, ".....using GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + else + { + VID_Printf( PRINT_ALL, "...no tc preference specified\n" ); + VID_Printf( PRINT_ALL, ".....using GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + } + else + { + // User has specified a preference, now see if this request can be honored + if ( old_tc && newer_tc ) + { + // both are avaiable, so we can use the desired tc method + if ( r_ext_preferred_tc_method->integer == TC_S3TC ) + { + VID_Printf( PRINT_ALL, "...using preferred tc method, GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + else + { + VID_Printf( PRINT_ALL, "...using preferred tc method, GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + } + else + { + // Both methods are not available, so this gets trickier + if ( r_ext_preferred_tc_method->integer == TC_S3TC ) + { + // Preferring to user older compression + if ( old_tc ) + { + VID_Printf( PRINT_ALL, "...using GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + else + { + // Drat, preference can't be honored + VID_Printf( PRINT_ALL, "...preferred tc method, GL_S3_s3tc not available\n" ); + VID_Printf( PRINT_ALL, ".....falling back to GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + } + else + { + // Preferring to user newer compression + if ( newer_tc ) + { + VID_Printf( PRINT_ALL, "...using GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + else + { + // Drat, preference can't be honored + VID_Printf( PRINT_ALL, "...preferred tc method, GL_EXT_texture_compression_s3tc not available\n" ); + VID_Printf( PRINT_ALL, ".....falling back to GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + } + } + } + } +} + +/* +** GLW_InitExtensions +*/ +static void GLimp_InitExtensions( void ) +{ + if ( !r_allowExtensions->integer ) + { + VID_Printf( PRINT_ALL, "*** IGNORING OPENGL EXTENSIONS ***\n" ); + g_bDynamicGlowSupported = false; + Cvar_Set( "r_DynamicGlow","0" ); + return; + } + + VID_Printf( PRINT_ALL, "Initializing OpenGL extensions\n" ); + + // Select our tc scheme + GLW_InitTextureCompression(); + + // 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; + VID_Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); + } + else + { + glConfig.textureEnvAddAvailable = qfalse; + VID_Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" ); + } + } + else + { + VID_Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" ); + } + + // GL_EXT_texture_filter_anisotropic + glConfig.maxTextureFilterAnisotropy = 0; + if ( strstr( glConfig.extensions_string, "EXT_texture_filter_anisotropic" ) ) + { +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF //can't include glext.h here ... sigh + qglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.maxTextureFilterAnisotropy ); + Com_Printf ("...GL_EXT_texture_filter_anisotropic available\n" ); + + if ( r_ext_texture_filter_anisotropic->integer>1 ) + { + Com_Printf ("...using GL_EXT_texture_filter_anisotropic\n" ); + } + else + { + Com_Printf ("...ignoring GL_EXT_texture_filter_anisotropic\n" ); + } + Cvar_Set( "r_ext_texture_filter_anisotropic_avail", va("%f",glConfig.maxTextureFilterAnisotropy) ); + if ( r_ext_texture_filter_anisotropic->value > glConfig.maxTextureFilterAnisotropy ) + { + Cvar_Set( "r_ext_texture_filter_anisotropic", va("%f",glConfig.maxTextureFilterAnisotropy) ); + } + } + else + { + Com_Printf ("...GL_EXT_texture_filter_anisotropic not found\n" ); + Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "0" ); + } + + // GL_EXT_clamp_to_edge + glConfig.clampToEdgeAvailable = qfalse; + if ( strstr( glConfig.extensions_string, "GL_EXT_texture_edge_clamp" ) ) + { + glConfig.clampToEdgeAvailable = qtrue; + VID_Printf( PRINT_ALL, "...Using GL_EXT_texture_edge_clamp\n" ); + } + +#if 0 + // WGL_EXT_swap_control + qwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) SDL_GL_GetProcAddress( "wglSwapIntervalEXT" ); + if ( qwglSwapIntervalEXT ) + { + VID_Printf( PRINT_ALL, "...using WGL_EXT_swap_control\n" ); + r_swapInterval->modified = qtrue; // force a set next frame + } + else + { + VID_Printf( PRINT_ALL, "...WGL_EXT_swap_control not found\n" ); + } +#endif + + // GL_ARB_multitexture + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + if ( strstr( glConfig.extensions_string, "GL_ARB_multitexture" ) ) + { + if ( r_ext_multitexture->integer ) + { + qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) SDL_GL_GetProcAddress( "glMultiTexCoord2fARB" ); + qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) SDL_GL_GetProcAddress( "glActiveTextureARB" ); + qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) SDL_GL_GetProcAddress( "glClientActiveTextureARB" ); + + if ( qglActiveTextureARB ) + { + qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glConfig.maxActiveTextures ); + + if ( glConfig.maxActiveTextures > 1 ) + { + VID_Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); + } + else + { + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + VID_Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" ); + } + } + } + else + { + VID_Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); + } + } + else + { + VID_Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); + } + + // GL_EXT_compiled_vertex_array + qglLockArraysEXT = NULL; + qglUnlockArraysEXT = NULL; + if ( strstr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) ) + { + if ( r_ext_compiled_vertex_array->integer ) + { + VID_Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" ); + qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) SDL_GL_GetProcAddress( "glLockArraysEXT" ); + qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) SDL_GL_GetProcAddress( "glUnlockArraysEXT" ); + if (!qglLockArraysEXT || !qglUnlockArraysEXT) { + Com_Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + VID_Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); + } + } + else + { + VID_Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); + } + + // GL_EXT_point_parameters + qglPointParameterfEXT = NULL; + qglPointParameterfvEXT = NULL; + if ( strstr( glConfig.extensions_string, "GL_EXT_point_parameters" ) ) + { + if ( r_ext_point_parameters->integer ) + { + qglPointParameterfEXT = ( void ( APIENTRY * )( GLenum, GLfloat) ) SDL_GL_GetProcAddress( "glPointParameterfEXT" ); + qglPointParameterfvEXT = ( void ( APIENTRY * )( GLenum, GLfloat *) ) SDL_GL_GetProcAddress( "glPointParameterfvEXT" ); + if (!qglPointParameterfEXT || !qglPointParameterfvEXT) + { + VID_Printf( ERR_FATAL, "Bad GetProcAddress for GL_EXT_point_parameters"); + } + VID_Printf( PRINT_ALL, "...using GL_EXT_point_parameters\n" ); + } + else + { + VID_Printf( PRINT_ALL, "...ignoring GL_EXT_point_parameters\n" ); + } + } + else + { + VID_Printf( PRINT_ALL, "...GL_EXT_point_parameters not found\n" ); + } + + // GL_NV_point_sprite + qglPointParameteriNV = NULL; + qglPointParameterivNV = NULL; + if ( strstr( glConfig.extensions_string, "GL_NV_point_sprite" ) ) + { + if ( r_ext_nv_point_sprite->integer ) + { + qglPointParameteriNV = ( void ( APIENTRY * )( GLenum, GLint) ) SDL_GL_GetProcAddress( "glPointParameteriNV" ); + qglPointParameterivNV = ( void ( APIENTRY * )( GLenum, const GLint *) ) SDL_GL_GetProcAddress( "glPointParameterivNV" ); + if (!qglPointParameteriNV || !qglPointParameterivNV) + { + VID_Printf( ERR_FATAL, "Bad GetProcAddress for GL_NV_point_sprite"); + } + VID_Printf( PRINT_ALL, "...using GL_NV_point_sprite\n" ); + } + else + { + VID_Printf( PRINT_ALL, "...ignoring GL_NV_point_sprite\n" ); + } + } + else + { + VID_Printf( PRINT_ALL, "...GL_NV_point_sprite not found\n" ); + } + + bool bNVRegisterCombiners = false; + // Register Combiners. + if ( strstr( glConfig.extensions_string, "GL_NV_register_combiners" ) ) + { + // NOTE: This extension requires multitexture support (over 2 units). + if ( glConfig.maxActiveTextures >= 2 ) + { + bNVRegisterCombiners = true; + // Register Combiners function pointer address load. - AReis + // NOTE: VV guys will _definetly_ not be able to use regcoms. Pixel Shaders are just as good though :-) + // NOTE: Also, this is an nVidia specific extension (of course), so fragment shaders would serve the same purpose + // if we needed some kind of fragment/pixel manipulation support. + qglCombinerParameterfvNV = ( PFNGLCOMBINERPARAMETERFVNV ) SDL_GL_GetProcAddress( "glCombinerParameterfvNV" ); + qglCombinerParameterivNV = ( PFNGLCOMBINERPARAMETERIVNV ) SDL_GL_GetProcAddress( "glCombinerParameterivNV" ); + qglCombinerParameterfNV = ( PFNGLCOMBINERPARAMETERFNV ) SDL_GL_GetProcAddress( "glCombinerParameterfNV" ); + qglCombinerParameteriNV = ( PFNGLCOMBINERPARAMETERINV ) SDL_GL_GetProcAddress( "glCombinerParameteriNV" ); + qglCombinerInputNV = ( PFNGLCOMBINERINPUTNV ) SDL_GL_GetProcAddress( "glCombinerInputNV" ); + qglCombinerOutputNV = ( PFNGLCOMBINEROUTPUTNV ) SDL_GL_GetProcAddress( "glCombinerOutputNV" ); + qglFinalCombinerInputNV = ( PFNGLFINALCOMBINERINPUTNV ) SDL_GL_GetProcAddress( "glFinalCombinerInputNV" ); + qglGetCombinerInputParameterfvNV = ( PFNGLGETCOMBINERINPUTPARAMETERFVNV ) SDL_GL_GetProcAddress( "glGetCombinerInputParameterfvNV" ); + qglGetCombinerInputParameterivNV = ( PFNGLGETCOMBINERINPUTPARAMETERIVNV ) SDL_GL_GetProcAddress( "glGetCombinerInputParameterivNV" ); + qglGetCombinerOutputParameterfvNV = ( PFNGLGETCOMBINEROUTPUTPARAMETERFVNV ) SDL_GL_GetProcAddress( "glGetCombinerOutputParameterfvNV" ); + qglGetCombinerOutputParameterivNV = ( PFNGLGETCOMBINEROUTPUTPARAMETERIVNV ) SDL_GL_GetProcAddress( "glGetCombinerOutputParameterivNV" ); + qglGetFinalCombinerInputParameterfvNV = ( PFNGLGETFINALCOMBINERINPUTPARAMETERFVNV ) SDL_GL_GetProcAddress( "glGetFinalCombinerInputParameterfvNV" ); + qglGetFinalCombinerInputParameterivNV = ( PFNGLGETFINALCOMBINERINPUTPARAMETERIVNV ) SDL_GL_GetProcAddress( "glGetFinalCombinerInputParameterivNV" ); + + // Validate the functions we need. + if ( !qglCombinerParameterfvNV || !qglCombinerParameterivNV || !qglCombinerParameterfNV || !qglCombinerParameteriNV || !qglCombinerInputNV || + !qglCombinerOutputNV || !qglFinalCombinerInputNV || !qglGetCombinerInputParameterfvNV || !qglGetCombinerInputParameterivNV || + !qglGetCombinerOutputParameterfvNV || !qglGetCombinerOutputParameterivNV || !qglGetFinalCombinerInputParameterfvNV || !qglGetFinalCombinerInputParameterivNV ) + { + bNVRegisterCombiners = false; + qglCombinerParameterfvNV = NULL; + qglCombinerParameteriNV = NULL; + Com_Printf ("...GL_NV_register_combiners failed\n" ); + } + } + else + { + bNVRegisterCombiners = false; + Com_Printf ("...ignoring GL_NV_register_combiners\n" ); + } + } + else + { + bNVRegisterCombiners = false; + Com_Printf ("...GL_NV_register_combiners not found\n" ); + } + + // NOTE: Vertex and Fragment Programs are very dependant on each other - this is actually a + // good thing! So, just check to see which we support (one or the other) and load the shared + // function pointers. ARB rocks! + + // Vertex Programs. + bool bARBVertexProgram = false; + if ( strstr( glConfig.extensions_string, "GL_ARB_vertex_program" ) ) + { + bARBVertexProgram = true; + } + else + { + bARBVertexProgram = false; + Com_Printf ("...GL_ARB_vertex_program not found\n" ); + } + + bool bARBFragmentProgram = false; + // Fragment Programs. + if ( strstr( glConfig.extensions_string, "GL_ARB_fragment_program" ) ) + { + bARBFragmentProgram = true; + } + else + { + bARBFragmentProgram = false; + Com_Printf ("...GL_ARB_fragment_program not found\n" ); + } + + // If we support one or the other, load the shared function pointers. + if ( bARBVertexProgram || bARBFragmentProgram ) + { + qglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) SDL_GL_GetProcAddress("glProgramStringARB"); + qglBindProgramARB = (PFNGLBINDPROGRAMARBPROC) SDL_GL_GetProcAddress("glBindProgramARB"); + qglDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) SDL_GL_GetProcAddress("glDeleteProgramsARB"); + qglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) SDL_GL_GetProcAddress("glGenProgramsARB"); + qglProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4dARB"); + qglProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4dvARB"); + qglProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4fARB"); + qglProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4fvARB"); + qglProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4dARB"); + qglProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4dvARB"); + qglProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4fARB"); + qglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4fvARB"); + qglGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) SDL_GL_GetProcAddress("glGetProgramEnvParameterdvARB"); + qglGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetProgramEnvParameterfvARB"); + qglGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) SDL_GL_GetProcAddress("glGetProgramLocalParameterdvARB"); + qglGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetProgramLocalParameterfvARB"); + qglGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) SDL_GL_GetProcAddress("glGetProgramivARB"); + qglGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) SDL_GL_GetProcAddress("glGetProgramStringARB"); + qglIsProgramARB = (PFNGLISPROGRAMARBPROC) SDL_GL_GetProcAddress("glIsProgramARB"); + + // Validate the functions we need. + if ( !qglProgramStringARB || !qglBindProgramARB || !qglDeleteProgramsARB || !qglGenProgramsARB || + !qglProgramEnvParameter4dARB || !qglProgramEnvParameter4dvARB || !qglProgramEnvParameter4fARB || + !qglProgramEnvParameter4fvARB || !qglProgramLocalParameter4dARB || !qglProgramLocalParameter4dvARB || + !qglProgramLocalParameter4fARB || !qglProgramLocalParameter4fvARB || !qglGetProgramEnvParameterdvARB || + !qglGetProgramEnvParameterfvARB || !qglGetProgramLocalParameterdvARB || !qglGetProgramLocalParameterfvARB || + !qglGetProgramivARB || !qglGetProgramStringARB || !qglIsProgramARB ) + { + bARBVertexProgram = false; + bARBFragmentProgram = false; + qglGenProgramsARB = NULL; //clear ptrs that get checked + qglProgramEnvParameter4fARB = NULL; + Com_Printf ("...ignoring GL_ARB_vertex_program\n" ); + Com_Printf ("...ignoring GL_ARB_fragment_program\n" ); + } + } + + // Figure out which texture rectangle extension to use. + bool bTexRectSupported = false; + if ( Q_strnicmp( glConfig.vendor_string, "ATI Technologies",16 )==0 + && Q_strnicmp( glConfig.version_string, "1.3.3",5 )==0 + && glConfig.version_string[5] < '9' ) //1.3.34 and 1.3.37 and 1.3.38 are broken for sure, 1.3.39 is not + { + g_bTextureRectangleHack = true; + } + + if ( strstr( glConfig.extensions_string, "GL_NV_texture_rectangle" ) + || strstr( glConfig.extensions_string, "GL_EXT_texture_rectangle" ) ) + { + bTexRectSupported = true; + } + +#if 0 + // OK, so not so good to put this here, but no one else uses it!!! -AReis + typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); + PFNWGLGETEXTENSIONSSTRINGARBPROC qwglGetExtensionsStringARB; + qwglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) SDL_GL_GetProcAddress("wglGetExtensionsStringARB"); + + const char *wglExtensions = NULL; +#endif + bool bHasPixelFormat = false; + bool bHasRenderTexture = false; + +#if 0 + // Get the WGL extensions string. + if ( qwglGetExtensionsStringARB ) + { + wglExtensions = qwglGetExtensionsStringARB( glw_state.hDC ); + } + + // This externsion is used to get the wgl extension string. + if ( wglExtensions ) + { + // Pixel Format. + if ( strstr( wglExtensions, "WGL_ARB_pixel_format" ) ) + { + qwglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) SDL_GL_GetProcAddress("wglGetPixelFormatAttribivARB"); + qwglGetPixelFormatAttribfvARB = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC) SDL_GL_GetProcAddress("wglGetPixelFormatAttribfvARB"); + qwglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) SDL_GL_GetProcAddress("wglChoosePixelFormatARB"); + + // Validate the functions we need. + if ( !qwglGetPixelFormatAttribivARB || !qwglGetPixelFormatAttribfvARB || !qwglChoosePixelFormatARB ) + { + Com_Printf ("...ignoring WGL_ARB_pixel_format\n" ); + } + else + { + bHasPixelFormat = true; + } + } + else + { + Com_Printf ("...ignoring WGL_ARB_pixel_format\n" ); + } + + // Offscreen pixel-buffer. + // NOTE: VV guys can use the equivelant SetRenderTarget() with the correct texture surfaces. + bool bWGLARBPbuffer = false; + if ( strstr( wglExtensions, "WGL_ARB_pbuffer" ) && bHasPixelFormat ) + { + bWGLARBPbuffer = true; + qwglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC) SDL_GL_GetProcAddress("wglCreatePbufferARB"); + qwglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC) SDL_GL_GetProcAddress("wglGetPbufferDCARB"); + qwglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC) SDL_GL_GetProcAddress("wglReleasePbufferDCARB"); + qwglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC) SDL_GL_GetProcAddress("wglDestroyPbufferARB"); + qwglQueryPbufferARB = (PFNWGLQUERYPBUFFERARBPROC) SDL_GL_GetProcAddress("wglQueryPbufferARB"); + + // Validate the functions we need. + if ( !qwglCreatePbufferARB || !qwglGetPbufferDCARB || !qwglReleasePbufferDCARB || !qwglDestroyPbufferARB || !qwglQueryPbufferARB ) + { + bWGLARBPbuffer = false; + Com_Printf ("...WGL_ARB_pbuffer failed\n" ); + } + } + else + { + bWGLARBPbuffer = false; + Com_Printf ("...WGL_ARB_pbuffer not found\n" ); + } + + // Render-Texture (requires pbuffer ext (and it's dependancies of course). + if ( strstr( wglExtensions, "WGL_ARB_render_texture" ) && bWGLARBPbuffer ) + { + qwglBindTexImageARB = (PFNWGLBINDTEXIMAGEARBPROC) SDL_GL_GetProcAddress("wglBindTexImageARB"); + qwglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARBPROC) SDL_GL_GetProcAddress("wglReleaseTexImageARB"); + qwglSetPbufferAttribARB = (PFNWGLSETPBUFFERATTRIBARBPROC) SDL_GL_GetProcAddress("wglSetPbufferAttribARB"); + + // Validate the functions we need. + if ( !qwglCreatePbufferARB || !qwglGetPbufferDCARB || !qwglReleasePbufferDCARB || !qwglDestroyPbufferARB || !qwglQueryPbufferARB ) + { + Com_Printf ("...ignoring WGL_ARB_render_texture\n" ); + } + else + { + bHasRenderTexture = true; + } + } + else + { + Com_Printf ("...ignoring WGL_ARB_render_texture\n" ); + } + } +#endif + + // Find out how many general combiners they have. + #define GL_MAX_GENERAL_COMBINERS_NV 0x854D + GLint iNumGeneralCombiners = 0; + qglGetIntegerv( GL_MAX_GENERAL_COMBINERS_NV, &iNumGeneralCombiners ); + + // Only allow dynamic glows/flares if they have the hardware + if ( bTexRectSupported && bARBVertexProgram && bHasRenderTexture && qglActiveTextureARB && glConfig.maxActiveTextures >= 4 && + ( ( bNVRegisterCombiners && iNumGeneralCombiners >= 2 ) || bARBFragmentProgram ) ) + { + g_bDynamicGlowSupported = true; + // this would overwrite any achived setting gwg + // Cvar_Set( "r_DynamicGlow", "1" ); + } + else + { + g_bDynamicGlowSupported = false; + Cvar_Set( "r_DynamicGlow","0" ); + } +} + +#define R_MODE_FALLBACK 3 // 640 * 480 + +/* +=============== +GLimp_Init + +This routine is responsible for initializing the OS specific portions +of OpenGL +=============== +*/ +void GLimp_Init( void ) +{ + r_allowSoftwareGL = Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); + r_sdlDriver = Cvar_Get( "r_sdlDriver", "", CVAR_ROM ); + r_allowResize = Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE ); + r_centerWindow = Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE ); + r_noborder = Cvar_Get( "r_noborder", "0", CVAR_ARCHIVE ); + qboolean fullscreen, noborder; + + if( Cvar_VariableIntegerValue( "com_abnormalExit" ) ) + { + Cvar_Set( "r_mode", va( "%d", R_MODE_FALLBACK ) ); + Cvar_Set( "r_fullscreen", "0" ); + Cvar_Set( "r_centerWindow", "0" ); + Cvar_Set( "com_abnormalExit", "0" ); + } + +#ifdef notyet + Sys_SetEnv( "SDL_VIDEO_CENTERED", r_centerWindow->integer ? "1" : "" ); +#endif + + Sys_GLimpInit( ); + + fullscreen = (r_fullscreen->integer) ? qtrue : qfalse; + noborder = (r_noborder->integer) ? qtrue : qfalse; + + // Create the window and set up the context + if(GLimp_StartDriverAndSetMode(r_mode->integer, fullscreen, noborder)) + goto success; + + // Try again, this time in a platform specific "safe mode" + Sys_GLimpSafeInit( ); + + if(GLimp_StartDriverAndSetMode(r_mode->integer, fullscreen, qfalse)) + goto success; + + // Finally, try the default screen resolution + if( r_mode->integer != R_MODE_FALLBACK ) + { + VID_Printf( PRINT_ALL, "Setting r_mode %d failed, falling back on r_mode %d\n", + r_mode->integer, R_MODE_FALLBACK ); + + if(GLimp_StartDriverAndSetMode(R_MODE_FALLBACK, qfalse, qfalse)) + goto success; + } + + // Nothing worked, give up + Com_Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem" ); + +success: +#if 0 + // This values force the UI to disable driver selection + glConfig.driverType = GLDRV_ICD; + glConfig.hardwareType = GLHW_GENERIC; +#endif + glConfig.deviceSupportsGamma = (SDL_SetGamma( 1.0f, 1.0f, 1.0f ) >= 0) ? qtrue : qfalse; + + // Mysteriously, if you use an NVidia graphics card and multiple monitors, + // SDL_SetGamma will incorrectly return false... the first time; ask + // again and you get the correct answer. This is a suspected driver bug, see + // http://bugzilla.icculus.org/show_bug.cgi?id=4316 + glConfig.deviceSupportsGamma = (SDL_SetGamma( 1.0f, 1.0f, 1.0f ) >= 0) ? qtrue : qfalse; + + if ( -1 == r_ignorehwgamma->integer) + glConfig.deviceSupportsGamma = qtrue; + + if ( 1 == r_ignorehwgamma->integer) + glConfig.deviceSupportsGamma = qfalse; + + // get our config strings + glConfig.vendor_string = (const char *) qglGetString (GL_VENDOR); + glConfig.renderer_string = (const char *) qglGetString (GL_RENDERER); + glConfig.version_string = (const char *) qglGetString (GL_VERSION); + glConfig.extensions_string = (const char *) qglGetString (GL_EXTENSIONS); + + // OpenGL driver constants + qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &glConfig.maxTextureSize ); + // stubbed or broken drivers may have reported 0... + if ( glConfig.maxTextureSize <= 0 ) + { + glConfig.maxTextureSize = 0; + } + + // initialize extensions + GLimp_InitExtensions( ); + + Cvar_Get( "r_availableModes", "", CVAR_ROM ); + + // This depends on SDL_INIT_VIDEO, hence having it here + IN_Init( ); +} + + +/* +=============== +GLimp_EndFrame + +Responsible for doing a swapbuffers +=============== +*/ +void GLimp_EndFrame( void ) +{ + // don't flip if drawing to front buffer + //if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 ) + { + SDL_GL_SwapBuffers(); + } + + if( r_fullscreen->modified ) + { + qboolean fullscreen; + qboolean needToToggle = qtrue; + qboolean sdlToggled = qfalse; + SDL_Surface *s = SDL_GetVideoSurface( ); + + if( s ) + { + // Find out the current state + fullscreen = (!!( s->flags & SDL_FULLSCREEN )) ? qtrue : qfalse; + + if( r_fullscreen->integer && Cvar_VariableIntegerValue( "in_nograb" ) ) + { + VID_Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n"); + Cvar_Set( "r_fullscreen", "0" ); + r_fullscreen->modified = qfalse; + } + + // Is the state we want different from the current state? + needToToggle = (!!r_fullscreen->integer != fullscreen) ? qtrue : qfalse; + + if( needToToggle ) + sdlToggled = SDL_WM_ToggleFullScreen( s ); + } + + if( needToToggle ) + { + // SDL_WM_ToggleFullScreen didn't work, so do it the slow way + if( !sdlToggled ) + Cbuf_AddText( "vid_restart\n" ); + + IN_Restart( ); + } + + r_fullscreen->modified = qfalse; + } +} diff --git a/code/sdl/sdl_input.cpp b/code/sdl/sdl_input.cpp new file mode 100644 index 0000000..5e0e4ac --- /dev/null +++ b/code/sdl/sdl_input.cpp @@ -0,0 +1,1107 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#ifdef USE_LOCAL_HEADERS +# include "SDL.h" +#else +# include +#endif + +#include +#include +#include + +#include "../client/client.h" +#include "sdl_local.h" + +#ifdef MACOS_X +// Mouse acceleration needs to be disabled +#define MACOS_X_ACCELERATION_HACK +// Cursor needs hack to hide +#define MACOS_X_CURSOR_HACK +#endif + +#ifdef MACOS_X_ACCELERATION_HACK +#include +#include +#include +#include +#endif + +static cvar_t *in_keyboardDebug = NULL; + +static SDL_Joystick *stick = NULL; + +static qboolean mouseAvailable = qfalse; +static qboolean mouseActive = qfalse; +static qboolean keyRepeatEnabled = qfalse; + +static cvar_t *in_mouse = NULL; +#ifdef MACOS_X_ACCELERATION_HACK +static cvar_t *in_disablemacosxmouseaccel = NULL; +static double originalMouseSpeed = -1.0; +#endif +static cvar_t *in_nograb; + +static cvar_t *in_joystick = NULL; +static cvar_t *in_joystickDebug = NULL; +static cvar_t *in_joystickThreshold = NULL; +static cvar_t *in_joystickNo = NULL; +static cvar_t *in_joystickUseAnalog = NULL; + +static int vidRestartTime = 0; + +#define CTRL(a) ((a)-'a'+1) + +/* +=============== +IN_PrintKey +=============== +*/ +static void IN_PrintKey( const SDL_keysym *keysym, fakeAscii_t key, qboolean down ) +{ + if( down ) + Com_Printf( "+ " ); + else + Com_Printf( " " ); + + Com_Printf( "0x%02x \"%s\"", keysym->scancode, + SDL_GetKeyName( keysym->sym ) ); + + if( keysym->mod & KMOD_LSHIFT ) Com_Printf( " KMOD_LSHIFT" ); + if( keysym->mod & KMOD_RSHIFT ) Com_Printf( " KMOD_RSHIFT" ); + if( keysym->mod & KMOD_LCTRL ) Com_Printf( " KMOD_LCTRL" ); + if( keysym->mod & KMOD_RCTRL ) Com_Printf( " KMOD_RCTRL" ); + if( keysym->mod & KMOD_LALT ) Com_Printf( " KMOD_LALT" ); + if( keysym->mod & KMOD_RALT ) Com_Printf( " KMOD_RALT" ); + if( keysym->mod & KMOD_LMETA ) Com_Printf( " KMOD_LMETA" ); + if( keysym->mod & KMOD_RMETA ) Com_Printf( " KMOD_RMETA" ); + if( keysym->mod & KMOD_NUM ) Com_Printf( " KMOD_NUM" ); + if( keysym->mod & KMOD_CAPS ) Com_Printf( " KMOD_CAPS" ); + if( keysym->mod & KMOD_MODE ) Com_Printf( " KMOD_MODE" ); + if( keysym->mod & KMOD_RESERVED ) Com_Printf( " KMOD_RESERVED" ); + + Com_Printf( " Q:0x%02x(%s)", key, Key_KeynumToString( key ) ); + + if( keysym->unicode ) + { + Com_Printf( " U:0x%02x", keysym->unicode ); + + if( keysym->unicode > ' ' && keysym->unicode < '~' ) + Com_Printf( "(%c)", (char)keysym->unicode ); + } + + Com_Printf( "\n" ); +} + +#define MAX_CONSOLE_KEYS 16 + +/* +=============== +IN_IsConsoleKey +=============== +*/ +static qboolean IN_IsConsoleKey( fakeAscii_t key, const unsigned char character ) +{ + typedef struct consoleKey_s + { + enum + { + KEY, + CHARACTER + } type; + + union + { + fakeAscii_t key; + unsigned char character; + } u; + } consoleKey_t; + + static consoleKey_t consoleKeys[ MAX_CONSOLE_KEYS ]; + static int numConsoleKeys = 0; + int i; + + // Only parse the variable when it changes + if( cl_consoleKeys->modified ) + { + char *text_p, *token; + + cl_consoleKeys->modified = qfalse; + text_p = cl_consoleKeys->string; + numConsoleKeys = 0; + + while( numConsoleKeys < MAX_CONSOLE_KEYS ) + { + consoleKey_t *c = &consoleKeys[ numConsoleKeys ]; + int charCode = 0; + + token = COM_Parse( &text_p ); + if( !token[ 0 ] ) + break; + + if( strlen( token ) == 4 ) + charCode = Com_HexStrToInt( token ); + + if( charCode > 0 ) + { + c->type = consoleKey_t::CHARACTER; + c->u.character = (unsigned char)charCode; + } + else + { + c->type = consoleKey_t::KEY; + c->u.key = Key_StringToKeynum( token ); + + // 0 isn't a key + if( c->u.key <= 0 ) + continue; + } + + numConsoleKeys++; + } + } + + // If the character is the same as the key, prefer the character + if( key == character ) + key = 0; + + for( i = 0; i < numConsoleKeys; i++ ) + { + consoleKey_t *c = &consoleKeys[ i ]; + + switch( c->type ) + { + case consoleKey_t::KEY: + if( key && c->u.key == key ) + return qtrue; + break; + + case consoleKey_t::CHARACTER: + if( c->u.character == character ) + return qtrue; + break; + } + } + + return qfalse; +} + +/* +=============== +IN_TranslateSDLToQ3Key +=============== +*/ +static const char *IN_TranslateSDLToQ3Key( SDL_keysym *keysym, + fakeAscii_t *key, qboolean down ) +{ + static unsigned char buf[ 2 ] = { '\0', '\0' }; + + *buf = '\0'; + *key = 0; + + if( keysym->sym >= SDLK_SPACE && keysym->sym < SDLK_DELETE ) + { + // These happen to match the ASCII chars + *key = (int)keysym->sym; + } + else + { + switch( keysym->sym ) + { + case SDLK_PAGEUP: *key = A_PAGE_UP; break; + case SDLK_KP9: *key = A_KP_9; break; + case SDLK_PAGEDOWN: *key = A_PAGE_DOWN; break; + case SDLK_KP3: *key = A_KP_3; break; + case SDLK_KP7: *key = A_KP_7; break; + case SDLK_HOME: *key = A_HOME; break; + case SDLK_KP1: *key = A_KP_1; break; + case SDLK_END: *key = A_END; break; + case SDLK_KP4: *key = A_KP_4; break; + case SDLK_LEFT: *key = A_CURSOR_LEFT; break; + case SDLK_KP6: *key = A_KP_6; break; + case SDLK_RIGHT: *key = A_CURSOR_RIGHT; break; + case SDLK_KP2: *key = A_KP_2; break; + case SDLK_DOWN: *key = A_CURSOR_DOWN; break; + case SDLK_KP8: *key = A_KP_8; break; + case SDLK_UP: *key = A_CURSOR_UP; break; + case SDLK_ESCAPE: *key = A_ESCAPE; break; + case SDLK_KP_ENTER: *key = A_KP_ENTER; break; + case SDLK_RETURN: *key = A_ENTER; break; + case SDLK_TAB: *key = A_TAB; break; + case SDLK_F1: *key = A_F1; break; + case SDLK_F2: *key = A_F2; break; + case SDLK_F3: *key = A_F3; break; + case SDLK_F4: *key = A_F4; break; + case SDLK_F5: *key = A_F5; break; + case SDLK_F6: *key = A_F6; break; + case SDLK_F7: *key = A_F7; break; + case SDLK_F8: *key = A_F8; break; + case SDLK_F9: *key = A_F9; break; + case SDLK_F10: *key = A_F10; break; + case SDLK_F11: *key = A_F11; break; + case SDLK_F12: *key = A_F12; break; +#if 0 + case SDLK_F13: *key = A_F13; break; + case SDLK_F14: *key = A_F14; break; + case SDLK_F15: *key = A_F15; break; +#endif + + case SDLK_BACKSPACE: *key = A_BACKSPACE; break; + case SDLK_KP_PERIOD: *key = A_KP_PERIOD; break; + case SDLK_DELETE: *key = A_DELETE; break; + case SDLK_PAUSE: *key = A_PAUSE; break; + + case SDLK_LSHIFT: + case SDLK_RSHIFT: *key = A_SHIFT; break; + + case SDLK_LCTRL: + case SDLK_RCTRL: *key = A_CTRL; break; + +#if 0 + case SDLK_RMETA: + case SDLK_LMETA: *key = A_COMMAND; break; +#endif + + case SDLK_RALT: + case SDLK_LALT: *key = A_ALT; break; + +#if 0 + case SDLK_LSUPER: + case SDLK_RSUPER: *key = A_SUPER; break; +#endif + + case SDLK_KP5: *key = A_KP_5; break; + case SDLK_INSERT: *key = A_INSERT; break; + case SDLK_KP0: *key = A_KP_0; break; + case SDLK_KP_MULTIPLY: *key = A_STAR; break; + case SDLK_KP_PLUS: *key = A_KP_PLUS; break; + case SDLK_KP_MINUS: *key = A_KP_MINUS; break; + case SDLK_KP_DIVIDE: *key = A_DIVIDE; break; +#if 0 + case SDLK_MODE: *key = A_MODE; break; + case SDLK_COMPOSE: *key = A_COMPOSE; break; + case SDLK_HELP: *key = A_HELP; break; +#endif + case SDLK_PRINT: *key = A_PRINTSCREEN; break; +#if 0 + case SDLK_SYSREQ: *key = A_SYSREQ; break; + case SDLK_BREAK: *key = A_BREAK; break; + case SDLK_MENU: *key = A_MENU; break; + case SDLK_POWER: *key = A_POWER; break; +#endif + case SDLK_EURO: *key = A_EURO; break; +// case SDLK_UNDO: *key = A_UNDO; break; + case SDLK_SCROLLOCK: *key = A_SCROLLLOCK; break; + case SDLK_NUMLOCK: *key = A_NUMLOCK; break; + case SDLK_CAPSLOCK: *key = A_CAPSLOCK; break; + + default: +#if 0 + if( keysym->sym >= SDLK_WORLD_0 && keysym->sym <= SDLK_WORLD_95 ) + *key = ( keysym->sym - SDLK_WORLD_0 ) + K_WORLD_0; +#endif + break; + } + } + + if( down && keysym->unicode && !( keysym->unicode & 0xFF00 ) ) + { + unsigned char ch = (unsigned char)keysym->unicode & 0xFF; + + switch( ch ) + { + case 127: // ASCII delete + if( *key != A_DELETE ) + { + // ctrl-h + *buf = CTRL('h'); + break; + } + // fallthrough + + default: *buf = ch; break; + } + } + + if( in_keyboardDebug->integer ) + IN_PrintKey( keysym, *key, down ); + + // Keys that have ASCII names but produce no character are probably + // dead keys -- ignore them + if( down && strlen( Key_KeynumToString( *key ) ) == 1 && + keysym->unicode == 0 ) + { + if( in_keyboardDebug->integer ) + Com_Printf( " Ignored dead key '%c'\n", *key ); + + *key = 0; + } + + if( IN_IsConsoleKey( *key, *buf ) ) + { + // Console keys can't be bound or generate characters + *key = A_CONSOLE; + *buf = '\0'; + } + + // Don't allow extended ASCII to generate characters + if( *buf & 0x80 ) + *buf = '\0'; + + return (char *)buf; +} + +#ifdef MACOS_X_ACCELERATION_HACK +/* +=============== +IN_GetIOHandle +=============== +*/ +static io_connect_t IN_GetIOHandle(void) // mac os x mouse accel hack +{ + io_connect_t iohandle = MACH_PORT_NULL; + kern_return_t status; + io_service_t iohidsystem = MACH_PORT_NULL; + mach_port_t masterport; + + status = IOMasterPort(MACH_PORT_NULL, &masterport); + if(status != KERN_SUCCESS) + return 0; + + iohidsystem = IORegistryEntryFromPath(masterport, kIOServicePlane ":/IOResources/IOHIDSystem"); + if(!iohidsystem) + return 0; + + status = IOServiceOpen(iohidsystem, mach_task_self(), kIOHIDParamConnectType, &iohandle); + IOObjectRelease(iohidsystem); + + return iohandle; +} +#endif + +/* +=============== +IN_GobbleMotionEvents +=============== +*/ +static void IN_GobbleMotionEvents( void ) +{ + SDL_Event dummy[ 1 ]; + + // Gobble any mouse motion events + SDL_PumpEvents( ); + while( SDL_PeepEvents( dummy, 1, SDL_GETEVENT, + SDL_EVENTMASK( SDL_MOUSEMOTION ) ) ) { } +} + +/* +=============== +IN_ActivateMouse +=============== +*/ +static void IN_ActivateMouse( void ) +{ + if (!mouseAvailable || !SDL_WasInit( SDL_INIT_VIDEO ) ) + return; + +#ifdef MACOS_X_ACCELERATION_HACK + if (!mouseActive) // mac os x mouse accel hack + { + // Save the status of mouse acceleration + originalMouseSpeed = -1.0; // in case of error + if(in_disablemacosxmouseaccel->integer) + { + io_connect_t mouseDev = IN_GetIOHandle(); + if(mouseDev != 0) + { + if(IOHIDGetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), &originalMouseSpeed) == kIOReturnSuccess) + { + Com_Printf("previous mouse acceleration: %f\n", originalMouseSpeed); + if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), -1.0) != kIOReturnSuccess) + { + Com_Printf("Could not disable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n"); + Cvar_Set ("in_disablemacosxmouseaccel", 0); + } + } + else + { + Com_Printf("Could not disable mouse acceleration (failed at IOHIDGetAccelerationWithKey).\n"); + Cvar_Set ("in_disablemacosxmouseaccel", 0); + } + IOServiceClose(mouseDev); + } + else + { + Com_Printf("Could not disable mouse acceleration (failed at IO_GetIOHandle).\n"); + Cvar_Set ("in_disablemacosxmouseaccel", 0); + } + } + } +#endif + + if( !mouseActive ) + { + SDL_ShowCursor( 0 ); +#ifdef MACOS_X_CURSOR_HACK + // This is a bug in the current SDL/macosx...have to toggle it a few + // times to get the cursor to hide. + SDL_ShowCursor( 1 ); + SDL_ShowCursor( 0 ); +#endif + SDL_WM_GrabInput( SDL_GRAB_ON ); + + IN_GobbleMotionEvents( ); + } + + // in_nograb makes no sense in fullscreen mode + if( !Cvar_VariableIntegerValue("r_fullscreen") ) + { + if( in_nograb->modified || !mouseActive ) + { + if( in_nograb->integer ) + SDL_WM_GrabInput( SDL_GRAB_OFF ); + else + SDL_WM_GrabInput( SDL_GRAB_ON ); + + in_nograb->modified = qfalse; + } + } + + mouseActive = qtrue; +} + +/* +=============== +IN_DeactivateMouse +=============== +*/ +static void IN_DeactivateMouse( void ) +{ + if( !SDL_WasInit( SDL_INIT_VIDEO ) ) + return; + + // Always show the cursor when the mouse is disabled, + // but not when fullscreen + if( !Cvar_VariableIntegerValue("r_fullscreen") ) + SDL_ShowCursor( 1 ); + + if( !mouseAvailable ) + return; + +#ifdef MACOS_X_ACCELERATION_HACK + if (mouseActive) // mac os x mouse accel hack + { + if(originalMouseSpeed != -1.0) + { + io_connect_t mouseDev = IN_GetIOHandle(); + if(mouseDev != 0) + { + Com_Printf("restoring mouse acceleration to: %f\n", originalMouseSpeed); + if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), originalMouseSpeed) != kIOReturnSuccess) + Com_Printf("Could not re-enable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n"); + IOServiceClose(mouseDev); + } + else + Com_Printf("Could not re-enable mouse acceleration (failed at IO_GetIOHandle).\n"); + } + } +#endif + + if( mouseActive ) + { + IN_GobbleMotionEvents( ); + + SDL_WM_GrabInput( SDL_GRAB_OFF ); + + // Don't warp the mouse unless the cursor is within the window + if( SDL_GetAppState( ) & SDL_APPMOUSEFOCUS ) + SDL_WarpMouse( cls.glconfig.vidWidth / 2, cls.glconfig.vidHeight / 2 ); + + mouseActive = qfalse; + } +} + +// We translate axes movement into keypresses +static int joy_keys[16] = { + A_CURSOR_LEFT, A_CURSOR_RIGHT, + A_CURSOR_UP, A_CURSOR_DOWN, + A_JOY16, A_JOY17, + A_JOY18, A_JOY19, + A_JOY20, A_JOY21, + A_JOY22, A_JOY23, + A_JOY24, A_JOY25, + A_JOY26, A_JOY27 +}; + +// translate hat events into keypresses +// the 4 highest buttons are used for the first hat ... +static int hat_keys[16] = { + A_JOY28, A_JOY29, + A_JOY30, A_JOY31, + A_JOY24, A_JOY25, + A_JOY26, A_JOY27, + A_JOY20, A_JOY21, + A_JOY22, A_JOY23, + A_JOY16, A_JOY17, + A_JOY18, A_JOY19 +}; + + +struct +{ + qboolean buttons[16]; // !!! FIXME: these might be too many. + unsigned int oldaxes; + int oldaaxes[MAX_JOYSTICK_AXIS]; + unsigned int oldhats; +} stick_state; + + +/* +=============== +IN_InitJoystick +=============== +*/ +static void IN_InitJoystick( void ) +{ + int i = 0; + int total = 0; + char buf[16384] = ""; + + if (stick != NULL) + SDL_JoystickClose(stick); + + stick = NULL; + memset(&stick_state, '\0', sizeof (stick_state)); + + if (!SDL_WasInit(SDL_INIT_JOYSTICK)) + { + Com_DPrintf("Calling SDL_Init(SDL_INIT_JOYSTICK)...\n"); + if (SDL_Init(SDL_INIT_JOYSTICK) == -1) + { + Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) failed: %s\n", SDL_GetError()); + return; + } + Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) passed.\n"); + } + + total = SDL_NumJoysticks(); + Com_DPrintf("%d possible joysticks\n", total); + + // Print list and build cvar to allow ui to select joystick. + for (i = 0; i < total; i++) + { + Q_strcat(buf, sizeof(buf), SDL_JoystickName(i)); + Q_strcat(buf, sizeof(buf), "\n"); + } + + Cvar_Get( "in_availableJoysticks", buf, CVAR_ROM ); + + if( !in_joystick->integer ) { + Com_DPrintf( "Joystick is not active.\n" ); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + return; + } + + in_joystickNo = Cvar_Get( "in_joystickNo", "0", CVAR_ARCHIVE ); + if( in_joystickNo->integer < 0 || in_joystickNo->integer >= total ) + Cvar_Set( "in_joystickNo", "0" ); + + in_joystickUseAnalog = Cvar_Get( "in_joystickUseAnalog", "0", CVAR_ARCHIVE ); + + stick = SDL_JoystickOpen( in_joystickNo->integer ); + + if (stick == NULL) { + Com_DPrintf( "No joystick opened.\n" ); + return; + } + + Com_DPrintf( "Joystick %d opened\n", in_joystickNo->integer ); + Com_DPrintf( "Name: %s\n", SDL_JoystickName(in_joystickNo->integer) ); + Com_DPrintf( "Axes: %d\n", SDL_JoystickNumAxes(stick) ); + Com_DPrintf( "Hats: %d\n", SDL_JoystickNumHats(stick) ); + Com_DPrintf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) ); + Com_DPrintf( "Balls: %d\n", SDL_JoystickNumBalls(stick) ); + Com_DPrintf( "Use Analog: %s\n", in_joystickUseAnalog->integer ? "Yes" : "No" ); + + SDL_JoystickEventState(SDL_QUERY); +} + +/* +=============== +IN_ShutdownJoystick +=============== +*/ +static void IN_ShutdownJoystick( void ) +{ + if (stick) + { + SDL_JoystickClose(stick); + stick = NULL; + } + + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); +} + +/* +=============== +IN_JoyMove +=============== +*/ +static void IN_JoyMove( void ) +{ + qboolean joy_pressed[ARRAY_LEN(joy_keys)]; + unsigned int axes = 0; + unsigned int hats = 0; + int total = 0; + int i = 0; + + if (!stick) + return; + + SDL_JoystickUpdate(); + + memset(joy_pressed, '\0', sizeof (joy_pressed)); + + // update the ball state. + total = SDL_JoystickNumBalls(stick); + if (total > 0) + { + int balldx = 0; + int balldy = 0; + for (i = 0; i < total; i++) + { + int dx = 0; + int dy = 0; + SDL_JoystickGetBall(stick, i, &dx, &dy); + balldx += dx; + balldy += dy; + } + if (balldx || balldy) + { + // !!! FIXME: is this good for stick balls, or just mice? + // Scale like the mouse input... + if (abs(balldx) > 1) + balldx *= 2; + if (abs(balldy) > 1) + balldy *= 2; + Sys_QueEvent( 0, SE_MOUSE, balldx, balldy, 0, NULL ); + } + } + + // now query the stick buttons... + total = SDL_JoystickNumButtons(stick); + if (total > 0) + { + if (total > ARRAY_LEN(stick_state.buttons)) + total = ARRAY_LEN(stick_state.buttons); + for (i = 0; i < total; i++) + { + qboolean pressed = ((SDL_JoystickGetButton(stick, i) != 0)) ? qtrue : qfalse; + if (pressed != stick_state.buttons[i]) + { + Sys_QueEvent( 0, SE_KEY, A_JOY0 + i, pressed, 0, NULL ); + stick_state.buttons[i] = pressed; + } + } + } + + // look at the hats... + total = SDL_JoystickNumHats(stick); + if (total > 0) + { + if (total > 4) total = 4; + for (i = 0; i < total; i++) + { + ((Uint8 *)&hats)[i] = SDL_JoystickGetHat(stick, i); + } + } + + // update hat state + if (hats != stick_state.oldhats) + { + for( i = 0; i < 4; i++ ) { + if( ((Uint8 *)&hats)[i] != ((Uint8 *)&stick_state.oldhats)[i] ) { + // release event + switch( ((Uint8 *)&stick_state.oldhats)[i] ) { + case SDL_HAT_UP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); + break; + case SDL_HAT_RIGHT: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); + break; + case SDL_HAT_DOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); + break; + case SDL_HAT_LEFT: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); + break; + case SDL_HAT_RIGHTUP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); + break; + case SDL_HAT_RIGHTDOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); + break; + case SDL_HAT_LEFTUP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); + break; + case SDL_HAT_LEFTDOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); + break; + default: + break; + } + // press event + switch( ((Uint8 *)&hats)[i] ) { + case SDL_HAT_UP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); + break; + case SDL_HAT_RIGHT: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); + break; + case SDL_HAT_DOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); + break; + case SDL_HAT_LEFT: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); + break; + case SDL_HAT_RIGHTUP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); + break; + case SDL_HAT_RIGHTDOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); + break; + case SDL_HAT_LEFTUP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); + break; + case SDL_HAT_LEFTDOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); + break; + default: + break; + } + } + } + } + + // save hat state + stick_state.oldhats = hats; + + // finally, look at the axes... + total = SDL_JoystickNumAxes(stick); + if (total > 0) + { + if (in_joystickUseAnalog->integer) + { + if (total > MAX_JOYSTICK_AXIS) total = MAX_JOYSTICK_AXIS; + for (i = 0; i < total; i++) + { + Sint16 axis = SDL_JoystickGetAxis(stick, i); + float f = ( (float) abs(axis) ) / 32767.0f; + + if( f < in_joystickThreshold->value ) axis = 0; + + if ( axis != stick_state.oldaaxes[i] ) + { + Sys_QueEvent( 0, SE_JOYSTICK_AXIS, i, axis, 0, NULL ); + stick_state.oldaaxes[i] = axis; + } + } + } + else + { + if (total > 16) total = 16; + for (i = 0; i < total; i++) + { + Sint16 axis = SDL_JoystickGetAxis(stick, i); + float f = ( (float) axis ) / 32767.0f; + if( f < -in_joystickThreshold->value ) { + axes |= ( 1 << ( i * 2 ) ); + } else if( f > in_joystickThreshold->value ) { + axes |= ( 1 << ( ( i * 2 ) + 1 ) ); + } + } + } + } + + /* Time to update axes state based on old vs. new. */ + if (axes != stick_state.oldaxes) + { + for( i = 0; i < 16; i++ ) { + if( ( axes & ( 1 << i ) ) && !( stick_state.oldaxes & ( 1 << i ) ) ) { + Sys_QueEvent( 0, SE_KEY, joy_keys[i], qtrue, 0, NULL ); + } + + if( !( axes & ( 1 << i ) ) && ( stick_state.oldaxes & ( 1 << i ) ) ) { + Sys_QueEvent( 0, SE_KEY, joy_keys[i], qfalse, 0, NULL ); + } + } + } + + /* Save for future generations. */ + stick_state.oldaxes = axes; +} + +/* +=============== +IN_ProcessEvents +=============== +*/ +static void IN_ProcessEvents( void ) +{ + SDL_Event e; + const char *character = NULL; + fakeAscii_t key = 0; + + if( !SDL_WasInit( SDL_INIT_VIDEO ) ) + return; + + if( Key_GetCatcher( ) == 0 && keyRepeatEnabled ) + { + SDL_EnableKeyRepeat( 0, 0 ); + keyRepeatEnabled = qfalse; + } + else if( !keyRepeatEnabled ) + { + SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, + SDL_DEFAULT_REPEAT_INTERVAL ); + keyRepeatEnabled = qtrue; + } + + while( SDL_PollEvent( &e ) ) + { + switch( e.type ) + { + case SDL_KEYDOWN: + character = IN_TranslateSDLToQ3Key( &e.key.keysym, &key, qtrue ); + if( key ) + Sys_QueEvent( 0, SE_KEY, key, qtrue, 0, NULL ); + + if( character ) + Sys_QueEvent( 0, SE_CHAR, *character, 0, 0, NULL ); + break; + + case SDL_KEYUP: + IN_TranslateSDLToQ3Key( &e.key.keysym, &key, qfalse ); + + if( key ) + Sys_QueEvent( 0, SE_KEY, key, qfalse, 0, NULL ); + break; + + case SDL_MOUSEMOTION: + if( mouseActive ) + Sys_QueEvent( 0, SE_MOUSE, e.motion.xrel, e.motion.yrel, 0, NULL ); + break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + { + unsigned char b; + switch( e.button.button ) + { + case 1: b = A_MOUSE1; break; + case 2: b = A_MOUSE3; break; + case 3: b = A_MOUSE2; break; + case 4: b = A_MWHEELUP; break; + case 5: b = A_MWHEELDOWN; break; + case 6: b = A_MOUSE4; break; + case 7: b = A_MOUSE5; break; + default: b = A_AUX0 + ( e.button.button - 8 ) % 16; break; + } + Sys_QueEvent( 0, SE_KEY, b, + ( e.type == SDL_MOUSEBUTTONDOWN ? qtrue : qfalse ), 0, NULL ); + } + break; + + case SDL_QUIT: + Cbuf_ExecuteText(EXEC_NOW, "quit Closed window\n"); + break; + + case SDL_VIDEORESIZE: + { + char width[32], height[32]; + Com_sprintf( width, sizeof(width), "%d", e.resize.w ); + Com_sprintf( height, sizeof(height), "%d", e.resize.h ); + Cvar_Set( "r_customwidth", width ); + Cvar_Set( "r_customheight", height ); + Cvar_Set( "r_mode", "-1" ); + /* wait until user stops dragging for 1 second, so + we aren't constantly recreating the GL context while + he tries to drag...*/ + vidRestartTime = Sys_Milliseconds() + 1000; + } + break; + case SDL_ACTIVEEVENT: + if (e.active.state & SDL_APPINPUTFOCUS) { + Cvar_SetValue( "com_unfocused", !e.active.gain); + } + if (e.active.state & SDL_APPACTIVE) { + Cvar_SetValue( "com_minimized", !e.active.gain); + } + break; + + default: + break; + } + } +} + +/* +=============== +IN_Frame +=============== +*/ +void IN_Frame( void ) +{ + qboolean loading; + + IN_JoyMove( ); + IN_ProcessEvents( ); + + // If not DISCONNECTED (main menu) or ACTIVE (in game), we're loading + loading = ( cls.state != CA_DISCONNECTED && cls.state != CA_ACTIVE ) ? qtrue : qfalse; + + if( !Cvar_VariableIntegerValue("r_fullscreen") && ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ) + { + // Console is down in windowed mode + IN_DeactivateMouse( ); + } + else if( !Cvar_VariableIntegerValue("r_fullscreen") && loading ) + { + // Loading in windowed mode + IN_DeactivateMouse( ); + } + else if( !( SDL_GetAppState() & SDL_APPINPUTFOCUS ) ) + { + // Window not got focus + IN_DeactivateMouse( ); + } + else + IN_ActivateMouse( ); + + /* in case we had to delay actual restart of video system... */ + if ( (vidRestartTime != 0) && (vidRestartTime < Sys_Milliseconds()) ) + { + vidRestartTime = 0; + Cbuf_AddText( "vid_restart" ); + } +} + +/* +=============== +IN_InitKeyLockStates +=============== +*/ +void IN_InitKeyLockStates( void ) +{ +#if 0 + unsigned char *keystate = SDL_GetKeyState(NULL); + + keys[A_SCROLLLOCK].down = keystate[SDLK_SCROLLOCK]; + keys[A_NUMLOCK].down = keystate[SDLK_NUMLOCK]; + keys[A_CAPSLOCK].down = keystate[SDLK_CAPSLOCK]; +#endif +} + +/* +=============== +IN_Init +=============== +*/ +void IN_Init( void ) +{ + int appState; + + if( !SDL_WasInit( SDL_INIT_VIDEO ) ) + { + Com_Error( ERR_FATAL, "IN_Init called before SDL_Init( SDL_INIT_VIDEO )" ); + return; + } + + Com_DPrintf( "\n------- Input Initialization -------\n" ); + + in_keyboardDebug = Cvar_Get( "in_keyboardDebug", "0", CVAR_ARCHIVE ); + + // mouse variables + in_mouse = Cvar_Get( "in_mouse", "1", CVAR_ARCHIVE ); + in_nograb = Cvar_Get( "in_nograb", "0", CVAR_ARCHIVE ); + + in_joystick = Cvar_Get( "in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH ); + in_joystickDebug = Cvar_Get( "in_joystickDebug", "0", CVAR_TEMP ); + in_joystickThreshold = Cvar_Get( "joy_threshold", "0.15", CVAR_ARCHIVE ); + +#ifdef MACOS_X_ACCELERATION_HACK + in_disablemacosxmouseaccel = Cvar_Get( "in_disablemacosxmouseaccel", "1", CVAR_ARCHIVE ); +#endif + + SDL_EnableUNICODE( 1 ); + SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); + keyRepeatEnabled = qtrue; + + mouseAvailable = ( in_mouse->value != 0 ) ? qtrue : qfalse; + IN_DeactivateMouse( ); + + appState = SDL_GetAppState( ); + Cvar_SetValue( "com_unfocused", !( appState & SDL_APPINPUTFOCUS ) ); + Cvar_SetValue( "com_minimized", !( appState & SDL_APPACTIVE ) ); + + IN_InitKeyLockStates( ); + + IN_InitJoystick( ); + Com_DPrintf( "------------------------------------\n" ); +} + +/* +=============== +IN_Shutdown +=============== +*/ +void IN_Shutdown( void ) +{ + IN_DeactivateMouse( ); + mouseAvailable = qfalse; + + IN_ShutdownJoystick( ); +} + +/* +=============== +IN_Restart +=============== +*/ +void IN_Restart( void ) +{ + IN_ShutdownJoystick( ); + IN_Init( ); +} + +void Sys_SendKeyEvents (void) +{ +} diff --git a/code/sdl/sdl_local.h b/code/sdl/sdl_local.h new file mode 100644 index 0000000..cc2b529 --- /dev/null +++ b/code/sdl/sdl_local.h @@ -0,0 +1,11 @@ +#include "../game/q_shared.h" +#include "../qcommon/qcommon.h" +#include "../client/client.h" + +void IN_Init( void ); +void IN_Shutdown( void ); +void IN_Restart( void ); + +void Sys_GLimpSafeInit( void ); +void Sys_GLimpInit( void ); +void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ); diff --git a/code/unix/unix_glimp_common.cpp b/code/unix/unix_glimp_common.cpp new file mode 100644 index 0000000..50cc6c3 --- /dev/null +++ b/code/unix/unix_glimp_common.cpp @@ -0,0 +1,82 @@ +#include +#include +#include "../game/q_shared.h" + +/* +=========================================================== + +SMP acceleration + +=========================================================== +*/ + +sem_t renderCommandsEvent; +sem_t renderCompletedEvent; +sem_t renderActiveEvent; + +void (*glimpRenderThread)( void ); + +void *GLimp_RenderThreadWrapper( void *stub ) { + glimpRenderThread(); +} + +/* +======================= +GLimp_SpawnRenderThread +======================= +*/ +pthread_t renderThreadHandle; +qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) { + + sem_init( &renderCommandsEvent, 0, 0 ); + sem_init( &renderCompletedEvent, 0, 0 ); + sem_init( &renderActiveEvent, 0, 0 ); + + glimpRenderThread = function; + + if (pthread_create( &renderThreadHandle, NULL, + GLimp_RenderThreadWrapper, NULL)) { + return qfalse; + } + + return qtrue; +} + +static void *smpData; + +void *GLimp_RendererSleep( void ) { + void *data; + + // after this, the front end can exit GLimp_FrontEndSleep + sem_post ( &renderCompletedEvent ); + + sem_wait ( &renderCommandsEvent ); + + data = smpData; + + // after this, the main thread can exit GLimp_WakeRenderer + sem_post ( &renderActiveEvent ); + + return data; +} + +void GLimp_FrontEndSleep( void ) { + sem_wait ( &renderCompletedEvent ); +} + +void GLimp_WakeRenderer( void *data ) { + smpData = data; + + // after this, the renderer can continue through GLimp_RendererSleep + sem_post( &renderCommandsEvent ); + + sem_wait( &renderActiveEvent ); +} + +void Sys_GLimpInit( void ) +{ +} + +void Sys_GLimpSafeInit( void ) +{ +} diff --git a/code/unix/unix_main.cpp b/code/unix/unix_main.cpp index 7524a2c..4e1725e 100644 --- a/code/unix/unix_main.cpp +++ b/code/unix/unix_main.cpp @@ -144,7 +144,7 @@ void Sys_Init(void) Cvar_Set( "arch", "unknown" ); #endif - IN_Init(); +// IN_Init(); } From 96fa13bbdbd32a60009edf088e2b8d6f0ef70b67 Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Tue, 30 Apr 2013 13:49:36 +1000 Subject: [PATCH 2/3] add sdl glimp/input from ioquake3 for MP --- codemp/CMakeLists.txt | 26 +- codemp/client/cl_main.cpp | 5 + codemp/client/client.h | 3 + codemp/game/q_shared.c | 38 + codemp/game/q_shared.h | 3 + codemp/renderer/qgl.h | 20 +- codemp/renderer/qgl_linked.h | 336 ++++++++ codemp/renderer/tr_init.cpp | 8 - codemp/sdl/sdl_gamma.cpp | 92 +++ codemp/sdl/sdl_glimp.cpp | 1207 +++++++++++++++++++++++++++++ codemp/sdl/sdl_input.cpp | 1107 ++++++++++++++++++++++++++ codemp/sdl/sdl_local.h | 11 + codemp/unix/unix_glimp_common.cpp | 82 ++ codemp/unix/unix_main.cpp | 2 +- 14 files changed, 2919 insertions(+), 21 deletions(-) create mode 100644 codemp/renderer/qgl_linked.h create mode 100644 codemp/sdl/sdl_gamma.cpp create mode 100644 codemp/sdl/sdl_glimp.cpp create mode 100644 codemp/sdl/sdl_input.cpp create mode 100644 codemp/sdl/sdl_local.h create mode 100644 codemp/unix/unix_glimp_common.cpp diff --git a/codemp/CMakeLists.txt b/codemp/CMakeLists.txt index aa308e4..a0f3246 100644 --- a/codemp/CMakeLists.txt +++ b/codemp/CMakeLists.txt @@ -47,11 +47,14 @@ add_definitions( -DFINAL_BUILD ) add_definitions( -D_JK2 ) add_definitions( -D_JK2MP ) -include_directories(/usr/X11R6/include/) -link_directories(/usr/X11R6/lib) +find_package (SDL REQUIRED) +include_directories(${SDL_INCLUDE_DIR}) -include_directories(/usr/local/include/) -link_directories(/usr/local/lib) +find_package(OpenGL REQUIRED) +include_directories(${OPENGL_INCLUDE_DIR}) + +find_package(OpenAL REQUIRED) +include_directories(${OPENAL_INCLUDE_DIR}) set(src_main_rmg RMG/RM_Area.cpp @@ -304,11 +307,16 @@ set(src_unix_common set(src_main_unix ${src_unix_common} - unix/linux_glimp.cpp - unix/linux_qgl.cpp + unix/unix_glimp_common.cpp null/null_snddma.cpp ) +set(src_sdl + sdl/sdl_gamma.cpp + sdl/sdl_glimp.cpp + sdl/sdl_input.cpp +) + set(src_botlib botlib/be_aas_bspq3.cpp botlib/be_aas_cluster.cpp @@ -354,6 +362,7 @@ set(src_jk2mp ${src_main_zlib} ${src_botlib} ${src_main_unix} + ${src_sdl} ) add_executable(jamp @@ -364,8 +373,9 @@ set_target_properties(jamp PROPERTIES COMPILE_DEFINITIONS "_JK2EXE;_FF_DISABLE;B target_link_libraries(jamp m pthread - X11 Xxf86vm Xxf86dga - openal + ${SDL_LIBRARY} + ${OPENGL_gl_LIBRARY} + ${OPENAL_LIBRARY} ) if (CMAKE_SYSTEM_NAME MATCHES "Linux") diff --git a/codemp/client/cl_main.cpp b/codemp/client/cl_main.cpp index 1dac58c..794c55b 100644 --- a/codemp/client/cl_main.cpp +++ b/codemp/client/cl_main.cpp @@ -102,6 +102,8 @@ char cl_cdkey[34] = " "; #endif // USE_CD_KEY +cvar_t *cl_consoleKeys; + clientActive_t cl; clientConnection_t clc; clientStatic_t cls; @@ -2631,6 +2633,9 @@ void CL_Init( void ) { Cvar_Get( "cl_maxPing", "800", CVAR_ARCHIVE ); + // ~ and `, as keys and characters + cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60", CVAR_ARCHIVE); + // userinfo Cvar_Get ("name", "Padawan", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("rate", "4000", CVAR_USERINFO | CVAR_ARCHIVE ); diff --git a/codemp/client/client.h b/codemp/client/client.h index 0cb20d7..6c231c6 100644 --- a/codemp/client/client.h +++ b/codemp/client/client.h @@ -432,6 +432,8 @@ extern cvar_t *cl_allowAltEnter; extern cvar_t *cl_conXOffset; extern cvar_t *cl_inGameVideo; +extern cvar_t *cl_consoleKeys; + //================================================= // @@ -499,6 +501,7 @@ void IN_CenterView (void); void CL_VerifyCode( void ); float CL_KeyState (kbutton_t *key); +int Key_StringToKeynum( char *str ); const char *Key_KeynumToString( int keynum/*, qboolean bTranslate */ ); //note: translate is only called for menu display not configs // diff --git a/codemp/game/q_shared.c b/codemp/game/q_shared.c index 49aa6e1..7a96921 100644 --- a/codemp/game/q_shared.c +++ b/codemp/game/q_shared.c @@ -759,6 +759,44 @@ void Parse3DMatrix (const char **buf_p, int z, int y, int x, float *m) { COM_MatchToken( buf_p, ")" ); } +/* +=================== +Com_HexStrToInt +=================== +*/ +int Com_HexStrToInt( const char *str ) +{ + if ( !str || !str[ 0 ] ) + return -1; + + // check for hex code + if( str[ 0 ] == '0' && str[ 1 ] == 'x' ) + { + int i, n = 0; + + for( i = 2; i < strlen( str ); i++ ) + { + char digit; + + n *= 16; + + digit = tolower( str[ i ] ); + + if( digit >= '0' && digit <= '9' ) + digit -= '0'; + else if( digit >= 'a' && digit <= 'f' ) + digit = digit - 'a' + 10; + else + return -1; + + n += digit; + } + + return n; + } + + return -1; +} /* ============================================================================ diff --git a/codemp/game/q_shared.h b/codemp/game/q_shared.h index 328d0dc..17edee8 100644 --- a/codemp/game/q_shared.h +++ b/codemp/game/q_shared.h @@ -410,6 +410,8 @@ typedef int clipHandle_t; #define MAX_QINT 0x7fffffff #define MIN_QINT (-MAX_QINT-1) +#define ARRAY_LEN(x) (sizeof(x) / sizeof(*(x))) +#define STRARRAY_LEN(x) (ARRAY_LEN(x) - 1) // angle indexes #define PITCH 0 // up / down @@ -1718,6 +1720,7 @@ void SkipRestOfLine ( const char **data ); void Parse1DMatrix (const char **buf_p, int x, float *m); void Parse2DMatrix (const char **buf_p, int y, int x, float *m); void Parse3DMatrix (const char **buf_p, int z, int y, int x, float *m); +int Com_HexStrToInt( const char *str ); void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...); diff --git a/codemp/renderer/qgl.h b/codemp/renderer/qgl.h index 0482734..1d8fbff 100644 --- a/codemp/renderer/qgl.h +++ b/codemp/renderer/qgl.h @@ -5,7 +5,17 @@ #ifndef __QGL_H__ #define __QGL_H__ -#if defined( __LINT__ ) +#ifndef DYNAMIC_LINK_GL + +#ifdef USE_LOCAL_HEADERS +# include "SDL_opengl.h" +#else +# include +#endif + +#include "qgl_linked.h" + +#elif defined( __LINT__ ) #include @@ -33,7 +43,7 @@ #include #endif -#endif +#endif // !DYNAMIC_LINK_GL #ifndef APIENTRY #define APIENTRY @@ -338,6 +348,7 @@ extern void ( APIENTRY * qglTexImage3DEXT) (GLenum, GLint, GLenum, GLsizei, GLsi extern void ( APIENTRY * qglTexSubImage3DEXT) (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); //=========================================================================== +#ifdef DYNAMIC_LINK_GL #if defined(MACOS_X) // This includes #ifdefs for optional logging and GL error checking after every GL call as well as #defines to prevent incorrect usage of the non-'qgl' versions of the GL API. @@ -734,6 +745,7 @@ extern void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable ); #endif // __linux__ || __FreeBSD__ // rb010123 -#endif // _WIN32 && __linux__ +#endif // _MACOS_X -#endif +#endif // DYNAMIC_LINK_GL +#endif // __QGL_H__ diff --git a/codemp/renderer/qgl_linked.h b/codemp/renderer/qgl_linked.h new file mode 100644 index 0000000..af71ba4 --- /dev/null +++ b/codemp/renderer/qgl_linked.h @@ -0,0 +1,336 @@ + +#define qglAccum glAccum +#define qglAlphaFunc glAlphaFunc +#define qglAreTexturesResident glAreTexturesResident +#define qglArrayElement glArrayElement +#define qglBegin glBegin +#define qglBindTexture glBindTexture +#define qglBitmap glBitmap +#define qglBlendFunc glBlendFunc +#define qglCallList glCallList +#define qglCallLists glCallLists +#define qglClear glClear +#define qglClearAccum glClearAccum +#define qglClearColor glClearColor +#define qglClearDepth glClearDepth +#define qglClearIndex glClearIndex +#define qglClearStencil glClearStencil +#define qglClipPlane glClipPlane +#define qglColor3b glColor3b +#define qglColor3bv glColor3bv +#define qglColor3d glColor3d +#define qglColor3dv glColor3dv +#define qglColor3f glColor3f +#define qglColor3fv glColor3fv +#define qglColor3i glColor3i +#define qglColor3iv glColor3iv +#define qglColor3s glColor3s +#define qglColor3sv glColor3sv +#define qglColor3ub glColor3ub +#define qglColor3ubv glColor3ubv +#define qglColor3ui glColor3ui +#define qglColor3uiv glColor3uiv +#define qglColor3us glColor3us +#define qglColor3usv glColor3usv +#define qglColor4b glColor4b +#define qglColor4bv glColor4bv +#define qglColor4d glColor4d +#define qglColor4dv glColor4dv +#define qglColor4f glColor4f +#define qglColor4fv glColor4fv +#define qglColor4i glColor4i +#define qglColor4iv glColor4iv +#define qglColor4s glColor4s +#define qglColor4sv glColor4sv +#define qglColor4ub glColor4ub +#define qglColor4ubv glColor4ubv +#define qglColor4ui glColor4ui +#define qglColor4uiv glColor4uiv +#define qglColor4us glColor4us +#define qglColor4usv glColor4usv +#define qglColorMask glColorMask +#define qglColorMaterial glColorMaterial +#define qglColorPointer glColorPointer +#define qglCopyPixels glCopyPixels +#define qglCopyTexImage1D glCopyTexImage1D +#define qglCopyTexImage2D glCopyTexImage2D +#define qglCopyTexSubImage1D glCopyTexSubImage1D +#define qglCopyTexSubImage2D glCopyTexSubImage2D +#define qglCullFace glCullFace +#define qglDeleteLists glDeleteLists +#define qglDeleteTextures glDeleteTextures +#define qglDepthFunc glDepthFunc +#define qglDepthMask glDepthMask +#define qglDepthRange glDepthRange +#define qglDisable glDisable +#define qglDisableClientState glDisableClientState +#define qglDrawArrays glDrawArrays +#define qglDrawBuffer glDrawBuffer +#define qglDrawElements glDrawElements +#define qglDrawPixels glDrawPixels +#define qglEdgeFlag glEdgeFlag +#define qglEdgeFlagPointer glEdgeFlagPointer +#define qglEdgeFlagv glEdgeFlagv +#define qglEnable glEnable +#define qglEnableClientState glEnableClientState +#define qglEnd glEnd +#define qglEndList glEndList +#define qglEvalCoord1d glEvalCoord1d +#define qglEvalCoord1dv glEvalCoord1dv +#define qglEvalCoord1f glEvalCoord1f +#define qglEvalCoord1fv glEvalCoord1fv +#define qglEvalCoord2d glEvalCoord2d +#define qglEvalCoord2dv glEvalCoord2dv +#define qglEvalCoord2f glEvalCoord2f +#define qglEvalCoord2fv glEvalCoord2fv +#define qglEvalMesh1 glEvalMesh1 +#define qglEvalMesh2 glEvalMesh2 +#define qglEvalPoint1 glEvalPoint1 +#define qglEvalPoint2 glEvalPoint2 +#define qglFeedbackBuffer glFeedbackBuffer +#define qglFinish glFinish +#define qglFlush glFlush +#define qglFogf glFogf +#define qglFogfv glFogfv +#define qglFogi glFogi +#define qglFogiv glFogiv +#define qglFrontFace glFrontFace +#define qglFrustum glFrustum +#define qglGenLists glGenLists +#define qglGenTextures glGenTextures +#define qglGetBooleanv glGetBooleanv +#define qglGetClipPlane glGetClipPlane +#define qglGetDoublev glGetDoublev +#define qglGetError glGetError +#define qglGetFloatv glGetFloatv +#define qglGetIntegerv glGetIntegerv +#define qglGetLightfv glGetLightfv +#define qglGetLightiv glGetLightiv +#define qglGetMapdv glGetMapdv +#define qglGetMapfv glGetMapfv +#define qglGetMapiv glGetMapiv +#define qglGetMaterialfv glGetMaterialfv +#define qglGetMaterialiv glGetMaterialiv +#define qglGetPixelMapfv glGetPixelMapfv +#define qglGetPixelMapuiv glGetPixelMapuiv +#define qglGetPixelMapusv glGetPixelMapusv +#define qglGetPointerv glGetPointerv +#define qglGetPolygonStipple glGetPolygonStipple +#define qglGetString glGetString +#define qglGetTexGendv glGetTexGendv +#define qglGetTexGenfv glGetTexGenfv +#define qglGetTexGeniv glGetTexGeniv +#define qglGetTexImage glGetTexImage +#define qglGetTexLevelParameterfv glGetTexLevelParameterfv +#define qglGetTexLevelParameteriv glGetTexLevelParameteriv +#define qglGetTexParameterfv glGetTexParameterfv +#define qglGetTexParameteriv glGetTexParameteriv +#define qglHint glHint +#define qglIndexMask glIndexMask +#define qglIndexPointer glIndexPointer +#define qglIndexd glIndexd +#define qglIndexdv glIndexdv +#define qglIndexf glIndexf +#define qglIndexfv glIndexfv +#define qglIndexi glIndexi +#define qglIndexiv glIndexiv +#define qglIndexs glIndexs +#define qglIndexsv glIndexsv +#define qglIndexub glIndexub +#define qglIndexubv glIndexubv +#define qglInitNames glInitNames +#define qglInterleavedArrays glInterleavedArrays +#define qglIsEnabled glIsEnabled +#define qglIsList glIsList +#define qglIsTexture glIsTexture +#define qglLightModelf glLightModelf +#define qglLightModelfv glLightModelfv +#define qglLightModeli glLightModeli +#define qglLightModeliv glLightModeliv +#define qglLightf glLightf +#define qglLightfv glLightfv +#define qglLighti glLighti +#define qglLightiv glLightiv +#define qglLineStipple glLineStipple +#define qglLineWidth glLineWidth +#define qglListBase glListBase +#define qglLoadIdentity glLoadIdentity +#define qglLoadMatrixd glLoadMatrixd +#define qglLoadMatrixf glLoadMatrixf +#define qglLoadName glLoadName +#define qglLogicOp glLogicOp +#define qglMap1d glMap1d +#define qglMap1f glMap1f +#define qglMap2d glMap2d +#define qglMap2f glMap2f +#define qglMapGrid1d glMapGrid1d +#define qglMapGrid1f glMapGrid1f +#define qglMapGrid2d glMapGrid2d +#define qglMapGrid2f glMapGrid2f +#define qglMaterialf glMaterialf +#define qglMaterialfv glMaterialfv +#define qglMateriali glMateriali +#define qglMaterialiv glMaterialiv +#define qglMatrixMode glMatrixMode +#define qglMultMatrixd glMultMatrixd +#define qglMultMatrixf glMultMatrixf +#define qglNewList glNewList +#define qglNormal3b glNormal3b +#define qglNormal3bv glNormal3bv +#define qglNormal3d glNormal3d +#define qglNormal3dv glNormal3dv +#define qglNormal3f glNormal3f +#define qglNormal3fv glNormal3fv +#define qglNormal3i glNormal3i +#define qglNormal3iv glNormal3iv +#define qglNormal3s glNormal3s +#define qglNormal3sv glNormal3sv +#define qglNormalPointer glNormalPointer +#define qglOrtho glOrtho +#define qglPassThrough glPassThrough +#define qglPixelMapfv glPixelMapfv +#define qglPixelMapuiv glPixelMapuiv +#define qglPixelMapusv glPixelMapusv +#define qglPixelStoref glPixelStoref +#define qglPixelStorei glPixelStorei +#define qglPixelTransferf glPixelTransferf +#define qglPixelTransferi glPixelTransferi +#define qglPixelZoom glPixelZoom +#define qglPointSize glPointSize +#define qglPolygonMode glPolygonMode +#define qglPolygonOffset glPolygonOffset +#define qglPolygonStipple glPolygonStipple +#define qglPopAttrib glPopAttrib +#define qglPopClientAttrib glPopClientAttrib +#define qglPopMatrix glPopMatrix +#define qglPopName glPopName +#define qglPrioritizeTextures glPrioritizeTextures +#define qglPushAttrib glPushAttrib +#define qglPushClientAttrib glPushClientAttrib +#define qglPushMatrix glPushMatrix +#define qglPushName glPushName +#define qglRasterPos2d glRasterPos2d +#define qglRasterPos2dv glRasterPos2dv +#define qglRasterPos2f glRasterPos2f +#define qglRasterPos2fv glRasterPos2fv +#define qglRasterPos2i glRasterPos2i +#define qglRasterPos2iv glRasterPos2iv +#define qglRasterPos2s glRasterPos2s +#define qglRasterPos2sv glRasterPos2sv +#define qglRasterPos3d glRasterPos3d +#define qglRasterPos3dv glRasterPos3dv +#define qglRasterPos3f glRasterPos3f +#define qglRasterPos3fv glRasterPos3fv +#define qglRasterPos3i glRasterPos3i +#define qglRasterPos3iv glRasterPos3iv +#define qglRasterPos3s glRasterPos3s +#define qglRasterPos3sv glRasterPos3sv +#define qglRasterPos4d glRasterPos4d +#define qglRasterPos4dv glRasterPos4dv +#define qglRasterPos4f glRasterPos4f +#define qglRasterPos4fv glRasterPos4fv +#define qglRasterPos4i glRasterPos4i +#define qglRasterPos4iv glRasterPos4iv +#define qglRasterPos4s glRasterPos4s +#define qglRasterPos4sv glRasterPos4sv +#define qglReadBuffer glReadBuffer +#define qglReadPixels glReadPixels +#define qglRectd glRectd +#define qglRectdv glRectdv +#define qglRectf glRectf +#define qglRectfv glRectfv +#define qglRecti glRecti +#define qglRectiv glRectiv +#define qglRects glRects +#define qglRectsv glRectsv +#define qglRenderMode glRenderMode +#define qglRotated glRotated +#define qglRotatef glRotatef +#define qglScaled glScaled +#define qglScalef glScalef +#define qglScissor glScissor +#define qglSelectBuffer glSelectBuffer +#define qglShadeModel glShadeModel +#define qglStencilFunc glStencilFunc +#define qglStencilMask glStencilMask +#define qglStencilOp glStencilOp +#define qglTexCoord1d glTexCoord1d +#define qglTexCoord1dv glTexCoord1dv +#define qglTexCoord1f glTexCoord1f +#define qglTexCoord1fv glTexCoord1fv +#define qglTexCoord1i glTexCoord1i +#define qglTexCoord1iv glTexCoord1iv +#define qglTexCoord1s glTexCoord1s +#define qglTexCoord1sv glTexCoord1sv +#define qglTexCoord2d glTexCoord2d +#define qglTexCoord2dv glTexCoord2dv +#define qglTexCoord2f glTexCoord2f +#define qglTexCoord2fv glTexCoord2fv +#define qglTexCoord2i glTexCoord2i +#define qglTexCoord2iv glTexCoord2iv +#define qglTexCoord2s glTexCoord2s +#define qglTexCoord2sv glTexCoord2sv +#define qglTexCoord3d glTexCoord3d +#define qglTexCoord3dv glTexCoord3dv +#define qglTexCoord3f glTexCoord3f +#define qglTexCoord3fv glTexCoord3fv +#define qglTexCoord3i glTexCoord3i +#define qglTexCoord3iv glTexCoord3iv +#define qglTexCoord3s glTexCoord3s +#define qglTexCoord3sv glTexCoord3sv +#define qglTexCoord4d glTexCoord4d +#define qglTexCoord4dv glTexCoord4dv +#define qglTexCoord4f glTexCoord4f +#define qglTexCoord4fv glTexCoord4fv +#define qglTexCoord4i glTexCoord4i +#define qglTexCoord4iv glTexCoord4iv +#define qglTexCoord4s glTexCoord4s +#define qglTexCoord4sv glTexCoord4sv +#define qglTexCoordPointer glTexCoordPointer +#define qglTexEnvf glTexEnvf +#define qglTexEnvfv glTexEnvfv +#define qglTexEnvi glTexEnvi +#define qglTexEnviv glTexEnviv +#define qglTexGend glTexGend +#define qglTexGendv glTexGendv +#define qglTexGenf glTexGenf +#define qglTexGenfv glTexGenfv +#define qglTexGeni glTexGeni +#define qglTexGeniv glTexGeniv +#define qglTexImage1D glTexImage1D +#define qglTexImage2D glTexImage2D +#define qglTexParameterf glTexParameterf +#define qglTexParameterfv glTexParameterfv +#define qglTexParameteri glTexParameteri +#define qglTexParameteriv glTexParameteriv +#define qglTexSubImage1D glTexSubImage1D +#define qglTexSubImage2D glTexSubImage2D +#define qglTranslated glTranslated +#define qglTranslatef glTranslatef +#define qglVertex2d glVertex2d +#define qglVertex2dv glVertex2dv +#define qglVertex2f glVertex2f +#define qglVertex2fv glVertex2fv +#define qglVertex2i glVertex2i +#define qglVertex2iv glVertex2iv +#define qglVertex2s glVertex2s +#define qglVertex2sv glVertex2sv +#define qglVertex3d glVertex3d +#define qglVertex3dv glVertex3dv +#define qglVertex3f glVertex3f +#define qglVertex3fv glVertex3fv +#define qglVertex3i glVertex3i +#define qglVertex3iv glVertex3iv +#define qglVertex3s glVertex3s +#define qglVertex3sv glVertex3sv +#define qglVertex4d glVertex4d +#define qglVertex4dv glVertex4dv +#define qglVertex4f glVertex4f +#define qglVertex4fv glVertex4fv +#define qglVertex4i glVertex4i +#define qglVertex4iv glVertex4iv +#define qglVertex4s glVertex4s +#define qglVertex4sv glVertex4sv +#define qglVertexPointer glVertexPointer +#define qglViewport glViewport + diff --git a/codemp/renderer/tr_init.cpp b/codemp/renderer/tr_init.cpp index 63fae51..2a54c97 100644 --- a/codemp/renderer/tr_init.cpp +++ b/codemp/renderer/tr_init.cpp @@ -1019,11 +1019,7 @@ void R_Register( void ) r_ext_gamma_control = Cvar_Get( "r_ext_gamma_control", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_ext_multitexture = Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_ext_compiled_vertex_array = Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH); -#ifdef __linux__ // broken on linux - r_ext_texture_env_add = Cvar_Get( "r_ext_texture_env_add", "0", CVAR_ARCHIVE | CVAR_LATCH); -#else r_ext_texture_env_add = Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH); -#endif r_ext_texture_filter_anisotropic = Cvar_Get( "r_ext_texture_filter_anisotropic", "16", CVAR_ARCHIVE ); r_DynamicGlow = Cvar_Get( "r_DynamicGlow", "0", CVAR_ARCHIVE ); @@ -1042,11 +1038,7 @@ void R_Register( void ) r_texturebitslm = Cvar_Get( "r_texturebitslm", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_colorbits = Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_stereo = Cvar_Get( "r_stereo", "0", CVAR_ARCHIVE | CVAR_LATCH ); -#ifdef __linux__ - r_stencilbits = Cvar_Get( "r_stencilbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); -#else r_stencilbits = Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH ); -#endif r_depthbits = Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_overBrightBits = Cvar_Get ("r_overBrightBits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_ignorehwgamma = Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); diff --git a/codemp/sdl/sdl_gamma.cpp b/codemp/sdl/sdl_gamma.cpp new file mode 100644 index 0000000..ef2a520 --- /dev/null +++ b/codemp/sdl/sdl_gamma.cpp @@ -0,0 +1,92 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#ifdef USE_LOCAL_HEADERS +# include "SDL.h" +#else +# include +#endif + +#include "../game/q_shared.h" +#include "../renderer/tr_local.h" +#include "../qcommon/qcommon.h" + +/* +================= +GLimp_SetGamma +================= +*/ +void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] ) +{ + Uint16 table[3][256]; + int i, j; + + if( !glConfig.deviceSupportsGamma || r_ignorehwgamma->integer > 0 ) + return; + + for (i = 0; i < 256; i++) + { + table[0][i] = ( ( ( Uint16 ) red[i] ) << 8 ) | red[i]; + table[1][i] = ( ( ( Uint16 ) green[i] ) << 8 ) | green[i]; + table[2][i] = ( ( ( Uint16 ) blue[i] ) << 8 ) | blue[i]; + } + +#ifdef _WIN32 +#include + + // Win2K and newer put this odd restriction on gamma ramps... + { + OSVERSIONINFO vinfo; + + vinfo.dwOSVersionInfoSize = sizeof( vinfo ); + GetVersionEx( &vinfo ); + if( vinfo.dwMajorVersion >= 5 && vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) + { + ri.Printf( PRINT_DEVELOPER, "performing gamma clamp.\n" ); + for( j = 0 ; j < 3 ; j++ ) + { + for( i = 0 ; i < 128 ; i++ ) + { + if( table[ j ] [ i] > ( ( 128 + i ) << 8 ) ) + table[ j ][ i ] = ( 128 + i ) << 8; + } + + if( table[ j ] [127 ] > 254 << 8 ) + table[ j ][ 127 ] = 254 << 8; + } + } + } +#endif + + // enforce constantly increasing + for (j = 0; j < 3; j++) + { + for (i = 1; i < 256; i++) + { + if (table[j][i] < table[j][i-1]) + table[j][i] = table[j][i-1]; + } + } + + SDL_SetGammaRamp(table[0], table[1], table[2]); +} + diff --git a/codemp/sdl/sdl_glimp.cpp b/codemp/sdl/sdl_glimp.cpp new file mode 100644 index 0000000..c7ef8d2 --- /dev/null +++ b/codemp/sdl/sdl_glimp.cpp @@ -0,0 +1,1207 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#ifdef USE_LOCAL_HEADERS +# include "SDL.h" +#else +# include +#endif + +#include +#include +#include +#include + +#include "sdl_local.h" +#include "../renderer/tr_local.h" +#ifdef notyet +#include "sdl_icon.h" +#endif + +#define CLIENT_WINDOW_TITLE "Jedi Outcast" +#define CLIENT_WINDOW_MIN_TITLE "JO" + +/* Just hack it for now. */ +#ifdef MACOS_X +#include +typedef CGLContextObj QGLContext; +#define GLimp_GetCurrentContext() CGLGetCurrentContext() +#define GLimp_SetCurrentContext(ctx) CGLSetCurrentContext(ctx) +#else +typedef void *QGLContext; +#define GLimp_GetCurrentContext() (NULL) +#define GLimp_SetCurrentContext(ctx) +#endif + +static QGLContext opengl_context; +static float displayAspect; + +typedef enum +{ + RSERR_OK, + + RSERR_INVALID_FULLSCREEN, + RSERR_INVALID_MODE, + + RSERR_UNKNOWN +} rserr_t; + +static SDL_Surface *screen = NULL; +static const SDL_VideoInfo *videoInfo = NULL; + +cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obtained +cvar_t *r_allowResize; // make window resizable +cvar_t *r_centerWindow; +cvar_t *r_sdlDriver; +cvar_t *r_noborder; + +// Whether the current hardware supports dynamic glows/flares. +extern bool g_bDynamicGlowSupported; + +// Hack variable for deciding which kind of texture rectangle thing to do (for some +// reason it acts different on radeon! It's against the spec!). +bool g_bTextureRectangleHack = false; + +/* +=============== +GLimp_Shutdown +=============== +*/ +void GLimp_Shutdown( void ) +{ + IN_Shutdown(); + + SDL_QuitSubSystem( SDL_INIT_VIDEO ); + screen = NULL; +} + +/* +=============== +GLimp_Minimize + +Minimize the game so that user is back at the desktop +=============== +*/ +void GLimp_Minimize(void) +{ + SDL_WM_IconifyWindow(); +} + + +/* +=============== +GLimp_LogComment +=============== +*/ +void GLimp_LogComment( char *comment ) +{ +} + +/* +=============== +GLimp_CompareModes +=============== +*/ +static int GLimp_CompareModes( const void *a, const void *b ) +{ + const float ASPECT_EPSILON = 0.001f; + SDL_Rect *modeA = *(SDL_Rect **)a; + SDL_Rect *modeB = *(SDL_Rect **)b; + float aspectA = (float)modeA->w / (float)modeA->h; + float aspectB = (float)modeB->w / (float)modeB->h; + int areaA = modeA->w * modeA->h; + int areaB = modeB->w * modeB->h; + float aspectDiffA = fabs( aspectA - displayAspect ); + float aspectDiffB = fabs( aspectB - displayAspect ); + float aspectDiffsDiff = aspectDiffA - aspectDiffB; + + if( aspectDiffsDiff > ASPECT_EPSILON ) + return 1; + else if( aspectDiffsDiff < -ASPECT_EPSILON ) + return -1; + else + return areaA - areaB; +} + + +/* +=============== +GLimp_DetectAvailableModes +=============== +*/ +static void GLimp_DetectAvailableModes(void) +{ + char buf[ MAX_STRING_CHARS ] = { 0 }; + SDL_Rect **modes; + int numModes; + int i; + + modes = SDL_ListModes( videoInfo->vfmt, SDL_OPENGL | SDL_FULLSCREEN ); + + if( !modes ) + { + Com_Printf( "Can't get list of available modes\n" ); + return; + } + + if( modes == (SDL_Rect **)-1 ) + { + Com_Printf( "Display supports any resolution\n" ); + return; // can set any resolution + } + + for( numModes = 0; modes[ numModes ]; numModes++ ); + + if( numModes > 1 ) + qsort( modes, numModes, sizeof( SDL_Rect* ), GLimp_CompareModes ); + + for( i = 0; i < numModes; i++ ) + { + const char *newModeString = va( "%ux%u ", modes[ i ]->w, modes[ i ]->h ); + + if( strlen( newModeString ) < (int)sizeof( buf ) - strlen( buf ) ) + Q_strcat( buf, sizeof( buf ), newModeString ); + else + Com_Printf( "Skipping mode %ux%x, buffer too small\n", modes[i]->w, modes[i]->h ); + } + + if( *buf ) + { + buf[ strlen( buf ) - 1 ] = 0; + Com_Printf( "Available modes: '%s'\n", buf ); + Cvar_Set( "r_availableModes", buf ); + } +} + +/* +=============== +GLimp_SetMode +=============== +*/ +static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) +{ + const char* glstring; + int sdlcolorbits; + int colorbits, depthbits, stencilbits; + int tcolorbits, tdepthbits, tstencilbits; + int samples; + int i = 0; + SDL_Surface *vidscreen = NULL; + Uint32 flags = SDL_OPENGL; + + Com_Printf( "Initializing OpenGL display\n"); + + if ( r_allowResize->integer ) + flags |= SDL_RESIZABLE; + + if( videoInfo == NULL ) + { + static SDL_VideoInfo sVideoInfo; + static SDL_PixelFormat sPixelFormat; + + videoInfo = SDL_GetVideoInfo( ); + + // Take a copy of the videoInfo + memcpy( &sPixelFormat, videoInfo->vfmt, sizeof( SDL_PixelFormat ) ); + sPixelFormat.palette = NULL; // Should already be the case + memcpy( &sVideoInfo, videoInfo, sizeof( SDL_VideoInfo ) ); + sVideoInfo.vfmt = &sPixelFormat; + videoInfo = &sVideoInfo; + + if( videoInfo->current_h > 0 ) + { + // Guess the display aspect ratio through the desktop resolution + // by assuming (relatively safely) that it is set at or close to + // the display's native aspect ratio + displayAspect = (float)videoInfo->current_w / (float)videoInfo->current_h; + + Com_Printf( "Estimated display aspect: %.3f\n", displayAspect ); + } + else + { + Com_Printf( "Cannot estimate display aspect, assuming 1.333\n" ); + } + } + + Com_Printf ( "...setting mode %d:", mode ); + + if (mode == -2) + { + // use desktop video resolution + if( videoInfo->current_h > 0 ) + { + glConfig.vidWidth = videoInfo->current_w; + glConfig.vidHeight = videoInfo->current_h; + } + else + { + glConfig.vidWidth = 640; + glConfig.vidHeight = 480; + Com_Printf( "Cannot determine display resolution, assuming 640x480\n" ); + } + +#if 0 + glConfig.windowAspect = (float)glConfig.vidWidth / (float)glConfig.vidHeight; +#endif + } + else if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, mode ) ) + { + Com_Printf( " invalid mode\n" ); + return RSERR_INVALID_MODE; + } + Com_Printf(" %d %d\n", glConfig.vidWidth, glConfig.vidHeight); + + if (fullscreen) + { + flags |= SDL_FULLSCREEN; + glConfig.isFullscreen = qtrue; + } + else + { + if (noborder) + flags |= SDL_NOFRAME; + + glConfig.isFullscreen = qfalse; + } + + colorbits = r_colorbits->value; + if ((!colorbits) || (colorbits >= 32)) + colorbits = 24; + + if (!r_depthbits->value) + depthbits = 24; + else + depthbits = r_depthbits->value; + stencilbits = r_stencilbits->value; +#ifdef notyet + samples = r_ext_multisample->value; +#else + samples = 0; +#endif + + for (i = 0; i < 16; i++) + { + // 0 - default + // 1 - minus colorbits + // 2 - minus depthbits + // 3 - minus stencil + if ((i % 4) == 0 && i) + { + // one pass, reduce + switch (i / 4) + { + case 2 : + if (colorbits == 24) + colorbits = 16; + break; + case 1 : + if (depthbits == 24) + depthbits = 16; + else if (depthbits == 16) + depthbits = 8; + case 3 : + if (stencilbits == 24) + stencilbits = 16; + else if (stencilbits == 16) + stencilbits = 8; + } + } + + tcolorbits = colorbits; + tdepthbits = depthbits; + tstencilbits = stencilbits; + + if ((i % 4) == 3) + { // reduce colorbits + if (tcolorbits == 24) + tcolorbits = 16; + } + + if ((i % 4) == 2) + { // reduce depthbits + if (tdepthbits == 24) + tdepthbits = 16; + else if (tdepthbits == 16) + tdepthbits = 8; + } + + if ((i % 4) == 1) + { // reduce stencilbits + if (tstencilbits == 24) + tstencilbits = 16; + else if (tstencilbits == 16) + tstencilbits = 8; + else + tstencilbits = 0; + } + + sdlcolorbits = 4; + if (tcolorbits == 24) + sdlcolorbits = 8; + +#ifdef __sgi /* Fix for SGIs grabbing too many bits of color */ + if (sdlcolorbits == 4) + sdlcolorbits = 0; /* Use minimum size for 16-bit color */ + + /* Need alpha or else SGIs choose 36+ bit RGB mode */ + SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 1); +#endif + + SDL_GL_SetAttribute( SDL_GL_RED_SIZE, sdlcolorbits ); + SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, sdlcolorbits ); + SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, sdlcolorbits ); + SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits ); + SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits ); + + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0 ); + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, samples ); + +#ifdef notyet + if(r_stereoEnabled->integer) + { + glConfig.stereoEnabled = qtrue; + SDL_GL_SetAttribute(SDL_GL_STEREO, 1); + } + else + { + glConfig.stereoEnabled = qfalse; + SDL_GL_SetAttribute(SDL_GL_STEREO, 0); + } +#endif + + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + +#if 0 // See http://bugzilla.icculus.org/show_bug.cgi?id=3526 + // If not allowing software GL, demand accelerated + if( !r_allowSoftwareGL->integer ) + { + if( SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 ) < 0 ) + { + Com_Printf( "Unable to guarantee accelerated " + "visual with libSDL < 1.2.10\n" ); + } + } +#endif + + if( SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, r_swapInterval->integer ) < 0 ) + Com_Printf( "r_swapInterval requires libSDL >= 1.2.10\n" ); + +#ifdef USE_ICON + { + SDL_Surface *icon = SDL_CreateRGBSurfaceFrom( + (void *)CLIENT_WINDOW_ICON.pixel_data, + CLIENT_WINDOW_ICON.width, + CLIENT_WINDOW_ICON.height, + CLIENT_WINDOW_ICON.bytes_per_pixel * 8, + CLIENT_WINDOW_ICON.bytes_per_pixel * CLIENT_WINDOW_ICON.width, +#ifdef Q3_LITTLE_ENDIAN + 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 +#else + 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF +#endif + ); + + SDL_WM_SetIcon( icon, NULL ); + SDL_FreeSurface( icon ); + } +#endif + + SDL_WM_SetCaption(CLIENT_WINDOW_TITLE, CLIENT_WINDOW_MIN_TITLE); + SDL_ShowCursor(0); + + if (!(vidscreen = SDL_SetVideoMode(glConfig.vidWidth, glConfig.vidHeight, colorbits, flags))) + { + Com_Printf( "SDL_SetVideoMode failed: %s\n", SDL_GetError( ) ); + continue; + } + + opengl_context = GLimp_GetCurrentContext(); + + Com_Printf( "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n", + sdlcolorbits, sdlcolorbits, sdlcolorbits, tdepthbits, tstencilbits); + + glConfig.colorBits = tcolorbits; + glConfig.depthBits = tdepthbits; + glConfig.stencilBits = tstencilbits; + break; + } + + GLimp_DetectAvailableModes(); + + if (!vidscreen) + { + Com_Printf( "Couldn't get a visual\n" ); + return RSERR_INVALID_MODE; + } + + screen = vidscreen; + + glstring = (char *) qglGetString (GL_RENDERER); + Com_Printf( "GL_RENDERER: %s\n", glstring ); + + return RSERR_OK; +} + +/* +=============== +GLimp_StartDriverAndSetMode +=============== +*/ +static qboolean GLimp_StartDriverAndSetMode(int mode, qboolean fullscreen, qboolean noborder) +{ + rserr_t err; + + if (!SDL_WasInit(SDL_INIT_VIDEO)) + { + char driverName[ 64 ]; + + if (SDL_Init(SDL_INIT_VIDEO) == -1) + { + Com_Printf("SDL_Init( SDL_INIT_VIDEO ) FAILED (%s)\n", + SDL_GetError()); + return qfalse; + } + + SDL_VideoDriverName( driverName, sizeof( driverName ) - 1 ); + Com_Printf( "SDL using driver \"%s\"\n", driverName ); + Cvar_Set( "r_sdlDriver", driverName ); + } + + if (fullscreen && Cvar_VariableIntegerValue( "in_nograb" ) ) + { + Com_Printf( "Fullscreen not allowed with in_nograb 1\n"); + Cvar_Set( "r_fullscreen", "0" ); + r_fullscreen->modified = qfalse; + fullscreen = qfalse; + } + + err = (rserr_t) GLimp_SetMode(mode, fullscreen, noborder); + + switch ( err ) + { + case RSERR_INVALID_FULLSCREEN: + Com_Printf( "...WARNING: fullscreen unavailable in this mode\n" ); + return qfalse; + case RSERR_INVALID_MODE: + Com_Printf( "...WARNING: could not set the given mode (%d)\n", mode ); + return qfalse; + default: + break; + } + + return qtrue; +} + +//-------------------------------------------- +static void GLW_InitTextureCompression( void ) +{ + qboolean newer_tc, old_tc; + + // Check for available tc methods. + newer_tc = ( strstr( glConfig.extensions_string, "ARB_texture_compression" ) + && strstr( glConfig.extensions_string, "EXT_texture_compression_s3tc" )) ? qtrue : qfalse; + old_tc = ( strstr( glConfig.extensions_string, "GL_S3_s3tc" )) ? qtrue : qfalse; + + if ( old_tc ) + { + Com_Printf ("...GL_S3_s3tc available\n" ); + } + + if ( newer_tc ) + { + Com_Printf ("...GL_EXT_texture_compression_s3tc available\n" ); + } + + if ( !r_ext_compressed_textures->value ) + { + // Compressed textures are off + glConfig.textureCompression = TC_NONE; + Com_Printf ("...ignoring texture compression\n" ); + } + else if ( !old_tc && !newer_tc ) + { + // Requesting texture compression, but no method found + glConfig.textureCompression = TC_NONE; + Com_Printf ("...no supported texture compression method found\n" ); + Com_Printf (".....ignoring texture compression\n" ); + } + else + { + // some form of supported texture compression is avaiable, so see if the user has a preference + if ( r_ext_preferred_tc_method->integer == TC_NONE ) + { + // No preference, so pick the best + if ( newer_tc ) + { + Com_Printf ("...no tc preference specified\n" ); + Com_Printf (".....using GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + else + { + Com_Printf ("...no tc preference specified\n" ); + Com_Printf (".....using GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + } + else + { + // User has specified a preference, now see if this request can be honored + if ( old_tc && newer_tc ) + { + // both are avaiable, so we can use the desired tc method + if ( r_ext_preferred_tc_method->integer == TC_S3TC ) + { + Com_Printf ("...using preferred tc method, GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + else + { + Com_Printf ("...using preferred tc method, GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + } + else + { + // Both methods are not available, so this gets trickier + if ( r_ext_preferred_tc_method->integer == TC_S3TC ) + { + // Preferring to user older compression + if ( old_tc ) + { + Com_Printf ("...using GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + else + { + // Drat, preference can't be honored + Com_Printf ("...preferred tc method, GL_S3_s3tc not available\n" ); + Com_Printf (".....falling back to GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + } + else + { + // Preferring to user newer compression + if ( newer_tc ) + { + Com_Printf ("...using GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + else + { + // Drat, preference can't be honored + Com_Printf ("...preferred tc method, GL_EXT_texture_compression_s3tc not available\n" ); + Com_Printf (".....falling back to GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + } + } + } + } +} + +/* +** GLW_InitExtensions +*/ +static void GLimp_InitExtensions( void ) +{ + if ( !r_allowExtensions->integer ) + { + Com_Printf ("*** IGNORING OPENGL EXTENSIONS ***\n" ); + g_bDynamicGlowSupported = false; + Cvar_Set( "r_DynamicGlow","0" ); + return; + } + + Com_Printf ("Initializing OpenGL extensions\n" ); + + // Select our tc scheme + GLW_InitTextureCompression(); + + // 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; + Com_Printf ("...using GL_EXT_texture_env_add\n" ); + } + else + { + glConfig.textureEnvAddAvailable = qfalse; + Com_Printf ("...ignoring GL_EXT_texture_env_add\n" ); + } + } + else + { + Com_Printf ("...GL_EXT_texture_env_add not found\n" ); + } + + // GL_EXT_texture_filter_anisotropic + glConfig.maxTextureFilterAnisotropy = 0; + if ( strstr( glConfig.extensions_string, "EXT_texture_filter_anisotropic" ) ) + { +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF //can't include glext.h here ... sigh + qglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.maxTextureFilterAnisotropy ); + Com_Printf ("...GL_EXT_texture_filter_anisotropic available\n" ); + + if ( r_ext_texture_filter_anisotropic->integer>1 ) + { + Com_Printf ("...using GL_EXT_texture_filter_anisotropic\n" ); + } + else + { + Com_Printf ("...ignoring GL_EXT_texture_filter_anisotropic\n" ); + } + Cvar_Set( "r_ext_texture_filter_anisotropic_avail", va("%f",glConfig.maxTextureFilterAnisotropy) ); + if ( r_ext_texture_filter_anisotropic->value > glConfig.maxTextureFilterAnisotropy ) + { + Cvar_Set( "r_ext_texture_filter_anisotropic", va("%f",glConfig.maxTextureFilterAnisotropy) ); + } + } + else + { + Com_Printf ("...GL_EXT_texture_filter_anisotropic not found\n" ); + Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "0" ); + } + + // GL_EXT_clamp_to_edge + glConfig.clampToEdgeAvailable = qfalse; + if ( strstr( glConfig.extensions_string, "GL_EXT_texture_edge_clamp" ) ) + { + glConfig.clampToEdgeAvailable = qtrue; + Com_Printf ("...Using GL_EXT_texture_edge_clamp\n" ); + } + +#if 0 + // WGL_EXT_swap_control + qwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) SDL_GL_GetProcAddress( "wglSwapIntervalEXT" ); + if ( qwglSwapIntervalEXT ) + { + Com_Printf ("...using WGL_EXT_swap_control\n" ); + r_swapInterval->modified = qtrue; // force a set next frame + } + else + { + Com_Printf ("...WGL_EXT_swap_control not found\n" ); + } +#endif + + // GL_ARB_multitexture + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + if ( strstr( glConfig.extensions_string, "GL_ARB_multitexture" ) ) + { + if ( r_ext_multitexture->integer ) + { + qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) SDL_GL_GetProcAddress( "glMultiTexCoord2fARB" ); + qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) SDL_GL_GetProcAddress( "glActiveTextureARB" ); + qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) SDL_GL_GetProcAddress( "glClientActiveTextureARB" ); + + if ( qglActiveTextureARB ) + { + qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glConfig.maxActiveTextures ); + + if ( glConfig.maxActiveTextures > 1 ) + { + Com_Printf ("...using GL_ARB_multitexture\n" ); + } + else + { + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + Com_Printf ("...not using GL_ARB_multitexture, < 2 texture units\n" ); + } + } + } + else + { + Com_Printf ("...ignoring GL_ARB_multitexture\n" ); + } + } + else + { + Com_Printf ("...GL_ARB_multitexture not found\n" ); + } + + // GL_EXT_compiled_vertex_array + qglLockArraysEXT = NULL; + qglUnlockArraysEXT = NULL; + if ( strstr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) ) + { + if ( r_ext_compiled_vertex_array->integer ) + { + Com_Printf ("...using GL_EXT_compiled_vertex_array\n" ); + qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) SDL_GL_GetProcAddress( "glLockArraysEXT" ); + qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) SDL_GL_GetProcAddress( "glUnlockArraysEXT" ); + if (!qglLockArraysEXT || !qglUnlockArraysEXT) { + Com_Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + Com_Printf ("...ignoring GL_EXT_compiled_vertex_array\n" ); + } + } + else + { + Com_Printf ("...GL_EXT_compiled_vertex_array not found\n" ); + } + + qglPointParameterfEXT = NULL; + qglPointParameterfvEXT = NULL; + + //3d textures -rww + qglTexImage3DEXT = NULL; + qglTexSubImage3DEXT = NULL; + + if ( strstr( glConfig.extensions_string, "GL_EXT_point_parameters" ) ) + { + if ( r_ext_compiled_vertex_array->integer || 1) + { + Com_Printf ("...using GL_EXT_point_parameters\n" ); + qglPointParameterfEXT = ( void ( APIENTRY * )( GLenum, GLfloat) ) SDL_GL_GetProcAddress( "glPointParameterfEXT" ); + qglPointParameterfvEXT = ( void ( APIENTRY * )( GLenum, GLfloat *) ) SDL_GL_GetProcAddress( "glPointParameterfvEXT" ); + + //3d textures -rww + qglTexImage3DEXT = (void ( APIENTRY * ) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *) ) SDL_GL_GetProcAddress( "glTexImage3DEXT" ); + qglTexSubImage3DEXT = (void ( APIENTRY * ) (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *) ) SDL_GL_GetProcAddress( "glTexSubImage3DEXT" ); + + if (!qglPointParameterfEXT || !qglPointParameterfvEXT) + { + Com_Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + Com_Printf ("...ignoring GL_EXT_point_parameters\n" ); + } + } + else + { + Com_Printf ("...GL_EXT_point_parameters not found\n" ); + } + + bool bNVRegisterCombiners = false; + // Register Combiners. + if ( strstr( glConfig.extensions_string, "GL_NV_register_combiners" ) ) + { + // NOTE: This extension requires multitexture support (over 2 units). + if ( glConfig.maxActiveTextures >= 2 ) + { + bNVRegisterCombiners = true; + // Register Combiners function pointer address load. - AReis + // NOTE: VV guys will _definetly_ not be able to use regcoms. Pixel Shaders are just as good though :-) + // NOTE: Also, this is an nVidia specific extension (of course), so fragment shaders would serve the same purpose + // if we needed some kind of fragment/pixel manipulation support. + qglCombinerParameterfvNV = ( PFNGLCOMBINERPARAMETERFVNV ) SDL_GL_GetProcAddress( "glCombinerParameterfvNV" ); + qglCombinerParameterivNV = ( PFNGLCOMBINERPARAMETERIVNV ) SDL_GL_GetProcAddress( "glCombinerParameterivNV" ); + qglCombinerParameterfNV = ( PFNGLCOMBINERPARAMETERFNV ) SDL_GL_GetProcAddress( "glCombinerParameterfNV" ); + qglCombinerParameteriNV = ( PFNGLCOMBINERPARAMETERINV ) SDL_GL_GetProcAddress( "glCombinerParameteriNV" ); + qglCombinerInputNV = ( PFNGLCOMBINERINPUTNV ) SDL_GL_GetProcAddress( "glCombinerInputNV" ); + qglCombinerOutputNV = ( PFNGLCOMBINEROUTPUTNV ) SDL_GL_GetProcAddress( "glCombinerOutputNV" ); + qglFinalCombinerInputNV = ( PFNGLFINALCOMBINERINPUTNV ) SDL_GL_GetProcAddress( "glFinalCombinerInputNV" ); + qglGetCombinerInputParameterfvNV = ( PFNGLGETCOMBINERINPUTPARAMETERFVNV ) SDL_GL_GetProcAddress( "glGetCombinerInputParameterfvNV" ); + qglGetCombinerInputParameterivNV = ( PFNGLGETCOMBINERINPUTPARAMETERIVNV ) SDL_GL_GetProcAddress( "glGetCombinerInputParameterivNV" ); + qglGetCombinerOutputParameterfvNV = ( PFNGLGETCOMBINEROUTPUTPARAMETERFVNV ) SDL_GL_GetProcAddress( "glGetCombinerOutputParameterfvNV" ); + qglGetCombinerOutputParameterivNV = ( PFNGLGETCOMBINEROUTPUTPARAMETERIVNV ) SDL_GL_GetProcAddress( "glGetCombinerOutputParameterivNV" ); + qglGetFinalCombinerInputParameterfvNV = ( PFNGLGETFINALCOMBINERINPUTPARAMETERFVNV ) SDL_GL_GetProcAddress( "glGetFinalCombinerInputParameterfvNV" ); + qglGetFinalCombinerInputParameterivNV = ( PFNGLGETFINALCOMBINERINPUTPARAMETERIVNV ) SDL_GL_GetProcAddress( "glGetFinalCombinerInputParameterivNV" ); + + // Validate the functions we need. + if ( !qglCombinerParameterfvNV || !qglCombinerParameterivNV || !qglCombinerParameterfNV || !qglCombinerParameteriNV || !qglCombinerInputNV || + !qglCombinerOutputNV || !qglFinalCombinerInputNV || !qglGetCombinerInputParameterfvNV || !qglGetCombinerInputParameterivNV || + !qglGetCombinerOutputParameterfvNV || !qglGetCombinerOutputParameterivNV || !qglGetFinalCombinerInputParameterfvNV || !qglGetFinalCombinerInputParameterivNV ) + { + bNVRegisterCombiners = false; + qglCombinerParameterfvNV = NULL; + qglCombinerParameteriNV = NULL; + Com_Printf ("...GL_NV_register_combiners failed\n" ); + } + } + else + { + bNVRegisterCombiners = false; + Com_Printf ("...ignoring GL_NV_register_combiners\n" ); + } + } + else + { + bNVRegisterCombiners = false; + Com_Printf ("...GL_NV_register_combiners not found\n" ); + } + + // NOTE: Vertex and Fragment Programs are very dependant on each other - this is actually a + // good thing! So, just check to see which we support (one or the other) and load the shared + // function pointers. ARB rocks! + + // Vertex Programs. + bool bARBVertexProgram = false; + if ( strstr( glConfig.extensions_string, "GL_ARB_vertex_program" ) ) + { + bARBVertexProgram = true; + } + else + { + bARBVertexProgram = false; + Com_Printf ("...GL_ARB_vertex_program not found\n" ); + } + + // Fragment Programs. + bool bARBFragmentProgram = false; + if ( strstr( glConfig.extensions_string, "GL_ARB_fragment_program" ) ) + { + bARBFragmentProgram = true; + } + else + { + bARBFragmentProgram = false; + Com_Printf ("...GL_ARB_fragment_program not found\n" ); + } + + // If we support one or the other, load the shared function pointers. + if ( bARBVertexProgram || bARBFragmentProgram ) + { + qglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) SDL_GL_GetProcAddress("glProgramStringARB"); + qglBindProgramARB = (PFNGLBINDPROGRAMARBPROC) SDL_GL_GetProcAddress("glBindProgramARB"); + qglDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) SDL_GL_GetProcAddress("glDeleteProgramsARB"); + qglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) SDL_GL_GetProcAddress("glGenProgramsARB"); + qglProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4dARB"); + qglProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4dvARB"); + qglProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4fARB"); + qglProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4fvARB"); + qglProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4dARB"); + qglProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4dvARB"); + qglProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4fARB"); + qglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4fvARB"); + qglGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) SDL_GL_GetProcAddress("glGetProgramEnvParameterdvARB"); + qglGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetProgramEnvParameterfvARB"); + qglGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) SDL_GL_GetProcAddress("glGetProgramLocalParameterdvARB"); + qglGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetProgramLocalParameterfvARB"); + qglGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) SDL_GL_GetProcAddress("glGetProgramivARB"); + qglGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) SDL_GL_GetProcAddress("glGetProgramStringARB"); + qglIsProgramARB = (PFNGLISPROGRAMARBPROC) SDL_GL_GetProcAddress("glIsProgramARB"); + + // Validate the functions we need. + if ( !qglProgramStringARB || !qglBindProgramARB || !qglDeleteProgramsARB || !qglGenProgramsARB || + !qglProgramEnvParameter4dARB || !qglProgramEnvParameter4dvARB || !qglProgramEnvParameter4fARB || + !qglProgramEnvParameter4fvARB || !qglProgramLocalParameter4dARB || !qglProgramLocalParameter4dvARB || + !qglProgramLocalParameter4fARB || !qglProgramLocalParameter4fvARB || !qglGetProgramEnvParameterdvARB || + !qglGetProgramEnvParameterfvARB || !qglGetProgramLocalParameterdvARB || !qglGetProgramLocalParameterfvARB || + !qglGetProgramivARB || !qglGetProgramStringARB || !qglIsProgramARB ) + { + bARBVertexProgram = false; + bARBFragmentProgram = false; + qglGenProgramsARB = NULL; //clear ptrs that get checked + qglProgramEnvParameter4fARB = NULL; + Com_Printf ("...ignoring GL_ARB_vertex_program\n" ); + Com_Printf ("...ignoring GL_ARB_fragment_program\n" ); + } + } + + // Figure out which texture rectangle extension to use. + bool bTexRectSupported = false; + if ( Q_strnicmp( glConfig.vendor_string, "ATI Technologies",16 )==0 + && Q_strnicmp( glConfig.version_string, "1.3.3",5 )==0 + && glConfig.version_string[5] < '9' ) //1.3.34 and 1.3.37 and 1.3.38 are broken for sure, 1.3.39 is not + { + g_bTextureRectangleHack = true; + } + + if ( strstr( glConfig.extensions_string, "GL_NV_texture_rectangle" ) + || strstr( glConfig.extensions_string, "GL_EXT_texture_rectangle" ) ) + { + bTexRectSupported = true; + } + +#if 0 + // OK, so not so good to put this here, but no one else uses it!!! -AReis + typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); + PFNWGLGETEXTENSIONSSTRINGARBPROC qwglGetExtensionsStringARB; + qwglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) SDL_GL_GetProcAddress("wglGetExtensionsStringARB"); + + const char *wglExtensions = NULL; +#endif + bool bHasPixelFormat = false; + bool bHasRenderTexture = false; + +#if 0 + // Get the WGL extensions string. + if ( qwglGetExtensionsStringARB ) + { + wglExtensions = qwglGetExtensionsStringARB( glw_state.hDC ); + } + + // This externsion is used to get the wgl extension string. + if ( wglExtensions ) + { + // Pixel Format. + if ( strstr( wglExtensions, "WGL_ARB_pixel_format" ) ) + { + qwglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) SDL_GL_GetProcAddress("wglGetPixelFormatAttribivARB"); + qwglGetPixelFormatAttribfvARB = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC) SDL_GL_GetProcAddress("wglGetPixelFormatAttribfvARB"); + qwglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) SDL_GL_GetProcAddress("wglChoosePixelFormatARB"); + + // Validate the functions we need. + if ( !qwglGetPixelFormatAttribivARB || !qwglGetPixelFormatAttribfvARB || !qwglChoosePixelFormatARB ) + { + Com_Printf ("...ignoring WGL_ARB_pixel_format\n" ); + } + else + { + bHasPixelFormat = true; + } + } + else + { + Com_Printf ("...ignoring WGL_ARB_pixel_format\n" ); + } + + // Offscreen pixel-buffer. + // NOTE: VV guys can use the equivelant SetRenderTarget() with the correct texture surfaces. + bool bWGLARBPbuffer = false; + if ( strstr( wglExtensions, "WGL_ARB_pbuffer" ) && bHasPixelFormat ) + { + bWGLARBPbuffer = true; + qwglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC) SDL_GL_GetProcAddress("wglCreatePbufferARB"); + qwglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC) SDL_GL_GetProcAddress("wglGetPbufferDCARB"); + qwglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC) SDL_GL_GetProcAddress("wglReleasePbufferDCARB"); + qwglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC) SDL_GL_GetProcAddress("wglDestroyPbufferARB"); + qwglQueryPbufferARB = (PFNWGLQUERYPBUFFERARBPROC) SDL_GL_GetProcAddress("wglQueryPbufferARB"); + + // Validate the functions we need. + if ( !qwglCreatePbufferARB || !qwglGetPbufferDCARB || !qwglReleasePbufferDCARB || !qwglDestroyPbufferARB || !qwglQueryPbufferARB ) + { + bWGLARBPbuffer = false; + Com_Printf ("...WGL_ARB_pbuffer failed\n" ); + } + } + else + { + bWGLARBPbuffer = false; + Com_Printf ("...WGL_ARB_pbuffer not found\n" ); + } + + // Render-Texture (requires pbuffer ext (and it's dependancies of course). + if ( strstr( wglExtensions, "WGL_ARB_render_texture" ) && bWGLARBPbuffer ) + { + qwglBindTexImageARB = (PFNWGLBINDTEXIMAGEARBPROC) SDL_GL_GetProcAddress("wglBindTexImageARB"); + qwglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARBPROC) SDL_GL_GetProcAddress("wglReleaseTexImageARB"); + qwglSetPbufferAttribARB = (PFNWGLSETPBUFFERATTRIBARBPROC) SDL_GL_GetProcAddress("wglSetPbufferAttribARB"); + + // Validate the functions we need. + if ( !qwglCreatePbufferARB || !qwglGetPbufferDCARB || !qwglReleasePbufferDCARB || !qwglDestroyPbufferARB || !qwglQueryPbufferARB ) + { + Com_Printf ("...ignoring WGL_ARB_render_texture\n" ); + } + else + { + bHasRenderTexture = true; + } + } + else + { + Com_Printf ("...ignoring WGL_ARB_render_texture\n" ); + } + } +#endif + + // Find out how many general combiners they have. + #define GL_MAX_GENERAL_COMBINERS_NV 0x854D + GLint iNumGeneralCombiners = 0; + qglGetIntegerv( GL_MAX_GENERAL_COMBINERS_NV, &iNumGeneralCombiners ); + + // Only allow dynamic glows/flares if they have the hardware + if ( bTexRectSupported && bARBVertexProgram && bHasRenderTexture && qglActiveTextureARB && glConfig.maxActiveTextures >= 4 && + ( ( bNVRegisterCombiners && iNumGeneralCombiners >= 2 ) || bARBFragmentProgram ) ) + { + g_bDynamicGlowSupported = true; + // this would overwrite any achived setting gwg + // Cvar_Set( "r_DynamicGlow", "1" ); + } + else + { + g_bDynamicGlowSupported = false; + Cvar_Set( "r_DynamicGlow","0" ); + } +} + +#define R_MODE_FALLBACK 3 // 640 * 480 + +/* +=============== +GLimp_Init + +This routine is responsible for initializing the OS specific portions +of OpenGL +=============== +*/ +void GLimp_Init( void ) +{ + r_allowSoftwareGL = Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); + r_sdlDriver = Cvar_Get( "r_sdlDriver", "", CVAR_ROM ); + r_allowResize = Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE ); + r_centerWindow = Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE ); + r_noborder = Cvar_Get( "r_noborder", "0", CVAR_ARCHIVE ); + qboolean fullscreen, noborder; + + if( Cvar_VariableIntegerValue( "com_abnormalExit" ) ) + { + Cvar_Set( "r_mode", va( "%d", R_MODE_FALLBACK ) ); + Cvar_Set( "r_fullscreen", "0" ); + Cvar_Set( "r_centerWindow", "0" ); + Cvar_Set( "com_abnormalExit", "0" ); + } + +#ifdef notyet + Sys_SetEnv( "SDL_VIDEO_CENTERED", r_centerWindow->integer ? "1" : "" ); +#endif + + Sys_GLimpInit( ); + + fullscreen = (r_fullscreen->integer) ? qtrue : qfalse; + noborder = (r_noborder->integer) ? qtrue : qfalse; + + // Create the window and set up the context + if(GLimp_StartDriverAndSetMode(r_mode->integer, fullscreen, noborder)) + goto success; + + // Try again, this time in a platform specific "safe mode" + Sys_GLimpSafeInit( ); + + if(GLimp_StartDriverAndSetMode(r_mode->integer, fullscreen, qfalse)) + goto success; + + // Finally, try the default screen resolution + if( r_mode->integer != R_MODE_FALLBACK ) + { + Com_Printf( "Setting r_mode %d failed, falling back on r_mode %d\n", + r_mode->integer, R_MODE_FALLBACK ); + + if(GLimp_StartDriverAndSetMode(R_MODE_FALLBACK, qfalse, qfalse)) + goto success; + } + + // Nothing worked, give up + Com_Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem" ); + +success: +#if 0 + // This values force the UI to disable driver selection + glConfig.driverType = GLDRV_ICD; + glConfig.hardwareType = GLHW_GENERIC; +#endif + glConfig.deviceSupportsGamma = (SDL_SetGamma( 1.0f, 1.0f, 1.0f ) >= 0) ? qtrue : qfalse; + + // Mysteriously, if you use an NVidia graphics card and multiple monitors, + // SDL_SetGamma will incorrectly return false... the first time; ask + // again and you get the correct answer. This is a suspected driver bug, see + // http://bugzilla.icculus.org/show_bug.cgi?id=4316 + glConfig.deviceSupportsGamma = (SDL_SetGamma( 1.0f, 1.0f, 1.0f ) >= 0) ? qtrue : qfalse; + + if ( -1 == r_ignorehwgamma->integer) + glConfig.deviceSupportsGamma = qtrue; + + if ( 1 == r_ignorehwgamma->integer) + glConfig.deviceSupportsGamma = qfalse; + + // get our config strings + glConfig.vendor_string = (const char *) qglGetString (GL_VENDOR); + glConfig.renderer_string = (const char *) qglGetString (GL_RENDERER); + glConfig.version_string = (const char *) qglGetString (GL_VERSION); + glConfig.extensions_string = (const char *) qglGetString (GL_EXTENSIONS); + + // OpenGL driver constants + qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &glConfig.maxTextureSize ); + // stubbed or broken drivers may have reported 0... + if ( glConfig.maxTextureSize <= 0 ) + { + glConfig.maxTextureSize = 0; + } + + // initialize extensions + GLimp_InitExtensions( ); + + Cvar_Get( "r_availableModes", "", CVAR_ROM ); + + // This depends on SDL_INIT_VIDEO, hence having it here + IN_Init( ); +} + + +/* +=============== +GLimp_EndFrame + +Responsible for doing a swapbuffers +=============== +*/ +void GLimp_EndFrame( void ) +{ + // don't flip if drawing to front buffer + //if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 ) + { + SDL_GL_SwapBuffers(); + } + + if( r_fullscreen->modified ) + { + qboolean fullscreen; + qboolean needToToggle = qtrue; + qboolean sdlToggled = qfalse; + SDL_Surface *s = SDL_GetVideoSurface( ); + + if( s ) + { + // Find out the current state + fullscreen = (!!( s->flags & SDL_FULLSCREEN )) ? qtrue : qfalse; + + if( r_fullscreen->integer && Cvar_VariableIntegerValue( "in_nograb" ) ) + { + Com_Printf( "Fullscreen not allowed with in_nograb 1\n"); + Cvar_Set( "r_fullscreen", "0" ); + r_fullscreen->modified = qfalse; + } + + // Is the state we want different from the current state? + needToToggle = (!!r_fullscreen->integer != fullscreen) ? qtrue : qfalse; + + if( needToToggle ) + sdlToggled = SDL_WM_ToggleFullScreen( s ); + } + + if( needToToggle ) + { + // SDL_WM_ToggleFullScreen didn't work, so do it the slow way + if( !sdlToggled ) + Cbuf_AddText( "vid_restart\n" ); + + IN_Restart( ); + } + + r_fullscreen->modified = qfalse; + } +} diff --git a/codemp/sdl/sdl_input.cpp b/codemp/sdl/sdl_input.cpp new file mode 100644 index 0000000..c0632f2 --- /dev/null +++ b/codemp/sdl/sdl_input.cpp @@ -0,0 +1,1107 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#ifdef USE_LOCAL_HEADERS +# include "SDL.h" +#else +# include +#endif + +#include +#include +#include + +#include "../client/client.h" +#include "sdl_local.h" + +#ifdef MACOS_X +// Mouse acceleration needs to be disabled +#define MACOS_X_ACCELERATION_HACK +// Cursor needs hack to hide +#define MACOS_X_CURSOR_HACK +#endif + +#ifdef MACOS_X_ACCELERATION_HACK +#include +#include +#include +#include +#endif + +static cvar_t *in_keyboardDebug = NULL; + +static SDL_Joystick *stick = NULL; + +static qboolean mouseAvailable = qfalse; +static qboolean mouseActive = qfalse; +static qboolean keyRepeatEnabled = qfalse; + +static cvar_t *in_mouse = NULL; +#ifdef MACOS_X_ACCELERATION_HACK +static cvar_t *in_disablemacosxmouseaccel = NULL; +static double originalMouseSpeed = -1.0; +#endif +static cvar_t *in_nograb; + +cvar_t *in_joystick = NULL; +static cvar_t *in_joystickDebug = NULL; +static cvar_t *in_joystickThreshold = NULL; +static cvar_t *in_joystickNo = NULL; +static cvar_t *in_joystickUseAnalog = NULL; + +static int vidRestartTime = 0; + +#define CTRL(a) ((a)-'a'+1) + +/* +=============== +IN_PrintKey +=============== +*/ +static void IN_PrintKey( const SDL_keysym *keysym, fakeAscii_t key, qboolean down ) +{ + if( down ) + Com_Printf( "+ " ); + else + Com_Printf( " " ); + + Com_Printf( "0x%02x \"%s\"", keysym->scancode, + SDL_GetKeyName( keysym->sym ) ); + + if( keysym->mod & KMOD_LSHIFT ) Com_Printf( " KMOD_LSHIFT" ); + if( keysym->mod & KMOD_RSHIFT ) Com_Printf( " KMOD_RSHIFT" ); + if( keysym->mod & KMOD_LCTRL ) Com_Printf( " KMOD_LCTRL" ); + if( keysym->mod & KMOD_RCTRL ) Com_Printf( " KMOD_RCTRL" ); + if( keysym->mod & KMOD_LALT ) Com_Printf( " KMOD_LALT" ); + if( keysym->mod & KMOD_RALT ) Com_Printf( " KMOD_RALT" ); + if( keysym->mod & KMOD_LMETA ) Com_Printf( " KMOD_LMETA" ); + if( keysym->mod & KMOD_RMETA ) Com_Printf( " KMOD_RMETA" ); + if( keysym->mod & KMOD_NUM ) Com_Printf( " KMOD_NUM" ); + if( keysym->mod & KMOD_CAPS ) Com_Printf( " KMOD_CAPS" ); + if( keysym->mod & KMOD_MODE ) Com_Printf( " KMOD_MODE" ); + if( keysym->mod & KMOD_RESERVED ) Com_Printf( " KMOD_RESERVED" ); + + Com_Printf( " Q:0x%02x(%s)", key, Key_KeynumToString( key ) ); + + if( keysym->unicode ) + { + Com_Printf( " U:0x%02x", keysym->unicode ); + + if( keysym->unicode > ' ' && keysym->unicode < '~' ) + Com_Printf( "(%c)", (char)keysym->unicode ); + } + + Com_Printf( "\n" ); +} + +#define MAX_CONSOLE_KEYS 16 + +/* +=============== +IN_IsConsoleKey +=============== +*/ +static qboolean IN_IsConsoleKey( fakeAscii_t key, const unsigned char character ) +{ + typedef struct consoleKey_s + { + enum + { + KEY, + CHARACTER + } type; + + union + { + fakeAscii_t key; + unsigned char character; + } u; + } consoleKey_t; + + static consoleKey_t consoleKeys[ MAX_CONSOLE_KEYS ]; + static int numConsoleKeys = 0; + int i; + + // Only parse the variable when it changes + if( cl_consoleKeys->modified ) + { + char *text_p, *token; + + cl_consoleKeys->modified = qfalse; + text_p = cl_consoleKeys->string; + numConsoleKeys = 0; + + while( numConsoleKeys < MAX_CONSOLE_KEYS ) + { + consoleKey_t *c = &consoleKeys[ numConsoleKeys ]; + int charCode = 0; + + token = COM_Parse( &text_p ); + if( !token[ 0 ] ) + break; + + if( strlen( token ) == 4 ) + charCode = Com_HexStrToInt( token ); + + if( charCode > 0 ) + { + c->type = consoleKey_t::CHARACTER; + c->u.character = (unsigned char)charCode; + } + else + { + c->type = consoleKey_t::KEY; + c->u.key = Key_StringToKeynum( token ); + + // 0 isn't a key + if( c->u.key <= 0 ) + continue; + } + + numConsoleKeys++; + } + } + + // If the character is the same as the key, prefer the character + if( key == character ) + key = 0; + + for( i = 0; i < numConsoleKeys; i++ ) + { + consoleKey_t *c = &consoleKeys[ i ]; + + switch( c->type ) + { + case consoleKey_t::KEY: + if( key && c->u.key == key ) + return qtrue; + break; + + case consoleKey_t::CHARACTER: + if( c->u.character == character ) + return qtrue; + break; + } + } + + return qfalse; +} + +/* +=============== +IN_TranslateSDLToQ3Key +=============== +*/ +static const char *IN_TranslateSDLToQ3Key( SDL_keysym *keysym, + fakeAscii_t *key, qboolean down ) +{ + static unsigned char buf[ 2 ] = { '\0', '\0' }; + + *buf = '\0'; + *key = 0; + + if( keysym->sym >= SDLK_SPACE && keysym->sym < SDLK_DELETE ) + { + // These happen to match the ASCII chars + *key = (int)keysym->sym; + } + else + { + switch( keysym->sym ) + { + case SDLK_PAGEUP: *key = A_PAGE_UP; break; + case SDLK_KP9: *key = A_KP_9; break; + case SDLK_PAGEDOWN: *key = A_PAGE_DOWN; break; + case SDLK_KP3: *key = A_KP_3; break; + case SDLK_KP7: *key = A_KP_7; break; + case SDLK_HOME: *key = A_HOME; break; + case SDLK_KP1: *key = A_KP_1; break; + case SDLK_END: *key = A_END; break; + case SDLK_KP4: *key = A_KP_4; break; + case SDLK_LEFT: *key = A_CURSOR_LEFT; break; + case SDLK_KP6: *key = A_KP_6; break; + case SDLK_RIGHT: *key = A_CURSOR_RIGHT; break; + case SDLK_KP2: *key = A_KP_2; break; + case SDLK_DOWN: *key = A_CURSOR_DOWN; break; + case SDLK_KP8: *key = A_KP_8; break; + case SDLK_UP: *key = A_CURSOR_UP; break; + case SDLK_ESCAPE: *key = A_ESCAPE; break; + case SDLK_KP_ENTER: *key = A_KP_ENTER; break; + case SDLK_RETURN: *key = A_ENTER; break; + case SDLK_TAB: *key = A_TAB; break; + case SDLK_F1: *key = A_F1; break; + case SDLK_F2: *key = A_F2; break; + case SDLK_F3: *key = A_F3; break; + case SDLK_F4: *key = A_F4; break; + case SDLK_F5: *key = A_F5; break; + case SDLK_F6: *key = A_F6; break; + case SDLK_F7: *key = A_F7; break; + case SDLK_F8: *key = A_F8; break; + case SDLK_F9: *key = A_F9; break; + case SDLK_F10: *key = A_F10; break; + case SDLK_F11: *key = A_F11; break; + case SDLK_F12: *key = A_F12; break; +#if 0 + case SDLK_F13: *key = A_F13; break; + case SDLK_F14: *key = A_F14; break; + case SDLK_F15: *key = A_F15; break; +#endif + + case SDLK_BACKSPACE: *key = A_BACKSPACE; break; + case SDLK_KP_PERIOD: *key = A_KP_PERIOD; break; + case SDLK_DELETE: *key = A_DELETE; break; + case SDLK_PAUSE: *key = A_PAUSE; break; + + case SDLK_LSHIFT: + case SDLK_RSHIFT: *key = A_SHIFT; break; + + case SDLK_LCTRL: + case SDLK_RCTRL: *key = A_CTRL; break; + +#if 0 + case SDLK_RMETA: + case SDLK_LMETA: *key = A_COMMAND; break; +#endif + + case SDLK_RALT: + case SDLK_LALT: *key = A_ALT; break; + +#if 0 + case SDLK_LSUPER: + case SDLK_RSUPER: *key = A_SUPER; break; +#endif + + case SDLK_KP5: *key = A_KP_5; break; + case SDLK_INSERT: *key = A_INSERT; break; + case SDLK_KP0: *key = A_KP_0; break; + case SDLK_KP_MULTIPLY: *key = A_STAR; break; + case SDLK_KP_PLUS: *key = A_KP_PLUS; break; + case SDLK_KP_MINUS: *key = A_KP_MINUS; break; + case SDLK_KP_DIVIDE: *key = A_DIVIDE; break; +#if 0 + case SDLK_MODE: *key = A_MODE; break; + case SDLK_COMPOSE: *key = A_COMPOSE; break; + case SDLK_HELP: *key = A_HELP; break; +#endif + case SDLK_PRINT: *key = A_PRINTSCREEN; break; +#if 0 + case SDLK_SYSREQ: *key = A_SYSREQ; break; + case SDLK_BREAK: *key = A_BREAK; break; + case SDLK_MENU: *key = A_MENU; break; + case SDLK_POWER: *key = A_POWER; break; +#endif + case SDLK_EURO: *key = A_EURO; break; +// case SDLK_UNDO: *key = A_UNDO; break; + case SDLK_SCROLLOCK: *key = A_SCROLLLOCK; break; + case SDLK_NUMLOCK: *key = A_NUMLOCK; break; + case SDLK_CAPSLOCK: *key = A_CAPSLOCK; break; + + default: +#if 0 + if( keysym->sym >= SDLK_WORLD_0 && keysym->sym <= SDLK_WORLD_95 ) + *key = ( keysym->sym - SDLK_WORLD_0 ) + K_WORLD_0; +#endif + break; + } + } + + if( down && keysym->unicode && !( keysym->unicode & 0xFF00 ) ) + { + unsigned char ch = (unsigned char)keysym->unicode & 0xFF; + + switch( ch ) + { + case 127: // ASCII delete + if( *key != A_DELETE ) + { + // ctrl-h + *buf = CTRL('h'); + break; + } + // fallthrough + + default: *buf = ch; break; + } + } + + if( in_keyboardDebug->integer ) + IN_PrintKey( keysym, *key, down ); + + // Keys that have ASCII names but produce no character are probably + // dead keys -- ignore them + if( down && strlen( Key_KeynumToString( *key ) ) == 1 && + keysym->unicode == 0 ) + { + if( in_keyboardDebug->integer ) + Com_Printf( " Ignored dead key '%c'\n", *key ); + + *key = 0; + } + + if( IN_IsConsoleKey( *key, *buf ) ) + { + // Console keys can't be bound or generate characters + *key = A_CONSOLE; + *buf = '\0'; + } + + // Don't allow extended ASCII to generate characters + if( *buf & 0x80 ) + *buf = '\0'; + + return (char *)buf; +} + +#ifdef MACOS_X_ACCELERATION_HACK +/* +=============== +IN_GetIOHandle +=============== +*/ +static io_connect_t IN_GetIOHandle(void) // mac os x mouse accel hack +{ + io_connect_t iohandle = MACH_PORT_NULL; + kern_return_t status; + io_service_t iohidsystem = MACH_PORT_NULL; + mach_port_t masterport; + + status = IOMasterPort(MACH_PORT_NULL, &masterport); + if(status != KERN_SUCCESS) + return 0; + + iohidsystem = IORegistryEntryFromPath(masterport, kIOServicePlane ":/IOResources/IOHIDSystem"); + if(!iohidsystem) + return 0; + + status = IOServiceOpen(iohidsystem, mach_task_self(), kIOHIDParamConnectType, &iohandle); + IOObjectRelease(iohidsystem); + + return iohandle; +} +#endif + +/* +=============== +IN_GobbleMotionEvents +=============== +*/ +static void IN_GobbleMotionEvents( void ) +{ + SDL_Event dummy[ 1 ]; + + // Gobble any mouse motion events + SDL_PumpEvents( ); + while( SDL_PeepEvents( dummy, 1, SDL_GETEVENT, + SDL_EVENTMASK( SDL_MOUSEMOTION ) ) ) { } +} + +/* +=============== +IN_ActivateMouse +=============== +*/ +static void IN_ActivateMouse( void ) +{ + if (!mouseAvailable || !SDL_WasInit( SDL_INIT_VIDEO ) ) + return; + +#ifdef MACOS_X_ACCELERATION_HACK + if (!mouseActive) // mac os x mouse accel hack + { + // Save the status of mouse acceleration + originalMouseSpeed = -1.0; // in case of error + if(in_disablemacosxmouseaccel->integer) + { + io_connect_t mouseDev = IN_GetIOHandle(); + if(mouseDev != 0) + { + if(IOHIDGetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), &originalMouseSpeed) == kIOReturnSuccess) + { + Com_Printf("previous mouse acceleration: %f\n", originalMouseSpeed); + if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), -1.0) != kIOReturnSuccess) + { + Com_Printf("Could not disable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n"); + Cvar_Set ("in_disablemacosxmouseaccel", 0); + } + } + else + { + Com_Printf("Could not disable mouse acceleration (failed at IOHIDGetAccelerationWithKey).\n"); + Cvar_Set ("in_disablemacosxmouseaccel", 0); + } + IOServiceClose(mouseDev); + } + else + { + Com_Printf("Could not disable mouse acceleration (failed at IO_GetIOHandle).\n"); + Cvar_Set ("in_disablemacosxmouseaccel", 0); + } + } + } +#endif + + if( !mouseActive ) + { + SDL_ShowCursor( 0 ); +#ifdef MACOS_X_CURSOR_HACK + // This is a bug in the current SDL/macosx...have to toggle it a few + // times to get the cursor to hide. + SDL_ShowCursor( 1 ); + SDL_ShowCursor( 0 ); +#endif + SDL_WM_GrabInput( SDL_GRAB_ON ); + + IN_GobbleMotionEvents( ); + } + + // in_nograb makes no sense in fullscreen mode + if( !Cvar_VariableIntegerValue("r_fullscreen") ) + { + if( in_nograb->modified || !mouseActive ) + { + if( in_nograb->integer ) + SDL_WM_GrabInput( SDL_GRAB_OFF ); + else + SDL_WM_GrabInput( SDL_GRAB_ON ); + + in_nograb->modified = qfalse; + } + } + + mouseActive = qtrue; +} + +/* +=============== +IN_DeactivateMouse +=============== +*/ +static void IN_DeactivateMouse( void ) +{ + if( !SDL_WasInit( SDL_INIT_VIDEO ) ) + return; + + // Always show the cursor when the mouse is disabled, + // but not when fullscreen + if( !Cvar_VariableIntegerValue("r_fullscreen") ) + SDL_ShowCursor( 1 ); + + if( !mouseAvailable ) + return; + +#ifdef MACOS_X_ACCELERATION_HACK + if (mouseActive) // mac os x mouse accel hack + { + if(originalMouseSpeed != -1.0) + { + io_connect_t mouseDev = IN_GetIOHandle(); + if(mouseDev != 0) + { + Com_Printf("restoring mouse acceleration to: %f\n", originalMouseSpeed); + if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), originalMouseSpeed) != kIOReturnSuccess) + Com_Printf("Could not re-enable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n"); + IOServiceClose(mouseDev); + } + else + Com_Printf("Could not re-enable mouse acceleration (failed at IO_GetIOHandle).\n"); + } + } +#endif + + if( mouseActive ) + { + IN_GobbleMotionEvents( ); + + SDL_WM_GrabInput( SDL_GRAB_OFF ); + + // Don't warp the mouse unless the cursor is within the window + if( SDL_GetAppState( ) & SDL_APPMOUSEFOCUS ) + SDL_WarpMouse( cls.glconfig.vidWidth / 2, cls.glconfig.vidHeight / 2 ); + + mouseActive = qfalse; + } +} + +// We translate axes movement into keypresses +static int joy_keys[16] = { + A_CURSOR_LEFT, A_CURSOR_RIGHT, + A_CURSOR_UP, A_CURSOR_DOWN, + A_JOY16, A_JOY17, + A_JOY18, A_JOY19, + A_JOY20, A_JOY21, + A_JOY22, A_JOY23, + A_JOY24, A_JOY25, + A_JOY26, A_JOY27 +}; + +// translate hat events into keypresses +// the 4 highest buttons are used for the first hat ... +static int hat_keys[16] = { + A_JOY28, A_JOY29, + A_JOY30, A_JOY31, + A_JOY24, A_JOY25, + A_JOY26, A_JOY27, + A_JOY20, A_JOY21, + A_JOY22, A_JOY23, + A_JOY16, A_JOY17, + A_JOY18, A_JOY19 +}; + + +struct +{ + qboolean buttons[16]; // !!! FIXME: these might be too many. + unsigned int oldaxes; + int oldaaxes[MAX_JOYSTICK_AXIS]; + unsigned int oldhats; +} stick_state; + + +/* +=============== +IN_InitJoystick +=============== +*/ +static void IN_InitJoystick( void ) +{ + int i = 0; + int total = 0; + char buf[16384] = ""; + + if (stick != NULL) + SDL_JoystickClose(stick); + + stick = NULL; + memset(&stick_state, '\0', sizeof (stick_state)); + + if (!SDL_WasInit(SDL_INIT_JOYSTICK)) + { + Com_DPrintf("Calling SDL_Init(SDL_INIT_JOYSTICK)...\n"); + if (SDL_Init(SDL_INIT_JOYSTICK) == -1) + { + Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) failed: %s\n", SDL_GetError()); + return; + } + Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) passed.\n"); + } + + total = SDL_NumJoysticks(); + Com_DPrintf("%d possible joysticks\n", total); + + // Print list and build cvar to allow ui to select joystick. + for (i = 0; i < total; i++) + { + Q_strcat(buf, sizeof(buf), SDL_JoystickName(i)); + Q_strcat(buf, sizeof(buf), "\n"); + } + + Cvar_Get( "in_availableJoysticks", buf, CVAR_ROM ); + + if( !in_joystick->integer ) { + Com_DPrintf( "Joystick is not active.\n" ); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + return; + } + + in_joystickNo = Cvar_Get( "in_joystickNo", "0", CVAR_ARCHIVE ); + if( in_joystickNo->integer < 0 || in_joystickNo->integer >= total ) + Cvar_Set( "in_joystickNo", "0" ); + + in_joystickUseAnalog = Cvar_Get( "in_joystickUseAnalog", "0", CVAR_ARCHIVE ); + + stick = SDL_JoystickOpen( in_joystickNo->integer ); + + if (stick == NULL) { + Com_DPrintf( "No joystick opened.\n" ); + return; + } + + Com_DPrintf( "Joystick %d opened\n", in_joystickNo->integer ); + Com_DPrintf( "Name: %s\n", SDL_JoystickName(in_joystickNo->integer) ); + Com_DPrintf( "Axes: %d\n", SDL_JoystickNumAxes(stick) ); + Com_DPrintf( "Hats: %d\n", SDL_JoystickNumHats(stick) ); + Com_DPrintf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) ); + Com_DPrintf( "Balls: %d\n", SDL_JoystickNumBalls(stick) ); + Com_DPrintf( "Use Analog: %s\n", in_joystickUseAnalog->integer ? "Yes" : "No" ); + + SDL_JoystickEventState(SDL_QUERY); +} + +/* +=============== +IN_ShutdownJoystick +=============== +*/ +static void IN_ShutdownJoystick( void ) +{ + if (stick) + { + SDL_JoystickClose(stick); + stick = NULL; + } + + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); +} + +/* +=============== +IN_JoyMove +=============== +*/ +static void IN_JoyMove( void ) +{ + qboolean joy_pressed[ARRAY_LEN(joy_keys)]; + unsigned int axes = 0; + unsigned int hats = 0; + int total = 0; + int i = 0; + + if (!stick) + return; + + SDL_JoystickUpdate(); + + memset(joy_pressed, '\0', sizeof (joy_pressed)); + + // update the ball state. + total = SDL_JoystickNumBalls(stick); + if (total > 0) + { + int balldx = 0; + int balldy = 0; + for (i = 0; i < total; i++) + { + int dx = 0; + int dy = 0; + SDL_JoystickGetBall(stick, i, &dx, &dy); + balldx += dx; + balldy += dy; + } + if (balldx || balldy) + { + // !!! FIXME: is this good for stick balls, or just mice? + // Scale like the mouse input... + if (abs(balldx) > 1) + balldx *= 2; + if (abs(balldy) > 1) + balldy *= 2; + Sys_QueEvent( 0, SE_MOUSE, balldx, balldy, 0, NULL ); + } + } + + // now query the stick buttons... + total = SDL_JoystickNumButtons(stick); + if (total > 0) + { + if (total > ARRAY_LEN(stick_state.buttons)) + total = ARRAY_LEN(stick_state.buttons); + for (i = 0; i < total; i++) + { + qboolean pressed = ((SDL_JoystickGetButton(stick, i) != 0)) ? qtrue : qfalse; + if (pressed != stick_state.buttons[i]) + { + Sys_QueEvent( 0, SE_KEY, A_JOY0 + i, pressed, 0, NULL ); + stick_state.buttons[i] = pressed; + } + } + } + + // look at the hats... + total = SDL_JoystickNumHats(stick); + if (total > 0) + { + if (total > 4) total = 4; + for (i = 0; i < total; i++) + { + ((Uint8 *)&hats)[i] = SDL_JoystickGetHat(stick, i); + } + } + + // update hat state + if (hats != stick_state.oldhats) + { + for( i = 0; i < 4; i++ ) { + if( ((Uint8 *)&hats)[i] != ((Uint8 *)&stick_state.oldhats)[i] ) { + // release event + switch( ((Uint8 *)&stick_state.oldhats)[i] ) { + case SDL_HAT_UP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); + break; + case SDL_HAT_RIGHT: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); + break; + case SDL_HAT_DOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); + break; + case SDL_HAT_LEFT: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); + break; + case SDL_HAT_RIGHTUP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); + break; + case SDL_HAT_RIGHTDOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); + break; + case SDL_HAT_LEFTUP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); + break; + case SDL_HAT_LEFTDOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); + break; + default: + break; + } + // press event + switch( ((Uint8 *)&hats)[i] ) { + case SDL_HAT_UP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); + break; + case SDL_HAT_RIGHT: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); + break; + case SDL_HAT_DOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); + break; + case SDL_HAT_LEFT: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); + break; + case SDL_HAT_RIGHTUP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); + break; + case SDL_HAT_RIGHTDOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); + break; + case SDL_HAT_LEFTUP: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); + break; + case SDL_HAT_LEFTDOWN: + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); + Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); + break; + default: + break; + } + } + } + } + + // save hat state + stick_state.oldhats = hats; + + // finally, look at the axes... + total = SDL_JoystickNumAxes(stick); + if (total > 0) + { + if (in_joystickUseAnalog->integer) + { + if (total > MAX_JOYSTICK_AXIS) total = MAX_JOYSTICK_AXIS; + for (i = 0; i < total; i++) + { + Sint16 axis = SDL_JoystickGetAxis(stick, i); + float f = ( (float) abs(axis) ) / 32767.0f; + + if( f < in_joystickThreshold->value ) axis = 0; + + if ( axis != stick_state.oldaaxes[i] ) + { + Sys_QueEvent( 0, SE_JOYSTICK_AXIS, i, axis, 0, NULL ); + stick_state.oldaaxes[i] = axis; + } + } + } + else + { + if (total > 16) total = 16; + for (i = 0; i < total; i++) + { + Sint16 axis = SDL_JoystickGetAxis(stick, i); + float f = ( (float) axis ) / 32767.0f; + if( f < -in_joystickThreshold->value ) { + axes |= ( 1 << ( i * 2 ) ); + } else if( f > in_joystickThreshold->value ) { + axes |= ( 1 << ( ( i * 2 ) + 1 ) ); + } + } + } + } + + /* Time to update axes state based on old vs. new. */ + if (axes != stick_state.oldaxes) + { + for( i = 0; i < 16; i++ ) { + if( ( axes & ( 1 << i ) ) && !( stick_state.oldaxes & ( 1 << i ) ) ) { + Sys_QueEvent( 0, SE_KEY, joy_keys[i], qtrue, 0, NULL ); + } + + if( !( axes & ( 1 << i ) ) && ( stick_state.oldaxes & ( 1 << i ) ) ) { + Sys_QueEvent( 0, SE_KEY, joy_keys[i], qfalse, 0, NULL ); + } + } + } + + /* Save for future generations. */ + stick_state.oldaxes = axes; +} + +/* +=============== +IN_ProcessEvents +=============== +*/ +static void IN_ProcessEvents( void ) +{ + SDL_Event e; + const char *character = NULL; + fakeAscii_t key = 0; + + if( !SDL_WasInit( SDL_INIT_VIDEO ) ) + return; + + if( Key_GetCatcher( ) == 0 && keyRepeatEnabled ) + { + SDL_EnableKeyRepeat( 0, 0 ); + keyRepeatEnabled = qfalse; + } + else if( !keyRepeatEnabled ) + { + SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, + SDL_DEFAULT_REPEAT_INTERVAL ); + keyRepeatEnabled = qtrue; + } + + while( SDL_PollEvent( &e ) ) + { + switch( e.type ) + { + case SDL_KEYDOWN: + character = IN_TranslateSDLToQ3Key( &e.key.keysym, &key, qtrue ); + if( key ) + Sys_QueEvent( 0, SE_KEY, key, qtrue, 0, NULL ); + + if( character ) + Sys_QueEvent( 0, SE_CHAR, *character, 0, 0, NULL ); + break; + + case SDL_KEYUP: + IN_TranslateSDLToQ3Key( &e.key.keysym, &key, qfalse ); + + if( key ) + Sys_QueEvent( 0, SE_KEY, key, qfalse, 0, NULL ); + break; + + case SDL_MOUSEMOTION: + if( mouseActive ) + Sys_QueEvent( 0, SE_MOUSE, e.motion.xrel, e.motion.yrel, 0, NULL ); + break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + { + unsigned char b; + switch( e.button.button ) + { + case 1: b = A_MOUSE1; break; + case 2: b = A_MOUSE3; break; + case 3: b = A_MOUSE2; break; + case 4: b = A_MWHEELUP; break; + case 5: b = A_MWHEELDOWN; break; + case 6: b = A_MOUSE4; break; + case 7: b = A_MOUSE5; break; + default: b = A_AUX0 + ( e.button.button - 8 ) % 16; break; + } + Sys_QueEvent( 0, SE_KEY, b, + ( e.type == SDL_MOUSEBUTTONDOWN ? qtrue : qfalse ), 0, NULL ); + } + break; + + case SDL_QUIT: + Cbuf_ExecuteText(EXEC_NOW, "quit Closed window\n"); + break; + + case SDL_VIDEORESIZE: + { + char width[32], height[32]; + Com_sprintf( width, sizeof(width), "%d", e.resize.w ); + Com_sprintf( height, sizeof(height), "%d", e.resize.h ); + Cvar_Set( "r_customwidth", width ); + Cvar_Set( "r_customheight", height ); + Cvar_Set( "r_mode", "-1" ); + /* wait until user stops dragging for 1 second, so + we aren't constantly recreating the GL context while + he tries to drag...*/ + vidRestartTime = Sys_Milliseconds() + 1000; + } + break; + case SDL_ACTIVEEVENT: + if (e.active.state & SDL_APPINPUTFOCUS) { + Cvar_SetValue( "com_unfocused", !e.active.gain); + } + if (e.active.state & SDL_APPACTIVE) { + Cvar_SetValue( "com_minimized", !e.active.gain); + } + break; + + default: + break; + } + } +} + +/* +=============== +IN_Frame +=============== +*/ +void IN_Frame( void ) +{ + qboolean loading; + + IN_JoyMove( ); + IN_ProcessEvents( ); + + // If not DISCONNECTED (main menu) or ACTIVE (in game), we're loading + loading = ( cls.state != CA_DISCONNECTED && cls.state != CA_ACTIVE ) ? qtrue : qfalse; + + if( !Cvar_VariableIntegerValue("r_fullscreen") && ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ) + { + // Console is down in windowed mode + IN_DeactivateMouse( ); + } + else if( !Cvar_VariableIntegerValue("r_fullscreen") && loading ) + { + // Loading in windowed mode + IN_DeactivateMouse( ); + } + else if( !( SDL_GetAppState() & SDL_APPINPUTFOCUS ) ) + { + // Window not got focus + IN_DeactivateMouse( ); + } + else + IN_ActivateMouse( ); + + /* in case we had to delay actual restart of video system... */ + if ( (vidRestartTime != 0) && (vidRestartTime < Sys_Milliseconds()) ) + { + vidRestartTime = 0; + Cbuf_AddText( "vid_restart" ); + } +} + +/* +=============== +IN_InitKeyLockStates +=============== +*/ +void IN_InitKeyLockStates( void ) +{ +#if 0 + unsigned char *keystate = SDL_GetKeyState(NULL); + + keys[A_SCROLLLOCK].down = keystate[SDLK_SCROLLOCK]; + keys[A_NUMLOCK].down = keystate[SDLK_NUMLOCK]; + keys[A_CAPSLOCK].down = keystate[SDLK_CAPSLOCK]; +#endif +} + +/* +=============== +IN_Init +=============== +*/ +void IN_Init( void ) +{ + int appState; + + if( !SDL_WasInit( SDL_INIT_VIDEO ) ) + { + Com_Error( ERR_FATAL, "IN_Init called before SDL_Init( SDL_INIT_VIDEO )" ); + return; + } + + Com_DPrintf( "\n------- Input Initialization -------\n" ); + + in_keyboardDebug = Cvar_Get( "in_keyboardDebug", "0", CVAR_ARCHIVE ); + + // mouse variables + in_mouse = Cvar_Get( "in_mouse", "1", CVAR_ARCHIVE ); + in_nograb = Cvar_Get( "in_nograb", "0", CVAR_ARCHIVE ); + + in_joystick = Cvar_Get( "in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH ); + in_joystickDebug = Cvar_Get( "in_joystickDebug", "0", CVAR_TEMP ); + in_joystickThreshold = Cvar_Get( "joy_threshold", "0.15", CVAR_ARCHIVE ); + +#ifdef MACOS_X_ACCELERATION_HACK + in_disablemacosxmouseaccel = Cvar_Get( "in_disablemacosxmouseaccel", "1", CVAR_ARCHIVE ); +#endif + + SDL_EnableUNICODE( 1 ); + SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); + keyRepeatEnabled = qtrue; + + mouseAvailable = ( in_mouse->value != 0 ) ? qtrue : qfalse; + IN_DeactivateMouse( ); + + appState = SDL_GetAppState( ); + Cvar_SetValue( "com_unfocused", !( appState & SDL_APPINPUTFOCUS ) ); + Cvar_SetValue( "com_minimized", !( appState & SDL_APPACTIVE ) ); + + IN_InitKeyLockStates( ); + + IN_InitJoystick( ); + Com_DPrintf( "------------------------------------\n" ); +} + +/* +=============== +IN_Shutdown +=============== +*/ +void IN_Shutdown( void ) +{ + IN_DeactivateMouse( ); + mouseAvailable = qfalse; + + IN_ShutdownJoystick( ); +} + +/* +=============== +IN_Restart +=============== +*/ +void IN_Restart( void ) +{ + IN_ShutdownJoystick( ); + IN_Init( ); +} + +void Sys_SendKeyEvents (void) +{ +} diff --git a/codemp/sdl/sdl_local.h b/codemp/sdl/sdl_local.h new file mode 100644 index 0000000..cc2b529 --- /dev/null +++ b/codemp/sdl/sdl_local.h @@ -0,0 +1,11 @@ +#include "../game/q_shared.h" +#include "../qcommon/qcommon.h" +#include "../client/client.h" + +void IN_Init( void ); +void IN_Shutdown( void ); +void IN_Restart( void ); + +void Sys_GLimpSafeInit( void ); +void Sys_GLimpInit( void ); +void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ); diff --git a/codemp/unix/unix_glimp_common.cpp b/codemp/unix/unix_glimp_common.cpp new file mode 100644 index 0000000..50cc6c3 --- /dev/null +++ b/codemp/unix/unix_glimp_common.cpp @@ -0,0 +1,82 @@ +#include +#include +#include "../game/q_shared.h" + +/* +=========================================================== + +SMP acceleration + +=========================================================== +*/ + +sem_t renderCommandsEvent; +sem_t renderCompletedEvent; +sem_t renderActiveEvent; + +void (*glimpRenderThread)( void ); + +void *GLimp_RenderThreadWrapper( void *stub ) { + glimpRenderThread(); +} + +/* +======================= +GLimp_SpawnRenderThread +======================= +*/ +pthread_t renderThreadHandle; +qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) { + + sem_init( &renderCommandsEvent, 0, 0 ); + sem_init( &renderCompletedEvent, 0, 0 ); + sem_init( &renderActiveEvent, 0, 0 ); + + glimpRenderThread = function; + + if (pthread_create( &renderThreadHandle, NULL, + GLimp_RenderThreadWrapper, NULL)) { + return qfalse; + } + + return qtrue; +} + +static void *smpData; + +void *GLimp_RendererSleep( void ) { + void *data; + + // after this, the front end can exit GLimp_FrontEndSleep + sem_post ( &renderCompletedEvent ); + + sem_wait ( &renderCommandsEvent ); + + data = smpData; + + // after this, the main thread can exit GLimp_WakeRenderer + sem_post ( &renderActiveEvent ); + + return data; +} + +void GLimp_FrontEndSleep( void ) { + sem_wait ( &renderCompletedEvent ); +} + +void GLimp_WakeRenderer( void *data ) { + smpData = data; + + // after this, the renderer can continue through GLimp_RendererSleep + sem_post( &renderCommandsEvent ); + + sem_wait( &renderActiveEvent ); +} + +void Sys_GLimpInit( void ) +{ +} + +void Sys_GLimpSafeInit( void ) +{ +} diff --git a/codemp/unix/unix_main.cpp b/codemp/unix/unix_main.cpp index 6a29600..ddb52eb 100644 --- a/codemp/unix/unix_main.cpp +++ b/codemp/unix/unix_main.cpp @@ -212,7 +212,7 @@ void Sys_Init(void) Cvar_Set( "username", Sys_GetCurrentUser() ); - IN_Init(); +// IN_Init(); } From dad17e40f123a52e8532925235c7ab86aa8478bd Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Tue, 30 Apr 2013 15:05:13 +1000 Subject: [PATCH 3/3] windowed mouse is fixed with sdl --- README.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.txt b/README.txt index d4f824d..136c135 100644 --- a/README.txt +++ b/README.txt @@ -25,8 +25,6 @@ copy *.so to your base directory Known issues: -When running windowed the mouse does not work in the menus. - Save games do not yet work on amd64. The demo has various issues and does not work properly.