2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
7
Quake III Arena source code is free software; you can redistribute it
8
and/or modify it under the terms of the GNU General Public License as
9
published by the Free Software Foundation; either version 2 of the License,
10
or (at your option) any later version.
12
Quake III Arena source code is distributed in the hope that it will be
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
25
** This file contains ALL Linux specific stuff having to do with the
26
** OpenGL refresh. When a port is being made the following functions
27
** must be implemented by the port:
32
** GLimp_SwitchFullscreen
40
#include <sys/ioctl.h>
49
#include <semaphore.h>
54
// bk001206 - from my Heretic2 by way of Ryan's Fakk2
55
// Needed for the new X11_PendingInput() function.
57
#include <sys/types.h>
60
#include "../renderer/tr_local.h"
61
#include "../client/client.h"
62
#include "linux_local.h" // bk001130
68
#include <X11/keysym.h>
69
#include <X11/cursorfont.h>
72
#include <X11/extensions/xf86dga.h>
73
#include <X11/extensions/xf86vmode.h>
77
#include <X11/Sunkeysym.h>
88
RSERR_INVALID_FULLSCREEN,
96
static Display *dpy = NULL;
98
static Window win = 0;
99
static GLXContext ctx = NULL;
101
// bk001206 - not needed anymore
102
// static qboolean autorepeaton = qtrue;
104
#define KEY_MASK (KeyPressMask | KeyReleaseMask)
105
#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
106
PointerMotionMask | ButtonMotionMask )
107
#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask )
109
static qboolean mouse_avail;
110
static qboolean mouse_active = qfalse;
112
static int mx = 0, my = 0;
114
// Time mouse was reset, we ignore the first 50ms of the mouse to allow settling of events
115
static int mouseResetTime = 0;
116
#define MOUSE_RESET_DELAY 50
118
static cvar_t *in_mouse;
119
static cvar_t *in_dgamouse; // user pref for dga mouse
120
static cvar_t *in_shiftedKeys; // obey modifiers for certain keys in non-console (comma, numbers, etc)
122
cvar_t *in_nograb; // this is strictly for developers
124
// bk001130 - from cvs1.17 (mkv), but not static
125
cvar_t *in_joystick = NULL;
126
cvar_t *in_joystickDebug = NULL;
127
cvar_t *joy_threshold = NULL;
129
cvar_t *r_allowSoftwareGL; // don't abort out if the pixelformat claims software
130
cvar_t *r_previousglDriver;
132
qboolean vidmode_ext = qfalse;
134
static int vidmode_MajorVersion = 0, vidmode_MinorVersion = 0; // major and minor of XF86VidExtensions
136
// gamma value of the X display before we start playing with it
137
static XF86VidModeGamma vidmode_InitialGamma;
138
#endif /* HAVE_XF86DGA */
140
static int win_x, win_y;
143
static XF86VidModeModeInfo **vidmodes;
144
#endif /* HAVE_XF86DGA */
145
//static int default_dotclock_vidmode; // bk001204 - unused
146
static int num_vidmodes;
147
static qboolean vidmode_active = qfalse;
149
static int mouse_accel_numerator;
150
static int mouse_accel_denominator;
151
static int mouse_threshold;
154
* Find the first occurrence of find in s.
156
// bk001130 - from cvs1.17 (mkv), const
157
// bk001130 - made first argument const
158
static const char *Q_stristr( const char *s, const char *find)
163
if ((c = *find++) != 0)
165
if (c >= 'a' && c <= 'z')
174
if ((sc = *s++) == 0)
176
if (sc >= 'a' && sc <= 'z')
181
} while (Q_stricmpn(s, find, len) != 0);
187
/*****************************************************************************
189
** NOTE TTimo the keyboard handling is done with KeySyms
190
** that means relying on the keyboard mapping provided by X
191
** in-game it would probably be better to use KeyCode (i.e. hardware key codes)
192
** you would still need the KeySyms in some cases, such as for the console and all entry textboxes
193
** (cause there's nothing worse than a qwerty mapping on a french keyboard)
195
** you can turn on some debugging and verbose of the keyboard code with #define KBD_DBG
196
******************************************************************************/
200
static char *XLateKey(XKeyEvent *ev, int *key)
203
static char bufnomod[2];
209
XLookupRet = XLookupString(ev, buf, sizeof buf, &keysym, 0);
211
ri.Printf(PRINT_ALL, "XLookupString ret: %d buf: %s keysym: %x\n", XLookupRet, buf, keysym);
214
if (!in_shiftedKeys->integer) {
215
// also get a buffer without modifiers held
217
XLookupRet = XLookupString(ev, bufnomod, sizeof bufnomod, &keysym, 0);
219
ri.Printf(PRINT_ALL, "XLookupString (minus modifiers) ret: %d buf: %s keysym: %x\n", XLookupRet, buf, keysym);
226
case XK_KP_9: *key = K_KP_PGUP; break;
227
case XK_Page_Up: *key = K_PGUP; break;
229
case XK_KP_Page_Down:
230
case XK_KP_3: *key = K_KP_PGDN; break;
231
case XK_Page_Down: *key = K_PGDN; break;
233
case XK_KP_Home: *key = K_KP_HOME; break;
234
case XK_KP_7: *key = K_KP_HOME; break;
235
case XK_Home: *key = K_HOME; break;
238
case XK_KP_1: *key = K_KP_END; break;
239
case XK_End: *key = K_END; break;
241
case XK_KP_Left: *key = K_KP_LEFTARROW; break;
242
case XK_KP_4: *key = K_KP_LEFTARROW; break;
243
case XK_Left: *key = K_LEFTARROW; break;
245
case XK_KP_Right: *key = K_KP_RIGHTARROW; break;
246
case XK_KP_6: *key = K_KP_RIGHTARROW; break;
247
case XK_Right: *key = K_RIGHTARROW; break;
250
case XK_KP_2: *key = K_KP_DOWNARROW; break;
251
case XK_Down: *key = K_DOWNARROW; break;
254
case XK_KP_8: *key = K_KP_UPARROW; break;
255
case XK_Up: *key = K_UPARROW; break;
257
case XK_Escape: *key = K_ESCAPE; break;
259
case XK_KP_Enter: *key = K_KP_ENTER; break;
260
case XK_Return: *key = K_ENTER; break;
262
case XK_Tab: *key = K_TAB; break;
264
case XK_F1: *key = K_F1; break;
266
case XK_F2: *key = K_F2; break;
268
case XK_F3: *key = K_F3; break;
270
case XK_F4: *key = K_F4; break;
272
case XK_F5: *key = K_F5; break;
274
case XK_F6: *key = K_F6; break;
276
case XK_F7: *key = K_F7; break;
278
case XK_F8: *key = K_F8; break;
280
case XK_F9: *key = K_F9; break;
282
case XK_F10: *key = K_F10; break;
284
case XK_F11: *key = K_F11; break;
286
case XK_F12: *key = K_F12; break;
288
// bk001206 - from Ryan's Fakk2
289
//case XK_BackSpace: *key = 8; break; // ctrl-h
290
case XK_BackSpace: *key = K_BACKSPACE; break; // ctrl-h
293
case XK_KP_Decimal: *key = K_KP_DEL; break;
294
case XK_Delete: *key = K_DEL; break;
296
case XK_Pause: *key = K_PAUSE; break;
299
case XK_Shift_R: *key = K_SHIFT; break;
303
case XK_Control_R: *key = K_CTRL; break;
308
case XK_Meta_R: *key = K_ALT; break;
310
case XK_KP_Begin: *key = K_KP_5; break;
312
case XK_Insert: *key = K_INS; break;
314
case XK_KP_0: *key = K_KP_INS; break;
316
case XK_KP_Multiply: *key = '*'; break;
317
case XK_KP_Add: *key = K_KP_PLUS; break;
318
case XK_KP_Subtract: *key = K_KP_MINUS; break;
319
case XK_KP_Divide: *key = K_KP_SLASH; break;
321
// bk001130 - from cvs1.17 (mkv)
322
case XK_exclam: *key = '1'; break;
323
case XK_at: *key = '2'; break;
324
case XK_numbersign: *key = '3'; break;
325
case XK_dollar: *key = '4'; break;
326
case XK_percent: *key = '5'; break;
327
case XK_asciicircum: *key = '6'; break;
328
case XK_ampersand: *key = '7'; break;
329
case XK_asterisk: *key = '8'; break;
330
case XK_parenleft: *key = '9'; break;
331
case XK_parenright: *key = '0'; break;
333
// weird french keyboards ..
334
// NOTE: console toggle is hardcoded in cl_keys.c, can't be unbound
335
// cleaner would be .. using hardware key codes instead of the key syms
336
// could also add a new K_KP_CONSOLE
337
case XK_twosuperior: *key = '~'; break;
339
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=472
341
case XK_KP_Space: *key = K_SPACE; break;
346
if (com_developer->value)
348
ri.Printf(PRINT_ALL, "Warning: XLookupString failed on KeySym %d\n", keysym);
354
// XK_* tests failed, but XLookupString got a buffer, so let's try it
355
if (in_shiftedKeys->integer) {
356
*key = *(unsigned char *)buf;
357
if (*key >= 'A' && *key <= 'Z')
358
*key = *key - 'A' + 'a';
359
// if ctrl is pressed, the keys are not between 'A' and 'Z', for instance ctrl-z == 26 ^Z ^C etc.
360
// see https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=19
361
else if (*key >= 1 && *key <= 26)
362
*key = *key + 'a' - 1;
373
// ========================================================================
374
// makes a null cursor
375
// ========================================================================
377
static Cursor CreateNullCursor(Display *display, Window root)
385
cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
386
xgc.function = GXclear;
387
gc = XCreateGC(display, cursormask, GCFunction, &xgc);
388
XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
389
dummycolour.pixel = 0;
391
dummycolour.flags = 04;
392
cursor = XCreatePixmapCursor(display, cursormask, cursormask,
393
&dummycolour,&dummycolour, 0,0);
394
XFreePixmap(display,cursormask);
399
static void install_grabs(void)
402
XWarpPointer(dpy, None, win,
404
glConfig.vidWidth / 2, glConfig.vidHeight / 2);
407
XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
409
XGrabPointer(dpy, win, // bk010108 - do this earlier?
412
GrabModeAsync, GrabModeAsync,
417
XGetPointerControl(dpy, &mouse_accel_numerator, &mouse_accel_denominator,
420
XChangePointerControl(dpy, True, True, 1, 1, 0);
424
mouseResetTime = Sys_Milliseconds ();
427
if (in_dgamouse->value)
429
int MajorVersion, MinorVersion;
431
if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion))
433
// unable to query, probalby not supported, force the setting to 0
434
ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
435
ri.Cvar_Set( "in_dgamouse", "0" );
438
XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
439
XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
442
#endif /* HAVE_XF86DGA */
444
mwx = glConfig.vidWidth / 2;
445
mwy = glConfig.vidHeight / 2;
449
XGrabKeyboard(dpy, win,
451
GrabModeAsync, GrabModeAsync,
457
static void uninstall_grabs(void)
460
if (in_dgamouse->value)
462
if (com_developer->value)
463
ri.Printf( PRINT_ALL, "DGA Mouse - Disabling DGA DirectVideo\n" );
464
XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
466
#endif /* HAVE_XF86DGA */
468
XChangePointerControl(dpy, qtrue, qtrue, mouse_accel_numerator,
469
mouse_accel_denominator, mouse_threshold);
471
XUngrabPointer(dpy, CurrentTime);
472
XUngrabKeyboard(dpy, CurrentTime);
474
XWarpPointer(dpy, None, win,
476
glConfig.vidWidth / 2, glConfig.vidHeight / 2);
479
XUndefineCursor(dpy, win);
482
// bk001206 - from Ryan's Fakk2
484
* XPending() actually performs a blocking read
485
* if no events available. From Fakk2, by way of
486
* Heretic2, by way of SDL, original idea GGI project.
487
* The benefit of this approach over the quite
488
* badly behaved XAutoRepeatOn/Off is that you get
489
* focus handling for free, which is a major win
490
* with debug and windowed mode. It rests on the
491
* assumption that the X server will use the
492
* same timestamp on press/release event pairs
495
static qboolean X11_PendingInput(void) {
499
// Flush the display connection
500
// and look to see if events are queued
502
if ( XEventsQueued( dpy, QueuedAlready) )
507
// More drastic measures are required -- see if X is ready to talk
509
static struct timeval zero_time;
513
x11_fd = ConnectionNumber( dpy );
515
FD_SET(x11_fd, &fdset);
516
if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 )
518
return(XPending(dpy));
522
// Oh well, nothing is ready ..
526
// bk001206 - from Ryan's Fakk2. See above.
527
static qboolean repeated_press(XEvent *event)
530
qboolean repeated = qfalse;
534
if (X11_PendingInput())
536
XPeekEvent(dpy, &peekevent);
538
if ((peekevent.type == KeyPress) &&
539
(peekevent.xkey.keycode == event->xkey.keycode) &&
540
(peekevent.xkey.time == event->xkey.time))
543
XNextEvent(dpy, &peekevent); // skip event.
550
int Sys_XTimeToSysTime (Time xtime);
551
static void HandleEvents(void)
556
qboolean dowarp = qfalse;
559
int t = 0; // default to 0 in case we don't set
564
while (XPending(dpy))
566
XNextEvent(dpy, &event);
570
t = Sys_XTimeToSysTime(event.xkey.time);
571
p = XLateKey(&event.xkey, &key);
574
Sys_QueEvent( t, SE_KEY, key, qtrue, 0, NULL );
580
Sys_QueEvent( t, SE_CHAR, *p++, 0, 0, NULL );
586
t = Sys_XTimeToSysTime(event.xkey.time);
587
// bk001206 - handle key repeat w/o XAutRepatOn/Off
588
// also: not done if console/menu is active.
589
// From Ryan's Fakk2.
590
// see game/q_shared.h, KEYCATCH_* . 0 == in 3d game.
591
if (cls.keyCatchers == 0)
592
{ // FIXME: KEYCATCH_NONE
593
if (repeated_press(&event) == qtrue)
596
XLateKey(&event.xkey, &key);
598
Sys_QueEvent( t, SE_KEY, key, qfalse, 0, NULL );
602
t = Sys_XTimeToSysTime(event.xkey.time);
606
if (in_dgamouse->value)
608
mx += event.xmotion.x_root;
609
my += event.xmotion.y_root;
610
if (t - mouseResetTime > MOUSE_RESET_DELAY )
612
Sys_QueEvent( t, SE_MOUSE, mx, my, 0, NULL );
616
#endif /* HAVE_XF86DGA */
618
// If it's a center motion, we've just returned from our warp
619
if (event.xmotion.x == glConfig.vidWidth/2 &&
620
event.xmotion.y == glConfig.vidHeight/2)
622
mwx = glConfig.vidWidth/2;
623
mwy = glConfig.vidHeight/2;
624
if (t - mouseResetTime > MOUSE_RESET_DELAY )
626
Sys_QueEvent( t, SE_MOUSE, mx, my, 0, NULL );
632
dx = ((int)event.xmotion.x - mwx);
633
dy = ((int)event.xmotion.y - mwy);
637
mwx = event.xmotion.x;
638
mwy = event.xmotion.y;
645
t = Sys_XTimeToSysTime(event.xkey.time);
646
if (event.xbutton.button == 4)
648
Sys_QueEvent( t, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );
649
} else if (event.xbutton.button == 5)
651
Sys_QueEvent( t, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );
654
// NOTE TTimo there seems to be a weird mapping for K_MOUSE1 K_MOUSE2 K_MOUSE3 ..
656
if (event.xbutton.button == 1)
659
} else if (event.xbutton.button == 2)
662
} else if (event.xbutton.button == 3)
665
} else if (event.xbutton.button == 6)
668
} else if (event.xbutton.button == 7)
673
Sys_QueEvent( t, SE_KEY, K_MOUSE1 + b, qtrue, 0, NULL );
678
t = Sys_XTimeToSysTime(event.xkey.time);
679
if (event.xbutton.button == 4)
681
Sys_QueEvent( t, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );
682
} else if (event.xbutton.button == 5)
684
Sys_QueEvent( t, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );
688
if (event.xbutton.button == 1)
691
} else if (event.xbutton.button == 2)
694
} else if (event.xbutton.button == 3)
697
} else if (event.xbutton.button == 6)
700
} else if (event.xbutton.button == 7)
704
Sys_QueEvent( t, SE_KEY, K_MOUSE1 + b, qfalse, 0, NULL );
709
win_x = event.xcreatewindow.x;
710
win_y = event.xcreatewindow.y;
713
case ConfigureNotify :
714
win_x = event.xconfigure.x;
715
win_y = event.xconfigure.y;
722
XWarpPointer(dpy,None,win,0,0,0,0,
723
(glConfig.vidWidth/2),(glConfig.vidHeight/2));
727
// NOTE TTimo for the tty console input, we didn't rely on those ..
728
// it's not very surprising actually cause they are not used otherwise
737
void IN_ActivateMouse( void )
739
if (!mouse_avail || !dpy || !win)
744
if (!in_nograb->value)
746
else if (in_dgamouse->value) // force dga mouse to 0 if using nograb
747
ri.Cvar_Set("in_dgamouse", "0");
748
mouse_active = qtrue;
752
void IN_DeactivateMouse( void )
754
if (!mouse_avail || !dpy || !win)
759
if (!in_nograb->value)
761
else if (in_dgamouse->value) // force dga mouse to 0 if using nograb
762
ri.Cvar_Set("in_dgamouse", "0");
763
mouse_active = qfalse;
766
/*****************************************************************************/
771
** This routine should only be called if glConfig.deviceSupportsGamma is TRUE
773
void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] )
775
// NOTE TTimo we get the gamma value from cvar, because we can't work with the s_gammatable
776
// the API wasn't changed to avoid breaking other OSes
778
float g = Cvar_Get("r_gamma", "1.0", 0)->value;
779
XF86VidModeGamma gamma;
780
assert(glConfig.deviceSupportsGamma);
784
XF86VidModeSetGamma(dpy, scrnum, &gamma);
785
#endif /* HAVE_XF86DGA */
791
** This routine does all OS specific shutdown procedures for the OpenGL
792
** subsystem. Under OpenGL this means NULLing out the current DC and
793
** HGLRC, deleting the rendering context, and releasing the DC acquired
794
** for the window. The state structure is also nulled out.
797
void GLimp_Shutdown( void )
801
IN_DeactivateMouse();
802
// bk001206 - replaced with H2/Fakk2 solution
803
// XAutoRepeatOn(dpy);
804
// autorepeaton = qfalse; // bk001130 - from cvs1.17 (mkv)
808
qglXDestroyContext(dpy, ctx);
810
XDestroyWindow(dpy, win);
813
XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]);
814
if (glConfig.deviceSupportsGamma)
816
XF86VidModeSetGamma(dpy, scrnum, &vidmode_InitialGamma);
818
#endif /* HAVE_XF86DGA */
819
// NOTE TTimo opening/closing the display should be necessary only once per run
820
// but it seems QGL_Shutdown gets called in a lot of occasion
821
// in some cases, this XCloseDisplay is known to raise some X errors
822
// ( https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=33 )
825
vidmode_active = qfalse;
830
memset( &glConfig, 0, sizeof( glConfig ) );
831
memset( &glState, 0, sizeof( glState ) );
839
void GLimp_LogComment( char *comment )
841
if ( glw_state.log_fp )
843
fprintf( glw_state.log_fp, "%s", comment );
848
** GLW_StartDriverAndSetMode
850
// bk001204 - prototype needed
851
int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen );
852
static qboolean GLW_StartDriverAndSetMode( const char *drivername,
854
qboolean fullscreen )
858
// don't ever bother going into fullscreen with a voodoo card
859
#if 1 // JDC: I reenabled this
860
if ( Q_stristr( drivername, "Voodoo" ) )
862
ri.Cvar_Set( "r_fullscreen", "0" );
863
r_fullscreen->modified = qfalse;
868
if (fullscreen && in_nograb->value)
870
ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n");
871
ri.Cvar_Set( "r_fullscreen", "0" );
872
r_fullscreen->modified = qfalse;
876
err = GLW_SetMode( drivername, mode, fullscreen );
880
case RSERR_INVALID_FULLSCREEN:
881
ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" );
883
case RSERR_INVALID_MODE:
884
ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode );
895
int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen )
899
GLX_RED_SIZE, 4, // 1, 2
900
GLX_GREEN_SIZE, 4, // 3, 4
901
GLX_BLUE_SIZE, 4, // 5, 6
902
GLX_DOUBLEBUFFER, // 7
903
GLX_DEPTH_SIZE, 1, // 8, 9
904
GLX_STENCIL_SIZE, 1, // 10, 11
907
// these match in the array
908
#define ATTR_RED_IDX 2
909
#define ATTR_GREEN_IDX 4
910
#define ATTR_BLUE_IDX 6
911
#define ATTR_DEPTH_IDX 9
912
#define ATTR_STENCIL_IDX 11
914
XVisualInfo *visinfo;
915
XSetWindowAttributes attr;
916
XSizeHints sizehints;
918
int colorbits, depthbits, stencilbits;
919
int tcolorbits, tdepthbits, tstencilbits;
920
int dga_MajorVersion, dga_MinorVersion;
921
int actualWidth, actualHeight;
923
const char* glstring; // bk001130 - from cvs1.17 (mkv)
925
ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");
927
ri.Printf (PRINT_ALL, "...setting mode %d:", mode );
929
if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) )
931
ri.Printf( PRINT_ALL, " invalid mode\n" );
932
return RSERR_INVALID_MODE;
934
ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);
936
if (!(dpy = XOpenDisplay(NULL)))
938
fprintf(stderr, "Error couldn't open the X display\n");
939
return RSERR_INVALID_MODE;
942
scrnum = DefaultScreen(dpy);
943
root = RootWindow(dpy, scrnum);
945
actualWidth = glConfig.vidWidth;
946
actualHeight = glConfig.vidHeight;
948
// Get video mode list
950
if (!XF86VidModeQueryVersion(dpy, &vidmode_MajorVersion, &vidmode_MinorVersion))
952
#endif /* HAVE_XF86DGA */
953
vidmode_ext = qfalse;
957
ri.Printf(PRINT_ALL, "Using XFree86-VidModeExtension Version %d.%d\n",
958
vidmode_MajorVersion, vidmode_MinorVersion);
961
#endif /* HAVE_XF86DGA */
964
dga_MajorVersion = 0, dga_MinorVersion = 0;
966
if (in_dgamouse->value)
968
if (!XF86DGAQueryVersion(dpy, &dga_MajorVersion, &dga_MinorVersion))
970
// unable to query, probably not supported
971
ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
972
ri.Cvar_Set( "in_dgamouse", "0" );
975
ri.Printf( PRINT_ALL, "XF86DGA Mouse (Version %d.%d) initialized\n",
976
dga_MajorVersion, dga_MinorVersion);
979
#endif /* HAVE_XF86DGA */
984
int best_fit, best_dist, dist, x, y;
986
XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
988
// Are we going fullscreen? If so, let's change video mode
994
for (i = 0; i < num_vidmodes; i++)
996
if (glConfig.vidWidth > vidmodes[i]->hdisplay ||
997
glConfig.vidHeight > vidmodes[i]->vdisplay)
1000
x = glConfig.vidWidth - vidmodes[i]->hdisplay;
1001
y = glConfig.vidHeight - vidmodes[i]->vdisplay;
1002
dist = (x * x) + (y * y);
1003
if (dist < best_dist)
1012
actualWidth = vidmodes[best_fit]->hdisplay;
1013
actualHeight = vidmodes[best_fit]->vdisplay;
1015
// change to the mode
1016
XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
1017
vidmode_active = qtrue;
1019
// Move the viewport to top left
1020
XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
1022
ri.Printf(PRINT_ALL, "XFree86-VidModeExtension Activated at %dx%d\n",
1023
actualWidth, actualHeight);
1028
ri.Printf(PRINT_ALL, "XFree86-VidModeExtension: No acceptable modes found\n");
1032
ri.Printf(PRINT_ALL, "XFree86-VidModeExtension: Ignored on non-fullscreen/Voodoo\n");
1035
#endif /* HAVE_XF86DGA */
1038
if (!r_colorbits->value)
1041
colorbits = r_colorbits->value;
1043
if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
1046
if (!r_depthbits->value)
1049
depthbits = r_depthbits->value;
1050
stencilbits = r_stencilbits->value;
1052
for (i = 0; i < 16; i++)
1055
// 1 - minus colorbits
1056
// 2 - minus depthbits
1057
// 3 - minus stencil
1058
if ((i % 4) == 0 && i)
1064
if (colorbits == 24)
1068
if (depthbits == 24)
1070
else if (depthbits == 16)
1073
if (stencilbits == 24)
1075
else if (stencilbits == 16)
1080
tcolorbits = colorbits;
1081
tdepthbits = depthbits;
1082
tstencilbits = stencilbits;
1085
{ // reduce colorbits
1086
if (tcolorbits == 24)
1091
{ // reduce depthbits
1092
if (tdepthbits == 24)
1094
else if (tdepthbits == 16)
1099
{ // reduce stencilbits
1100
if (tstencilbits == 24)
1102
else if (tstencilbits == 16)
1108
if (tcolorbits == 24)
1110
attrib[ATTR_RED_IDX] = 8;
1111
attrib[ATTR_GREEN_IDX] = 8;
1112
attrib[ATTR_BLUE_IDX] = 8;
1116
attrib[ATTR_RED_IDX] = 4;
1117
attrib[ATTR_GREEN_IDX] = 4;
1118
attrib[ATTR_BLUE_IDX] = 4;
1121
attrib[ATTR_DEPTH_IDX] = tdepthbits; // default to 24 depth
1122
attrib[ATTR_STENCIL_IDX] = tstencilbits;
1124
visinfo = qglXChooseVisual(dpy, scrnum, attrib);
1130
ri.Printf( PRINT_ALL, "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n",
1131
attrib[ATTR_RED_IDX], attrib[ATTR_GREEN_IDX], attrib[ATTR_BLUE_IDX],
1132
attrib[ATTR_DEPTH_IDX], attrib[ATTR_STENCIL_IDX]);
1134
glConfig.colorBits = tcolorbits;
1135
glConfig.depthBits = tdepthbits;
1136
glConfig.stencilBits = tstencilbits;
1142
ri.Printf( PRINT_ALL, "Couldn't get a visual\n" );
1143
return RSERR_INVALID_MODE;
1146
/* window attributes */
1147
attr.background_pixel = BlackPixel(dpy, scrnum);
1148
attr.border_pixel = 0;
1149
attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
1150
attr.event_mask = X_MASK;
1153
mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore |
1154
CWEventMask | CWOverrideRedirect;
1155
attr.override_redirect = True;
1156
attr.backing_store = NotUseful;
1157
attr.save_under = False;
1159
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
1161
win = XCreateWindow(dpy, root, 0, 0,
1162
actualWidth, actualHeight,
1163
0, visinfo->depth, InputOutput,
1164
visinfo->visual, mask, &attr);
1166
XStoreName( dpy, win, CLIENT_WINDOW_TITLE );
1168
/* GH: Don't let the window be resized */
1169
sizehints.flags = PMinSize | PMaxSize;
1170
sizehints.min_width = sizehints.max_width = actualWidth;
1171
sizehints.min_height = sizehints.max_height = actualHeight;
1173
XSetWMNormalHints( dpy, win, &sizehints );
1175
XMapWindow( dpy, win );
1178
XMoveWindow(dpy, win, 0, 0);
1181
XSync(dpy,False); // bk001130 - from cvs1.17 (mkv)
1182
ctx = qglXCreateContext(dpy, visinfo, NULL, True);
1183
XSync(dpy,False); // bk001130 - from cvs1.17 (mkv)
1185
/* GH: Free the visinfo after we're done with it */
1188
qglXMakeCurrent(dpy, win, ctx);
1190
// bk001130 - from cvs1.17 (mkv)
1191
glstring = (char *)qglGetString (GL_RENDERER);
1192
ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glstring );
1194
// bk010122 - new software token (Indirect)
1195
if ( !Q_stricmp( glstring, "Mesa X11")
1196
|| !Q_stricmp( glstring, "Mesa GLX Indirect") )
1198
if ( !r_allowSoftwareGL->integer )
1200
ri.Printf( PRINT_ALL, "\n\n***********************************************************\n" );
1201
ri.Printf( PRINT_ALL, " You are using software Mesa (no hardware acceleration)! \n" );
1202
ri.Printf( PRINT_ALL, " Driver DLL used: %s\n", drivername );
1203
ri.Printf( PRINT_ALL, " If this is intentional, add\n" );
1204
ri.Printf( PRINT_ALL, " \"+set r_allowSoftwareGL 1\"\n" );
1205
ri.Printf( PRINT_ALL, " to the command line when starting the game.\n" );
1206
ri.Printf( PRINT_ALL, "***********************************************************\n");
1208
return RSERR_INVALID_MODE;
1211
ri.Printf( PRINT_ALL, "...using software Mesa (r_allowSoftwareGL==1).\n" );
1219
** GLW_InitExtensions
1221
static void GLW_InitExtensions( void )
1223
if ( !r_allowExtensions->integer )
1225
ri.Printf( PRINT_ALL, "*** IGNORING OPENGL EXTENSIONS ***\n" );
1229
ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" );
1232
if ( Q_stristr( glConfig.extensions_string, "GL_S3_s3tc" ) )
1234
if ( r_ext_compressed_textures->value )
1236
glConfig.textureCompression = TC_S3TC;
1237
ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" );
1240
glConfig.textureCompression = TC_NONE;
1241
ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" );
1245
glConfig.textureCompression = TC_NONE;
1246
ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" );
1249
// GL_EXT_texture_env_add
1250
glConfig.textureEnvAddAvailable = qfalse;
1251
if ( Q_stristr( glConfig.extensions_string, "EXT_texture_env_add" ) )
1253
if ( r_ext_texture_env_add->integer )
1255
glConfig.textureEnvAddAvailable = qtrue;
1256
ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" );
1259
glConfig.textureEnvAddAvailable = qfalse;
1260
ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" );
1264
ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" );
1267
// GL_ARB_multitexture
1268
qglMultiTexCoord2fARB = NULL;
1269
qglActiveTextureARB = NULL;
1270
qglClientActiveTextureARB = NULL;
1271
if ( Q_stristr( glConfig.extensions_string, "GL_ARB_multitexture" ) )
1273
if ( r_ext_multitexture->value )
1275
qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) dlsym( glw_state.OpenGLLib, "glMultiTexCoord2fARB" );
1276
qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glActiveTextureARB" );
1277
qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glClientActiveTextureARB" );
1279
if ( qglActiveTextureARB )
1282
qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glint );
1283
glConfig.maxActiveTextures = (int) glint;
1285
if ( glConfig.maxActiveTextures > 1 )
1287
ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" );
1290
qglMultiTexCoord2fARB = NULL;
1291
qglActiveTextureARB = NULL;
1292
qglClientActiveTextureARB = NULL;
1293
ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" );
1298
ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" );
1302
ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" );
1305
// GL_EXT_compiled_vertex_array
1306
if ( Q_stristr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) )
1308
if ( r_ext_compiled_vertex_array->value )
1310
ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" );
1311
qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) dlsym( glw_state.OpenGLLib, "glLockArraysEXT" );
1312
qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) dlsym( glw_state.OpenGLLib, "glUnlockArraysEXT" );
1313
if (!qglLockArraysEXT || !qglUnlockArraysEXT)
1315
ri.Error (ERR_FATAL, "bad getprocaddress");
1319
ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" );
1323
ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" );
1326
textureFilterAnisotropic = qfalse;
1327
if ( strstr( glConfig.extensions_string, "GL_EXT_texture_filter_anisotropic" ) )
1329
if ( r_ext_texture_filter_anisotropic->integer ) {
1330
qglGetIntegerv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy );
1331
if ( maxAnisotropy <= 0 ) {
1332
ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not properly supported!\n" );
1337
ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic (max: %i)\n", maxAnisotropy );
1338
textureFilterAnisotropic = qtrue;
1343
ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" );
1348
ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" );
1352
static void GLW_InitGamma(void)
1354
/* Minimum extension version required */
1355
#define GAMMA_MINMAJOR 2
1356
#define GAMMA_MINMINOR 0
1358
glConfig.deviceSupportsGamma = qfalse;
1363
if (vidmode_MajorVersion < GAMMA_MINMAJOR ||
1364
(vidmode_MajorVersion == GAMMA_MINMAJOR && vidmode_MinorVersion < GAMMA_MINMINOR)) {
1365
ri.Printf( PRINT_ALL, "XF86 Gamma extension not supported in this version\n");
1368
XF86VidModeGetGamma(dpy, scrnum, &vidmode_InitialGamma);
1369
ri.Printf( PRINT_ALL, "XF86 Gamma extension initialized\n");
1370
glConfig.deviceSupportsGamma = qtrue;
1372
#endif /* HAVE_XF86DGA */
1378
** GLimp_win.c internal function that that attempts to load and use
1379
** a specific OpenGL DLL.
1381
static qboolean GLW_LoadOpenGL( const char *name )
1383
qboolean fullscreen;
1385
ri.Printf( PRINT_ALL, "...loading %s: ", name );
1387
// disable the 3Dfx splash screen and set gamma
1388
// we do this all the time, but it shouldn't hurt anything
1389
// on non-3Dfx stuff
1390
putenv("FX_GLIDE_NO_SPLASH=0");
1392
// Mesa VooDoo hacks
1393
putenv("MESA_GLX_FX=fullscreen\n");
1395
// load the QGL layer
1396
if ( QGL_Init( name ) )
1398
fullscreen = r_fullscreen->integer;
1400
// create the window and set up the context
1401
if ( !GLW_StartDriverAndSetMode( name, r_mode->integer, fullscreen ) )
1403
if (r_mode->integer != 3)
1405
if ( !GLW_StartDriverAndSetMode( name, 3, fullscreen ) )
1416
ri.Printf( PRINT_ALL, "failed\n" );
1427
** the default X error handler exits the application
1428
** I found out that on some hosts some operations would raise X errors (GLXUnsupportedPrivateRequest)
1429
** but those don't seem to be fatal .. so the default would be to just ignore them
1430
** our implementation mimics the default handler behaviour (not completely cause I'm lazy)
1432
int qXErrorHandler(Display *dpy, XErrorEvent *ev)
1434
static char buf[1024];
1435
XGetErrorText(dpy, ev->error_code, buf, 1024);
1436
ri.Printf( PRINT_ALL, "X Error of failed request: %s\n", buf);
1437
ri.Printf( PRINT_ALL, " Major opcode of failed request: %d\n", ev->request_code, buf);
1438
ri.Printf( PRINT_ALL, " Minor opcode of failed request: %d\n", ev->minor_code);
1439
ri.Printf( PRINT_ALL, " Serial number of failed request: %d\n", ev->serial);
1446
** This routine is responsible for initializing the OS specific portions
1449
void GLimp_Init( void )
1451
qboolean attemptedlibGL = qfalse;
1452
qboolean attempted3Dfx = qfalse;
1453
qboolean success = qfalse;
1455
cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE );
1457
// guarded, as this is only relevant to SMP renderer thread
1459
if (!XInitThreads())
1461
Com_Printf("GLimp_Init() - XInitThreads() failed, disabling r_smp\n");
1462
ri.Cvar_Set( "r_smp", "0" );
1466
r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH );
1468
r_previousglDriver = ri.Cvar_Get( "r_previousglDriver", "", CVAR_ROM );
1472
IN_Init(); // rcg08312005 moved into glimp.
1474
// Hack here so that if the UI
1475
if ( *r_previousglDriver->string )
1477
// The UI changed it on us, hack it back
1478
// This means the renderer can't be changed on the fly
1479
ri.Cvar_Set( "r_glDriver", r_previousglDriver->string );
1482
// set up our custom error handler for X failures
1483
XSetErrorHandler(&qXErrorHandler);
1486
// load and initialize the specific OpenGL driver
1488
if ( !GLW_LoadOpenGL( r_glDriver->string ) )
1490
if ( !Q_stricmp( r_glDriver->string, OPENGL_DRIVER_NAME ) )
1492
attemptedlibGL = qtrue;
1493
} else if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
1495
attempted3Dfx = qtrue;
1500
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=455
1501
// old legacy load code, was confusing people who had a bad OpenGL setup
1502
if ( !attempted3Dfx && !success )
1504
attempted3Dfx = qtrue;
1505
if ( GLW_LoadOpenGL( _3DFX_DRIVER_NAME ) )
1507
ri.Cvar_Set( "r_glDriver", _3DFX_DRIVER_NAME );
1508
r_glDriver->modified = qfalse;
1514
// try ICD before trying 3Dfx standalone driver
1515
if ( !attemptedlibGL && !success )
1517
attemptedlibGL = qtrue;
1518
if ( GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) )
1520
ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME );
1521
r_glDriver->modified = qfalse;
1527
ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" );
1531
// Save it in case the UI stomps it
1532
ri.Cvar_Set( "r_previousglDriver", r_glDriver->string );
1534
// This values force the UI to disable driver selection
1535
glConfig.driverType = GLDRV_ICD;
1536
glConfig.hardwareType = GLHW_GENERIC;
1538
// get our config strings
1539
Q_strncpyz( glConfig.vendor_string, (char *)qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) );
1540
Q_strncpyz( glConfig.renderer_string, (char *)qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) );
1541
if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n')
1542
glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0;
1543
Q_strncpyz( glConfig.version_string, (char *)qglGetString (GL_VERSION), sizeof( glConfig.version_string ) );
1544
Q_strncpyz( glConfig.extensions_string, (char *)qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) );
1547
// chipset specific configuration
1549
strcpy( buf, glConfig.renderer_string );
1553
// NOTE: if changing cvars, do it within this block. This allows them
1554
// to be overridden when testing driver fixes, etc. but only sets
1555
// them to their default state when the hardware is first installed/run.
1557
if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) )
1559
glConfig.hardwareType = GLHW_GENERIC;
1561
ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );
1563
// VOODOO GRAPHICS w/ 2MB
1564
if ( Q_stristr( buf, "voodoo graphics/1 tmu/2 mb" ) )
1566
ri.Cvar_Set( "r_picmip", "2" );
1567
ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
1570
ri.Cvar_Set( "r_picmip", "1" );
1572
if ( Q_stristr( buf, "rage 128" ) || Q_stristr( buf, "rage128" ) )
1574
ri.Cvar_Set( "r_finish", "0" );
1576
// Savage3D and Savage4 should always have trilinear enabled
1577
else if ( Q_stristr( buf, "savage3d" ) || Q_stristr( buf, "s3 savage4" ) )
1579
ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
1585
// this is where hardware specific workarounds that should be
1586
// detected/initialized every startup should go.
1588
if ( Q_stristr( buf, "banshee" ) || Q_stristr( buf, "Voodoo_Graphics" ) )
1590
glConfig.hardwareType = GLHW_3DFX_2D3D;
1591
} else if ( Q_stristr( buf, "rage pro" ) || Q_stristr( buf, "RagePro" ) )
1593
glConfig.hardwareType = GLHW_RAGEPRO;
1594
} else if ( Q_stristr( buf, "permedia2" ) )
1596
glConfig.hardwareType = GLHW_PERMEDIA2;
1597
} else if ( Q_stristr( buf, "riva 128" ) )
1599
glConfig.hardwareType = GLHW_RIVA128;
1600
} else if ( Q_stristr( buf, "riva tnt " ) )
1604
ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string );
1606
// initialize extensions
1607
GLW_InitExtensions();
1610
InitSig(); // not clear why this is at begin & end of function
1619
** Responsible for doing a swapbuffers and possibly for other stuff
1620
** as yet to be determined. Probably better not to make this a GLimp
1621
** function and instead do a call to GLimp_SwapBuffers.
1623
void GLimp_EndFrame (void)
1625
// don't flip if drawing to front buffer
1626
if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 )
1628
qglXSwapBuffers(dpy, win);
1632
QGL_EnableLogging( (qboolean)r_logFile->integer ); // bk001205 - was ->value
1637
===========================================================
1641
===========================================================
1644
static pthread_mutex_t smpMutex = PTHREAD_MUTEX_INITIALIZER;
1646
static pthread_cond_t renderCommandsEvent = PTHREAD_COND_INITIALIZER;
1647
static pthread_cond_t renderCompletedEvent = PTHREAD_COND_INITIALIZER;
1649
static void (*glimpRenderThread)( void );
1651
static void *GLimp_RenderThreadWrapper( void *arg )
1653
Com_Printf( "Render thread starting\n" );
1655
glimpRenderThread();
1657
qglXMakeCurrent( dpy, None, NULL );
1659
Com_Printf( "Render thread terminating\n" );
1664
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
1666
pthread_t renderThread;
1669
pthread_mutex_init( &smpMutex, NULL );
1671
pthread_cond_init( &renderCommandsEvent, NULL );
1672
pthread_cond_init( &renderCompletedEvent, NULL );
1674
glimpRenderThread = function;
1676
ret = pthread_create( &renderThread,
1678
GLimp_RenderThreadWrapper,
1681
ri.Printf( PRINT_ALL, "pthread_create returned %d: %s", ret, strerror( ret ) );
1684
ret = pthread_detach( renderThread );
1686
ri.Printf( PRINT_ALL, "pthread_detach returned %d: %s", ret, strerror( ret ) );
1693
static volatile void *smpData = NULL;
1694
static volatile qboolean smpDataReady;
1696
void *GLimp_RendererSleep( void )
1700
qglXMakeCurrent( dpy, None, NULL );
1702
pthread_mutex_lock( &smpMutex );
1705
smpDataReady = qfalse;
1707
// after this, the front end can exit GLimp_FrontEndSleep
1708
pthread_cond_signal( &renderCompletedEvent );
1710
while ( !smpDataReady ) {
1711
pthread_cond_wait( &renderCommandsEvent, &smpMutex );
1714
data = (void *)smpData;
1716
pthread_mutex_unlock( &smpMutex );
1718
qglXMakeCurrent( dpy, win, ctx );
1723
void GLimp_FrontEndSleep( void )
1725
pthread_mutex_lock( &smpMutex );
1728
pthread_cond_wait( &renderCompletedEvent, &smpMutex );
1731
pthread_mutex_unlock( &smpMutex );
1733
qglXMakeCurrent( dpy, win, ctx );
1736
void GLimp_WakeRenderer( void *data )
1738
qglXMakeCurrent( dpy, None, NULL );
1740
pthread_mutex_lock( &smpMutex );
1742
assert( smpData == NULL );
1744
smpDataReady = qtrue;
1746
// after this, the renderer can continue through GLimp_RendererSleep
1747
pthread_cond_signal( &renderCommandsEvent );
1749
pthread_mutex_unlock( &smpMutex );
1754
void GLimp_RenderThreadWrapper( void *stub ) {}
1755
qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) {
1756
ri.Printf( PRINT_WARNING, "ERROR: SMP support was disabled at compile time\n");
1759
void *GLimp_RendererSleep( void ) {
1762
void GLimp_FrontEndSleep( void ) {}
1763
void GLimp_WakeRenderer( void *data ) {}
1767
/*****************************************************************************/
1769
/*****************************************************************************/
1771
void IN_Init(void) {
1772
Com_Printf ("\n------- Input Initialization -------\n");
1774
in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
1775
in_dgamouse = Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE);
1776
in_shiftedKeys = Cvar_Get ("in_shiftedKeys", "0", CVAR_ARCHIVE);
1778
// turn on-off sub-frame timing of X events
1779
in_subframe = Cvar_Get ("in_subframe", "1", CVAR_ARCHIVE);
1781
// developer feature, allows to break without loosing mouse pointer
1782
in_nograb = Cvar_Get ("in_nograb", "0", 0);
1784
// bk001130 - from cvs.17 (mkv), joystick variables
1785
in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH);
1786
// bk001130 - changed this to match win32
1787
in_joystickDebug = Cvar_Get ("in_debugjoystick", "0", CVAR_TEMP);
1788
joy_threshold = Cvar_Get ("joy_threshold", "0.15", CVAR_ARCHIVE); // FIXME: in_joythreshold
1790
Cvar_Set( "cl_platformSensitivity", "2.0" );
1792
if (in_mouse->value)
1793
mouse_avail = qtrue;
1795
mouse_avail = qfalse;
1797
IN_StartupJoystick( ); // bk001130 - from cvs1.17 (mkv)
1798
Com_Printf ("------------------------------------\n");
1801
void IN_Shutdown(void)
1803
mouse_avail = qfalse;
1806
void IN_Frame (void) {
1808
// bk001130 - from cvs 1.17 (mkv)
1809
IN_JoyMove(); // FIXME: disable if on desktop?
1811
if ( cls.keyCatchers & KEYCATCH_CONSOLE )
1813
// temporarily deactivate if not in the game and
1814
// running on the desktop
1815
// voodoo always counts as full screen
1816
if (Cvar_VariableValue ("r_fullscreen") == 0
1817
&& strcmp( Cvar_VariableString("r_glDriver"), _3DFX_DRIVER_NAME ) )
1819
IN_DeactivateMouse ();
1827
void IN_Activate(void)
1831
// bk001130 - cvs1.17 joystick code (mkv) was here, no linux_joystick.c
1833
void Sys_SendKeyEvents (void) {
1834
// XEvent event; // bk001204 - unused
1842
// bk010216 - added stubs for non-Linux UNIXes here
1843
// FIXME - use NO_JOYSTICK or something else generic
1845
#if (defined( __FreeBSD__ ) || defined( __sun)) // rb010123
1846
void IN_StartupJoystick( void ) {}
1847
void IN_JoyMove( void ) {}
1850
#endif // !USE_SDL_VIDEO