]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - vid_sdl.c
more fullscreen cleanup
[xonotic/darkplaces.git] / vid_sdl.c
index 2580104f1b6e16f385bb37d3b550606c2d71fe76..342b7acf0d93649daa441bfe1fedd31c47c93eed 100644 (file)
--- a/vid_sdl.c
+++ b/vid_sdl.c
@@ -16,6 +16,7 @@ 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.
 */
+#undef WIN32_LEAN_AND_MEAN  //hush a warning, SDL.h redefines this
 #include <SDL.h>
 #include <stdio.h>
 
@@ -23,8 +24,41 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 // Tell startup code that we have a client
 int cl_available = true;
-static qboolean vid_usingmouse;
+
+qboolean vid_supportrefreshrate = false;
+
+cvar_t joy_detected = {CVAR_READONLY, "joy_detected", "0", "number of joysticks detected by engine"};
+cvar_t joy_enable = {CVAR_SAVE, "joy_enable", "0", "enables joystick support"};
+cvar_t joy_index = {0, "joy_index", "0", "selects which joystick to use if you have multiple"};
+cvar_t joy_axisforward = {0, "joy_axisforward", "1", "which joystick axis to query for forward/backward movement"};
+cvar_t joy_axisside = {0, "joy_axisside", "0", "which joystick axis to query for right/left movement"};
+cvar_t joy_axisup = {0, "joy_axisup", "-1", "which joystick axis to query for up/down movement"};
+cvar_t joy_axispitch = {0, "joy_axispitch", "3", "which joystick axis to query for looking up/down"};
+cvar_t joy_axisyaw = {0, "joy_axisyaw", "2", "which joystick axis to query for looking right/left"};
+cvar_t joy_axisroll = {0, "joy_axisroll", "-1", "which joystick axis to query for tilting head right/left"};
+cvar_t joy_deadzoneforward = {0, "joy_deadzoneforward", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_deadzoneside = {0, "joy_deadzoneside", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_deadzoneup = {0, "joy_deadzoneup", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_deadzonepitch = {0, "joy_deadzonepitch", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_deadzoneyaw = {0, "joy_deadzoneyaw", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_deadzoneroll = {0, "joy_deadzoneroll", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_sensitivityforward = {0, "joy_sensitivityforward", "-1", "movement multiplier"};
+cvar_t joy_sensitivityside = {0, "joy_sensitivityside", "1", "movement multiplier"};
+cvar_t joy_sensitivityup = {0, "joy_sensitivityup", "1", "movement multiplier"};
+cvar_t joy_sensitivitypitch = {0, "joy_sensitivitypitch", "1", "movement multiplier"};
+cvar_t joy_sensitivityyaw = {0, "joy_sensitivityyaw", "-1", "movement multiplier"};
+cvar_t joy_sensitivityroll = {0, "joy_sensitivityroll", "1", "movement multiplier"};
+
+static qboolean vid_usingmouse = false;
+static qboolean vid_usinghidecursor = false;
 static qboolean vid_isfullscreen;
+static int vid_numjoysticks = 0;
+#define MAX_JOYSTICKS 8
+static SDL_Joystick *vid_joysticks[MAX_JOYSTICKS];
+
+static int win_half_width = 50;
+static int win_half_height = 50;
+static int video_bpp, video_flags;
 
 static SDL_Surface *screen;
 
@@ -177,7 +211,7 @@ static unsigned int tbl_sdltoquake[] =
        0,                      //SDLK_LMETA    = 310,
        0,                      //SDLK_LSUPER   = 311,          /* Left "Windows" key */
        0,                      //SDLK_RSUPER   = 312,          /* Right "Windows" key */
-       0,                      //SDLK_MODE             = 313,          /* "Alt Gr" key */
+       K_ALT,                  //SDLK_MODE             = 313,          /* "Alt Gr" key */
        0,                      //SDLK_COMPOSE  = 314,          /* Multi-key compose key */
        0,                      //SDLK_HELP             = 315,
        0,                      //SDLK_PRINT    = 316,
@@ -199,38 +233,89 @@ static int MapKey( unsigned int sdlkey )
     return tbl_sdltoquake[ sdlkey ];
 }
 
-static void IN_Activate( qboolean grab )
+void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecursor)
 {
-       if (grab)
+       if (vid_usingmouse != relative)
        {
-               if (!vid_usingmouse)
-               {
-                       vid_usingmouse = true;
-                       cl_ignoremousemove = true;
-                       SDL_WM_GrabInput( SDL_GRAB_ON );
-                       SDL_ShowCursor( SDL_DISABLE );
-               }
+               vid_usingmouse = relative;
+               cl_ignoremousemoves = 2;
+               SDL_WM_GrabInput( relative ? SDL_GRAB_ON : SDL_GRAB_OFF );
        }
-       else
+       if (vid_usinghidecursor != hidecursor)
        {
-               if (vid_usingmouse)
-               {
-                       vid_usingmouse = false;
-                       cl_ignoremousemove = true;
-                       SDL_WM_GrabInput( SDL_GRAB_OFF );
-                       SDL_ShowCursor( SDL_ENABLE );
-               }
+               vid_usinghidecursor = hidecursor;
+               SDL_ShowCursor( hidecursor ? SDL_DISABLE : SDL_ENABLE);
        }
 }
 
+static double IN_JoystickGetAxis(SDL_Joystick *joy, int axis, double sensitivity, double deadzone)
+{
+       double value;
+       if (axis < 0 || axis >= SDL_JoystickNumAxes(joy))
+               return 0; // no such axis on this joystick
+       value = SDL_JoystickGetAxis(joy, axis) * (1.0 / 32767.0);
+       value = bound(-1, value, 1);
+       if (fabs(value) < deadzone)
+               return 0; // within deadzone around center
+       return value * sensitivity;
+}
+
 void IN_Move( void )
 {
-       if( vid_usingmouse )
+       int j;
+       static int old_x = 0, old_y = 0;
+       static int stuck = 0;
+       int x, y;
+       if (vid_usingmouse)
        {
-               int x, y;
-               SDL_GetRelativeMouseState( &x, &y );
-               in_mouse_x = x;
-               in_mouse_y = y;
+               if(vid_stick_mouse.integer)
+               {
+                       // have the mouse stuck in the middle, example use: prevent expose effect of beryl during the game when not using
+                       // window grabbing. --blub
+
+                       // we need 2 frames to initialize the center position
+                       if(!stuck)
+                       {
+                               SDL_WarpMouse(win_half_width, win_half_height);
+                               SDL_GetMouseState(&x, &y);
+                               SDL_GetRelativeMouseState(&x, &y);
+                               ++stuck;
+                       } else {
+                               SDL_GetRelativeMouseState(&x, &y);
+                               in_mouse_x = x + old_x;
+                               in_mouse_y = y + old_y;
+                               SDL_GetMouseState(&x, &y);
+                               old_x = x - win_half_width;
+                               old_y = y - win_half_height;
+                               SDL_WarpMouse(win_half_width, win_half_height);
+                       }
+               } else {
+                       SDL_GetRelativeMouseState( &x, &y );
+                       in_mouse_x = x;
+                       in_mouse_y = y;
+               }
+       }
+
+       SDL_GetMouseState(&x, &y);
+       in_windowmouse_x = x;
+       in_windowmouse_y = y;
+
+       if (vid_numjoysticks && joy_enable.integer && joy_index.integer >= 0 && joy_index.integer < vid_numjoysticks)
+       {
+               SDL_Joystick *joy = vid_joysticks[joy_index.integer];
+               int numballs = SDL_JoystickNumBalls(joy);
+               for (j = 0;j < numballs;j++)
+               {
+                       SDL_JoystickGetBall(joy, j, &x, &y);
+                       in_mouse_x += x;
+                       in_mouse_y += y;
+               }
+               cl.cmd.forwardmove += IN_JoystickGetAxis(joy, joy_axisforward.integer, joy_sensitivityforward.value, joy_deadzoneforward.value) * cl_forwardspeed.value;
+               cl.cmd.sidemove    += IN_JoystickGetAxis(joy, joy_axisside.integer, joy_sensitivityside.value, joy_deadzoneside.value) * cl_sidespeed.value;
+               cl.cmd.upmove      += IN_JoystickGetAxis(joy, joy_axisup.integer, joy_sensitivityup.value, joy_deadzoneup.value) * cl_upspeed.value;
+               cl.viewangles[0]   += IN_JoystickGetAxis(joy, joy_axispitch.integer, joy_sensitivitypitch.value, joy_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value;
+               cl.viewangles[1]   += IN_JoystickGetAxis(joy, joy_axisyaw.integer, joy_sensitivityyaw.value, joy_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value;
+               //cl.viewangles[2]   += IN_JoystickGetAxis(joy, joy_axisroll.integer, joy_sensitivityroll.value, joy_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value;
        }
 }
 
@@ -241,21 +326,23 @@ void IN_Move( void )
 static int Sys_EventFilter( SDL_Event *event )
 {
        //TODO: Add a quit query in linux, too - though linux user are more likely to know what they do
+       if (event->type == SDL_QUIT)
+       {
 #ifdef WIN32
-       if( event->type == SDL_QUIT && MessageBox( NULL, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION ) == IDNO )
-               return 0;
-       else
-               return 1;
-#else
-       return 1;
+               if (MessageBox( NULL, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION ) == IDNO)
+                       return 0;
 #endif
+       }
+       return 1;
 }
 
-static keynum_t buttonremap[16] =
+static keynum_t buttonremap[18] =
 {
        K_MOUSE1,
        K_MOUSE3,
        K_MOUSE2,
+       K_MWHEELUP,
+       K_MWHEELDOWN,
        K_MOUSE4,
        K_MOUSE5,
        K_MOUSE6,
@@ -273,12 +360,13 @@ static keynum_t buttonremap[16] =
 
 void Sys_SendKeyEvents( void )
 {
+       static qboolean sound_active = true;
        SDL_Event event;
 
        while( SDL_PollEvent( &event ) )
                switch( event.type ) {
                        case SDL_QUIT:
-                               Sys_Quit();
+                               Sys_Quit(0);
                                break;
                        case SDL_KEYDOWN:
                        case SDL_KEYUP:
@@ -294,14 +382,44 @@ void Sys_SendKeyEvents( void )
                                }
                                break;
                        case SDL_MOUSEBUTTONDOWN:
-                               if (event.button.button <= 16)
-                                       Key_Event( buttonremap[event.button.button - 1], 0, true );
-                               break;
                        case SDL_MOUSEBUTTONUP:
-                               if (event.button.button <= 16)
-                                       Key_Event( buttonremap[event.button.button - 1], 0, false );
+                               if (event.button.button <= 18)
+                                       Key_Event( buttonremap[event.button.button - 1], 0, event.button.state == SDL_PRESSED );
+                               break;
+                       case SDL_JOYBUTTONDOWN:
+                               if (!joy_enable.integer)
+                                       break; // ignore down events if joystick has been disabled
+                       case SDL_JOYBUTTONUP:
+                               if (event.jbutton.button < 48)
+                                       Key_Event( event.jbutton.button + (event.jbutton.button < 16 ? K_JOY1 : K_AUX1 - 16), 0, (event.jbutton.state == SDL_PRESSED) );
                                break;
+                       case SDL_VIDEORESIZE:
+                               if(vid_resizable.integer < 2)
+                               {
+                                       vid.width = event.resize.w;
+                                       vid.height = event.resize.h;
+                                       SDL_SetVideoMode(vid.width, vid.height, video_bpp, video_flags);
+                               }
+                               break;
+               }
+
+       // enable/disable sound on focus gain/loss
+       if (!vid_hidden && (vid_activewindow || !snd_mutewhenidle.integer))
+       {
+               if (!sound_active)
+               {
+                       S_UnblockSound ();
+                       sound_active = true;
                }
+       }
+       else
+       {
+               if (sound_active)
+               {
+                       S_BlockSound ();
+                       sound_active = false;
+               }
+       }
 }
 
 /////////////////
@@ -316,10 +434,36 @@ void *GL_GetProcAddress(const char *name)
 }
 
 static int Sys_EventFilter( SDL_Event *event );
+static qboolean vid_sdl_initjoysticksystem = false;
 void VID_Init (void)
 {
+       Cvar_RegisterVariable(&joy_detected);
+       Cvar_RegisterVariable(&joy_enable);
+       Cvar_RegisterVariable(&joy_index);
+       Cvar_RegisterVariable(&joy_axisforward);
+       Cvar_RegisterVariable(&joy_axisside);
+       Cvar_RegisterVariable(&joy_axisup);
+       Cvar_RegisterVariable(&joy_axispitch);
+       Cvar_RegisterVariable(&joy_axisyaw);
+       //Cvar_RegisterVariable(&joy_axisroll);
+       Cvar_RegisterVariable(&joy_deadzoneforward);
+       Cvar_RegisterVariable(&joy_deadzoneside);
+       Cvar_RegisterVariable(&joy_deadzoneup);
+       Cvar_RegisterVariable(&joy_deadzonepitch);
+       Cvar_RegisterVariable(&joy_deadzoneyaw);
+       //Cvar_RegisterVariable(&joy_deadzoneroll);
+       Cvar_RegisterVariable(&joy_sensitivityforward);
+       Cvar_RegisterVariable(&joy_sensitivityside);
+       Cvar_RegisterVariable(&joy_sensitivityup);
+       Cvar_RegisterVariable(&joy_sensitivitypitch);
+       Cvar_RegisterVariable(&joy_sensitivityyaw);
+       //Cvar_RegisterVariable(&joy_sensitivityroll);
+
        if (SDL_Init(SDL_INIT_VIDEO) < 0)
-               Sys_Error ("Failed to init video: %s", SDL_GetError());
+               Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError());
+       vid_sdl_initjoysticksystem = SDL_Init(SDL_INIT_JOYSTICK) >= 0;
+       if (vid_sdl_initjoysticksystem)
+               Con_Printf("Failed to init SDL joystick subsystem: %s\n", SDL_GetError());
        vid_isfullscreen = false;
 }
 
@@ -341,9 +485,129 @@ static void VID_SetCaption()
                return;
 
        icon = LoadIcon( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDI_ICON1 ) );
-       SetClassLong( info.window, GCL_HICON, (LONG) icon );
+#ifndef _W64 //If Windows 64bit data types don't exist
+#ifndef SetClassLongPtr
+#define SetClassLongPtr SetClassLong
+#endif
+#ifndef GCLP_HICON
+#define GCLP_HICON GCL_HICON
+#endif
+#ifndef LONG_PTR
+#define LONG_PTR LONG
+#endif
+#endif
+       SetClassLongPtr( info.window, GCLP_HICON, (LONG_PTR)icon );
+}
+static void VID_SetIcon()
+{
 }
 #else
+// Adding the OS independent XPM version --blub
+#include "darkplaces.xpm"
+#include "nexuiz.xpm"
+static SDL_Surface *icon = NULL;
+static void VID_SetIcon()
+{
+       /*
+        * Somewhat restricted XPM reader. Only supports XPMs saved by GIMP 2.4 at
+        * default settings with less than 91 colors and transparency.
+        */
+
+       int width, height, colors, isize, i, j;
+       int thenone = -1;
+       static SDL_Color palette[256];
+       unsigned short palenc[256]; // store color id by char
+
+       char **idata = ENGINE_ICON;
+       char *data = idata[0];
+
+       if(sscanf(data, "%i %i %i %i", &width, &height, &colors, &isize) != 4)
+       {
+               // NOTE: Only 1-char colornames are supported
+               Con_Printf("Sorry, but this does not even look similar to an XPM.\n");
+               return;
+       }
+
+       if(isize != 1)
+       {
+               // NOTE: Only 1-char colornames are supported
+               Con_Printf("This XPM's palette is either huge or idiotically unoptimized. It's key size is %i\n", isize);
+               return;
+       }
+
+       for(i = 0; i < colors; ++i)
+       {
+               int r, g, b;
+               char idx;
+
+               if(sscanf(idata[i+1], "%c c #%02x%02x%02x", &idx, &r, &g, &b) != 4)
+               {
+                       char foo[2];
+                       if(sscanf(idata[i+1], "%c c Non%1[e]", &idx, foo) != 2) // I take the DailyWTF credit for this. --div0
+                       {
+                               Con_Printf("This XPM's palette looks odd. Can't continue.\n");
+                               return;
+                       }
+                       else
+                       {
+                               palette[i].r = 255; // color key
+                               palette[i].g = 0;
+                               palette[i].b = 255;
+                               thenone = i; // weeeee
+                       }
+               }
+               else
+               {
+                       palette[i].r = r - (r == 255 && g == 0 && b == 255); // change 255/0/255 pink to 254/0/255 for color key
+                       palette[i].g = g;
+                       palette[i].b = b;
+               }
+
+               palenc[(unsigned char) idx] = i;
+       }
+
+       // allocate the image data
+       data = (char*) malloc(width*height);
+
+       for(j = 0; j < height; ++j)
+       {
+               for(i = 0; i < width; ++i)
+               {
+                       // casting to the safest possible datatypes ^^
+                       data[j * width + i] = palenc[((unsigned char*)idata[colors+j+1])[i]];
+               }
+       }
+
+       if(icon != NULL)
+       {
+               // SDL_FreeSurface should free the data too
+               // but for completeness' sake...
+               if(icon->flags & SDL_PREALLOC)
+               {
+                       free(icon->pixels);
+                       icon->pixels = NULL; // safety
+               }
+               SDL_FreeSurface(icon);
+       }
+
+       icon = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, width, height, 8, 0,0,0,0);// rmask, gmask, bmask, amask); no mask needed
+       // 8 bit surfaces get an empty palette allocated according to the docs
+       // so it's a palette image for sure :) no endian check necessary for the mask
+
+       if(icon == NULL) {
+               Con_Printf(     "Failed to create surface for the window Icon!\n"
+                               "%s\n", SDL_GetError());
+               free(data);
+               return;
+       }
+       icon->pixels = data;
+       SDL_SetPalette(icon, SDL_PHYSPAL|SDL_LOGPAL, palette, 0, colors);
+       SDL_SetColorKey(icon, SDL_SRCCOLORKEY, thenone);
+
+       SDL_WM_SetIcon(icon, NULL);
+}
+
+
 static void VID_SetCaption()
 {
        SDL_WM_SetCaption( gamename, NULL );
@@ -360,12 +624,19 @@ static void VID_OutputVersion()
                                        version->major, version->minor, version->patch );
 }
 
