1 /* $Id: gl_sdl.c,v 1.3 2007/05/12 20:09:36 r1ch Exp $
2  *
3  * all os-specific SDL refresher code
4  *
5  * Copyright (c) 2002 The QuakeForge Project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  * See the GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22 
23 /*
24 ** RW_SDL.C
25 **
26 ** This file contains ALL Linux specific stuff having to do with the
27 ** software refresh.  When a port is being made the following functions
28 ** must be implemented by the port:
29 **
30 ** GLimp_EndFrame
31 ** GLimp_Init
32 ** GLimp_InitGraphics
33 ** GLimp_Shutdown
34 ** GLimp_SwitchFullscreen
35 */
36 
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <sys/mman.h>
42 
43 #include <SDL.h>
44 
45 #include <GL/gl.h>
46 
47 #include "../client/client.h"
48 #include "../ref_gl/gl_local.h"
49 #include "../linux/glw.h"
50 
51 #include "../client/keys.h"
52 #include "../linux/rw_linux.h"
53 
54 /*****************************************************************************/
55 
56 #define JOY_AXIS_X			0
57 #define JOY_AXIS_Y			1
58 #define JOY_AXIS_Z			2
59 #define JOY_AXIS_R			3
60 #define JOY_AXIS_U			4
61 #define JOY_AXIS_V			5
62 
63 static qboolean                 X11_active = false;
64 
65 static SDL_Surface *surface;
66 
67 struct
68 {
69 	int key;
70 	int down;
71 } keyq[64];
72 int keyq_head=0;
73 int keyq_tail=0;
74 
75 int config_notify=0;
76 int config_notify_width;
77 int config_notify_height;
78 
79 glwstate_t glw_state;
80 
81 // Console variables that we need to access from this module
82 
83 /*****************************************************************************/
84 /* MOUSE                                                                     */
85 /*****************************************************************************/
86 
87 // this is inside the renderer shared lib, so these are called from vid_so
88 
89 static qboolean        mouse_avail;
90 static int     mouse_buttonstate;
91 static int     mouse_oldbuttonstate;
92 static int   mouse_x, mouse_y;
93 static int	old_mouse_x, old_mouse_y;
94 static int		mx, my;
95 static float old_windowed_mouse;
96 static qboolean mouse_active;
97 
98 static cvar_t	*_windowed_mouse;
99 static cvar_t	*m_filter;
100 static cvar_t	*in_mouse;
101 
102 static qboolean	mlooking;
103 
104 /* stencilbuffer shadows */
105 qboolean have_stencil = false;
106 
107 // state struct passed in Init
108 static in_state_t	*in_state;
109 
110 cvar_t *sensitivity;
111 static cvar_t *my_lookstrafe;
112 cvar_t *m_side;
113 cvar_t *m_yaw;
114 cvar_t *m_pitch;
115 cvar_t *m_forward;
116 static cvar_t *my_freelook;
117 
118 #ifdef HAVE_JOYSTICK
119 /************************
120  * Joystick
121  ************************/
122 static cvar_t   *in_joystick;
123 static cvar_t   *j_invert_y;
124 static qboolean joystick_avail;
125 static SDL_Joystick *joy;
126 static int joy_oldbuttonstate;
127 static int joy_numbuttons;
128 static int jx, jy, jt;
129 static int lr_axis, ud_axis, throttle_axis;
130 #endif /* HAVE_JOYSTICK */
131 
Force_CenterView_f(void)132 static void Force_CenterView_f (void)
133 {
134 	in_state->viewangles[PITCH] = 0;
135 }
136 
RW_IN_MLookDown(void)137 static void RW_IN_MLookDown (void)
138 {
139 	mlooking = true;
140 }
141 
RW_IN_MLookUp(void)142 static void RW_IN_MLookUp (void)
143 {
144 	mlooking = false;
145 	in_state->IN_CenterView_fp ();
146 }
147 
RW_IN_Init(in_state_t * in_state_p)148 void EXPORT RW_IN_Init(in_state_t *in_state_p)
149 {
150 	in_state = in_state_p;
151 
152 	// mouse variables
153 	_windowed_mouse = ri.Cvar_Get ("_windowed_mouse", "0", CVAR_ARCHIVE);
154 	m_filter = ri.Cvar_Get ("m_filter", "0", 0);
155 	in_mouse = ri.Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
156 #ifdef HAVE_JOYSTICK
157 	in_joystick = ri.Cvar_Get("in_joystick", "0", CVAR_ARCHIVE);
158 	j_invert_y = ri.Cvar_Get("j_invert_y", "1", 0);
159 	lr_axis = (int) ri.Cvar_Get("j_lr_axis", "0", CVAR_ARCHIVE)->value;
160 	ud_axis = (int) ri.Cvar_Get("j_ud_axis", "1", CVAR_ARCHIVE)->value;
161 	throttle_axis = (int) ri.Cvar_Get("j_throttle", "3", CVAR_ARCHIVE)->value;
162 #endif
163 	my_freelook = ri.Cvar_Get( "freelook", "0", 0);
164 	my_lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);
165 
166 	sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);
167 	m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);
168 	m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);
169 	m_forward = ri.Cvar_Get ("m_forward", "1", 0);
170 	m_side = ri.Cvar_Get ("m_side", "0.8", 0);
171 
172 	ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);
173 	ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);
174 
175 	ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);
176 
177 	mouse_x = mouse_y = 0.0;
178 	mouse_avail = true;
179 }
180 
RW_IN_Shutdown(void)181 void EXPORT RW_IN_Shutdown(void) {
182     if (mouse_avail) {
183 	mouse_avail = false;
184 
185 	ri.Cmd_RemoveCommand ("+mlook");
186 	ri.Cmd_RemoveCommand ("-mlook");
187 
188 	ri.Cmd_RemoveCommand ("force_centerview");
189     }
190 
191 #ifdef HAVE_JOYSTICK
192     if (joy) {
193 	SDL_JoystickClose(joy);
194 	joy = NULL;
195     }
196 #endif
197 }
198 
199 /*
200 ===========
201 IN_Commands
202 ===========
203 */
RW_IN_Commands(void)204 void EXPORT RW_IN_Commands (void)
205 {
206     int i;
207 #ifdef HAVE_JOYSTICK
208     int key_index;
209 #endif
210 
211     if (mouse_avail) {
212 	for (i = 0; i < 3; i++) {
213 	    if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
214 		in_state->Key_Event_fp (K_MOUSE1 + i, true);
215 
216 	    if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
217 		in_state->Key_Event_fp (K_MOUSE1 + i, false);
218 	}
219 	/* can't put in loop because K_MOUSE4 doesn't come after K_MOUSE3 */
220 	if ((mouse_buttonstate & (1<<3)) && !(mouse_oldbuttonstate & (1<<3)))
221 	    in_state->Key_Event_fp(K_MOUSE4, true);
222 	if (!(mouse_buttonstate * (1<<3)) && (mouse_oldbuttonstate & (1<<3)))
223 	    in_state->Key_Event_fp(K_MOUSE4, false);
224 
225 	if ((mouse_buttonstate & (1<<4)) && !(mouse_oldbuttonstate & (1<<4)))
226 	    in_state->Key_Event_fp(K_MOUSE5, true);
227 	if (!(mouse_buttonstate * (1<<4)) && (mouse_oldbuttonstate & (1<<4)))
228 	    in_state->Key_Event_fp(K_MOUSE5, false);
229 
230 	mouse_oldbuttonstate = mouse_buttonstate;
231     }
232 #ifdef HAVE_JOYSTICK
233     if (joystick_avail && joy) {
234 	for (i = 0; i < joy_numbuttons; i++) {
235 	    if (SDL_JoystickGetButton(joy, i) && joy_oldbuttonstate != i) {
236 		key_index = (i < 4) ? K_JOY1 : K_AUX1;
237 		in_state->Key_Event_fp(key_index + i, true);
238 		joy_oldbuttonstate = i;
239 	    }
240 	    if (!SDL_JoystickGetButton(joy, i) && joy_oldbuttonstate != i) {
241 		key_index = (i < 4) ? K_JOY1 : K_AUX1;
242 		in_state->Key_Event_fp(key_index + i, false);
243 		joy_oldbuttonstate = i;
244 	    }
245 	}
246     }
247 #endif
248 }
249 
250 /*
251 ===========
252 IN_Move
253 ===========
254 */
RW_IN_Move(usercmd_t * cmd)255 void EXPORT RW_IN_Move (usercmd_t *cmd)
256 {
257   /*** FIXME
258    *   You can accelerate while in the air, this doesn't
259    *   make physical sense.  Try falling off something and then moving
260    *   forward.
261    ***/
262 
263   if (mouse_avail) {
264     if (m_filter->value)
265       {
266 	mouse_x = (mx + old_mouse_x) * 0.5;
267 	mouse_y = (my + old_mouse_y) * 0.5;
268       } else {
269 	mouse_x = mx;
270 	mouse_y = my;
271       }
272 
273     old_mouse_x = mx;
274     old_mouse_y = my;
275 
276     if (mouse_x || mouse_y) {
277       mouse_x *= sensitivity->value;
278       mouse_y *= sensitivity->value;
279 
280       /* add mouse X/Y movement to cmd */
281       if ( (*in_state->in_strafe_state & 1) ||
282 	   (my_lookstrafe->value && mlooking ))
283 	cmd->sidemove += m_side->value * mouse_x;
284       else
285 	in_state->viewangles[YAW] -= m_yaw->value * mouse_x;
286 
287 
288       if ( (mlooking || my_freelook->value) &&
289 	   !(*in_state->in_strafe_state & 1))
290 	{
291 	  in_state->viewangles[PITCH] += m_pitch->value * mouse_y;
292 	}
293       else
294 	{
295 	  cmd->forwardmove -= m_forward->value * mouse_y;
296 	}
297       mx = my = 0;
298     }
299   }
300 #ifdef HAVE_JOYSTICK
301   if (joystick_avail && joy) {
302       /* add joy X/Y movement to cmd */
303     if ( (*in_state->in_strafe_state & 1) ||
304 	 (my_lookstrafe->value && mlooking ))
305       cmd->sidemove += m_side->value * (jx/100);
306     else
307       in_state->viewangles[YAW] -= m_yaw->value * (jx/100);
308 
309     if ((mlooking || my_freelook->value) && !(*in_state->in_strafe_state & 1)) {
310 	if (j_invert_y)
311 	    in_state->viewangles[PITCH] -= m_pitch->value * (jy/100);
312 	else
313 	    in_state->viewangles[PITCH] += m_pitch->value * (jy/100);
314 	cmd->forwardmove -= m_forward->value * (jt/100);
315     } else {
316 	cmd->forwardmove -= m_forward->value * (jy/100);
317     }
318     jt = jx = jy = 0;
319   }
320 #endif
321 }
322 
IN_DeactivateMouse(void)323 void IN_DeactivateMouse( void )
324 {
325 	if (!mouse_avail)
326 		return;
327 
328 	if (mouse_active) {
329 		/* uninstall_grabs(); */
330 		mouse_active = false;
331 	}
332 }
333 
IN_ActivateMouse(void)334 static void IN_ActivateMouse( void )
335 {
336 	if (!mouse_avail)
337 		return;
338 
339 	if (!mouse_active) {
340 		mx = my = 0; // don't spazz
341 		/* install_grabs(); */
342 		mouse_active = true;
343 	}
344 }
345 
RW_IN_Frame(void)346 void EXPORT RW_IN_Frame (void)
347 {
348 }
349 
RW_IN_Activate(qboolean active)350 void EXPORT RW_IN_Activate(qboolean active)
351 {
352     /*	if (active || vidmode_active) */
353     	if (active)
354 		IN_ActivateMouse();
355 	else
356 		IN_DeactivateMouse();
357 }
358 
359 /*****************************************************************************/
360 
361 #if 0 /* SDL parachute should catch everything... */
362 // ========================================================================
363 // Tragic death handler
364 // ========================================================================
365 
366 void TragicDeath(int signal_num)
367 {
368 	/* SDL_Quit(); */
369 	Sys_Error("This death brought to you by the number %d\n", signal_num);
370 }
371 #endif
372 
XLateKey(unsigned int keysym)373 int XLateKey(unsigned int keysym)
374 {
375 	int key;
376 
377 	key = 0;
378 	switch(keysym) {
379 		case SDLK_KP9:			key = K_KP_PGUP; break;
380 		case SDLK_PAGEUP:		key = K_PGUP; break;
381 
382 		case SDLK_KP3:			key = K_KP_PGDN; break;
383 		case SDLK_PAGEDOWN:		key = K_PGDN; break;
384 
385 		case SDLK_KP7:			key = K_KP_HOME; break;
386 		case SDLK_HOME:			key = K_HOME; break;
387 
388 		case SDLK_KP1:			key = K_KP_END; break;
389 		case SDLK_END:			key = K_END; break;
390 
391 		case SDLK_KP4:			key = K_KP_LEFTARROW; break;
392 		case SDLK_LEFT:			key = K_LEFTARROW; break;
393 
394 		case SDLK_KP6:			key = K_KP_RIGHTARROW; break;
395 		case SDLK_RIGHT:		key = K_RIGHTARROW; break;
396 
397 		case SDLK_KP2:			key = K_KP_DOWNARROW; break;
398 		case SDLK_DOWN:			key = K_DOWNARROW; break;
399 
400 		case SDLK_KP8:			key = K_KP_UPARROW; break;
401 		case SDLK_UP:			key = K_UPARROW; break;
402 
403 		case SDLK_ESCAPE:		key = K_ESCAPE; break;
404 
405 		case SDLK_KP_ENTER:		key = K_KP_ENTER; break;
406 		case SDLK_RETURN:		key = K_ENTER; break;
407 
408 		case SDLK_TAB:			key = K_TAB; break;
409 
410 		case SDLK_F1:			key = K_F1; break;
411 		case SDLK_F2:			key = K_F2; break;
412 		case SDLK_F3:			key = K_F3; break;
413 		case SDLK_F4:			key = K_F4; break;
414 		case SDLK_F5:			key = K_F5; break;
415 		case SDLK_F6:			key = K_F6; break;
416 		case SDLK_F7:			key = K_F7; break;
417 		case SDLK_F8:			key = K_F8; break;
418 		case SDLK_F9:			key = K_F9; break;
419 		case SDLK_F10:			key = K_F10; break;
420 		case SDLK_F11:			key = K_F11; break;
421 		case SDLK_F12:			key = K_F12; break;
422 
423 		case SDLK_BACKSPACE:		key = K_BACKSPACE; break;
424 
425 		case SDLK_KP_PERIOD:		key = K_KP_DEL; break;
426 		case SDLK_DELETE:		key = K_DEL; break;
427 
428 		case SDLK_PAUSE:		key = K_PAUSE; break;
429 
430 		case SDLK_LSHIFT:
431 		case SDLK_RSHIFT:		key = K_SHIFT; break;
432 
433 		case SDLK_LCTRL:
434 		case SDLK_RCTRL:		key = K_CTRL; break;
435 
436 		case SDLK_LMETA:
437 		case SDLK_RMETA:
438 		case SDLK_LALT:
439 		case SDLK_RALT:			key = K_ALT; break;
440 
441 		case SDLK_KP5:			key = K_KP_5; break;
442 
443 		case SDLK_INSERT:		key = K_INS; break;
444 		case SDLK_KP0:			key = K_KP_INS; break;
445 
446 		case SDLK_KP_MULTIPLY:		key = '*'; break;
447 		case SDLK_KP_PLUS:		key = K_KP_PLUS; break;
448 		case SDLK_KP_MINUS:		key = K_KP_MINUS; break;
449 		case SDLK_KP_DIVIDE:		key = K_KP_SLASH; break;
450 
451 		/* suggestions on how to handle this better would be appreciated */
452 		case SDLK_WORLD_7:		key = '`'; break;
453 
454 		default: /* assuming that the other sdl keys are mapped to ascii */
455 			if (keysym < 128)
456 				key = keysym;
457 			break;
458 	}
459 
460 	return key;
461 }
462 
463 static unsigned char KeyStates[SDLK_LAST];
464 
GetEvent(SDL_Event * event)465 void GetEvent(SDL_Event *event)
466 {
467 	unsigned int key;
468 
469 	switch(event->type) {
470 	case SDL_MOUSEBUTTONDOWN:
471 		if (event->button.button == 4) {
472 			keyq[keyq_head].key = K_MWHEELUP;
473 			keyq[keyq_head].down = true;
474 			keyq_head = (keyq_head + 1) & 63;
475 			keyq[keyq_head].key = K_MWHEELUP;
476 			keyq[keyq_head].down = false;
477 			keyq_head = (keyq_head + 1) & 63;
478 		} else if (event->button.button == 5) {
479 			keyq[keyq_head].key = K_MWHEELDOWN;
480 			keyq[keyq_head].down = true;
481 			keyq_head = (keyq_head + 1) & 63;
482 			keyq[keyq_head].key = K_MWHEELDOWN;
483 			keyq[keyq_head].down = false;
484 			keyq_head = (keyq_head + 1) & 63;
485 		}
486 		break;
487 	case SDL_MOUSEBUTTONUP:
488 		break;
489 #ifdef HAVE_JOYSTICK
490 	case SDL_JOYBUTTONDOWN:
491 	  keyq[keyq_head].key =
492 	    ((((SDL_JoyButtonEvent*)event)->button < 4)?K_JOY1:K_AUX1)+
493 	    ((SDL_JoyButtonEvent*)event)->button;
494 	  keyq[keyq_head].down = true;
495 	  keyq_head = (keyq_head+1)&63;
496 	  break;
497 	case SDL_JOYBUTTONUP:
498 	  keyq[keyq_head].key =
499 	    ((((SDL_JoyButtonEvent*)event)->button < 4)?K_JOY1:K_AUX1)+
500 	    ((SDL_JoyButtonEvent*)event)->button;
501 	  keyq[keyq_head].down = false;
502 	  keyq_head = (keyq_head+1)&63;
503 	  break;
504 #endif
505 	case SDL_KEYDOWN:
506 		if ( (KeyStates[SDLK_LALT] || KeyStates[SDLK_RALT]) &&
507 			(event->key.keysym.sym == SDLK_RETURN) ) {
508 			cvar_t	*fullscreen;
509 
510 			SDL_WM_ToggleFullScreen(surface);
511 
512 			if (surface->flags & SDL_FULLSCREEN) {
513 				ri.Cvar_SetValue( "vid_fullscreen", 1 );
514 			} else {
515 				ri.Cvar_SetValue( "vid_fullscreen", 0 );
516 			}
517 
518 			fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", 0 );
519 			fullscreen->modified = false;	// we just changed it with SDL.
520 
521 			break; /* ignore this key */
522 		}
523 
524 		if ( (KeyStates[SDLK_LCTRL] || KeyStates[SDLK_RCTRL]) &&
525 			(event->key.keysym.sym == SDLK_g) ) {
526 			SDL_GrabMode gm = SDL_WM_GrabInput(SDL_GRAB_QUERY);
527 			/*
528 			SDL_WM_GrabInput((gm == SDL_GRAB_ON) ? SDL_GRAB_OFF : SDL_GRAB_ON);
529 			gm = SDL_WM_GrabInput(SDL_GRAB_QUERY);
530 			*/
531 			ri.Cvar_SetValue( "_windowed_mouse", (gm == SDL_GRAB_ON) ? /*1*/ 0 : /*0*/ 1 );
532 
533 			break; /* ignore this key */
534 		}
535 
536 		KeyStates[event->key.keysym.sym] = 1;
537 
538 		key = XLateKey(event->key.keysym.sym);
539 		if (key) {
540 			keyq[keyq_head].key = key;
541 			keyq[keyq_head].down = true;
542 			keyq_head = (keyq_head + 1) & 63;
543 		}
544 		break;
545 	case SDL_KEYUP:
546 		if (KeyStates[event->key.keysym.sym]) {
547 			KeyStates[event->key.keysym.sym] = 0;
548 
549 			key = XLateKey(event->key.keysym.sym);
550 			if (key) {
551 				keyq[keyq_head].key = key;
552 				keyq[keyq_head].down = false;
553 				keyq_head = (keyq_head + 1) & 63;
554 			}
555 		}
556 		break;
557 	case SDL_QUIT:
558 		ri.Cmd_ExecuteText(EXEC_NOW, "quit");
559 		break;
560 	}
561 
562 }
563 
init_joystick()564 void init_joystick() {
565 #ifdef HAVE_JOYSTICK
566     int num_joysticks, i;
567     joy = NULL;
568 
569     if (!(SDL_INIT_JOYSTICK&SDL_WasInit(SDL_INIT_JOYSTICK))) {
570 	ri.Con_Printf(PRINT_ALL, "SDL Joystick not initialized, trying to init...\n");
571 	SDL_Init(SDL_INIT_JOYSTICK);
572     }
573     if (in_joystick) {
574 	ri.Con_Printf(PRINT_ALL, "Trying to start-up joystick...\n");
575 	if ((num_joysticks=SDL_NumJoysticks())) {
576 	    for(i=0;i<num_joysticks;i++) {
577 		ri.Con_Printf(PRINT_ALL, "Trying joystick [%s]\n",
578 			      SDL_JoystickName(i));
579 		if (!SDL_JoystickOpened(i)) {
580 		    joy = SDL_JoystickOpen(i);
581 		    if (joy) {
582 			ri.Con_Printf(PRINT_ALL, "Joytick activated.\n");
583 			joystick_avail = true;
584 			joy_numbuttons = SDL_JoystickNumButtons(joy);
585 			break;
586 		    }
587 		}
588 	    }
589 	    if (!joy) {
590 		ri.Con_Printf(PRINT_ALL, "Failed to open any joysticks\n");
591 		joystick_avail = false;
592 	    }
593 	}
594 	else {
595 	    ri.Con_Printf(PRINT_ALL, "No joysticks available\n");
596 	    joystick_avail = false;
597 	}
598     }
599     else {
600 	ri.Con_Printf(PRINT_ALL, "Joystick Inactive\n");
601 	joystick_avail = false;
602     }
603 #endif
604 }
605 
InitJoystick()606 void InitJoystick() {
607 #ifdef HAVE_JOYSTICK
608   int num_joysticks, i;
609   joy = NULL;
610 
611   if (!(SDL_INIT_JOYSTICK&SDL_WasInit(SDL_INIT_JOYSTICK))) {
612     ri.Con_Printf(PRINT_ALL, "SDL Joystick not initialized, trying to init...\n");
613     SDL_Init(SDL_INIT_JOYSTICK);
614   }
615   if (in_joystick) {
616     ri.Con_Printf(PRINT_ALL, "Trying to start-up joystick...\n");
617     if ((num_joysticks=SDL_NumJoysticks())) {
618       for(i=0;i<num_joysticks;i++) {
619 	ri.Con_Printf(PRINT_ALL, "Trying joystick [%s]\n",
620 		      SDL_JoystickName(i));
621 	if (!SDL_JoystickOpened(i)) {
622 	  joy = SDL_JoystickOpen(0);
623 	  if (joy) {
624 	    ri.Con_Printf(PRINT_ALL, "Joytick activated.\n");
625 	    joystick_avail = true;
626 	    joy_numbuttons = SDL_JoystickNumButtons(joy);
627 	    break;
628 	  }
629 	}
630       }
631       if (!joy) {
632 	ri.Con_Printf(PRINT_ALL, "Failed to open any joysticks\n");
633 	joystick_avail = false;
634       }
635     }
636     else {
637       ri.Con_Printf(PRINT_ALL, "No joysticks available\n");
638       joystick_avail = false;
639     }
640   }
641   else {
642     ri.Con_Printf(PRINT_ALL, "Joystick Inactive\n");
643     joystick_avail = false;
644   }
645 #endif
646 }
647 
648 /*****************************************************************************/
649 
650 /*
651 ** SWimp_Init
652 **
653 ** This routine is responsible for initializing the implementation
654 ** specific stuff in a software rendering subsystem.
655 */
SWimp_Init(void * hInstance,void * wndProc)656 int SWimp_Init( void *hInstance, void *wndProc )
657 {
658 	if (SDL_WasInit(SDL_INIT_AUDIO|SDL_INIT_CDROM|SDL_INIT_VIDEO) == 0) {
659 		if (SDL_Init(SDL_INIT_VIDEO) < 0) {
660 			Sys_Error("SDL Init failed: %s\n", SDL_GetError());
661 			return false;
662 		}
663 	} else if (SDL_WasInit(SDL_INIT_VIDEO) == 0) {
664 		if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
665 			Sys_Error("SDL Init failed: %s\n", SDL_GetError());
666 			return false;
667 		}
668 	}
669 
670 	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
671 
672 // catch signals so i can turn on auto-repeat
673 #if 0
674  	{
675 		struct sigaction sa;
676 		sigaction(SIGINT, 0, &sa);
677 		sa.sa_handler = TragicDeath;
678 		sigaction(SIGINT, &sa, 0);
679 		sigaction(SIGTERM, &sa, 0);
680 	}
681 #endif
682 #ifdef HAVE_JOYSTICK
683 	init_joystick();
684 #endif
685 	return true;
686 }
687 
GLimp_GetProcAddress(const char * func)688 void *GLimp_GetProcAddress(const char *func)
689 {
690 	return SDL_GL_GetProcAddress(func);
691 }
692 
GLimp_Init(void * hInstance,void * wndProc)693 int GLimp_Init( void *hInstance, void *wndProc )
694 {
695 	return SWimp_Init(hInstance, wndProc);
696 }
697 
SetSDLIcon(void)698 static void SetSDLIcon(void) {
699 #include "q2icon.xbm"
700     SDL_Surface * icon;
701     SDL_Color color;
702     Uint8 * ptr;
703     int i, mask;
704 
705     icon = SDL_CreateRGBSurface(SDL_SWSURFACE, q2icon_width, q2icon_height, 8,
706 				0, 0, 0, 0);
707     if (icon == NULL)
708 	return; /* oh well... */
709     SDL_SetColorKey(icon, SDL_SRCCOLORKEY, 0);
710 
711     color.r = 255;
712     color.g = 255;
713     color.b = 255;
714     SDL_SetColors(icon, &color, 0, 1); /* just in case */
715     color.r = 0;
716     color.g = 16;
717     color.b = 0;
718     SDL_SetColors(icon, &color, 1, 1);
719 
720     ptr = (Uint8 *)icon->pixels;
721     for (i = 0; i < sizeof(q2icon_bits); i++) {
722 	for (mask = 1; mask != 0x100; mask <<= 1) {
723 	    *ptr = (q2icon_bits[i] & mask) ? 1 : 0;
724 	    ptr++;
725 	}
726     }
727 
728     SDL_WM_SetIcon(icon, NULL);
729     SDL_FreeSurface(icon);
730 }
731 
732 /*
733 ** SWimp_InitGraphics
734 **
735 ** This initializes the software refresh's implementation specific
736 ** graphics subsystem.  In the case of Windows it creates DIB or
737 ** DDRAW surfaces.
738 **
739 ** The necessary width and height parameters are grabbed from
740 ** vid.width and vid.height.
741 */
GLimp_InitGraphics(qboolean fullscreen)742 static qboolean GLimp_InitGraphics( qboolean fullscreen )
743 {
744 	int flags;
745 
746 	/* Just toggle fullscreen if that's all that has been changed */
747 	if (surface && (surface->w == vid.width) && (surface->h == vid.height)) {
748 		int isfullscreen = (surface->flags & SDL_FULLSCREEN) ? 1 : 0;
749 		if (fullscreen != isfullscreen)
750 			SDL_WM_ToggleFullScreen(surface);
751 
752 		isfullscreen = (surface->flags & SDL_FULLSCREEN) ? 1 : 0;
753 		if (fullscreen == isfullscreen)
754 			return true;
755 	}
756 
757 	srandom(getpid());
758 
759 	// free resources in use
760 	if (surface)
761 		SDL_FreeSurface(surface);
762 
763 	// let the sound and input subsystems know about the new window
764 	ri.Vid_NewWindow (vid.width, vid.height);
765 
766 	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
767 	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
768 	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
769 	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
770 	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
771 
772 	flags = SDL_OPENGL;
773 	if (fullscreen)
774 		flags |= SDL_FULLSCREEN;
775 
776 	SetSDLIcon(); /* currently uses q2icon.xbm data */
777 
778 	if ((surface = SDL_SetVideoMode(vid.width, vid.height, 0, flags)) == NULL) {
779 		Sys_Error("(SDLGL) SDL SetVideoMode failed: %s\n", SDL_GetError());
780 		return false;
781 	}
782 
783 	SDL_WM_SetCaption("Quake II", "Quake II");
784 
785 	SDL_ShowCursor(0);
786 
787 	X11_active = true;
788 
789 
790 
791 	return true;
792 }
793 
GLimp_BeginFrame(void)794 void GLimp_BeginFrame(void)
795 {
796 }
797 
798 /*
799 ** GLimp_EndFrame
800 **
801 ** This does an implementation specific copy from the backbuffer to the
802 ** front buffer.  In the Win32 case it uses BitBlt or BltFast depending
803 ** on whether we're using DIB sections/GDI or DDRAW.
804 */
805 
GLimp_EndFrame(void)806 void GLimp_EndFrame (void)
807 {
808 	SDL_GL_SwapBuffers();
809 }
810 
811 /*
812 ** GLimp_SetMode
813 */
GLimp_SetMode(unsigned int * pwidth,unsigned int * pheight,int mode,qboolean fullscreen)814 int GLimp_SetMode( unsigned int *pwidth, unsigned int *pheight, int mode, qboolean fullscreen )
815 {
816 	ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
817 
818 	if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
819 	{
820 		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
821 		return VID_ERR_INVALID_MODE;
822 	}
823 
824 	ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight);
825 
826 	if ( !GLimp_InitGraphics( fullscreen ) ) {
827 		// failed to set a valid mode in windowed mode
828 		return VID_ERR_INVALID_MODE;
829 	}
830 
831 	return VID_ERR_NONE;
832 }
833 
834 
835 /*
836 ** SWimp_Shutdown
837 **
838 ** System specific graphics subsystem shutdown routine.  Destroys
839 ** DIBs or DDRAW surfaces as appropriate.
840 */
841 
SWimp_Shutdown(void)842 void SWimp_Shutdown( void )
843 {
844 	if (surface)
845 		SDL_FreeSurface(surface);
846 	surface = NULL;
847 
848 	if (SDL_WasInit(SDL_INIT_EVERYTHING) == SDL_INIT_VIDEO)
849 		SDL_Quit();
850 	else
851 		SDL_QuitSubSystem(SDL_INIT_VIDEO);
852 
853 	X11_active = false;
854 }
855 
GLimp_Shutdown(void)856 void GLimp_Shutdown( void )
857 {
858 	SWimp_Shutdown();
859 }
860 
861 /*
862 ** GLimp_AppActivate
863 */
GLimp_AppActivate(qboolean active)864 void GLimp_AppActivate( qboolean active )
865 {
866 }
867 
868 //===============================================================================
869 
870 /*
871 ================
872 Sys_MakeCodeWriteable
873 ================
874 */
Sys_MakeCodeWriteable(unsigned long startaddr,unsigned long length)875 void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
876 {
877 
878 	int r;
879 	unsigned long addr;
880 	int psize = getpagesize();
881 
882 	addr = (startaddr & ~(psize-1)) - psize;
883 
884 //	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
885 //			addr, startaddr+length, length);
886 
887 	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
888 
889 	if (r < 0)
890     		Sys_Error("Protection change failed\n");
891 
892 }
893 
894 /*****************************************************************************/
895 /* KEYBOARD                                                                  */
896 /*****************************************************************************/
897 
898 Key_Event_fp_t Key_Event_fp;
899 
KBD_Init(Key_Event_fp_t fp)900 void EXPORT KBD_Init(Key_Event_fp_t fp)
901 {
902 	Key_Event_fp = fp;
903 }
904 
KBD_Update(void)905 void EXPORT KBD_Update(void)
906 {
907 	SDL_Event event;
908 	static int KBD_Update_Flag;
909 
910 	if (KBD_Update_Flag == 1)
911 		return;
912 
913 	KBD_Update_Flag = 1;
914 
915 // get events from x server
916 	if (X11_active)
917 	{
918 		int bstate;
919 
920 		while (SDL_PollEvent(&event))
921 			GetEvent(&event);
922 
923 	if (!mx && !my)
924 		SDL_GetRelativeMouseState(&mx, &my);
925 
926 #ifdef HAVE_JOYSTICK
927 	if (joystick_avail && joy) {
928 	  jx = SDL_JoystickGetAxis(joy, lr_axis);
929 	  jy = SDL_JoystickGetAxis(joy, ud_axis);
930 	  jt = SDL_JoystickGetAxis(joy, throttle_axis);
931 	}
932 #endif
933 	mouse_buttonstate = 0;
934 	bstate = SDL_GetMouseState(NULL, NULL);
935 	if (SDL_BUTTON(1) & bstate)
936 		mouse_buttonstate |= (1 << 0);
937 	if (SDL_BUTTON(3) & bstate) /* quake2 has the right button be mouse2 */
938 		mouse_buttonstate |= (1 << 1);
939 	if (SDL_BUTTON(2) & bstate) /* quake2 has the middle button be mouse3 */
940 		mouse_buttonstate |= (1 << 2);
941 	if (SDL_BUTTON(6) & bstate)
942 		mouse_buttonstate |= (1 << 3);
943 
944 	if (SDL_BUTTON(7) & bstate)
945 		mouse_buttonstate |= (1 << 4);
946 
947 	if (old_windowed_mouse != _windowed_mouse->value) {
948 		old_windowed_mouse = _windowed_mouse->value;
949 
950 		if (!_windowed_mouse->value) {
951 			/* ungrab the pointer */
952 			SDL_WM_GrabInput(SDL_GRAB_OFF);
953 		} else {
954 			/* grab the pointer */
955 			SDL_WM_GrabInput(SDL_GRAB_ON);
956 		}
957 	}
958 		while (keyq_head != keyq_tail)
959 		{
960 			Key_Event_fp(keyq[keyq_tail].key, keyq[keyq_tail].down);
961 			keyq_tail = (keyq_tail + 1) & 63;
962 		}
963 	}
964 
965 	KBD_Update_Flag = 0;
966 }
967 
KBD_Close(void)968 void EXPORT KBD_Close(void)
969 {
970 	keyq_head = 0;
971 	keyq_tail = 0;
972 
973 	memset(keyq, 0, sizeof(keyq));
974 }
975