summaryrefslogtreecommitdiff
path: root/source/vid_sdl.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/vid_sdl.c')
-rw-r--r--source/vid_sdl.c568
1 files changed, 568 insertions, 0 deletions
diff --git a/source/vid_sdl.c b/source/vid_sdl.c
new file mode 100644
index 0000000..00184eb
--- /dev/null
+++ b/source/vid_sdl.c
@@ -0,0 +1,568 @@
+/*
+Copyright (C) 2003-2005 Andrey Nazarov
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+//
+// vid_sdl.c
+//
+
+#include "com_local.h"
+#include "in_public.h"
+#include "vid_public.h"
+#include "vid_local.h"
+#include "ref_public.h"
+#include "key_public.h"
+#include "q2pro.xbm"
+#include <SDL.h>
+
+typedef struct {
+ SDL_Surface *surface;
+ SDL_Surface *icon;
+ Uint16 gamma[3][256];
+ vidFlags_t flags;
+ qboolean mouseactive; // qfalse when not focus app
+ qboolean mouseinitialized;
+} sdl_state_t;
+
+static sdl_state_t sdl;
+
+/*
+===============================================================================
+
+COMMON SDL VIDEO RELATED ROUTINES
+
+===============================================================================
+*/
+
+static qboolean QSDL_SetMode( int flags, int forcedepth ) {
+ SDL_Surface *surf;
+ vrect_t rc;
+ int depth;
+
+ flags &= ~(SDL_FULLSCREEN|SDL_RESIZABLE);
+ sdl.flags &= ~QVF_FULLSCREEN;
+
+ if( vid_fullscreen->integer > 0 ) {
+ Video_GetModeFS( &rc, NULL, &depth );
+ if( forcedepth ) {
+ depth = forcedepth;
+ }
+ Com_DPrintf( "...setting fullscreen mode: %dx%d:%d\n",
+ rc.width, rc.height, depth );
+ surf = SDL_SetVideoMode( rc.width, rc.height, depth,
+ flags | SDL_FULLSCREEN );
+ if( surf ) {
+ sdl.flags |= QVF_FULLSCREEN;
+ goto success;
+ }
+ Com_EPrintf( "FS video mode failed: %s\n", SDL_GetError() );
+ Cvar_Set( "vid_fullscreen", "0" );
+ }
+
+ flags |= SDL_RESIZABLE;
+ Video_GetPlacement( &rc );
+ Com_DPrintf( "...setting windowed mode: %dx%d\n", rc.width, rc.height );
+ surf = SDL_SetVideoMode( rc.width, rc.height, forcedepth, flags );
+ if( !surf ) {
+ return qfalse;
+ }
+
+success:
+ sdl.surface = surf;
+ ref.ModeChanged( rc.width, rc.height, sdl.flags, surf->pitch, surf->pixels );
+ SCR_ModeChanged();
+ return qtrue;
+}
+
+void Video_ModeChanged( void ) {
+ if( !QSDL_SetMode( sdl.surface->flags, sdl.surface->format->BitsPerPixel ) ) {
+ Com_Error( ERR_FATAL, "Couldn't change video mode: %s", SDL_GetError() );
+ }
+}
+
+static qboolean QSDL_InitVideo( void ) {
+ SDL_Color color;
+ byte *dst;
+ char buffer[MAX_QPATH];
+ int i, ret;
+
+ if( SDL_WasInit( SDL_INIT_EVERYTHING ) == 0 ) {
+ ret = SDL_Init( SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE );
+ } else {
+ ret = SDL_InitSubSystem( SDL_INIT_VIDEO );
+ }
+
+ if( ret == -1 ) {
+ Com_EPrintf( "Couldn't initialize SDL video: %s\n", SDL_GetError() );
+ return qfalse;
+ }
+
+ if( SDL_VideoDriverName( buffer, sizeof( buffer ) ) != NULL ) {
+ Com_Printf( "Using SDL video driver: %s\n", buffer );
+ }
+
+ sdl.icon = SDL_CreateRGBSurface( SDL_SWSURFACE, q2icon_width,
+ q2icon_height, 8, 0, 0, 0, 0 );
+ if( sdl.icon ) {
+ SDL_SetColorKey( sdl.icon, SDL_SRCCOLORKEY, 0 );
+
+ /* setup transparent pixel */
+ color.r = 255; color.g = 255; color.b = 255;
+ SDL_SetColors( sdl.icon, &color, 0, 1 );
+
+ /* setup colored pixel */
+ color.r = 0; color.g = 128; color.b = 128;
+ SDL_SetColors( sdl.icon, &color, 1, 1 );
+
+ /* expand the bitmap */
+ dst = sdl.icon->pixels;
+ for( i = 0; i < q2icon_width * q2icon_height; i++ ) {
+ *dst++ = Q_IsBitSet( q2icon_bits, i );
+ }
+
+ SDL_WM_SetIcon( sdl.icon, NULL );
+ }
+
+ if( SDL_GetGammaRamp( sdl.gamma[0], sdl.gamma[1], sdl.gamma[2] ) != -1 ) {
+ Com_DPrintf( "...enabling gamma control\n" );
+ sdl.flags |= QVF_GAMMARAMP;
+ }
+
+ SDL_WM_SetCaption( APPLICATION, APPLICATION );
+
+ SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
+
+ return qtrue;
+}
+
+static void QSDL_ShutdownVideo( void ) {
+ if( sdl.flags & QVF_GAMMARAMP ) {
+ SDL_SetGammaRamp( sdl.gamma[0], sdl.gamma[1], sdl.gamma[2] );
+ }
+
+ if( sdl.icon ) {
+ SDL_FreeSurface( sdl.icon );
+ }
+
+ memset( &sdl, 0, sizeof( sdl ) );
+
+ if( SDL_WasInit( SDL_INIT_EVERYTHING ) == SDL_INIT_VIDEO ) {
+ SDL_Quit();
+ } else {
+ SDL_QuitSubSystem( SDL_INIT_VIDEO );
+ }
+}
+
+static void QSDL_UpdateGamma( const byte *table ) {
+ Uint16 ramp[256];
+ int i;
+
+ if( sdl.flags & QVF_GAMMARAMP ) {
+ for( i = 0; i < 256; i++ ) {
+ ramp[i] = table[i] << 8;
+ }
+ SDL_SetGammaRamp( ramp, ramp, ramp );
+ }
+}
+
+static void QSDL_KeyEvent( SDL_keysym *keysym, qboolean down ) {
+ uint32 key;
+
+ if( keysym->sym <= 127 ) {
+ // ASCII chars are mapped directly
+ Key_Event( keysym->sym, down, com_eventTime );
+ return;
+ }
+
+#define K( s, d ) case SDLK_ ## s: key = K_ ## d; break;
+
+ switch( keysym->sym ) {
+ K( KP0, KP_INS )
+ K( KP1, KP_END )
+ K( KP2, KP_DOWNARROW )
+ K( KP3, KP_PGDN )
+ K( KP4, KP_LEFTARROW )
+ K( KP5, KP_5 )
+ K( KP6, KP_RIGHTARROW )
+ K( KP7, KP_HOME )
+ K( KP8, KP_UPARROW )
+ K( KP9, KP_PGUP )
+ K( KP_PERIOD, KP_DEL )
+ K( KP_DIVIDE, KP_SLASH )
+ K( KP_MULTIPLY, KP_MULTIPLY )
+ K( KP_MINUS, KP_MINUS )
+ K( KP_PLUS, KP_PLUS )
+ K( KP_ENTER, KP_ENTER )
+
+ K( UP, UPARROW )
+ K( DOWN, DOWNARROW )
+ K( RIGHT, RIGHTARROW )
+ K( LEFT, LEFTARROW )
+ K( INSERT, INS )
+ K( HOME, HOME )
+ K( END, END )
+ K( PAGEUP, PGUP )
+ K( PAGEDOWN, PGDN )
+
+ K( F1, F1 )
+ K( F2, F2 )
+ K( F3, F3 )
+ K( F4, F4 )
+ K( F5, F5 )
+ K( F6, F6 )
+ K( F7, F7 )
+ K( F8, F8 )
+ K( F9, F9 )
+ K( F10, F10 )
+ K( F11, F11 )
+ K( F12, F12 )
+
+ K( NUMLOCK, NUMLOCK )
+ K( CAPSLOCK, CAPSLOCK )
+ K( SCROLLOCK, SCROLLOCK )
+ K( LSUPER, LWINKEY )
+ K( RSUPER, RWINKEY )
+ K( MENU, MENU )
+
+ K( RSHIFT, SHIFT )
+ K( LSHIFT, SHIFT )
+ K( RCTRL, CTRL )
+ K( LCTRL, CTRL )
+ K( RALT, ALT )
+ K( LALT, ALT )
+
+#undef K
+
+ default:
+ Com_DPrintf( "%s: unknown keysym %d\n", __func__, keysym->sym );
+ return;
+ }
+
+ Key_Event( key, down, com_eventTime );
+}
+
+static void QSDL_MouseButtonEvent( int button, qboolean down ) {
+ uint32 key;
+
+ if( !sdl.mouseinitialized ) {
+ return;
+ }
+
+#define K( s, d ) case SDL_BUTTON_ ## s: key = K_ ## d; break;
+
+ switch( button ) {
+ K( LEFT, MOUSE1 )
+ K( RIGHT, MOUSE2 )
+ K( MIDDLE, MOUSE3 )
+ K( WHEELUP, MWHEELUP )
+ K( WHEELDOWN, MWHEELDOWN )
+
+#undef K
+
+ default:
+ Com_DPrintf( "%s: unknown button %d\n", __func__, button );
+ return;
+ }
+
+ Key_Event( key, down, com_eventTime );
+}
+
+/*
+============
+Video_PumpEvents
+============
+*/
+void Video_PumpEvents( void ) {
+ SDL_Event event;
+
+ while( SDL_PollEvent( &event ) ) {
+ switch( event.type ) {
+ case SDL_ACTIVEEVENT:
+ /* state is actually a bitmask! */
+ if( event.active.state & SDL_APPACTIVE ) {
+ if( event.active.gain ) {
+ CL_AppActivate( qtrue );
+ } else {
+ CL_AppActivate( qfalse );
+ }
+ }
+ break;
+
+ case SDL_QUIT:
+ Com_Quit();
+ break;
+
+ case SDL_VIDEORESIZE:
+ if( sdl.surface->flags & SDL_RESIZABLE ) {
+ Cvar_Set( "vid_placement", va( "%dx%d", event.resize.w,
+ event.resize.h ) );
+ Video_ModeChanged();
+ }
+ break;
+
+ case SDL_KEYDOWN:
+ QSDL_KeyEvent( &event.key.keysym, qtrue );
+ break;
+
+ case SDL_KEYUP:
+ QSDL_KeyEvent( &event.key.keysym, qfalse );
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ QSDL_MouseButtonEvent( event.button.button, qtrue );
+ break;
+
+ case SDL_MOUSEBUTTONUP:
+ QSDL_MouseButtonEvent( event.button.button, qfalse );
+ break;
+ }
+ }
+}
+
+
+/*
+===============================================================================
+
+OPENGL SPECIFIC
+
+===============================================================================
+*/
+
+static qboolean QSDL_InitGL( void ) {
+ cvar_t *gl_driver;
+
+ if( !QSDL_InitVideo() ) {
+ return qfalse;
+ }
+
+ gl_driver = Cvar_Get( "gl_driver", DEFAULT_OPENGL_DRIVER, CVAR_LATCH );
+
+ if( SDL_GL_LoadLibrary( gl_driver->string ) == -1 ) {
+ Com_EPrintf( "Couldn't load OpenGL library: %s\n", SDL_GetError() );
+ goto fail;
+ }
+
+ SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
+ SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
+ SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
+ SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+
+ sdl.flags |= QVF_ACCELERATED;
+
+ if( !QSDL_SetMode( SDL_OPENGL|SDL_RESIZABLE, 0 ) ) {
+ Com_EPrintf( "Couldn't set video mode: %s\n", SDL_GetError() );
+ goto fail;
+ }
+
+ CL_AppActivate( qtrue );
+ return qtrue;
+
+fail:
+ QSDL_ShutdownVideo();
+ return qfalse;
+}
+
+static void QSDL_BeginFrameGL( void ) {
+}
+
+static void QSDL_EndFrameGL( void ) {
+ SDL_GL_SwapBuffers();
+}
+
+/*
+===============================================================================
+
+SOFTWARE SPECIFIC
+
+===============================================================================
+*/
+
+static qboolean QSDL_InitSoft( void ) {
+ if( !QSDL_InitVideo() ) {
+ return qfalse;
+ }
+
+ if( !QSDL_SetMode( SDL_SWSURFACE|SDL_HWPALETTE|SDL_RESIZABLE, 8 ) ) {
+ Com_EPrintf( "Couldn't set video mode: %s\n", SDL_GetError() );
+ QSDL_ShutdownVideo();
+ return qfalse;
+ }
+
+ CL_AppActivate( qtrue );
+ return qtrue;
+}
+
+static void QSDL_UpdatePalette( const byte *palette ) {
+ SDL_Color colors[256];
+ SDL_Color *c;
+
+ for( c = colors; c < colors + 256; c++ ) {
+ c->r = palette[0];
+ c->g = palette[1];
+ c->b = palette[2];
+ palette += 4;
+ }
+
+ SDL_SetPalette( sdl.surface, SDL_LOGPAL, colors, 0, 256 );
+}
+
+static void QSDL_BeginFrameSoft( void ) {
+ SDL_LockSurface( sdl.surface );
+}
+
+static void QSDL_EndFrameSoft( void ) {
+ SDL_UnlockSurface( sdl.surface );
+ SDL_Flip( sdl.surface );
+}
+
+/*
+===============================================================================
+
+SDL MOUSE DRIVER
+
+===============================================================================
+*/
+
+#define SDL_FULLFOCUS (SDL_APPACTIVE|SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS)
+
+void QSDL_AcquireMouse( void ) {
+ uint32 state;
+
+ /* move physical cursor at center of the
+ * main window just before we grab the mouse */
+ if( sdl.surface ) {
+ SDL_WarpMouse( sdl.surface->w / 2, sdl.surface->h / 2 );
+ }
+
+ /* pump mouse motion events generated by SDL_WarpMouse,
+ * this way SDL_APPMOUSEFOCUS gets set properly */
+ SDL_PollEvent( NULL );
+
+ /* grab the mouse, so SDL enters relative mouse mode */
+ SDL_WM_GrabInput( SDL_GRAB_ON );
+ state = SDL_GetAppState();
+ if( ( state & SDL_FULLFOCUS ) != SDL_FULLFOCUS ) {
+ Com_DPrintf( "QSDL_AcquireMouse: don't have full focus\n" );
+ }
+ SDL_ShowCursor( SDL_DISABLE );
+
+ /* pump mouse motion events still pending */
+ SDL_PollEvent( NULL );
+
+ /* clear large deltas generated */
+ SDL_GetRelativeMouseState( NULL, NULL );
+}
+
+
+static void QSDL_DeAcquireMouse( void ) {
+ /* release the mouse */
+ SDL_ShowCursor( SDL_ENABLE );
+ SDL_WM_GrabInput( SDL_GRAB_OFF );
+}
+
+static void QSDL_SendMouseMoveEvents( void ) {
+ int dx, dy;
+
+ if( !sdl.mouseinitialized ) {
+ return;
+ }
+
+ if( !sdl.mouseactive ) {
+ return;
+ }
+
+ SDL_GetRelativeMouseState( &dx, &dy );
+
+ if( dx || dy ) {
+ CL_MouseEvent( dx, dy );
+ }
+}
+
+static void QSDL_ShutdownMouse( void ) {
+ QSDL_DeAcquireMouse();
+ sdl.mouseactive = qfalse;
+ sdl.mouseinitialized = qfalse;
+}
+
+static qboolean QSDL_InitMouse( void ) {
+ if( SDL_WasInit( SDL_INIT_VIDEO ) != SDL_INIT_VIDEO ) {
+ return qfalse;
+ }
+
+ sdl.mouseinitialized = qtrue;
+
+ return qtrue;
+}
+
+static void QSDL_ActivateMouse( qboolean active ) {
+ if( !sdl.mouseinitialized ) {
+ return;
+ }
+
+ if( sdl.mouseactive == active ) {
+ // return;
+ }
+
+ if( active ) {
+ QSDL_AcquireMouse();
+ } else {
+ QSDL_DeAcquireMouse();
+ }
+
+ sdl.mouseactive = active;
+}
+
+static void QSDL_ClearMouseStates( void ) {
+ /* no work here */
+}
+
+void Video_FillGLAPI( videoAPI_t *api ) {
+ api->Init = QSDL_InitGL;
+ api->Shutdown = QSDL_ShutdownVideo;
+ api->UpdateGamma = QSDL_UpdateGamma;
+ api->UpdatePalette = NULL;
+ api->GetProcAddr = SDL_GL_GetProcAddress;
+ api->BeginFrame = QSDL_BeginFrameGL;
+ api->EndFrame = QSDL_EndFrameGL;
+}
+
+void Video_FillSWAPI( videoAPI_t *api ) {
+ api->Init = QSDL_InitSoft;
+ api->Shutdown = QSDL_ShutdownVideo;
+ api->UpdateGamma = QSDL_UpdateGamma;
+ api->UpdatePalette = QSDL_UpdatePalette;
+ api->GetProcAddr = NULL;
+ api->BeginFrame = QSDL_BeginFrameSoft;
+ api->EndFrame = QSDL_EndFrameSoft;
+}
+
+/*
+===================
+Video_FillInputAPI
+===================
+*/
+void Video_FillInputAPI( inputAPI_t *api ) {
+ api->Init = QSDL_InitMouse;
+ api->Shutdown = QSDL_ShutdownMouse;
+ api->Activate = QSDL_ActivateMouse;
+ api->Frame = QSDL_SendMouseMoveEvents;
+ api->ClearStates = QSDL_ClearMouseStates;
+}
+