-int VID_InitMode(int fullscreen, int width, int height, int bpp)
+int VID_InitMode(int fullscreen, int *width, int *height, int bpp, int refreshrate, int stereobuffer, int samples)
 {
        int i;
+       static int notfirstvideomode = false;
        int flags = SDL_OPENGL;
        const char *drivername;
 
+       win_half_width = *width>>1;
+       win_half_height = *height>>1;
+
+       if(vid_resizable.integer)
+               flags |= SDL_RESIZABLE;
+
        VID_OutputVersion();
 
        /*
@@ -373,7 +644,9 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp)
                We cant switch from one OpenGL video mode to another.
                Thus we first switch to some stupid 2D mode and then back to OpenGL.
        */
-       SDL_SetVideoMode( 0, 0, 0, 0 );
+       if (notfirstvideomode)
+               SDL_SetVideoMode( 0, 0, 0, 0 );
+       notfirstvideomode = true;
 
        // SDL usually knows best
        drivername = NULL;
@@ -402,6 +675,7 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp)
                flags |= SDL_FULLSCREEN;
                vid_isfullscreen = true;
        }
+       //flags |= SDL_HWSURFACE;
 
        SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
        if (bpp >= 32)
@@ -415,16 +689,31 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp)
        }
        else
        {
-               SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 1);
-               SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 1);
-               SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 1);
+               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);
        }
