From c918959862ec6fc80799d62062a84c61957caf6a Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Tue, 30 Apr 2013 10:29:42 +1000 Subject: [PATCH 1/3] add sdl glimp/input from ioquake3 for SP --- code/CMakeLists.txt | 26 +- code/client/cl_main.cpp | 5 + code/client/client.h | 6 +- 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 | 953 ++++++++++++++++++++++++++ code/sdl/sdl_input.cpp | 1107 +++++++++++++++++++++++++++++++ code/sdl/sdl_local.h | 10 + code/unix/unix_glimp_common.cpp | 82 +++ code/unix/unix_main.cpp | 2 +- 13 files changed, 2330 insertions(+), 17 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 957e447..6665ecb 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -33,11 +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_client client/cl_cgame.cpp @@ -252,11 +255,16 @@ set(src_jpeg set(src_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_ff} ${src_client} @@ -270,6 +278,7 @@ set(src_starwars ${src_main_game} ${src_jpeg} ${src_unix} + ${src_sdl} ) add_executable(jk2sp @@ -280,8 +289,9 @@ set_target_properties(jk2sp PROPERTIES COMPILE_DEFINITIONS "_JK2EXE;_FF_DISABLE" target_link_libraries(jk2sp 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 ce708af..ac0b6bb 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -60,6 +60,8 @@ cvar_t *cl_updateInfoString; cvar_t *cl_ingameVideo; +cvar_t *cl_consoleKeys; + clientActive_t cl; clientConnection_t clc; clientStatic_t cls; @@ -1187,6 +1189,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", "Kyle", 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 d33140d..d86a676 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -285,6 +285,8 @@ extern cvar_t *m_filter; extern cvar_t *cl_activeAction; +extern cvar_t *cl_consoleKeys; + //================================================= // @@ -330,6 +332,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 // @@ -429,8 +432,9 @@ 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); -#endif //__CLIENT_H__ \ No newline at end of file +#endif //__CLIENT_H__ diff --git a/code/game/q_shared.cpp b/code/game/q_shared.cpp index 0db3537..d8fba6a 100644 --- a/code/game/q_shared.cpp +++ b/code/game/q_shared.cpp @@ -568,6 +568,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 7a2bbb9..a64ab43 100644 --- a/code/game/q_shared.h +++ b/code/game/q_shared.h @@ -196,6 +196,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 @@ -918,6 +920,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 239ea7c..051ae22 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 @@ -130,6 +140,8 @@ extern void ( APIENTRY * qglPNTrianglesiATI )( GLenum pname, GLint param ); //extern void ( APIENTRY * qglPNTrianglesfATI )( GLenum pname, GLfloat param ); #endif // _NPATCH +#ifdef DYNAMIC_LINK_GL + //=========================================================================== // windows systems use a function pointer for each call so we can load minidrivers @@ -510,4 +522,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 c0ab795..d4978d6 100644 --- a/code/renderer/tr_init.cpp +++ b/code/renderer/tr_init.cpp @@ -996,11 +996,7 @@ void R_Register( void ) r_texturebitslm = ri.Cvar_Get( "r_texturebitslm", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_stereo = ri.Cvar_Get( "r_stereo", "0", CVAR_ARCHIVE | CVAR_LATCH ); -#ifdef __linux__ - r_stencilbits = ri.Cvar_Get( "r_stencilbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); -#else r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH ); -#endif r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_ignorehwgamma = ri.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..8955abb --- /dev/null +++ b/code/sdl/sdl_glimp.cpp @@ -0,0 +1,953 @@ +/* +=========================================================================== +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; + +/* +=============== +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 ) + { + ri.Printf( PRINT_WARNING, "Can't get list of available modes\n" ); + return; + } + + if( modes == (SDL_Rect **)-1 ) + { + ri.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 + ri.Printf( PRINT_WARNING, "Skipping mode %ux%x, buffer too small\n", modes[i]->w, modes[i]->h ); + } + + if( *buf ) + { + buf[ strlen( buf ) - 1 ] = 0; + ri.Printf( PRINT_ALL, "Available modes: '%s'\n", buf ); + ri.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; + + ri.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; + + ri.Printf( PRINT_ALL, "Estimated display aspect: %.3f\n", displayAspect ); + } + else + { + ri.Printf( PRINT_ALL, + "Cannot estimate display aspect, assuming 1.333\n" ); + } + } + + ri.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; + ri.Printf( PRINT_ALL, + "Cannot determine display resolution, assuming 640x480\n" ); + } + + glConfig.windowAspect = (float)glConfig.vidWidth / (float)glConfig.vidHeight; + } + else if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) ) + { + ri.Printf( PRINT_ALL, " invalid mode\n" ); + return RSERR_INVALID_MODE; + } + ri.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 ) + { + ri.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 ) + ri.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))) + { + ri.Printf( PRINT_DEVELOPER, "SDL_SetVideoMode failed: %s\n", SDL_GetError( ) ); + continue; + } + + opengl_context = GLimp_GetCurrentContext(); + + ri.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) + { + ri.Printf( PRINT_ALL, "Couldn't get a visual\n" ); + return RSERR_INVALID_MODE; + } + + screen = vidscreen; + + glstring = (char *) qglGetString (GL_RENDERER); + ri.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) + { + ri.Printf( PRINT_ALL, "SDL_Init( SDL_INIT_VIDEO ) FAILED (%s)\n", + SDL_GetError()); + return qfalse; + } + + SDL_VideoDriverName( driverName, sizeof( driverName ) - 1 ); + ri.Printf( PRINT_ALL, "SDL using driver \"%s\"\n", driverName ); + ri.Cvar_Set( "r_sdlDriver", driverName ); + } + + if (fullscreen && Cvar_VariableIntegerValue( "in_nograb" ) ) + { + ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n"); + ri.Cvar_Set( "r_fullscreen", "0" ); + r_fullscreen->modified = qfalse; + fullscreen = qfalse; + } + + err = (rserr_t) GLimp_SetMode(mode, fullscreen, noborder); + + switch ( err ) + { + case RSERR_INVALID_FULLSCREEN: + ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" ); + return qfalse; + case RSERR_INVALID_MODE: + ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode ); + return qfalse; + default: + break; + } + + return qtrue; +} + +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 ) + { + ri.Printf( PRINT_ALL, "...GL_S3_s3tc available\n" ); + } + + if ( newer_tc ) + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_compression_s3tc available\n" ); + } + + if ( !r_ext_compressed_textures->value ) + { + // Compressed textures are off + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...ignoring texture compression\n" ); + } + else if ( !old_tc && !newer_tc ) + { + // Requesting texture compression, but no method found + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...no supported texture compression method found\n" ); + ri.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 ) + { + ri.Printf( PRINT_ALL, "...no tc preference specified\n" ); + ri.Printf( PRINT_ALL, ".....using GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + else + { + ri.Printf( PRINT_ALL, "...no tc preference specified\n" ); + ri.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 ) + { + ri.Printf( PRINT_ALL, "...using preferred tc method, GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + else + { + ri.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 ) + { + ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + else + { + // Drat, preference can't be honored + ri.Printf( PRINT_ALL, "...preferred tc method, GL_S3_s3tc not available\n" ); + ri.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 ) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + else + { + // Drat, preference can't be honored + ri.Printf( PRINT_ALL, "...preferred tc method, GL_EXT_texture_compression_s3tc not available\n" ); + ri.Printf( PRINT_ALL, ".....falling back to GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + } + } + } + } +} + +/* +** GLW_InitExtensions +*/ +cvar_t *r_ATI_NPATCH_available = NULL; +static void GLimp_InitExtensions( void ) +{ + if ( !r_allowExtensions->integer ) + { + ri.Printf( PRINT_ALL, "*** IGNORING OPENGL EXTENSIONS ***\n" ); + return; + } + + ri.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; + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); + } + else + { + glConfig.textureEnvAddAvailable = qfalse; + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" ); + } + + // GL_EXT_texture_filter_anisotropic + glConfig.textureFilterAnisotropicAvailable = qfalse; + if ( strstr( glConfig.extensions_string, "EXT_texture_filter_anisotropic" ) ) + { + glConfig.textureFilterAnisotropicAvailable = qtrue; + ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic available\n" ); + + if ( r_ext_texture_filter_anisotropic->integer ) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic\n" ); + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" ); + } + ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "1" ); + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" ); + ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "0" ); + } + + // GL_EXT_clamp_to_edge + glConfig.clampToEdgeAvailable = qfalse; + if ( strstr( glConfig.extensions_string, "GL_EXT_texture_edge_clamp" ) ) + { + glConfig.clampToEdgeAvailable = qtrue; + ri.Printf( PRINT_ALL, "...Using GL_EXT_texture_edge_clamp\n" ); + } + + // 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 ) + { + ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); + } + else + { + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" ); + } + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); + } + + // GL_EXT_compiled_vertex_array + qglLockArraysEXT = NULL; + qglUnlockArraysEXT = NULL; + if ( strstr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) ) + { + if ( r_ext_compiled_vertex_array->integer ) + { + ri.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) { + ri.Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); + } + + qglPointParameterfEXT = NULL; + qglPointParameterfvEXT = NULL; + if ( strstr( glConfig.extensions_string, "GL_EXT_point_parameters" ) ) + { + if ( r_ext_compiled_vertex_array->integer || 1) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_point_parameters\n" ); + qglPointParameterfEXT = ( void ( APIENTRY * )( GLenum, GLfloat) ) SDL_GL_GetProcAddress( "glPointParameterfEXT" ); + qglPointParameterfvEXT = ( void ( APIENTRY * )( GLenum, GLfloat *) ) SDL_GL_GetProcAddress( "glPointParameterfvEXT" ); + if (!qglPointParameterfEXT || !qglPointParameterfvEXT) + { + ri.Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_point_parameters\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_point_parameters not found\n" ); + } + +#ifdef _NPATCH + // GL_ATI_pn_triangles + qglPNTrianglesiATI = NULL; + r_ATI_NPATCH_available = ri.Cvar_Get( "r_ATI_NPATCH_available", "0",CVAR_ROM ); +/* if ( strstr( glConfig.extensions_string, "GL_ATI_pn_triangles" ) ) + { + ri.Cvar_Set( "r_ATI_NPATCH_available", "1" ); + if ( r_ati_pn_triangles->integer ) + { + ri.Printf( PRINT_ALL, "...using GL_ATI_pn_triangles\n" ); + qglPNTrianglesiATI = ( void ( APIENTRY * )( GLenum, GLint ) ) SDL_GL_GetProcAddress( "glPNTrianglesiATI" ); + if (!qglPNTrianglesiATI) { + ri.Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_ATI_pn_triangles\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_ATI_pn_triangles not found\n" ); + } +*/ +#endif // _NPATCH +} + +#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 = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); + r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM ); + r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE ); + r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE ); + r_noborder = Cvar_Get( "r_noborder", "0", CVAR_ARCHIVE ); + qboolean fullscreen, noborder; + + if( Cvar_VariableIntegerValue( "com_abnormalExit" ) ) + { + ri.Cvar_Set( "r_mode", va( "%d", R_MODE_FALLBACK ) ); + ri.Cvar_Set( "r_fullscreen", "0" ); + ri.Cvar_Set( "r_centerWindow", "0" ); + ri.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 ) + { + ri.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 + ri.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( ); + + ri.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" ) ) + { + ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n"); + ri.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 ) + ri.Cmd_ExecuteText(EXEC_APPEND, "vid_restart"); + + 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..843ca5f --- /dev/null +++ b/code/sdl/sdl_local.h @@ -0,0 +1,10 @@ +#include "../game/q_shared.h" +#include "../qcommon/qcommon.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 3ec2a4b..d2e963f 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 854e82ae96f7b863c119cf077694a08c6012c8d8 Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Tue, 30 Apr 2013 11:50:32 +1000 Subject: [PATCH 2/3] add sdl glimp/input from ioquake3 for MP --- CODE-mp/CMakeLists.txt | 26 +- CODE-mp/client/cl_main.cpp | 5 + CODE-mp/client/client.h | 3 + CODE-mp/game/q_shared.c | 38 + CODE-mp/game/q_shared.h | 3 + CODE-mp/renderer/qgl.h | 19 +- CODE-mp/renderer/qgl_linked.h | 336 +++++++++ CODE-mp/renderer/tr_init.cpp | 8 - CODE-mp/sdl/sdl_gamma.cpp | 92 +++ CODE-mp/sdl/sdl_glimp.cpp | 970 ++++++++++++++++++++++++ CODE-mp/sdl/sdl_input.cpp | 1107 ++++++++++++++++++++++++++++ CODE-mp/sdl/sdl_local.h | 7 + CODE-mp/unix/unix_glimp_common.cpp | 82 +++ CODE-mp/unix/unix_main.cpp | 2 +- 14 files changed, 2678 insertions(+), 20 deletions(-) create mode 100644 CODE-mp/renderer/qgl_linked.h create mode 100644 CODE-mp/sdl/sdl_gamma.cpp create mode 100644 CODE-mp/sdl/sdl_glimp.cpp create mode 100644 CODE-mp/sdl/sdl_input.cpp create mode 100644 CODE-mp/sdl/sdl_local.h create mode 100644 CODE-mp/unix/unix_glimp_common.cpp diff --git a/CODE-mp/CMakeLists.txt b/CODE-mp/CMakeLists.txt index 855896c..59834ab 100644 --- a/CODE-mp/CMakeLists.txt +++ b/CODE-mp/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_client client/FXExport.cpp @@ -271,11 +274,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 @@ -320,6 +328,7 @@ set(src_jk2mp ${src_main_zlib} ${src_botlib} ${src_main_unix} + ${src_sdl} ) add_executable(jk2mp @@ -330,8 +339,9 @@ set_target_properties(jk2mp PROPERTIES COMPILE_DEFINITIONS "_JK2EXE;_FF_DISABLE; target_link_libraries(jk2mp m pthread - X11 Xxf86vm Xxf86dga - openal + ${SDL_LIBRARY} + ${OPENGL_gl_LIBRARY} + ${OPENAL_LIBRARY} ) if (CMAKE_SYSTEM_NAME MATCHES "Linux") diff --git a/CODE-mp/client/cl_main.cpp b/CODE-mp/client/cl_main.cpp index f4d4236..350ec47 100644 --- a/CODE-mp/client/cl_main.cpp +++ b/CODE-mp/client/cl_main.cpp @@ -76,6 +76,8 @@ char cl_cdkey[34] = " "; #endif // USE_CD_KEY +cvar_t *cl_consoleKeys; + clientActive_t cl; clientConnection_t clc; clientStatic_t cls; @@ -2497,6 +2499,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/CODE-mp/client/client.h b/CODE-mp/client/client.h index fac43f8..7b3a4f4 100644 --- a/CODE-mp/client/client.h +++ b/CODE-mp/client/client.h @@ -375,6 +375,8 @@ extern cvar_t *cl_allowDownload; extern cvar_t *cl_conXOffset; extern cvar_t *cl_inGameVideo; +extern cvar_t *cl_consoleKeys; + //================================================= // @@ -442,6 +444,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/CODE-mp/game/q_shared.c b/CODE-mp/game/q_shared.c index 1112a30..6e34029 100644 --- a/CODE-mp/game/q_shared.c +++ b/CODE-mp/game/q_shared.c @@ -747,6 +747,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-mp/game/q_shared.h b/CODE-mp/game/q_shared.h index d77436b..419d9ba 100644 --- a/CODE-mp/game/q_shared.h +++ b/CODE-mp/game/q_shared.h @@ -350,6 +350,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 @@ -1028,6 +1030,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-mp/renderer/qgl.h b/CODE-mp/renderer/qgl.h index 39d9299..7f5a2ad 100644 --- a/CODE-mp/renderer/qgl.h +++ b/CODE-mp/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 @@ -119,6 +129,8 @@ extern void ( APIENTRY * qglUnlockArraysEXT) (void); extern void ( APIENTRY * qglPointParameterfEXT)( GLenum, GLfloat); extern void ( APIENTRY * qglPointParameterfvEXT)( GLenum, GLfloat *); +#ifdef DYNAMIC_LINK_GL + //=========================================================================== #if defined(MACOS_X) @@ -518,4 +530,5 @@ extern void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable ); #endif // _WIN32 && __linux__ -#endif +#endif // DYNAMIC_LINK_GL +#endif // __QGL_H__ diff --git a/CODE-mp/renderer/qgl_linked.h b/CODE-mp/renderer/qgl_linked.h new file mode 100644 index 0000000..af71ba4 --- /dev/null +++ b/CODE-mp/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/CODE-mp/renderer/tr_init.cpp b/CODE-mp/renderer/tr_init.cpp index 294bd52..7581bf8 100644 --- a/CODE-mp/renderer/tr_init.cpp +++ b/CODE-mp/renderer/tr_init.cpp @@ -853,11 +853,7 @@ void R_Register( void ) r_ext_gamma_control = ri.Cvar_Get( "r_ext_gamma_control", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH); -#ifdef __linux__ // broken on linux - r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "0", CVAR_ARCHIVE | CVAR_LATCH); -#else r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH); -#endif r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", "1", CVAR_ARCHIVE ); @@ -869,11 +865,7 @@ void R_Register( void ) r_texturebitslm = ri.Cvar_Get( "r_texturebitslm", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_stereo = ri.Cvar_Get( "r_stereo", "0", CVAR_ARCHIVE | CVAR_LATCH ); -#ifdef __linux__ - r_stencilbits = ri.Cvar_Get( "r_stencilbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); -#else r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH ); -#endif r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); diff --git a/CODE-mp/sdl/sdl_gamma.cpp b/CODE-mp/sdl/sdl_gamma.cpp new file mode 100644 index 0000000..ef2a520 --- /dev/null +++ b/CODE-mp/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-mp/sdl/sdl_glimp.cpp b/CODE-mp/sdl/sdl_glimp.cpp new file mode 100644 index 0000000..d13c3cf --- /dev/null +++ b/CODE-mp/sdl/sdl_glimp.cpp @@ -0,0 +1,970 @@ +/* +=========================================================================== +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; + +/* +=============== +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 ) + { + ri.Printf( PRINT_WARNING, "Can't get list of available modes\n" ); + return; + } + + if( modes == (SDL_Rect **)-1 ) + { + ri.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 + ri.Printf( PRINT_WARNING, "Skipping mode %ux%x, buffer too small\n", modes[i]->w, modes[i]->h ); + } + + if( *buf ) + { + buf[ strlen( buf ) - 1 ] = 0; + ri.Printf( PRINT_ALL, "Available modes: '%s'\n", buf ); + ri.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; + + ri.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; + + ri.Printf( PRINT_ALL, "Estimated display aspect: %.3f\n", displayAspect ); + } + else + { + ri.Printf( PRINT_ALL, + "Cannot estimate display aspect, assuming 1.333\n" ); + } + } + + ri.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; + ri.Printf( PRINT_ALL, + "Cannot determine display resolution, assuming 640x480\n" ); + } + + glConfig.windowAspect = (float)glConfig.vidWidth / (float)glConfig.vidHeight; + } + else if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) ) + { + ri.Printf( PRINT_ALL, " invalid mode\n" ); + return RSERR_INVALID_MODE; + } + ri.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 ) + { + ri.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 ) + ri.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))) + { + ri.Printf( PRINT_DEVELOPER, "SDL_SetVideoMode failed: %s\n", SDL_GetError( ) ); + continue; + } + + opengl_context = GLimp_GetCurrentContext(); + + ri.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) + { + ri.Printf( PRINT_ALL, "Couldn't get a visual\n" ); + return RSERR_INVALID_MODE; + } + + screen = vidscreen; + + glstring = (char *) qglGetString (GL_RENDERER); + ri.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) + { + ri.Printf( PRINT_ALL, "SDL_Init( SDL_INIT_VIDEO ) FAILED (%s)\n", + SDL_GetError()); + return qfalse; + } + + SDL_VideoDriverName( driverName, sizeof( driverName ) - 1 ); + ri.Printf( PRINT_ALL, "SDL using driver \"%s\"\n", driverName ); + ri.Cvar_Set( "r_sdlDriver", driverName ); + } + + if (fullscreen && Cvar_VariableIntegerValue( "in_nograb" ) ) + { + ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n"); + ri.Cvar_Set( "r_fullscreen", "0" ); + r_fullscreen->modified = qfalse; + fullscreen = qfalse; + } + + err = (rserr_t) GLimp_SetMode(mode, fullscreen, noborder); + + switch ( err ) + { + case RSERR_INVALID_FULLSCREEN: + ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" ); + return qfalse; + case RSERR_INVALID_MODE: + ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode ); + return qfalse; + default: + break; + } + + return qtrue; +} + +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 ) + { + ri.Printf( PRINT_ALL, "...GL_S3_s3tc available\n" ); + } + + if ( newer_tc ) + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_compression_s3tc available\n" ); + } + + if ( !r_ext_compressed_textures->value ) + { + // Compressed textures are off + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...ignoring texture compression\n" ); + } + else if ( !old_tc && !newer_tc ) + { + // Requesting texture compression, but no method found + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...no supported texture compression method found\n" ); + ri.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 ) + { + ri.Printf( PRINT_ALL, "...no tc preference specified\n" ); + ri.Printf( PRINT_ALL, ".....using GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + else + { + ri.Printf( PRINT_ALL, "...no tc preference specified\n" ); + ri.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 ) + { + ri.Printf( PRINT_ALL, "...using preferred tc method, GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + else + { + ri.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 ) + { + ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + else + { + // Drat, preference can't be honored + ri.Printf( PRINT_ALL, "...preferred tc method, GL_S3_s3tc not available\n" ); + ri.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 ) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + else + { + // Drat, preference can't be honored + ri.Printf( PRINT_ALL, "...preferred tc method, GL_EXT_texture_compression_s3tc not available\n" ); + ri.Printf( PRINT_ALL, ".....falling back to GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + } + } + } + } +} + +/* +** GLW_InitExtensions +*/ +cvar_t *r_ATI_NPATCH_available = NULL; +static void GLimp_InitExtensions( void ) +{ + if ( !r_allowExtensions->integer ) + { + ri.Printf( PRINT_ALL, "*** IGNORING OPENGL EXTENSIONS ***\n" ); + return; + } + + ri.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; + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); + } + else + { + glConfig.textureEnvAddAvailable = qfalse; + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" ); + } + + // GL_EXT_texture_filter_anisotropic + glConfig.textureFilterAnisotropicAvailable = qfalse; + if ( strstr( glConfig.extensions_string, "EXT_texture_filter_anisotropic" ) ) + { + glConfig.textureFilterAnisotropicAvailable = qtrue; + ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic available\n" ); + + if ( r_ext_texture_filter_anisotropic->integer ) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic\n" ); + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" ); + } + ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "1" ); + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" ); + ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "0" ); + } + + // GL_EXT_clamp_to_edge + glConfig.clampToEdgeAvailable = qfalse; + if ( strstr( glConfig.extensions_string, "GL_EXT_texture_edge_clamp" ) ) + { + glConfig.clampToEdgeAvailable = qtrue; + ri.Printf( PRINT_ALL, "...Using GL_EXT_texture_edge_clamp\n" ); + } + + // 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 ) + { + ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); + } + else + { + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" ); + } + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); + } + + // GL_EXT_compiled_vertex_array + qglLockArraysEXT = NULL; + qglUnlockArraysEXT = NULL; + if ( strstr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) ) + { + if ( r_ext_compiled_vertex_array->integer ) + { + ri.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) { + ri.Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); + } + + qglPointParameterfEXT = NULL; + qglPointParameterfvEXT = NULL; + if ( strstr( glConfig.extensions_string, "GL_EXT_point_parameters" ) ) + { + if ( r_ext_compiled_vertex_array->integer || 1) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_point_parameters\n" ); + qglPointParameterfEXT = ( void ( APIENTRY * )( GLenum, GLfloat) ) SDL_GL_GetProcAddress( "glPointParameterfEXT" ); + qglPointParameterfvEXT = ( void ( APIENTRY * )( GLenum, GLfloat *) ) SDL_GL_GetProcAddress( "glPointParameterfvEXT" ); + if (!qglPointParameterfEXT || !qglPointParameterfvEXT) + { + ri.Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_point_parameters\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_point_parameters not found\n" ); + } + +#ifdef _NPATCH + // GL_ATI_pn_triangles + qglPNTrianglesiATI = NULL; + r_ATI_NPATCH_available = ri.Cvar_Get( "r_ATI_NPATCH_available", "0",CVAR_ROM ); +/* if ( strstr( glConfig.extensions_string, "GL_ATI_pn_triangles" ) ) + { + ri.Cvar_Set( "r_ATI_NPATCH_available", "1" ); + if ( r_ati_pn_triangles->integer ) + { + ri.Printf( PRINT_ALL, "...using GL_ATI_pn_triangles\n" ); + qglPNTrianglesiATI = ( void ( APIENTRY * )( GLenum, GLint ) ) SDL_GL_GetProcAddress( "glPNTrianglesiATI" ); + if (!qglPNTrianglesiATI) { + ri.Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_ATI_pn_triangles\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_ATI_pn_triangles not found\n" ); + } +*/ +#endif // _NPATCH +} + +#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 = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); + r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM ); + r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE ); + r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE ); + r_noborder = Cvar_Get( "r_noborder", "0", CVAR_ARCHIVE ); + qboolean fullscreen, noborder; + + if( Cvar_VariableIntegerValue( "com_abnormalExit" ) ) + { + ri.Cvar_Set( "r_mode", va( "%d", R_MODE_FALLBACK ) ); + ri.Cvar_Set( "r_fullscreen", "0" ); + ri.Cvar_Set( "r_centerWindow", "0" ); + ri.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 ) + { + ri.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 + ri.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 + const char* glstring; + glstring = (const char *)qglGetString (GL_VENDOR); + if (!glstring) { + glstring = "invalid driver"; + } + Q_strncpyz( glConfig.vendor_string, glstring, sizeof( glConfig.vendor_string ) ); + glstring = (const char *)qglGetString (GL_RENDERER); + if (!glstring) { + glstring = "invalid driver"; + } + Q_strncpyz( glConfig.renderer_string, glstring, sizeof( glConfig.renderer_string ) ); + glstring = (const char *)qglGetString (GL_VERSION); + if (!glstring) { + glstring = "invalid driver"; + } + Q_strncpyz( glConfig.version_string, glstring, sizeof( glConfig.version_string ) ); + glstring = (const char *)qglGetString (GL_EXTENSIONS); + if (!glstring) { + glstring = "invalid driver"; + } + Q_strncpyz( glConfig.extensions_string, glstring, sizeof( glConfig.extensions_string ) ); + + // 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( ); + + ri.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" ) ) + { + ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n"); + ri.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 )) ? qtrue : qfalse; + } + + if( needToToggle ) + { + // SDL_WM_ToggleFullScreen didn't work, so do it the slow way + if( !sdlToggled ) + ri.Cmd_ExecuteText(EXEC_APPEND, "vid_restart"); + + IN_Restart( ); + } + + r_fullscreen->modified = qfalse; + } +} diff --git a/CODE-mp/sdl/sdl_input.cpp b/CODE-mp/sdl/sdl_input.cpp new file mode 100644 index 0000000..5e0e4ac --- /dev/null +++ b/CODE-mp/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-mp/sdl/sdl_local.h b/CODE-mp/sdl/sdl_local.h new file mode 100644 index 0000000..daead97 --- /dev/null +++ b/CODE-mp/sdl/sdl_local.h @@ -0,0 +1,7 @@ +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-mp/unix/unix_glimp_common.cpp b/CODE-mp/unix/unix_glimp_common.cpp new file mode 100644 index 0000000..50cc6c3 --- /dev/null +++ b/CODE-mp/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-mp/unix/unix_main.cpp b/CODE-mp/unix/unix_main.cpp index 0c9db9a..0a2bf13 100644 --- a/CODE-mp/unix/unix_main.cpp +++ b/CODE-mp/unix/unix_main.cpp @@ -211,7 +211,7 @@ void Sys_Init(void) Cvar_Set( "username", Sys_GetCurrentUser() ); - IN_Init(); +// IN_Init(); } From ae0d73a96ed4b7294b44720b04544a8699a0ba6a Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Tue, 30 Apr 2013 12:30:04 +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 de4d671..3424e22 100644 --- a/README.txt +++ b/README.txt @@ -28,8 +28,6 @@ copy *.so to your base directory Known issues: -When running windowed the mouse does not work in the menus. - With i386 linux with i965 graphics, levels seem to be zoomed in to point where only textures are seen. Does not seem to affect GL rendered cutscenes or OpenBSD/i386 with slightly older mesa.