2 Copyright (C) 2003 T. Joseph Carter
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #undef WIN32_LEAN_AND_MEAN //hush a warning, SDL.h redefines this
25 // Tell startup code that we have a client
26 int cl_available = true;
28 qboolean vid_supportrefreshrate = false;
30 static qboolean vid_usingmouse;
31 static qboolean vid_isfullscreen;
33 static SDL_Surface *screen;
35 /////////////////////////
38 //TODO: Add joystick support
39 //TODO: Add error checking
42 //keysym to quake keysym mapping
43 #define tenoh 0,0,0,0,0, 0,0,0,0,0
44 #define fiftyoh tenoh, tenoh, tenoh, tenoh, tenoh
45 #define hundredoh fiftyoh, fiftyoh
46 static unsigned int tbl_sdltoquake[] =
48 0,0,0,0, //SDLK_UNKNOWN = 0,
49 0,0,0,0, //SDLK_FIRST = 0,
50 K_BACKSPACE, //SDLK_BACKSPACE = 8,
51 K_TAB, //SDLK_TAB = 9,
54 K_ENTER, //SDLK_RETURN = 13,
56 K_PAUSE, //SDLK_PAUSE = 19,
58 K_ESCAPE, //SDLK_ESCAPE = 27,
60 K_SPACE, //SDLK_SPACE = 32,
61 '!', //SDLK_EXCLAIM = 33,
62 '"', //SDLK_QUOTEDBL = 34,
63 '#', //SDLK_HASH = 35,
64 '$', //SDLK_DOLLAR = 36,
66 '&', //SDLK_AMPERSAND = 38,
67 '\'', //SDLK_QUOTE = 39,
68 '(', //SDLK_LEFTPAREN = 40,
69 ')', //SDLK_RIGHTPAREN = 41,
70 '*', //SDLK_ASTERISK = 42,
71 '+', //SDLK_PLUS = 43,
72 ',', //SDLK_COMMA = 44,
73 '-', //SDLK_MINUS = 45,
74 '.', //SDLK_PERIOD = 46,
75 '/', //SDLK_SLASH = 47,
86 ':', //SDLK_COLON = 58,
87 ';', //SDLK_SEMICOLON = 59,
88 '<', //SDLK_LESS = 60,
89 '=', //SDLK_EQUALS = 61,
90 '>', //SDLK_GREATER = 62,
91 '?', //SDLK_QUESTION = 63,
93 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
94 '[', //SDLK_LEFTBRACKET = 91,
95 '\\', //SDLK_BACKSLASH = 92,
96 ']', //SDLK_RIGHTBRACKET = 93,
97 '^', //SDLK_CARET = 94,
98 '_', //SDLK_UNDERSCORE = 95,
99 '`', //SDLK_BACKQUOTE = 96,
127 K_DEL, //SDLK_DELETE = 127,
128 hundredoh /*227*/, tenoh, tenoh, 0,0,0,0,0,0,0,0,
129 K_KP_0, //SDLK_KP0 = 256,
130 K_KP_1, //SDLK_KP1 = 257,
131 K_KP_2, //SDLK_KP2 = 258,
132 K_KP_3, //SDLK_KP3 = 259,
133 K_KP_4, //SDLK_KP4 = 260,
134 K_KP_5, //SDLK_KP5 = 261,
135 K_KP_6, //SDLK_KP6 = 262,
136 K_KP_7, //SDLK_KP7 = 263,
137 K_KP_8, //SDLK_KP8 = 264,
138 K_KP_9, //SDLK_KP9 = 265,
139 K_KP_PERIOD,//SDLK_KP_PERIOD = 266,
140 K_KP_DIVIDE,//SDLK_KP_DIVIDE = 267,
141 K_KP_MULTIPLY,//SDLK_KP_MULTIPLY= 268,
142 K_KP_MINUS, //SDLK_KP_MINUS = 269,
143 K_KP_PLUS, //SDLK_KP_PLUS = 270,
144 K_KP_ENTER, //SDLK_KP_ENTER = 271,
145 K_KP_EQUALS,//SDLK_KP_EQUALS = 272,
146 K_UPARROW, //SDLK_UP = 273,
147 K_DOWNARROW,//SDLK_DOWN = 274,
148 K_RIGHTARROW,//SDLK_RIGHT = 275,
149 K_LEFTARROW,//SDLK_LEFT = 276,
150 K_INS, //SDLK_INSERT = 277,
151 K_HOME, //SDLK_HOME = 278,
152 K_END, //SDLK_END = 279,
153 K_PGUP, //SDLK_PAGEUP = 280,
154 K_PGDN, //SDLK_PAGEDOWN = 281,
155 K_F1, //SDLK_F1 = 282,
156 K_F2, //SDLK_F2 = 283,
157 K_F3, //SDLK_F3 = 284,
158 K_F4, //SDLK_F4 = 285,
159 K_F5, //SDLK_F5 = 286,
160 K_F6, //SDLK_F6 = 287,
161 K_F7, //SDLK_F7 = 288,
162 K_F8, //SDLK_F8 = 289,
163 K_F9, //SDLK_F9 = 290,
164 K_F10, //SDLK_F10 = 291,
165 K_F11, //SDLK_F11 = 292,
166 K_F12, //SDLK_F12 = 293,
171 K_NUMLOCK, //SDLK_NUMLOCK = 300,
172 K_CAPSLOCK, //SDLK_CAPSLOCK = 301,
173 K_SCROLLOCK,//SDLK_SCROLLOCK= 302,
174 K_SHIFT, //SDLK_RSHIFT = 303,
175 K_SHIFT, //SDLK_LSHIFT = 304,
176 K_CTRL, //SDLK_RCTRL = 305,
177 K_CTRL, //SDLK_LCTRL = 306,
178 K_ALT, //SDLK_RALT = 307,
179 K_ALT, //SDLK_LALT = 308,
180 0, //SDLK_RMETA = 309,
181 0, //SDLK_LMETA = 310,
182 0, //SDLK_LSUPER = 311, /* Left "Windows" key */
183 0, //SDLK_RSUPER = 312, /* Right "Windows" key */
184 K_ALT, //SDLK_MODE = 313, /* "Alt Gr" key */
185 0, //SDLK_COMPOSE = 314, /* Multi-key compose key */
186 0, //SDLK_HELP = 315,
187 0, //SDLK_PRINT = 316,
188 0, //SDLK_SYSREQ = 317,
189 K_PAUSE, //SDLK_BREAK = 318,
190 0, //SDLK_MENU = 319,
191 0, //SDLK_POWER = 320, /* Power Macintosh power key */
192 'e', //SDLK_EURO = 321, /* Some european keyboards */
193 0 //SDLK_UNDO = 322, /* Atari keyboard has Undo */
199 static int MapKey( unsigned int sdlkey )
201 if( sdlkey > sizeof(tbl_sdltoquake)/ sizeof(int) )
203 return tbl_sdltoquake[ sdlkey ];
206 static void IN_Activate( qboolean grab )
212 vid_usingmouse = true;
213 cl_ignoremousemove = true;
214 SDL_WM_GrabInput( SDL_GRAB_ON );
215 SDL_ShowCursor( SDL_DISABLE );
222 vid_usingmouse = false;
223 cl_ignoremousemove = true;
224 SDL_WM_GrabInput( SDL_GRAB_OFF );
225 SDL_ShowCursor( SDL_ENABLE );
235 SDL_GetRelativeMouseState( &x, &y );
241 /////////////////////
245 static int Sys_EventFilter( SDL_Event *event )
247 //TODO: Add a quit query in linux, too - though linux user are more likely to know what they do
249 if( event->type == SDL_QUIT && MessageBox( NULL, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION ) == IDNO )
258 static keynum_t buttonremap[18] =
280 void Sys_SendKeyEvents( void )
282 static qboolean sound_active = true;
285 while( SDL_PollEvent( &event ) )
286 switch( event.type ) {
292 Key_Event( MapKey( event.key.keysym.sym ), (char)event.key.keysym.unicode, (event.key.state == SDL_PRESSED) );
294 case SDL_ACTIVEEVENT:
295 if( event.active.state == SDL_APPACTIVE )
297 if( event.active.gain )
303 case SDL_MOUSEBUTTONDOWN:
304 if (event.button.button <= 18)
305 Key_Event( buttonremap[event.button.button - 1], 0, true );
307 case SDL_MOUSEBUTTONUP:
308 if (event.button.button <= 18)
309 Key_Event( buttonremap[event.button.button - 1], 0, false );
313 // enable/disable sound on focus gain/loss
314 if (!vid_activewindow && sound_active)
317 sound_active = false;
319 else if (vid_activewindow && !sound_active)
330 void *GL_GetProcAddress(const char *name)
333 p = SDL_GL_GetProcAddress(name);
337 static int Sys_EventFilter( SDL_Event *event );
340 if (SDL_Init(SDL_INIT_VIDEO) < 0)
341 Sys_Error ("Failed to init video: %s", SDL_GetError());
342 vid_isfullscreen = false;
345 // set the icon (we dont use SDL here since it would be too much a PITA)
347 #include "resource.h"
348 #include <SDL_syswm.h>
349 static void VID_SetCaption()
355 SDL_WM_SetCaption( gamename, NULL );
357 // get the HWND handle
358 SDL_VERSION( &info.version );
359 if( !SDL_GetWMInfo( &info ) )
362 icon = LoadIcon( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDI_ICON1 ) );
363 #ifndef _W64 //If Windows 64bit data types don't exist
364 #define SetClassLongPtr SetClassLong
365 #define GCLP_HICON GCL_HICON
366 #define LONG_PTR LONG
368 SetClassLongPtr( info.window, GCLP_HICON, (LONG_PTR)icon );
371 static void VID_SetCaption()
373 SDL_WM_SetCaption( gamename, NULL );
377 static void VID_OutputVersion()
379 const SDL_version *version;
380 version = SDL_Linked_Version();
381 Con_Printf( "Linked against SDL version %d.%d.%d\n"
382 "Using SDL library version %d.%d.%d\n",
383 SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL,
384 version->major, version->minor, version->patch );
387 int VID_InitMode(int fullscreen, int width, int height, int bpp, int refreshrate)
390 int flags = SDL_OPENGL;
391 const char *drivername;
397 We cant switch from one OpenGL video mode to another.
398 Thus we first switch to some stupid 2D mode and then back to OpenGL.
400 SDL_SetVideoMode( 0, 0, 0, 0 );
402 // SDL usually knows best
405 // COMMANDLINEOPTION: SDL GL: -gl_driver <drivername> selects a GL driver library, default is whatever SDL recommends, useful only for 3dfxogl.dll/3dfxvgl.dll or fxmesa or similar, if you don't know what this is for, you don't need it
406 i = COM_CheckParm("-gl_driver");
407 if (i && i < com_argc - 1)
408 drivername = com_argv[i + 1];
409 if (SDL_GL_LoadLibrary(drivername) < 0)
411 Con_Printf("Unable to load GL driver \"%s\": %s\n", drivername, SDL_GetError());
415 if ((qglGetString = (const GLubyte* (GLAPIENTRY *)(GLenum name))GL_GetProcAddress("glGetString")) == NULL)
418 Con_Print("Required OpenGL function glGetString not found\n");
422 // Knghtbrd: should do platform-specific extension string function here
424 vid_isfullscreen = false;
426 flags |= SDL_FULLSCREEN;
427 vid_isfullscreen = true;
430 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
433 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8);
434 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8);
435 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8);
436 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8);
437 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 24);
438 SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8);
442 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 1);
443 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 1);
444 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 1);
445 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 16);
448 screen = SDL_SetVideoMode(width, height, bpp, flags);
451 Con_Printf("Failed to set video mode to %ix%i: %s\n", width, height, SDL_GetError);
458 // set up an event filter to ask confirmation on close button in WIN32
459 SDL_SetEventFilter( (SDL_EventFilter) Sys_EventFilter );
461 SDL_EnableUNICODE( SDL_ENABLE );
462 // enable key repeat since everyone expects it
463 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
465 gl_renderer = (const char *)qglGetString(GL_RENDERER);
466 gl_vendor = (const char *)qglGetString(GL_VENDOR);
467 gl_version = (const char *)qglGetString(GL_VERSION);
468 gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
470 // Knghtbrd: should assign platform-specific extensions here
472 gl_platformextensions = "";
473 gl_videosyncavailable = false;
478 vid_activewindow = false;
479 vid_usingmouse = false;
483 void VID_Shutdown (void)
486 SDL_QuitSubSystem(SDL_INIT_VIDEO);
489 int VID_SetGamma (unsigned short *ramps, int rampsize)
491 return !SDL_SetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
494 int VID_GetGamma (unsigned short *ramps, int rampsize)
496 return !SDL_GetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
499 void VID_Finish (qboolean allowmousegrab)
502 qboolean vid_usemouse;
504 //react on appstate changes
505 appstate = SDL_GetAppState();
507 vid_hidden = !(appstate & SDL_APPACTIVE);
509 if( vid_hidden || !( appstate & SDL_APPMOUSEFOCUS ) || !( appstate & SDL_APPINPUTFOCUS ) )
510 vid_activewindow = false;
512 vid_activewindow = true;
514 vid_usemouse = false;
515 if( allowmousegrab && vid_mouse.integer && !key_consoleactive && (key_dest != key_game || !cls.demoplayback) )
517 if( vid_isfullscreen )
519 if( !vid_activewindow )
520 vid_usemouse = false;
522 IN_Activate(vid_usemouse);
524 VID_UpdateGamma(false, 256);
526 if (r_render.integer && !vid_hidden)
529 if (r_speeds.integer || gl_finish.integer)
531 qglFinish();CHECKGLERROR
533 SDL_GL_SwapBuffers();