+       if (stereobuffer)
+               SDL_GL_SetAttribute (SDL_GL_STEREO, 1);
+       if (vid_vsync.integer)
+               SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
+       else
+               SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 0);
+       if (samples > 1)
+       {
+               SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, 1);
+               SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, samples);
+       }
+
+       video_bpp = bpp;
+       video_flags = flags;
+       VID_SetIcon();
+       screen = SDL_SetVideoMode(*width, *height, bpp, flags);
 
-       screen = SDL_SetVideoMode(width, height, bpp, flags);
        if (screen == NULL)
        {
-               Con_Printf("Failed to set video mode to %ix%i: %s\n", width, height, SDL_GetError);
+               Con_Printf("Failed to set video mode to %ix%i: %s\n", *width, *height, SDL_GetError());
                VID_Shutdown();
                return false;
        }
@@ -438,64 +727,84 @@ int VID_InitMode(int fullscreen, int width, int height, int bpp)
        // enable key repeat since everyone expects it
        SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 
-       gl_renderer = (const char *)qglGetString(GL_RENDERER);
-       gl_vendor = (const char *)qglGetString(GL_VENDOR);
-       gl_version = (const char *)qglGetString(GL_VERSION);
-       gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
        gl_platform = "SDL";
-       // Knghtbrd: should assign platform-specific extensions here
-       //TODO: maybe ;)
        gl_platformextensions = "";
-       gl_videosyncavailable = false;
+       gl_videosyncavailable = true;
 
        GL_Init();
 
+       vid_numjoysticks = SDL_NumJoysticks();
+       vid_numjoysticks = bound(0, vid_numjoysticks, MAX_JOYSTICKS);
+       Cvar_SetValueQuick(&joy_detected, vid_numjoysticks);
+       Con_Printf("%d SDL joystick(s) found:\n", vid_numjoysticks);
+       memset(vid_joysticks, 0, sizeof(vid_joysticks));
+       for (i = 0;i < vid_numjoysticks;i++)
+       {
+               SDL_Joystick *joy;
+               joy = vid_joysticks[i] = SDL_JoystickOpen(i);
+               if (!joy)
+               {
+                       Con_Printf("joystick #%i: open failed: %s\n", i, SDL_GetError());
+                       continue;
+               }
+               Con_Printf("joystick #%i: opened \"%s\" with %i axes, %i buttons, %i balls\n", i, SDL_JoystickName(i), (int)SDL_JoystickNumAxes(joy), (int)SDL_JoystickNumButtons(joy), (int)SDL_JoystickNumBalls(joy));
+       }
+
        vid_hidden = false;
        vid_activewindow = false;
        vid_usingmouse = false;
+       vid_usinghidecursor = false;
+
+       SDL_WM_GrabInput(SDL_GRAB_OFF);
        return true;
 }
 
 void VID_Shutdown (void)
 {
-       IN_Activate(false);
+       VID_SetMouse(false, false, false);
+       VID_RestoreSystemGamma();
+
        SDL_QuitSubSystem(SDL_INIT_VIDEO);
+
+       gl_driver[0] = 0;
+       gl_extensions = "";
+       gl_platform = "";
+       gl_platformextensions = "";
 }
 
