* Merge unified-sdl to trunk
* Bump Q3_VERSION to 1.35
This commit is contained in:
parent
39abffeb3b
commit
672cfbf16f
188 changed files with 5071 additions and 41739 deletions
84
code/sdl/sdl_gamma.c
Normal file
84
code/sdl/sdl_gamma.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
===========================================================================
|
||||
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
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "SDL.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 )
|
||||
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 <windows.h>
|
||||
|
||||
// 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 )
|
||||
{
|
||||
Com_DPrintf( "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]);
|
||||
}
|
||||
|
804
code/sdl/sdl_glimp.c
Normal file
804
code/sdl/sdl_glimp.c
Normal file
|
@ -0,0 +1,804 @@
|
|||
/*
|
||||
===========================================================================
|
||||
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
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#ifdef SMP
|
||||
#include "SDL_thread.h"
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../renderer/tr_local.h"
|
||||
#include "../client/client.h"
|
||||
#include "../sys/sys_local.h"
|
||||
#include "sdl_icon.h"
|
||||
|
||||
/* Just hack it for now. */
|
||||
#ifdef MACOS_X
|
||||
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;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RSERR_OK,
|
||||
|
||||
RSERR_INVALID_FULLSCREEN,
|
||||
RSERR_INVALID_MODE,
|
||||
|
||||
RSERR_UNKNOWN
|
||||
} rserr_t;
|
||||
|
||||
static SDL_Surface *screen = NULL;
|
||||
|
||||
cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obtained
|
||||
|
||||
void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t );
|
||||
void ( APIENTRY * qglActiveTextureARB )( GLenum texture );
|
||||
void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture );
|
||||
|
||||
void ( APIENTRY * qglLockArraysEXT)( GLint, GLint);
|
||||
void ( APIENTRY * qglUnlockArraysEXT) ( void );
|
||||
|
||||
/*
|
||||
===============
|
||||
GLimp_Shutdown
|
||||
===============
|
||||
*/
|
||||
void GLimp_Shutdown( void )
|
||||
{
|
||||
IN_Shutdown();
|
||||
|
||||
SDL_QuitSubSystem( SDL_INIT_VIDEO );
|
||||
screen = NULL;
|
||||
|
||||
memset( &glConfig, 0, sizeof( glConfig ) );
|
||||
memset( &glState, 0, sizeof( glState ) );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
GLimp_LogComment
|
||||
===============
|
||||
*/
|
||||
void GLimp_LogComment( char *comment )
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
GLimp_SetMode
|
||||
===============
|
||||
*/
|
||||
static int GLimp_SetMode( int mode, qboolean fullscreen )
|
||||
{
|
||||
const char* glstring;
|
||||
int sdlcolorbits;
|
||||
int colorbits, depthbits, stencilbits;
|
||||
int tcolorbits, tdepthbits, tstencilbits;
|
||||
int i = 0;
|
||||
SDL_Surface *vidscreen = NULL;
|
||||
|
||||
ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");
|
||||
|
||||
ri.Printf (PRINT_ALL, "...setting mode %d:", mode );
|
||||
|
||||
if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) )
|
||||
{
|
||||
ri.Printf( PRINT_ALL, " invalid mode\n" );
|
||||
return RSERR_INVALID_MODE;
|
||||
}
|
||||
ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);
|
||||
|
||||
Uint32 flags = SDL_OPENGL;
|
||||
if (fullscreen)
|
||||
{
|
||||
flags |= SDL_FULLSCREEN;
|
||||
glConfig.isFullscreen = qtrue;
|
||||
}
|
||||
else
|
||||
glConfig.isFullscreen = qfalse;
|
||||
|
||||
if (!r_colorbits->value)
|
||||
colorbits = 24;
|
||||
else
|
||||
colorbits = r_colorbits->value;
|
||||
|
||||
if (!r_depthbits->value)
|
||||
depthbits = 24;
|
||||
else
|
||||
depthbits = r_depthbits->value;
|
||||
stencilbits = r_stencilbits->value;
|
||||
|
||||
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;
|
||||
|
||||
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_DOUBLEBUFFER, 1 );
|
||||
|
||||
// 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" );
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
|
||||
#else
|
||||
0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
|
||||
#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;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
rserr_t err;
|
||||
|
||||
if (!SDL_WasInit(SDL_INIT_VIDEO))
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "SDL_Init( SDL_INIT_VIDEO )... ");
|
||||
if (SDL_Init(SDL_INIT_VIDEO) == -1)
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "FAILED (%s)\n", SDL_GetError());
|
||||
return qfalse;
|
||||
}
|
||||
ri.Printf( PRINT_ALL, "OK\n");
|
||||
}
|
||||
|
||||
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 = GLimp_SetMode( mode, fullscreen );
|
||||
|
||||
switch ( err )
|
||||
{
|
||||
case RSERR_INVALID_FULLSCREEN:
|
||||
ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" );
|
||||
return qfalse;
|
||||
case RSERR_INVALID_MODE:
|
||||
ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode );
|
||||
return qfalse;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
/*
|
||||
===============
|
||||
GLimp_InitExtensions
|
||||
===============
|
||||
*/
|
||||
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" );
|
||||
|
||||
// GL_S3_s3tc
|
||||
if ( Q_stristr( glConfig.extensions_string, "GL_S3_s3tc" ) )
|
||||
{
|
||||
if ( r_ext_compressed_textures->value )
|
||||
{
|
||||
glConfig.textureCompression = TC_S3TC;
|
||||
ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
glConfig.textureCompression = TC_NONE;
|
||||
ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
glConfig.textureCompression = TC_NONE;
|
||||
ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" );
|
||||
}
|
||||
|
||||
// GL_EXT_texture_env_add
|
||||
glConfig.textureEnvAddAvailable = qfalse;
|
||||
if ( Q_stristr( glConfig.extensions_string, "EXT_texture_env_add" ) )
|
||||
{
|
||||
if ( r_ext_texture_env_add->integer )
|
||||
{
|
||||
glConfig.textureEnvAddAvailable = qtrue;
|
||||
ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
glConfig.textureEnvAddAvailable = qfalse;
|
||||
ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" );
|
||||
}
|
||||
|
||||
// GL_ARB_multitexture
|
||||
qglMultiTexCoord2fARB = NULL;
|
||||
qglActiveTextureARB = NULL;
|
||||
qglClientActiveTextureARB = NULL;
|
||||
if ( Q_stristr( glConfig.extensions_string, "GL_ARB_multitexture" ) )
|
||||
{
|
||||
if ( r_ext_multitexture->value )
|
||||
{
|
||||
qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) SDL_GL_GetProcAddress( "glMultiTexCoord2fARB" );
|
||||
qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) SDL_GL_GetProcAddress( "glActiveTextureARB" );
|
||||
qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) SDL_GL_GetProcAddress( "glClientActiveTextureARB" );
|
||||
|
||||
if ( qglActiveTextureARB )
|
||||
{
|
||||
GLint glint = 0;
|
||||
qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glint );
|
||||
glConfig.maxActiveTextures = (int) glint;
|
||||
if ( glConfig.maxActiveTextures > 1 )
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
qglMultiTexCoord2fARB = NULL;
|
||||
qglActiveTextureARB = NULL;
|
||||
qglClientActiveTextureARB = NULL;
|
||||
ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" );
|
||||
}
|
||||
|
||||
// GL_EXT_compiled_vertex_array
|
||||
if ( Q_stristr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) )
|
||||
{
|
||||
if ( r_ext_compiled_vertex_array->value )
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" );
|
||||
qglLockArraysEXT = ( void ( APIENTRY * )( GLint, GLint ) ) 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" );
|
||||
}
|
||||
|
||||
textureFilterAnisotropic = qfalse;
|
||||
if ( strstr( glConfig.extensions_string, "GL_EXT_texture_filter_anisotropic" ) )
|
||||
{
|
||||
if ( r_ext_texture_filter_anisotropic->integer ) {
|
||||
qglGetIntegerv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, (GLint *)&maxAnisotropy );
|
||||
if ( maxAnisotropy <= 0 ) {
|
||||
ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not properly supported!\n" );
|
||||
maxAnisotropy = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic (max: %i)\n", maxAnisotropy );
|
||||
textureFilterAnisotropic = qtrue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" );
|
||||
}
|
||||
}
|
||||
|
||||
#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 )
|
||||
{
|
||||
qboolean success = qtrue;
|
||||
|
||||
r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH );
|
||||
|
||||
// create the window and set up the context
|
||||
if( !GLimp_StartDriverAndSetMode( r_mode->integer, r_fullscreen->integer ) )
|
||||
{
|
||||
if( r_mode->integer != R_MODE_FALLBACK )
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "Setting r_mode %d failed, falling back on r_mode %d",
|
||||
r_mode->integer, R_MODE_FALLBACK );
|
||||
if( !GLimp_StartDriverAndSetMode( R_MODE_FALLBACK, r_fullscreen->integer ) )
|
||||
success = qfalse;
|
||||
}
|
||||
else
|
||||
success = qfalse;
|
||||
}
|
||||
|
||||
if( !success )
|
||||
ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" );
|
||||
|
||||
// This values force the UI to disable driver selection
|
||||
glConfig.driverType = GLDRV_ICD;
|
||||
glConfig.hardwareType = GLHW_GENERIC;
|
||||
glConfig.deviceSupportsGamma = !!( SDL_SetGamma( 1.0f, 1.0f, 1.0f ) >= 0 );
|
||||
|
||||
// get our config strings
|
||||
Q_strncpyz( glConfig.vendor_string, (char *) qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) );
|
||||
Q_strncpyz( glConfig.renderer_string, (char *) qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) );
|
||||
if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n')
|
||||
glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0;
|
||||
Q_strncpyz( glConfig.version_string, (char *) qglGetString (GL_VERSION), sizeof( glConfig.version_string ) );
|
||||
Q_strncpyz( glConfig.extensions_string, (char *) qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) );
|
||||
|
||||
// initialize extensions
|
||||
GLimp_InitExtensions( );
|
||||
|
||||
// This depends on SDL_INIT_VIDEO, hence having it here
|
||||
IN_Init( );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
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 sdlToggled = qfalse;
|
||||
SDL_Surface *s = SDL_GetVideoSurface( );
|
||||
|
||||
if( s )
|
||||
{
|
||||
// Find out the current state
|
||||
if( s->flags & SDL_FULLSCREEN )
|
||||
fullscreen = qtrue;
|
||||
else
|
||||
fullscreen = qfalse;
|
||||
|
||||
// Is the state we want different from the current state?
|
||||
if( !!r_fullscreen->integer != fullscreen )
|
||||
sdlToggled = SDL_WM_ToggleFullScreen( s );
|
||||
else
|
||||
sdlToggled = qtrue;
|
||||
}
|
||||
|
||||
// SDL_WM_ToggleFullScreen didn't work, so do it the slow way
|
||||
if( !sdlToggled )
|
||||
Cbuf_AddText( "vid_restart" );
|
||||
|
||||
r_fullscreen->modified = qfalse;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef SMP
|
||||
/*
|
||||
===========================================================
|
||||
|
||||
SMP acceleration
|
||||
|
||||
===========================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* I have no idea if this will even work...most platforms don't offer
|
||||
* thread-safe OpenGL libraries, and it looks like the original Linux
|
||||
* code counted on each thread claiming the GL context with glXMakeCurrent(),
|
||||
* which you can't currently do in SDL. We'll just have to hope for the best.
|
||||
*/
|
||||
|
||||
static SDL_mutex *smpMutex = NULL;
|
||||
static SDL_cond *renderCommandsEvent = NULL;
|
||||
static SDL_cond *renderCompletedEvent = NULL;
|
||||
static void (*glimpRenderThread)( void ) = NULL;
|
||||
static SDL_Thread *renderThread = NULL;
|
||||
|
||||
/*
|
||||
===============
|
||||
GLimp_ShutdownRenderThread
|
||||
===============
|
||||
*/
|
||||
static void GLimp_ShutdownRenderThread(void)
|
||||
{
|
||||
if (smpMutex != NULL)
|
||||
{
|
||||
SDL_DestroyMutex(smpMutex);
|
||||
smpMutex = NULL;
|
||||
}
|
||||
|
||||
if (renderCommandsEvent != NULL)
|
||||
{
|
||||
SDL_DestroyCond(renderCommandsEvent);
|
||||
renderCommandsEvent = NULL;
|
||||
}
|
||||
|
||||
if (renderCompletedEvent != NULL)
|
||||
{
|
||||
SDL_DestroyCond(renderCompletedEvent);
|
||||
renderCompletedEvent = NULL;
|
||||
}
|
||||
|
||||
glimpRenderThread = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
GLimp_RenderThreadWrapper
|
||||
===============
|
||||
*/
|
||||
static int GLimp_RenderThreadWrapper( void *arg )
|
||||
{
|
||||
Com_Printf( "Render thread starting\n" );
|
||||
|
||||
glimpRenderThread();
|
||||
|
||||
GLimp_SetCurrentContext(NULL);
|
||||
|
||||
Com_Printf( "Render thread terminating\n" );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
GLimp_SpawnRenderThread
|
||||
===============
|
||||
*/
|
||||
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
|
||||
{
|
||||
static qboolean warned = qfalse;
|
||||
if (!warned)
|
||||
{
|
||||
Com_Printf("WARNING: You enable r_smp at your own risk!\n");
|
||||
warned = qtrue;
|
||||
}
|
||||
|
||||
#ifndef MACOS_X
|
||||
return qfalse; /* better safe than sorry for now. */
|
||||
#endif
|
||||
|
||||
if (renderThread != NULL) /* hopefully just a zombie at this point... */
|
||||
{
|
||||
Com_Printf("Already a render thread? Trying to clean it up...\n");
|
||||
SDL_WaitThread(renderThread, NULL);
|
||||
renderThread = NULL;
|
||||
GLimp_ShutdownRenderThread();
|
||||
}
|
||||
|
||||
smpMutex = SDL_CreateMutex();
|
||||
if (smpMutex == NULL)
|
||||
{
|
||||
Com_Printf( "smpMutex creation failed: %s\n", SDL_GetError() );
|
||||
GLimp_ShutdownRenderThread();
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
renderCommandsEvent = SDL_CreateCond();
|
||||
if (renderCommandsEvent == NULL)
|
||||
{
|
||||
Com_Printf( "renderCommandsEvent creation failed: %s\n", SDL_GetError() );
|
||||
GLimp_ShutdownRenderThread();
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
renderCompletedEvent = SDL_CreateCond();
|
||||
if (renderCompletedEvent == NULL)
|
||||
{
|
||||
Com_Printf( "renderCompletedEvent creation failed: %s\n", SDL_GetError() );
|
||||
GLimp_ShutdownRenderThread();
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
glimpRenderThread = function;
|
||||
renderThread = SDL_CreateThread(GLimp_RenderThreadWrapper, NULL);
|
||||
if ( renderThread == NULL )
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "SDL_CreateThread() returned %s", SDL_GetError() );
|
||||
GLimp_ShutdownRenderThread();
|
||||
return qfalse;
|
||||
}
|
||||
else
|
||||
{
|
||||
// tma 01/09/07: don't think this is necessary anyway?
|
||||
//
|
||||
// !!! FIXME: No detach API available in SDL!
|
||||
//ret = pthread_detach( renderThread );
|
||||
//if ( ret ) {
|
||||
//ri.Printf( PRINT_ALL, "pthread_detach returned %d: %s", ret, strerror( ret ) );
|
||||
//}
|
||||
}
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
static volatile void *smpData = NULL;
|
||||
static volatile qboolean smpDataReady;
|
||||
|
||||
/*
|
||||
===============
|
||||
GLimp_RendererSleep
|
||||
===============
|
||||
*/
|
||||
void *GLimp_RendererSleep( void )
|
||||
{
|
||||
void *data = NULL;
|
||||
|
||||
GLimp_SetCurrentContext(NULL);
|
||||
|
||||
SDL_LockMutex(smpMutex);
|
||||
{
|
||||
smpData = NULL;
|
||||
smpDataReady = qfalse;
|
||||
|
||||
// after this, the front end can exit GLimp_FrontEndSleep
|
||||
SDL_CondSignal(renderCompletedEvent);
|
||||
|
||||
while ( !smpDataReady )
|
||||
SDL_CondWait(renderCommandsEvent, smpMutex);
|
||||
|
||||
data = (void *)smpData;
|
||||
}
|
||||
SDL_UnlockMutex(smpMutex);
|
||||
|
||||
GLimp_SetCurrentContext(opengl_context);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
GLimp_FrontEndSleep
|
||||
===============
|
||||
*/
|
||||
void GLimp_FrontEndSleep( void )
|
||||
{
|
||||
SDL_LockMutex(smpMutex);
|
||||
{
|
||||
while ( smpData )
|
||||
SDL_CondWait(renderCompletedEvent, smpMutex);
|
||||
}
|
||||
SDL_UnlockMutex(smpMutex);
|
||||
|
||||
GLimp_SetCurrentContext(opengl_context);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
GLimp_WakeRenderer
|
||||
===============
|
||||
*/
|
||||
void GLimp_WakeRenderer( void *data )
|
||||
{
|
||||
GLimp_SetCurrentContext(NULL);
|
||||
|
||||
SDL_LockMutex(smpMutex);
|
||||
{
|
||||
assert( smpData == NULL );
|
||||
smpData = data;
|
||||
smpDataReady = qtrue;
|
||||
|
||||
// after this, the renderer can continue through GLimp_RendererSleep
|
||||
SDL_CondSignal(renderCommandsEvent);
|
||||
}
|
||||
SDL_UnlockMutex(smpMutex);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// No SMP - stubs
|
||||
void GLimp_RenderThreadWrapper( void *arg )
|
||||
{
|
||||
}
|
||||
|
||||
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
|
||||
{
|
||||
ri.Printf( PRINT_WARNING, "ERROR: SMP support was disabled at compile time\n");
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
void *GLimp_RendererSleep( void )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GLimp_FrontEndSleep( void )
|
||||
{
|
||||
}
|
||||
|
||||
void GLimp_WakeRenderer( void *data )
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
132
code/sdl/sdl_icon.h
Normal file
132
code/sdl/sdl_icon.h
Normal file
|
@ -0,0 +1,132 @@
|
|||
/* GIMP RGBA C-Source image dump (sdl_icon.h) */
|
||||
|
||||
static const struct {
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */
|
||||
unsigned char pixel_data[32 * 32 * 4 + 1];
|
||||
} CLIENT_WINDOW_ICON = {
|
||||
32, 32, 4,
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377w\0\0"
|
||||
"\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0"
|
||||
"\0\377w\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377\210\0\0\377"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\210\0\0\377\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377\210\0\0"
|
||||
"\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\252\0\0"
|
||||
"\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0\377\210\0\0\377\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\252\0\0\377\0\0\0\0\273\0\0\377\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\231\0\0\377\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\273\0\0\377\314\0\0\377\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\231\0\0\377\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0"
|
||||
"\377\314\0\0\377\0\0\0\0\335\0\0\377\314\0\0\377\231\0\0\377\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\231\0\0\377\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0\377\314\0\0\377\335"
|
||||
"\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0\377\314\0\0\377\335\0\0\377\335"
|
||||
"\0\0\377\273\0\0\377\231\0\0\377\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\231\0\0\377\252\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\252\0\0\377\273\0\0\377\335\0\0\377\335\0\0"
|
||||
"\377\314\0\0\377\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\252\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377"
|
||||
"\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377\0\0\0\0\252\0\0\377\252"
|
||||
"\0\0\377\0\0\0\0\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0"
|
||||
"\377\314\0\0\377\314\0\0\377\314\0\0\377\252\0\0\377\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\210\0\0\377\231\0\0\377\273\0\0\377\314\0\0\377\314"
|
||||
"\0\0\377\0\0\0\0\252\0\0\377\252\0\0\377\0\0\0\0\314\0\0\377\314\0\0\377"
|
||||
"\273\0\0\377\231\0\0\377\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377"
|
||||
"\273\0\0\377\0\0\0\0\252\0\0\377\252\0\0\377\0\0\0\0\273\0\0\377\210\0\0"
|
||||
"\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377\273\0\0\377"
|
||||
"\0\0\0\0\231\0\0\377\252\0\0\377\0\0\0\0\273\0\0\377w\0\0\377\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\252\0\0\377\0\0\0\0\231\0\0"
|
||||
"\377\231\0\0\377\0\0\0\0\252\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\252\0\0\377\0\0\0\0\210\0\0\377\231\0\0\377"
|
||||
"\0\0\0\0\252\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\231\0\0\377\0\0\0\0\210\0\0\377\210\0\0\377\0\0\0\0\231\0\0"
|
||||
"\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231"
|
||||
"\0\0\377\0\0\0\0w\0\0\377\210\0\0\377\0\0\0\0\231\0\0\377\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377\0\0\0\0\210"
|
||||
"\0\0\377\210\0\0\377\0\0\0\0\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377\0\0\0\0w\0\0\377\210\0\0\377"
|
||||
"\0\0\0\0\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0w\0\0\377\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0w\0\0\377\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377\0\0\0\0"
|
||||
"w\0\0\377w\0\0\377\0\0\0\0w\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0w\0"
|
||||
"\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0f\0\0\377f\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0f\0\0\377f\0\0\377"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0",
|
||||
};
|
||||
|
801
code/sdl/sdl_input.c
Normal file
801
code/sdl/sdl_input.c
Normal file
|
@ -0,0 +1,801 @@
|
|||
/*
|
||||
===========================================================================
|
||||
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
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../renderer/tr_local.h"
|
||||
#include "../client/client.h"
|
||||
#include "../sys/sys_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 <IOKit/hidsystem/IOHIDLib.h>
|
||||
#include <IOKit/hidsystem/IOHIDParameter.h>
|
||||
#include <drivers/event_status_driver.h>
|
||||
#endif
|
||||
|
||||
//#define KBD_DBG
|
||||
|
||||
static SDL_Joystick *stick = NULL;
|
||||
|
||||
static qboolean mouseAvailable = qfalse;
|
||||
static qboolean mouseActive = qfalse;
|
||||
static qboolean keyRepeatEnabled = qfalse;
|
||||
|
||||
static cvar_t *in_mouse;
|
||||
#ifdef MACOS_X_ACCELERATION_HACK
|
||||
static cvar_t *in_disablemacosxmouseaccel;
|
||||
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;
|
||||
|
||||
/*
|
||||
===============
|
||||
IN_TranslateSDLToQ3Key
|
||||
===============
|
||||
*/
|
||||
static const char *IN_TranslateSDLToQ3Key(SDL_keysym *keysym, int *key)
|
||||
{
|
||||
static char buf[2] = { '\0', '\0' };
|
||||
*buf = '\0';
|
||||
|
||||
*key = 0;
|
||||
|
||||
// these happen to match the ASCII chars.
|
||||
if ((keysym->sym >= ' ') && (keysym->sym <= '~'))
|
||||
{
|
||||
*key = (int) keysym->sym;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (keysym->sym)
|
||||
{
|
||||
case SDLK_PAGEUP: *key = K_PGUP; break;
|
||||
case SDLK_KP9: *key = K_KP_PGUP; break;
|
||||
case SDLK_PAGEDOWN: *key = K_PGDN; break;
|
||||
case SDLK_KP3: *key = K_KP_PGDN; break;
|
||||
case SDLK_KP7: *key = K_KP_HOME; break;
|
||||
case SDLK_HOME: *key = K_HOME; break;
|
||||
case SDLK_KP1: *key = K_KP_END; break;
|
||||
case SDLK_END: *key = K_END; break;
|
||||
case SDLK_KP4: *key = K_KP_LEFTARROW; break;
|
||||
case SDLK_LEFT: *key = K_LEFTARROW; break;
|
||||
case SDLK_KP6: *key = K_KP_RIGHTARROW; break;
|
||||
case SDLK_RIGHT: *key = K_RIGHTARROW; break;
|
||||
case SDLK_KP2: *key = K_KP_DOWNARROW; break;
|
||||
case SDLK_DOWN: *key = K_DOWNARROW; break;
|
||||
case SDLK_KP8: *key = K_KP_UPARROW; break;
|
||||
case SDLK_UP: *key = K_UPARROW; break;
|
||||
case SDLK_ESCAPE: *key = K_ESCAPE; break;
|
||||
case SDLK_KP_ENTER: *key = K_KP_ENTER; break;
|
||||
case SDLK_RETURN: *key = K_ENTER; break;
|
||||
case SDLK_TAB: *key = K_TAB; break;
|
||||
case SDLK_F1: *key = K_F1; break;
|
||||
case SDLK_F2: *key = K_F2; break;
|
||||
case SDLK_F3: *key = K_F3; break;
|
||||
case SDLK_F4: *key = K_F4; break;
|
||||
case SDLK_F5: *key = K_F5; break;
|
||||
case SDLK_F6: *key = K_F6; break;
|
||||
case SDLK_F7: *key = K_F7; break;
|
||||
case SDLK_F8: *key = K_F8; break;
|
||||
case SDLK_F9: *key = K_F9; break;
|
||||
case SDLK_F10: *key = K_F10; break;
|
||||
case SDLK_F11: *key = K_F11; break;
|
||||
case SDLK_F12: *key = K_F12; break;
|
||||
case SDLK_F13: *key = K_F13; break;
|
||||
case SDLK_F14: *key = K_F14; break;
|
||||
case SDLK_F15: *key = K_F15; break;
|
||||
|
||||
case SDLK_BACKSPACE: *key = K_BACKSPACE; break; // ctrl-h
|
||||
case SDLK_KP_PERIOD: *key = K_KP_DEL; break;
|
||||
case SDLK_DELETE: *key = K_DEL; break;
|
||||
case SDLK_PAUSE: *key = K_PAUSE; break;
|
||||
|
||||
case SDLK_LSHIFT:
|
||||
case SDLK_RSHIFT: *key = K_SHIFT; break;
|
||||
|
||||
case SDLK_LCTRL:
|
||||
case SDLK_RCTRL: *key = K_CTRL; break;
|
||||
|
||||
case SDLK_RMETA:
|
||||
case SDLK_LMETA:
|
||||
case SDLK_RALT:
|
||||
case SDLK_LALT: *key = K_ALT; break;
|
||||
|
||||
case SDLK_LSUPER:
|
||||
case SDLK_RSUPER: *key = K_SUPER; break;
|
||||
|
||||
case SDLK_KP5: *key = K_KP_5; break;
|
||||
case SDLK_INSERT: *key = K_INS; break;
|
||||
case SDLK_KP0: *key = K_KP_INS; break;
|
||||
case SDLK_KP_MULTIPLY: *key = K_KP_STAR; break;
|
||||
case SDLK_KP_PLUS: *key = K_KP_PLUS; break;
|
||||
case SDLK_KP_MINUS: *key = K_KP_MINUS; break;
|
||||
case SDLK_KP_DIVIDE: *key = K_KP_SLASH; break;
|
||||
|
||||
case SDLK_MODE: *key = K_MODE; break;
|
||||
case SDLK_COMPOSE: *key = K_COMPOSE; break;
|
||||
case SDLK_HELP: *key = K_HELP; break;
|
||||
case SDLK_PRINT: *key = K_PRINT; break;
|
||||
case SDLK_SYSREQ: *key = K_SYSREQ; break;
|
||||
case SDLK_BREAK: *key = K_BREAK; break;
|
||||
case SDLK_MENU: *key = K_MENU; break;
|
||||
case SDLK_POWER: *key = K_POWER; break;
|
||||
case SDLK_EURO: *key = K_EURO; break;
|
||||
case SDLK_UNDO: *key = K_UNDO; break;
|
||||
case SDLK_SCROLLOCK: *key = K_SCROLLOCK; break;
|
||||
case SDLK_NUMLOCK: *key = K_KP_NUMLOCK; break;
|
||||
case SDLK_CAPSLOCK: *key = K_CAPSLOCK; break;
|
||||
|
||||
default:
|
||||
if (keysym->sym >= SDLK_WORLD_0 && keysym->sym <= SDLK_WORLD_95)
|
||||
*key = (keysym->sym - SDLK_WORLD_0) + K_WORLD_0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( keysym->unicode <= 127 ) // maps to ASCII?
|
||||
{
|
||||
char ch = (char) keysym->unicode;
|
||||
if (ch == '~')
|
||||
*key = '~'; // console HACK
|
||||
|
||||
// translate K_BACKSPACE to ctrl-h for MACOS_X (others?)
|
||||
if (ch == K_BACKSPACE && keysym->sym != SDLK_DELETE)
|
||||
{
|
||||
*key = 'h' - 'a' + 1;
|
||||
buf[0] = *key;
|
||||
}
|
||||
else
|
||||
buf[0] = ch;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
IN_PrintKey
|
||||
===============
|
||||
*/
|
||||
static void IN_PrintKey(const SDL_Event* event)
|
||||
{
|
||||
#ifdef KBD_DBG
|
||||
fprintf( stderr, "key name: %s", SDL_GetKeyName (event->key.keysym.sym ) );
|
||||
if(event->key.keysym.unicode)
|
||||
{
|
||||
fprintf( stderr, " unicode: %hx", event->key.keysym.unicode );
|
||||
if( event->key.keysym.unicode >= '0' &&
|
||||
event->key.keysym.unicode <= '~') // printable?
|
||||
{
|
||||
fprintf( stderr, " (%c)", (unsigned char)event->key.keysym.unicode );
|
||||
}
|
||||
}
|
||||
fflush( stderr );
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MACOS_X_ACCELERATION_HACK
|
||||
/*
|
||||
===============
|
||||
IN_GetIOHandle
|
||||
===============
|
||||
*/
|
||||
static io_connect_t IN_GetIOHandle() // 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_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_WM_GrabInput( SDL_GRAB_ON );
|
||||
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
|
||||
}
|
||||
|
||||
// in_nograb makes no sense unless fullscreen
|
||||
if( !r_fullscreen->integer )
|
||||
{
|
||||
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 (!mouseAvailable || !SDL_WasInit( SDL_INIT_VIDEO ) )
|
||||
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 )
|
||||
{
|
||||
SDL_ShowCursor( 1 );
|
||||
SDL_WM_GrabInput( SDL_GRAB_OFF );
|
||||
|
||||
mouseActive = qfalse;
|
||||
}
|
||||
}
|
||||
|
||||
// We translate axes movement into keypresses
|
||||
static int joy_keys[16] = {
|
||||
K_LEFTARROW, K_RIGHTARROW,
|
||||
K_UPARROW, K_DOWNARROW,
|
||||
K_JOY16, K_JOY17,
|
||||
K_JOY18, K_JOY19,
|
||||
K_JOY20, K_JOY21,
|
||||
K_JOY22, K_JOY23,
|
||||
|
||||
K_JOY24, K_JOY25,
|
||||
K_JOY26, K_JOY27
|
||||
};
|
||||
|
||||
// translate hat events into keypresses
|
||||
// the 4 highest buttons are used for the first hat ...
|
||||
static int hat_keys[16] = {
|
||||
K_JOY29, K_JOY30,
|
||||
K_JOY31, K_JOY32,
|
||||
K_JOY25, K_JOY26,
|
||||
K_JOY27, K_JOY28,
|
||||
K_JOY21, K_JOY22,
|
||||
K_JOY23, K_JOY24,
|
||||
K_JOY17, K_JOY18,
|
||||
K_JOY19, K_JOY20
|
||||
};
|
||||
|
||||
|
||||
extern cvar_t * in_joystick;
|
||||
extern cvar_t * in_joystickDebug;
|
||||
extern cvar_t * in_joystickThreshold;
|
||||
cvar_t *in_joystickNo;
|
||||
|
||||
#define ARRAYLEN(x) (sizeof (x) / sizeof (x[0]))
|
||||
struct
|
||||
{
|
||||
qboolean buttons[16]; // !!! FIXME: these might be too many.
|
||||
unsigned int oldaxes;
|
||||
unsigned int oldhats;
|
||||
} stick_state;
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
IN_StartupJoystick
|
||||
===============
|
||||
*/
|
||||
static void IN_StartupJoystick( void )
|
||||
{
|
||||
int i = 0;
|
||||
int total = 0;
|
||||
|
||||
if (stick != NULL)
|
||||
SDL_JoystickClose(stick);
|
||||
|
||||
stick = NULL;
|
||||
memset(&stick_state, '\0', sizeof (stick_state));
|
||||
|
||||
if( !in_joystick->integer ) {
|
||||
Com_DPrintf( "Joystick is not active.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
for (i = 0; i < total; i++)
|
||||
Com_DPrintf("[%d] %s\n", i, SDL_JoystickName(i));
|
||||
|
||||
in_joystickNo = Cvar_Get( "in_joystickNo", "0", CVAR_ARCHIVE );
|
||||
if( in_joystickNo->integer < 0 || in_joystickNo->integer >= total )
|
||||
Cvar_Set( "in_joystickNo", "0" );
|
||||
|
||||
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) );
|
||||
|
||||
SDL_JoystickEventState(SDL_QUERY);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
IN_JoyMove
|
||||
===============
|
||||
*/
|
||||
static void IN_JoyMove( void )
|
||||
{
|
||||
qboolean joy_pressed[ARRAYLEN(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;
|
||||
Com_QueueEvent( 0, SE_MOUSE, balldx, balldy, 0, NULL );
|
||||
}
|
||||
}
|
||||
|
||||
// now query the stick buttons...
|
||||
total = SDL_JoystickNumButtons(stick);
|
||||
if (total > 0)
|
||||
{
|
||||
if (total > ARRAYLEN(stick_state.buttons))
|
||||
total = ARRAYLEN(stick_state.buttons);
|
||||
for (i = 0; i < total; i++)
|
||||
{
|
||||
qboolean pressed = (SDL_JoystickGetButton(stick, i) != 0);
|
||||
if (pressed != stick_state.buttons[i])
|
||||
{
|
||||
Com_QueueEvent( 0, SE_KEY, K_JOY1 + 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:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_RIGHT:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_DOWN:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_LEFT:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_RIGHTUP:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_RIGHTDOWN:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_LEFTUP:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_LEFTDOWN:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// press event
|
||||
switch( ((Uint8 *)&hats)[i] ) {
|
||||
case SDL_HAT_UP:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_RIGHT:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_DOWN:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_LEFT:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_RIGHTUP:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_RIGHTDOWN:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_LEFTUP:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
|
||||
break;
|
||||
case SDL_HAT_LEFTDOWN:
|
||||
Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
|
||||
Com_QueueEvent( 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 (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 ) ) ) {
|
||||
Com_QueueEvent( 0, SE_KEY, joy_keys[i], qtrue, 0, NULL );
|
||||
}
|
||||
|
||||
if( !( axes & ( 1 << i ) ) && ( stick_state.oldaxes & ( 1 << i ) ) ) {
|
||||
Com_QueueEvent( 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 *p = NULL;
|
||||
int key = 0;
|
||||
|
||||
if( !SDL_WasInit( SDL_INIT_VIDEO ) )
|
||||
return;
|
||||
|
||||
if( cls.keyCatchers == 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:
|
||||
IN_PrintKey(&e);
|
||||
p = IN_TranslateSDLToQ3Key(&e.key.keysym, &key);
|
||||
if( key )
|
||||
Com_QueueEvent( 0, SE_KEY, key, qtrue, 0, NULL );
|
||||
|
||||
if( p )
|
||||
{
|
||||
while( *p )
|
||||
Com_QueueEvent( 0, SE_CHAR, *p++, 0, 0, NULL );
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
IN_TranslateSDLToQ3Key(&e.key.keysym, &key);
|
||||
Com_QueueEvent( 0, SE_KEY, key, qfalse, 0, NULL );
|
||||
break;
|
||||
|
||||
case SDL_MOUSEMOTION:
|
||||
if (mouseActive)
|
||||
Com_QueueEvent( 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 = K_MOUSE1; break;
|
||||
case 2: b = K_MOUSE3; break;
|
||||
case 3: b = K_MOUSE2; break;
|
||||
case 4: b = K_MWHEELUP; break;
|
||||
case 5: b = K_MWHEELDOWN; break;
|
||||
case 6: b = K_MOUSE4; break;
|
||||
case 7: b = K_MOUSE5; break;
|
||||
default: b = K_AUX1 + (e.button.button - 8)%16; break;
|
||||
}
|
||||
Com_QueueEvent( 0, SE_KEY, b,
|
||||
( e.type == SDL_MOUSEBUTTONDOWN ? qtrue : qfalse ), 0, NULL );
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
Sys_Quit();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
IN_Frame
|
||||
===============
|
||||
*/
|
||||
void IN_Frame (void)
|
||||
{
|
||||
IN_JoyMove( );
|
||||
|
||||
// Release the mouse if the console if down and we're windowed
|
||||
if( ( cls.keyCatchers & KEYCATCH_CONSOLE ) && !r_fullscreen->integer )
|
||||
IN_DeactivateMouse( );
|
||||
else
|
||||
IN_ActivateMouse( );
|
||||
|
||||
IN_ProcessEvents( );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
IN_Init
|
||||
===============
|
||||
*/
|
||||
void IN_Init(void)
|
||||
{
|
||||
if( !SDL_WasInit( SDL_INIT_VIDEO ) )
|
||||
{
|
||||
Com_Error( ERR_FATAL, "IN_Init called before SDL_Init( SDL_INIT_VIDEO )\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
Com_DPrintf ("\n------- Input Initialization -------\n");
|
||||
|
||||
// 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_debugjoystick", "0", CVAR_TEMP);
|
||||
in_joystickThreshold = Cvar_Get ("in_joystickThreshold", "0.15", CVAR_ARCHIVE);
|
||||
|
||||
#ifdef MACOS_X_ACCELERATION_HACK
|
||||
in_disablemacosxmouseaccel = Cvar_Get ("in_disablemacosxmouseaccel", "1", CVAR_ARCHIVE);
|
||||
#endif
|
||||
|
||||
Cvar_Set( "cl_platformSensitivity", "1.0" );
|
||||
|
||||
SDL_EnableUNICODE(1);
|
||||
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
|
||||
keyRepeatEnabled = qtrue;
|
||||
|
||||
if (in_mouse->value)
|
||||
mouseAvailable = qtrue;
|
||||
else
|
||||
mouseAvailable = qfalse;
|
||||
|
||||
IN_StartupJoystick( );
|
||||
Com_DPrintf ("------------------------------------\n");
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
IN_Shutdown
|
||||
===============
|
||||
*/
|
||||
void IN_Shutdown(void)
|
||||
{
|
||||
IN_DeactivateMouse();
|
||||
|
||||
mouseAvailable = qfalse;
|
||||
|
||||
if (stick)
|
||||
{
|
||||
SDL_JoystickClose(stick);
|
||||
stick = NULL;
|
||||
}
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
}
|
295
code/sdl/sdl_snd.c
Normal file
295
code/sdl/sdl_snd.c
Normal file
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
===========================================================================
|
||||
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
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#include "../qcommon/q_shared.h"
|
||||
#include "../client/snd_local.h"
|
||||
|
||||
qboolean snd_inited = qfalse;
|
||||
|
||||
cvar_t *s_sdlBits;
|
||||
cvar_t *s_sdlSpeed;
|
||||
cvar_t *s_sdlChannels;
|
||||
cvar_t *s_sdlDevSamps;
|
||||
cvar_t *s_sdlMixSamps;
|
||||
|
||||
/* The audio callback. All the magic happens here. */
|
||||
static int dmapos = 0;
|
||||
static int dmasize = 0;
|
||||
|
||||
/*
|
||||
===============
|
||||
SNDDMA_AudioCallback
|
||||
===============
|
||||
*/
|
||||
static void SNDDMA_AudioCallback(void *userdata, Uint8 *stream, int len)
|
||||
{
|
||||
int pos = (dmapos * (dma.samplebits/8));
|
||||
if (pos >= dmasize)
|
||||
dmapos = pos = 0;
|
||||
|
||||
if (!snd_inited) /* shouldn't happen, but just in case... */
|
||||
{
|
||||
memset(stream, '\0', len);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
int tobufend = dmasize - pos; /* bytes to buffer's end. */
|
||||
int len1 = len;
|
||||
int len2 = 0;
|
||||
|
||||
if (len1 > tobufend)
|
||||
{
|
||||
len1 = tobufend;
|
||||
len2 = len - len1;
|
||||
}
|
||||
memcpy(stream, dma.buffer + pos, len1);
|
||||
if (len2 <= 0)
|
||||
dmapos += (len1 / (dma.samplebits/8));
|
||||
else /* wraparound? */
|
||||
{
|
||||
memcpy(stream+len1, dma.buffer, len2);
|
||||
dmapos = (len2 / (dma.samplebits/8));
|
||||
}
|
||||
}
|
||||
|
||||
if (dmapos >= dmasize)
|
||||
dmapos = 0;
|
||||
}
|
||||
|
||||
static struct
|
||||
{
|
||||
Uint16 enumFormat;
|
||||
char *stringFormat;
|
||||
} formatToStringTable[ ] =
|
||||
{
|
||||
{ AUDIO_U8, "AUDIO_U8" },
|
||||
{ AUDIO_S8, "AUDIO_S8" },
|
||||
{ AUDIO_U16LSB, "AUDIO_U16LSB" },
|
||||
{ AUDIO_S16LSB, "AUDIO_S16LSB" },
|
||||
{ AUDIO_U16MSB, "AUDIO_U16MSB" },
|
||||
{ AUDIO_S16MSB, "AUDIO_S16MSB" }
|
||||
};
|
||||
|
||||
static int formatToStringTableSize =
|
||||
sizeof( formatToStringTable ) / sizeof( formatToStringTable[ 0 ] );
|
||||
|
||||
/*
|
||||
===============
|
||||
SNDDMA_PrintAudiospec
|
||||
===============
|
||||
*/
|
||||
static void SNDDMA_PrintAudiospec(const char *str, const SDL_AudioSpec *spec)
|
||||
{
|
||||
int i;
|
||||
char *fmt = NULL;
|
||||
|
||||
Com_Printf("%s:\n", str);
|
||||
|
||||
for( i = 0; i < formatToStringTableSize; i++ ) {
|
||||
if( spec->format == formatToStringTable[ i ].enumFormat ) {
|
||||
fmt = formatToStringTable[ i ].stringFormat;
|
||||
}
|
||||
}
|
||||
|
||||
if( fmt ) {
|
||||
Com_Printf( " Format: %s\n", fmt );
|
||||
} else {
|
||||
Com_Printf( " Format: " S_COLOR_RED "UNKNOWN\n");
|
||||
}
|
||||
|
||||
Com_Printf( " Freq: %d\n", (int) spec->freq );
|
||||
Com_Printf( " Samples: %d\n", (int) spec->samples );
|
||||
Com_Printf( " Channels: %d\n", (int) spec->channels );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SNDDMA_Init
|
||||
===============
|
||||
*/
|
||||
qboolean SNDDMA_Init(void)
|
||||
{
|
||||
char drivername[128];
|
||||
SDL_AudioSpec desired;
|
||||
SDL_AudioSpec obtained;
|
||||
int tmp;
|
||||
|
||||
if (snd_inited)
|
||||
return qtrue;
|
||||
|
||||
if (!s_sdlBits) {
|
||||
s_sdlBits = Cvar_Get("s_sdlBits", "16", CVAR_ARCHIVE);
|
||||
s_sdlSpeed = Cvar_Get("s_sdlSpeed", "0", CVAR_ARCHIVE);
|
||||
s_sdlChannels = Cvar_Get("s_sdlChannels", "2", CVAR_ARCHIVE);
|
||||
s_sdlDevSamps = Cvar_Get("s_sdlDevSamps", "0", CVAR_ARCHIVE);
|
||||
s_sdlMixSamps = Cvar_Get("s_sdlMixSamps", "0", CVAR_ARCHIVE);
|
||||
}
|
||||
|
||||
Com_Printf( "SDL_Init( SDL_INIT_AUDIO )... " );
|
||||
|
||||
if (!SDL_WasInit(SDL_INIT_AUDIO))
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_AUDIO) == -1)
|
||||
{
|
||||
Com_Printf( "FAILED (%s)\n", SDL_GetError( ) );
|
||||
return qfalse;
|
||||
}
|
||||
}
|
||||
|
||||
Com_Printf( "OK\n" );
|
||||
|
||||
if (SDL_AudioDriverName(drivername, sizeof (drivername)) == NULL)
|
||||
strcpy(drivername, "(UNKNOWN)");
|
||||
Com_Printf("SDL audio driver is \"%s\".\n", drivername);
|
||||
|
||||
memset(&desired, '\0', sizeof (desired));
|
||||
memset(&obtained, '\0', sizeof (obtained));
|
||||
|
||||
tmp = ((int) s_sdlBits->value);
|
||||
if ((tmp != 16) && (tmp != 8))
|
||||
tmp = 16;
|
||||
|
||||
desired.freq = (int) s_sdlSpeed->value;
|
||||
if(!desired.freq) desired.freq = 22050;
|
||||
desired.format = ((tmp == 16) ? AUDIO_S16SYS : AUDIO_U8);
|
||||
|
||||
// I dunno if this is the best idea, but I'll give it a try...
|
||||
// should probably check a cvar for this...
|
||||
if (s_sdlDevSamps->value)
|
||||
desired.samples = s_sdlDevSamps->value;
|
||||
else
|
||||
{
|
||||
// just pick a sane default.
|
||||
if (desired.freq <= 11025)
|
||||
desired.samples = 256;
|
||||
else if (desired.freq <= 22050)
|
||||
desired.samples = 512;
|
||||
else if (desired.freq <= 44100)
|
||||
desired.samples = 1024;
|
||||
else
|
||||
desired.samples = 2048; // (*shrug*)
|
||||
}
|
||||
|
||||
desired.channels = (int) s_sdlChannels->value;
|
||||
desired.callback = SNDDMA_AudioCallback;
|
||||
|
||||
if (SDL_OpenAudio(&desired, &obtained) == -1)
|
||||
{
|
||||
Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError());
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
SNDDMA_PrintAudiospec("SDL_AudioSpec", &obtained);
|
||||
|
||||
// dma.samples needs to be big, or id's mixer will just refuse to
|
||||
// work at all; we need to keep it significantly bigger than the
|
||||
// amount of SDL callback samples, and just copy a little each time
|
||||
// the callback runs.
|
||||
// 32768 is what the OSS driver filled in here on my system. I don't
|
||||
// know if it's a good value overall, but at least we know it's
|
||||
// reasonable...this is why I let the user override.
|
||||
tmp = s_sdlMixSamps->value;
|
||||
if (!tmp)
|
||||
tmp = (obtained.samples * obtained.channels) * 10;
|
||||
|
||||
if (tmp & (tmp - 1)) // not a power of two? Seems to confuse something.
|
||||
{
|
||||
int val = 1;
|
||||
while (val < tmp)
|
||||
val <<= 1;
|
||||
|
||||
tmp = val;
|
||||
}
|
||||
|
||||
dmapos = 0;
|
||||
dma.samplebits = obtained.format & 0xFF; // first byte of format is bits.
|
||||
dma.channels = obtained.channels;
|
||||
dma.samples = tmp;
|
||||
dma.submission_chunk = 1;
|
||||
dma.speed = obtained.freq;
|
||||
dmasize = (dma.samples * (dma.samplebits/8));
|
||||
dma.buffer = calloc(1, dmasize);
|
||||
|
||||
Com_Printf("Starting SDL audio callback...\n");
|
||||
SDL_PauseAudio(0); // start callback.
|
||||
|
||||
Com_Printf("SDL audio initialized.\n");
|
||||
snd_inited = qtrue;
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SNDDMA_GetDMAPos
|
||||
===============
|
||||
*/
|
||||
int SNDDMA_GetDMAPos(void)
|
||||
{
|
||||
return dmapos;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SNDDMA_Shutdown
|
||||
===============
|
||||
*/
|
||||
void SNDDMA_Shutdown(void)
|
||||
{
|
||||
Com_Printf("Closing SDL audio device...\n");
|
||||
SDL_PauseAudio(1);
|
||||
SDL_CloseAudio();
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
free(dma.buffer);
|
||||
dma.buffer = NULL;
|
||||
dmapos = dmasize = 0;
|
||||
snd_inited = qfalse;
|
||||
Com_Printf("SDL audio device shut down.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SNDDMA_Submit
|
||||
|
||||
Send sound to device if buffer isn't really the dma buffer
|
||||
===============
|
||||
*/
|
||||
void SNDDMA_Submit(void)
|
||||
{
|
||||
SDL_UnlockAudio();
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SNDDMA_BeginPainting
|
||||
===============
|
||||
*/
|
||||
void SNDDMA_BeginPainting (void)
|
||||
{
|
||||
SDL_LockAudio();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue