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