-Removed Sys_Quit and added Sys_Shutdown which will be called by Host_Shutdown.
[divverent/darkplaces.git] / vid_sdl.c
1 /*
2 Copyright (C) 2003  T. Joseph Carter
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18 */
19 /*
20 TODOs until first commit:
21         1. Hide and/or show the mouse whether the mainwindow is focused or not.
22         2. Minimize when losing focus in fullscreen mode.
23 d       3. GrabInput while mainwindow is active.
24         4
25
26 */
27 #include <SDL.h>
28 #include <stdio.h>
29
30 #include "quakedef.h"
31
32 // Tell startup code that we have a client
33 int cl_available = true;
34 static int vid_usingmouse;
35 static int vid_isfullscreen;
36
37 static SDL_Surface *screen;
38
39 static Uint8 in_mouse_buttons;
40
41 static void IN_Init( void );
42 static void IN_Shutdown( void );
43
44 /////////////////////////
45 // Input handling
46 ////
47 //TODO: Add joystick support
48 //TODO: Add error checking
49
50
51 //keysym to quake keysym mapping
52 #define tenoh   0,0,0,0,0, 0,0,0,0,0
53 #define fiftyoh tenoh, tenoh, tenoh, tenoh, tenoh
54 #define hundredoh fiftyoh, fiftyoh
55 static unsigned int tbl_sdltoquake[] = 
56 {
57         0,0,0,0,                //SDLK_UNKNOWN          = 0,
58         0,0,0,0,                //SDLK_FIRST            = 0,
59         K_BACKSPACE,    //SDLK_BACKSPACE        = 8,
60         K_TAB,                  //SDLK_TAB                      = 9,
61         0,0,
62         0,                              //SDLK_CLEAR            = 12,
63         K_ENTER,                //SDLK_RETURN           = 13,
64     0,0,0,0,0,
65         K_PAUSE,                //SDLK_PAUSE            = 19,
66         0,0,0,0,0,0,0,
67         K_ESCAPE,               //SDLK_ESCAPE           = 27,
68         0,0,0,0,
69         K_SPACE,                //SDLK_SPACE            = 32,
70         '!',                    //SDLK_EXCLAIM          = 33,
71         '"',                    //SDLK_QUOTEDBL         = 34,
72         '#',                    //SDLK_HASH                     = 35,
73         '$',                    //SDLK_DOLLAR           = 36,
74         0,
75         '&',                    //SDLK_AMPERSAND        = 38,
76         '\'',                   //SDLK_QUOTE            = 39,
77         '(',                    //SDLK_LEFTPAREN        = 40,
78         ')',                    //SDLK_RIGHTPAREN       = 41,
79         '*',                    //SDLK_ASTERISK         = 42,
80         '+',                    //SDLK_PLUS                     = 43,
81         ',',                    //SDLK_COMMA            = 44,
82         '-',                    //SDLK_MINUS            = 45,
83         '.',                    //SDLK_PERIOD           = 46,
84         '/',                    //SDLK_SLASH            = 47,
85         '0',                    //SDLK_0                        = 48,
86         '1',                    //SDLK_1                        = 49,
87         '2',                    //SDLK_2                        = 50,
88         '3',                    //SDLK_3                        = 51,
89         '4',                    //SDLK_4                        = 52,
90         '5',                    //SDLK_5                        = 53,
91         '6',                    //SDLK_6                        = 54,
92         '7',                    //SDLK_7                        = 55,
93         '8',                    //SDLK_8                        = 56,
94         '9',                    //SDLK_9                        = 57,
95         ':',                    //SDLK_COLON            = 58,
96         ';',                    //SDLK_SEMICOLON        = 59,
97         '<',                    //SDLK_LESS                     = 60,
98         '=',                    //SDLK_EQUALS           = 61,
99         '>',                    //SDLK_GREATER          = 62,
100         '?',                    //SDLK_QUESTION         = 63,
101         '@',                    //SDLK_AT                       = 64,
102         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
103         '[',            //SDLK_LEFTBRACKET      = 91,
104         '\\',           //SDLK_BACKSLASH        = 92,
105         ']',            //SDLK_RIGHTBRACKET     = 93,
106         '^',            //SDLK_CARET            = 94,
107         '_',            //SDLK_UNDERSCORE       = 95,
108         '`',            //SDLK_BACKQUOTE        = 96,
109         'a',            //SDLK_a                        = 97,
110         'b',            //SDLK_b                        = 98,
111         'c',            //SDLK_c                        = 99,
112         'd',            //SDLK_d                        = 100,
113         'e',            //SDLK_e                        = 101,
114         'f',            //SDLK_f                        = 102,
115         'g',            //SDLK_g                        = 103,
116         'h',            //SDLK_h                        = 104,
117         'i',            //SDLK_i                        = 105,
118         'j',            //SDLK_j                        = 106,
119         'k',            //SDLK_k                        = 107,
120         'l',            //SDLK_l                        = 108,
121         'm',            //SDLK_m                        = 109,
122         'n',            //SDLK_n                        = 110,
123         'o',            //SDLK_o                        = 111,
124         'p',            //SDLK_p                        = 112,
125         'q',            //SDLK_q                        = 113,
126         'r',            //SDLK_r                        = 114,
127         's',            //SDLK_s                        = 115,
128         't',            //SDLK_t                        = 116,
129         'u',            //SDLK_u                        = 117,
130         'v',            //SDLK_v                        = 118,
131         'w',            //SDLK_w                        = 119,
132         'x',            //SDLK_x                        = 120,
133         'y',            //SDLK_y                        = 121,
134         'z',            //SDLK_z                        = 122,
135         0,0,0,0,
136         K_DEL,          //SDLK_DELETE           = 127,
137         hundredoh /*227*/, tenoh, tenoh, 0,0,0,0,0,0,0,0,
138         K_KP_0,         //SDLK_KP0              = 256,
139         K_KP_1,         //SDLK_KP1              = 257,
140         K_KP_2,         //SDLK_KP2              = 258,
141         K_KP_3,         //SDLK_KP3              = 259,
142         K_KP_4,         //SDLK_KP4              = 260,
143         K_KP_5,         //SDLK_KP5              = 261,
144         K_KP_6,         //SDLK_KP6              = 262,
145         K_KP_7,         //SDLK_KP7              = 263,
146         K_KP_8,         //SDLK_KP8              = 264,
147         K_KP_9,         //SDLK_KP9              = 265,
148         K_KP_PERIOD,//SDLK_KP_PERIOD    = 266,
149         K_KP_DIVIDE,//SDLK_KP_DIVIDE    = 267,
150         K_KP_MULTIPLY,//SDLK_KP_MULTIPLY= 268,
151         K_KP_MINUS,     //SDLK_KP_MINUS         = 269,
152         K_KP_PLUS,      //SDLK_KP_PLUS          = 270,
153         K_KP_ENTER,     //SDLK_KP_ENTER         = 271,
154         K_KP_EQUALS,//SDLK_KP_EQUALS    = 272,
155         K_UPARROW,      //SDLK_UP               = 273,
156         K_DOWNARROW,//SDLK_DOWN         = 274,
157         K_RIGHTARROW,//SDLK_RIGHT       = 275,
158         K_LEFTARROW,//SDLK_LEFT         = 276,
159         K_INS,          //SDLK_INSERT   = 277,
160         K_HOME,         //SDLK_HOME             = 278,
161         K_END,          //SDLK_END              = 279,
162         K_PGUP,         //SDLK_PAGEUP   = 280,
163         K_PGDN,         //SDLK_PAGEDOWN = 281,
164         K_F1,           //SDLK_F1               = 282,
165         K_F2,           //SDLK_F2               = 283,
166         K_F3,           //SDLK_F3               = 284,
167         K_F4,           //SDLK_F4               = 285,
168         K_F5,           //SDLK_F5               = 286,
169         K_F6,           //SDLK_F6               = 287,
170         K_F7,           //SDLK_F7               = 288,
171         K_F8,           //SDLK_F8               = 289,
172         K_F9,           //SDLK_F9               = 290,
173         K_F10,          //SDLK_F10              = 291,
174         K_F11,          //SDLK_F11              = 292,
175         K_F12,          //SDLK_F12              = 293,
176         0,                      //SDLK_F13              = 294,
177         0,                      //SDLK_F14              = 295,
178         0,                      //SDLK_F15              = 296,
179         0,0,0,
180         K_NUMLOCK,      //SDLK_NUMLOCK  = 300,
181         K_CAPSLOCK,     //SDLK_CAPSLOCK = 301,
182         K_SCROLLOCK,//SDLK_SCROLLOCK= 302,
183         K_SHIFT,        //SDLK_RSHIFT   = 303,
184         K_SHIFT,        //SDLK_LSHIFT   = 304,
185         K_CTRL,         //SDLK_RCTRL    = 305,
186         K_CTRL,         //SDLK_LCTRL    = 306,
187         K_ALT,          //SDLK_RALT             = 307,
188         K_ALT,          //SDLK_LALT             = 308,
189         0,                      //SDLK_RMETA    = 309,
190         0,                      //SDLK_LMETA    = 310,
191         0,                      //SDLK_LSUPER   = 311,          /* Left "Windows" key */
192         0,                      //SDLK_RSUPER   = 312,          /* Right "Windows" key */
193         0,                      //SDLK_MODE             = 313,          /* "Alt Gr" key */
194         0,                      //SDLK_COMPOSE  = 314,          /* Multi-key compose key */
195         0,                      //SDLK_HELP             = 315,
196         0,                      //SDLK_PRINT    = 316,
197         0,                      //SDLK_SYSREQ   = 317,
198         K_PAUSE,        //SDLK_BREAK    = 318,
199         0,                      //SDLK_MENU             = 319,
200         0,                      //SDLK_POWER    = 320,          /* Power Macintosh power key */
201         'e',            //SDLK_EURO             = 321,          /* Some european keyboards */
202         0                       //SDLK_UNDO             = 322,          /* Atari keyboard has Undo */
203 };
204 #undef tenoh
205 #undef fiftyoh
206 #undef hundredoh
207
208 static int MapKey( int sdlkey )
209 {
210         if( sdlkey > sizeof(tbl_sdltoquake)/ sizeof(int) )
211                 return 0;
212     return tbl_sdltoquake[ sdlkey ];
213 }
214
215 static void IN_Activate( void )
216 {
217         SDL_WM_GrabInput( SDL_GRAB_ON );
218         SDL_ShowCursor( SDL_DISABLE );
219 }
220
221 static void IN_Deactivate( void )
222 {
223         SDL_WM_GrabInput( SDL_GRAB_OFF );
224         SDL_ShowCursor( SDL_ENABLE );
225 }
226
227 void IN_Commands (void)
228 {
229 }
230
231 static void IN_MouseMove (usercmd_t *cmd)
232 {
233         int x, y;
234         Uint8 state;
235         int i;
236
237         if( !vid_usingmouse ) {
238                 IN_Mouse( cmd, 0, 0 );
239                 return;
240         }
241
242         state = SDL_GetRelativeMouseState( &x, &y );
243         for( i = 0; i < 8 ; i++ )
244                 if( state & ~in_mouse_buttons & 1 << i  )
245                         Key_Event( K_MOUSE1 + i, 0, true );
246                 else if( ~state & in_mouse_buttons & 1 << i )
247                         Key_Event( K_MOUSE1 + i, 0, false );
248
249         in_mouse_buttons = state;
250     
251         IN_Mouse( cmd, x, y );
252 }
253
254 void IN_Move( usercmd_t *cmd )
255 {
256         IN_MouseMove( cmd );    
257 }
258
259 static void IN_Init( void )
260 {
261         // init keyboard
262         SDL_EnableUNICODE( SDL_ENABLE );
263
264         // init mouse
265         in_mouse_buttons = SDL_GetMouseState( NULL, NULL );
266         vid_usingmouse = false;
267 }
268
269 static void IN_Shutdown( void )
270 {
271 }
272
273 /////////////////////
274 // Message Handling
275 ////
276
277 static int Sys_EventFilter( SDL_Event *event ) 
278 {
279         //TODO: Add a quit query in linux, too - though linux user are more likely to know what they do
280 #ifdef WIN32
281         if( event->type == SDL_QUIT && MessageBox( NULL, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION ) == IDNO )
282                 return 0;
283         else 
284                 return 1;
285 #else
286         return 1;
287 #endif
288 }
289
290 void Sys_SendKeyEvents( void )
291 {
292         SDL_Event event;
293
294         while( SDL_PollEvent( &event ) )
295                 switch( event.type ) {
296                         case SDL_QUIT:
297                                 Sys_Quit();
298                                 break;
299                         case SDL_KEYDOWN:
300                         case SDL_KEYUP:
301                                 Key_Event( MapKey( event.key.keysym.sym ), event.key.keysym.unicode, (event.key.state == SDL_PRESSED) );
302                                 break;
303                         case SDL_ACTIVEEVENT:
304                                 if( event.active.state == SDL_APPACTIVE ) 
305                                         if( event.active.gain )
306                                                 vid_hidden = false;
307                                         else
308                                                 vid_hidden = true;
309                                 break;
310                 }
311 }
312
313 /////////////////
314 // Video system
315 ////
316
317 void *GL_GetProcAddress(const char *name)
318 {
319         void *p = NULL;
320         p = SDL_GL_GetProcAddress(name);
321         return p;
322 }
323
324 static int Sys_EventFilter( SDL_Event *event );
325 void VID_Init (void)
326 {
327         if (SDL_Init(SDL_INIT_VIDEO) < 0)
328                 Sys_Error ("Failed to init video: %s\n", SDL_GetError());
329         vid_isfullscreen = false;
330
331         SDL_SetEventFilter( (SDL_EventFilter) Sys_EventFilter );
332         IN_Init();
333 }
334
335 int VID_InitMode(int fullscreen, int width, int height, int bpp)
336 {
337         int i;
338         int flags = SDL_OPENGL;
339         const char *drivername;
340
341         /* 
342         SDL Hack 
343                 We cant switch from one OpenGL video mode to another.
344                 Thus we first switch to some stupid 2D mode and then back to OpenGL.
345         */
346         SDL_SetVideoMode( 0, 0, 0, 0 );
347
348 #ifdef WIN32
349         drivername = "opengl32.dll";
350 #elif defined(__APPLE__) && defined(__MACH__)
351         drivername = "OpenGL.framework";
352 #else
353         drivername = "libGL.so.1";
354 #endif
355
356         i = COM_CheckParm("-gl_driver");
357         if (i && i < com_argc - 1)
358                 drivername = com_argv[i + 1];
359         if (SDL_GL_LoadLibrary(drivername))
360         {   
361                 Con_Printf("Unable to load GL driver \"%s\": ", drivername, SDL_GetError());
362                 return false;
363         }
364
365         qglGetString = GL_GetProcAddress("glGetString");
366         
367         // Knghtbrd: should do platform-specific extension string function here
368
369         if (qglGetString == NULL)
370         {
371                 VID_Shutdown();
372                 Con_Print("Required OpenGL function glGetString not found\n");
373                 return false;
374         }
375
376         vid_isfullscreen = false;
377         if (fullscreen) {
378                 flags |= SDL_FULLSCREEN;
379                 vid_isfullscreen = true;
380         }
381
382         SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 1);
383         SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 1);
384         SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 1);
385         SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 16);
386         SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
387
388         screen = SDL_SetVideoMode(width, height, bpp, flags);
389         if (screen == NULL)
390         {
391                 Con_Printf("Failed to set video mode to %ix%i: %s\n", width, height, SDL_GetError);
392                 VID_Shutdown();
393                 return false;
394         }
395         
396         gl_renderer = qglGetString(GL_RENDERER);
397         gl_vendor = qglGetString(GL_VENDOR);
398         gl_version = qglGetString(GL_VERSION);
399         gl_extensions = qglGetString(GL_EXTENSIONS);
400         gl_platform = "SDL";
401         // Knghtbrd: should assign platform-specific extensions here
402         //TODO: maybe ;)
403         gl_platformextensions = "";
404         gl_videosyncavailable = false;
405         
406         GL_Init();
407
408         vid_hidden = false;
409         vid_activewindow = false;
410         vid_usingmouse = false;
411         IN_Init();
412         return true;
413 }
414
415 void VID_Shutdown (void)
416 {
417         IN_Shutdown();
418         SDL_QuitSubSystem(SDL_INIT_VIDEO);
419 }
420
421 int VID_SetGamma (unsigned short *ramps)
422 {
423         return !SDL_SetGammaRamp (ramps, ramps + 256, ramps + 512);
424 }
425
426 int VID_GetGamma (unsigned short *ramps)
427 {
428         return !SDL_GetGammaRamp( ramps, ramps + 256, ramps + 512);
429 }
430
431 void VID_GetWindowSize (int *x, int *y, int *width, int *height)
432 {
433         *x = *y = 0;
434         *width = screen->w;
435         *height = screen->h;
436 }
437
438 void VID_Finish (void)
439 {
440         Uint8 appstate;
441         int vid_usemouse;
442
443         qglFinish();
444         SDL_GL_SwapBuffers();
445
446         //react on appstate changes
447         appstate = SDL_GetAppState();
448
449         if( !( appstate & SDL_APPMOUSEFOCUS ) || !( appstate & SDL_APPINPUTFOCUS ) )
450                 vid_activewindow = false;
451         else 
452                 vid_activewindow = true;
453
454         vid_usemouse = false;
455         if( vid_mouse.integer && !key_consoleactive )
456                 vid_usemouse = true;
457         if( vid_isfullscreen )
458                 vid_usemouse = true;
459         if( !vid_activewindow )
460                 vid_usemouse = false;
461
462         if( vid_usemouse && !vid_usingmouse ) {
463                 vid_usingmouse = true;
464                 IN_Activate();
465         } else if( !vid_usemouse && vid_usingmouse ) {
466                 vid_usingmouse = false;
467                 IN_Deactivate();
468         }
469 }