-int VID_SetGamma (unsigned short *ramps)
+int VID_SetGamma (unsigned short *ramps, int rampsize)
 {
-       return !SDL_SetGammaRamp (ramps, ramps + 256, ramps + 512);
+       return !SDL_SetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
 }
 
-int VID_GetGamma (unsigned short *ramps)
+int VID_GetGamma (unsigned short *ramps, int rampsize)
 {
-       return !SDL_GetGammaRamp( ramps, ramps + 256, ramps + 512);
+       return !SDL_GetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
 }
 
 void VID_Finish (void)
 {
        Uint8 appstate;
-       qboolean vid_usemouse;
-
-       if (r_speeds.integer || gl_finish.integer)
-               qglFinish();
-       SDL_GL_SwapBuffers();
 
        //react on appstate changes
        appstate = SDL_GetAppState();
 
-       if( !( appstate & SDL_APPMOUSEFOCUS ) || !( appstate & SDL_APPINPUTFOCUS ) )
+       vid_hidden = !(appstate & SDL_APPACTIVE);
+
+       if( vid_hidden || !( appstate & SDL_APPMOUSEFOCUS ) || !( appstate & SDL_APPINPUTFOCUS ) )
                vid_activewindow = false;
        else
                vid_activewindow = true;
 
-       vid_usemouse = false;
-       if( vid_mouse.integer && !key_consoleactive && !cls.demoplayback )
-               vid_usemouse = true;
-       if( vid_isfullscreen )
-               vid_usemouse = true;
-       if( !vid_activewindow )
-               vid_usemouse = false;
+       VID_UpdateGamma(false, 256);
 
-       IN_Activate(vid_usemouse);
+       if (r_render.integer && !vid_hidden)
+       {
+               CHECKGLERROR
+               if (r_speeds.integer || gl_finish.integer)
+               {
+                       qglFinish();CHECKGLERROR
+               }
+               SDL_GL_SwapBuffers();
+       }
 }