~ubuntu-branches/ubuntu/precise/openarena/precise

« back to all changes in this revision

Viewing changes to code/unix/linux_glimp.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
===========================================================================
 
3
Copyright (C) 1999-2005 Id Software, Inc.
 
4
 
 
5
This file is part of Quake III Arena source code.
 
6
 
 
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.
 
11
 
 
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.
 
16
 
 
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
===========================================================================
 
21
*/
 
22
/*
 
23
** GLW_IMP.C
 
24
**
 
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:
 
28
**
 
29
** GLimp_EndFrame
 
30
** GLimp_Init
 
31
** GLimp_Shutdown
 
32
** GLimp_SwitchFullscreen
 
33
** GLimp_SetGamma
 
34
**
 
35
*/
 
36
 
 
37
#if !USE_SDL_VIDEO
 
38
 
 
39
#include <termios.h>
 
40
#include <sys/ioctl.h>
 
41
#ifdef __linux__
 
42
  #include <sys/stat.h>
 
43
  #include <sys/vt.h>
 
44
#endif
 
45
#include <stdarg.h>
 
46
#include <stdio.h>
 
47
#include <signal.h>
 
48
#include <pthread.h>
 
49
#include <semaphore.h>
 
50
 
 
51
// bk001204
 
52
#include <dlfcn.h>
 
53
 
 
54
// bk001206 - from my Heretic2 by way of Ryan's Fakk2
 
55
// Needed for the new X11_PendingInput() function.
 
56
#include <sys/time.h>
 
57
#include <sys/types.h>
 
58
#include <unistd.h>
 
59
 
 
60
#include "../renderer/tr_local.h"
 
61
#include "../client/client.h"
 
62
#include "linux_local.h" // bk001130
 
63
 
 
64
#include "unix_glw.h"
 
65
 
 
66
#include <GL/glx.h>
 
67
 
 
68
#include <X11/keysym.h>
 
69
#include <X11/cursorfont.h>
 
70
 
 
71
#if !defined(__sun)
 
72
#include <X11/extensions/xf86dga.h>
 
73
#include <X11/extensions/xf86vmode.h>
 
74
#endif
 
75
 
 
76
#if defined(__sun)
 
77
#include <X11/Sunkeysym.h>
 
78
#endif
 
79
 
 
80
#ifdef _XF86DGA_H_
 
81
#define HAVE_XF86DGA
 
82
#endif
 
83
 
 
84
typedef enum
 
85
{
 
86
  RSERR_OK,
 
87
 
 
88
  RSERR_INVALID_FULLSCREEN,
 
89
  RSERR_INVALID_MODE,
 
90
 
 
91
  RSERR_UNKNOWN
 
92
} rserr_t;
 
93
 
 
94
glwstate_t glw_state;
 
95
 
 
96
static Display *dpy = NULL;
 
97
static int scrnum;
 
98
static Window win = 0;
 
99
static GLXContext ctx = NULL;
 
100
 
 
101
// bk001206 - not needed anymore
 
102
// static qboolean autorepeaton = qtrue;
 
103
 
 
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 )
 
108
 
 
109
static qboolean mouse_avail;
 
110
static qboolean mouse_active = qfalse;
 
111
static int mwx, mwy;
 
112
static int mx = 0, my = 0;
 
113
 
 
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
 
117
 
 
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)
 
121
cvar_t *in_subframe;
 
122
cvar_t *in_nograb; // this is strictly for developers
 
123
 
 
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;
 
128
 
 
129
cvar_t  *r_allowSoftwareGL;   // don't abort out if the pixelformat claims software
 
130
cvar_t  *r_previousglDriver;
 
131
 
 
132
qboolean vidmode_ext = qfalse;
 
133
#ifdef HAVE_XF86DGA
 
134
static int vidmode_MajorVersion = 0, vidmode_MinorVersion = 0; // major and minor of XF86VidExtensions
 
135
 
 
136
// gamma value of the X display before we start playing with it
 
137
static XF86VidModeGamma vidmode_InitialGamma;
 
138
#endif /* HAVE_XF86DGA */
 
139
 
 
140
static int win_x, win_y;
 
141
 
 
142
#ifdef HAVE_XF86DGA
 
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;
 
148
 
 
149
static int mouse_accel_numerator;
 
150
static int mouse_accel_denominator;
 
151
static int mouse_threshold;    
 
152
 
 
153
/*
 
154
* Find the first occurrence of find in s.
 
155
*/
 
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)
 
159
{
 
160
  register char c, sc;
 
161
  register size_t len;
 
162
 
 
163
  if ((c = *find++) != 0)
 
164
  {
 
165
    if (c >= 'a' && c <= 'z')
 
166
    {
 
167
      c -= ('a' - 'A');
 
168
    }
 
169
    len = strlen(find);
 
170
    do
 
171
    {
 
172
      do
 
173
      {
 
174
        if ((sc = *s++) == 0)
 
175
          return NULL;
 
176
        if (sc >= 'a' && sc <= 'z')
 
177
        {
 
178
          sc -= ('a' - 'A');
 
179
        }
 
180
      } while (sc != c);
 
181
    } while (Q_stricmpn(s, find, len) != 0);
 
182
    s--;
 
183
  }
 
184
  return s;
 
185
}
 
186
 
 
187
/*****************************************************************************
 
188
** KEYBOARD
 
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)
 
194
**
 
195
** you can turn on some debugging and verbose of the keyboard code with #define KBD_DBG
 
196
******************************************************************************/
 
197
 
 
198
//#define KBD_DBG
 
199
 
 
200
static char *XLateKey(XKeyEvent *ev, int *key)
 
201
{
 
202
  static char buf[64];
 
203
  static char bufnomod[2];
 
204
  KeySym keysym;
 
205
  int XLookupRet;
 
206
 
 
207
  *key = 0;
 
208
 
 
209
  XLookupRet = XLookupString(ev, buf, sizeof buf, &keysym, 0);
 
210
#ifdef KBD_DBG
 
211
  ri.Printf(PRINT_ALL, "XLookupString ret: %d buf: %s keysym: %x\n", XLookupRet, buf, keysym);
 
212
#endif
 
213
 
 
214
  if (!in_shiftedKeys->integer) {
 
215
    // also get a buffer without modifiers held
 
216
    ev->state = 0;
 
217
    XLookupRet = XLookupString(ev, bufnomod, sizeof bufnomod, &keysym, 0);
 
218
#ifdef KBD_DBG
 
219
  ri.Printf(PRINT_ALL, "XLookupString (minus modifiers) ret: %d buf: %s keysym: %x\n", XLookupRet, buf, keysym);
 
220
#endif
 
221
  }
 
222
 
 
223
  switch (keysym)
 
224
  {
 
225
  case XK_KP_Page_Up:
 
226
  case XK_KP_9:  *key = K_KP_PGUP; break;
 
227
  case XK_Page_Up:   *key = K_PGUP; break;
 
228
 
 
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;
 
232
 
 
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;
 
236
 
 
237
  case XK_KP_End:
 
238
  case XK_KP_1:   *key = K_KP_END; break;
 
239
  case XK_End:   *key = K_END; break;
 
240
 
 
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;
 
244
 
 
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;
 
248
 
 
249
  case XK_KP_Down:
 
250
  case XK_KP_2:    *key = K_KP_DOWNARROW; break;
 
251
  case XK_Down:  *key = K_DOWNARROW; break;
 
252
 
 
253
  case XK_KP_Up:
 
254
  case XK_KP_8:    *key = K_KP_UPARROW; break;
 
255
  case XK_Up:    *key = K_UPARROW;   break;
 
256
 
 
257
  case XK_Escape: *key = K_ESCAPE;    break;
 
258
 
 
259
  case XK_KP_Enter: *key = K_KP_ENTER;  break;
 
260
  case XK_Return: *key = K_ENTER;    break;
 
261
 
 
262
  case XK_Tab:    *key = K_TAB;      break;
 
263
 
 
264
  case XK_F1:    *key = K_F1;       break;
 
265
 
 
266
  case XK_F2:    *key = K_F2;       break;
 
267
 
 
268
  case XK_F3:    *key = K_F3;       break;
 
269
 
 
270
  case XK_F4:    *key = K_F4;       break;
 
271
 
 
272
  case XK_F5:    *key = K_F5;       break;
 
273
 
 
274
  case XK_F6:    *key = K_F6;       break;
 
275
 
 
276
  case XK_F7:    *key = K_F7;       break;
 
277
 
 
278
  case XK_F8:    *key = K_F8;       break;
 
279
 
 
280
  case XK_F9:    *key = K_F9;       break;
 
281
 
 
282
  case XK_F10:    *key = K_F10;      break;
 
283
 
 
284
  case XK_F11:    *key = K_F11;      break;
 
285
 
 
286
  case XK_F12:    *key = K_F12;      break;
 
287
 
 
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
 
291
 
 
292
  case XK_KP_Delete:
 
293
  case XK_KP_Decimal: *key = K_KP_DEL; break;
 
294
  case XK_Delete: *key = K_DEL; break;
 
295
 
 
296
  case XK_Pause:  *key = K_PAUSE;    break;
 
297
 
 
298
  case XK_Shift_L:
 
299
  case XK_Shift_R:  *key = K_SHIFT;   break;
 
300
 
 
301
  case XK_Execute:
 
302
  case XK_Control_L:
 
303
  case XK_Control_R:  *key = K_CTRL;  break;
 
304
 
 
305
  case XK_Alt_L:
 
306
  case XK_Meta_L:
 
307
  case XK_Alt_R:
 
308
  case XK_Meta_R: *key = K_ALT;     break;
 
309
 
 
310
  case XK_KP_Begin: *key = K_KP_5;  break;
 
311
 
 
312
  case XK_Insert:   *key = K_INS; break;
 
313
  case XK_KP_Insert:
 
314
  case XK_KP_0: *key = K_KP_INS; break;
 
315
 
 
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;
 
320
 
 
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;
 
332
 
 
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;
 
338
 
 
339
  // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=472
 
340
  case XK_space:
 
341
  case XK_KP_Space: *key = K_SPACE; break;
 
342
 
 
343
  default:
 
344
    if (XLookupRet == 0)
 
345
    {
 
346
      if (com_developer->value)
 
347
      {
 
348
        ri.Printf(PRINT_ALL, "Warning: XLookupString failed on KeySym %d\n", keysym);
 
349
      }
 
350
      return NULL;
 
351
    }
 
352
    else
 
353
    {
 
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;
 
363
      } else {
 
364
        *key = bufnomod[0];
 
365
      }
 
366
    }
 
367
    break;
 
368
  }
 
369
 
 
370
  return buf;
 
371
}
 
372
 
 
373
// ========================================================================
 
374
// makes a null cursor
 
375
// ========================================================================
 
376
 
 
377
static Cursor CreateNullCursor(Display *display, Window root)
 
378
{
 
379
  Pixmap cursormask; 
 
380
  XGCValues xgc;
 
381
  GC gc;
 
382
  XColor dummycolour;
 
383
  Cursor cursor;
 
384
 
 
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;
 
390
  dummycolour.red = 0;
 
391
  dummycolour.flags = 04;
 
392
  cursor = XCreatePixmapCursor(display, cursormask, cursormask,
 
393
                               &dummycolour,&dummycolour, 0,0);
 
394
  XFreePixmap(display,cursormask);
 
395
  XFreeGC(display,gc);
 
396
  return cursor;
 
397
}
 
398
 
 
399
static void install_grabs(void)
 
400
{
 
401
  // inviso cursor
 
402
  XWarpPointer(dpy, None, win,
 
403
               0, 0, 0, 0,
 
404
               glConfig.vidWidth / 2, glConfig.vidHeight / 2);
 
405
  XSync(dpy, False);
 
406
 
 
407
  XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
 
408
 
 
409
  XGrabPointer(dpy, win, // bk010108 - do this earlier?
 
410
               False,
 
411
               MOUSE_MASK,
 
412
               GrabModeAsync, GrabModeAsync,
 
413
               win,
 
414
               None,
 
415
               CurrentTime);
 
416
 
 
417
  XGetPointerControl(dpy, &mouse_accel_numerator, &mouse_accel_denominator,
 
418
                     &mouse_threshold);
 
419
 
 
420
  XChangePointerControl(dpy, True, True, 1, 1, 0);
 
421
 
 
422
  XSync(dpy, False);
 
423
 
 
424
  mouseResetTime = Sys_Milliseconds ();
 
425
 
 
426
#ifdef HAVE_XF86DGA
 
427
  if (in_dgamouse->value)
 
428
  {
 
429
    int MajorVersion, MinorVersion;
 
430
 
 
431
    if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion))
 
432
    {
 
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" );
 
436
    } else
 
437
    {
 
438
      XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
 
439
      XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
 
440
    }
 
441
  } else
 
442
#endif /* HAVE_XF86DGA */
 
443
  {
 
444
    mwx = glConfig.vidWidth / 2;
 
445
    mwy = glConfig.vidHeight / 2;
 
446
    mx = my = 0;
 
447
  }
 
448
 
 
449
  XGrabKeyboard(dpy, win,
 
450
                False,
 
451
                GrabModeAsync, GrabModeAsync,
 
452
                CurrentTime);
 
453
 
 
454
  XSync(dpy, False);
 
455
}
 
456
 
 
457
static void uninstall_grabs(void)
 
458
{
 
459
#ifdef HAVE_XF86DGA
 
460
  if (in_dgamouse->value)
 
461
  {
 
462
                if (com_developer->value)
 
463
                        ri.Printf( PRINT_ALL, "DGA Mouse - Disabling DGA DirectVideo\n" );
 
464
    XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
 
465
  }
 
466
#endif /* HAVE_XF86DGA */
 
467
 
 
468
  XChangePointerControl(dpy, qtrue, qtrue, mouse_accel_numerator, 
 
469
                        mouse_accel_denominator, mouse_threshold);
 
470
 
 
471
  XUngrabPointer(dpy, CurrentTime);
 
472
  XUngrabKeyboard(dpy, CurrentTime);
 
473
 
 
474
  XWarpPointer(dpy, None, win,
 
475
               0, 0, 0, 0,
 
476
               glConfig.vidWidth / 2, glConfig.vidHeight / 2);
 
477
 
 
478
  // inviso cursor
 
479
  XUndefineCursor(dpy, win);
 
480
}
 
481
 
 
482
// bk001206 - from Ryan's Fakk2
 
483
/**
 
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 
 
493
 *  for key repeats. 
 
494
 */
 
495
static qboolean X11_PendingInput(void) {
 
496
 
 
497
  assert(dpy != NULL);
 
498
 
 
499
  // Flush the display connection
 
500
  //  and look to see if events are queued
 
501
  XFlush( dpy );
 
502
  if ( XEventsQueued( dpy, QueuedAlready) )
 
503
  {
 
504
    return qtrue;
 
505
  }
 
506
 
 
507
  // More drastic measures are required -- see if X is ready to talk
 
508
  {
 
509
    static struct timeval zero_time;
 
510
    int x11_fd;
 
511
    fd_set fdset;
 
512
 
 
513
    x11_fd = ConnectionNumber( dpy );
 
514
    FD_ZERO(&fdset);
 
515
    FD_SET(x11_fd, &fdset);
 
516
    if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 )
 
517
    {
 
518
      return(XPending(dpy));
 
519
    }
 
520
  }
 
521
 
 
522
  // Oh well, nothing is ready ..
 
523
  return qfalse;
 
524
}
 
525
 
 
526
// bk001206 - from Ryan's Fakk2. See above.
 
527
static qboolean repeated_press(XEvent *event)
 
528
{
 
529
  XEvent        peekevent;
 
530
  qboolean      repeated = qfalse;
 
531
 
 
532
  assert(dpy != NULL);
 
533
 
 
534
  if (X11_PendingInput())
 
535
  {
 
536
    XPeekEvent(dpy, &peekevent);
 
537
 
 
538
    if ((peekevent.type == KeyPress) &&
 
539
        (peekevent.xkey.keycode == event->xkey.keycode) &&
 
540
        (peekevent.xkey.time == event->xkey.time))
 
541
    {
 
542
      repeated = qtrue;
 
543
      XNextEvent(dpy, &peekevent);  // skip event.
 
544
    } // if
 
545
  } // if
 
546
 
 
547
  return(repeated);
 
548
} // repeated_press
 
549
 
 
550
int Sys_XTimeToSysTime (Time xtime);
 
551
static void HandleEvents(void)
 
552
{
 
553
  int b;
 
554
  int key;
 
555
  XEvent event;
 
556
  qboolean dowarp = qfalse;
 
557
  char *p;
 
558
  int dx, dy;
 
559
  int t = 0; // default to 0 in case we don't set
 
560
        
 
561
  if (!dpy)
 
562
    return;
 
563
 
 
564
  while (XPending(dpy))
 
565
  {
 
566
    XNextEvent(dpy, &event);
 
567
    switch (event.type)
 
568
    {
 
569
    case KeyPress:
 
570
                        t = Sys_XTimeToSysTime(event.xkey.time);
 
571
      p = XLateKey(&event.xkey, &key);
 
572
      if (key)
 
573
      {
 
574
        Sys_QueEvent( t, SE_KEY, key, qtrue, 0, NULL );
 
575
      }
 
576
      if (p)
 
577
      {
 
578
        while (*p)
 
579
        {
 
580
          Sys_QueEvent( t, SE_CHAR, *p++, 0, 0, NULL );
 
581
        }
 
582
      }
 
583
      break;
 
584
 
 
585
    case KeyRelease:
 
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)
 
594
          continue;
 
595
      } // if
 
596
      XLateKey(&event.xkey, &key);
 
597
 
 
598
      Sys_QueEvent( t, SE_KEY, key, qfalse, 0, NULL );
 
599
      break;
 
600
 
 
601
    case MotionNotify:
 
602
                        t = Sys_XTimeToSysTime(event.xkey.time);
 
603
      if (mouse_active)
 
604
      {
 
605
#ifdef HAVE_XF86DGA
 
606
        if (in_dgamouse->value)
 
607
        {
 
608
          mx += event.xmotion.x_root;
 
609
          my += event.xmotion.y_root;
 
610
          if (t - mouseResetTime > MOUSE_RESET_DELAY )
 
611
          {
 
612
            Sys_QueEvent( t, SE_MOUSE, mx, my, 0, NULL );
 
613
          }
 
614
          mx = my = 0;
 
615
        } else
 
616
#endif /* HAVE_XF86DGA */
 
617
        {
 
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)
 
621
          {
 
622
            mwx = glConfig.vidWidth/2;
 
623
            mwy = glConfig.vidHeight/2;
 
624
            if (t - mouseResetTime > MOUSE_RESET_DELAY )
 
625
            {
 
626
              Sys_QueEvent( t, SE_MOUSE, mx, my, 0, NULL );
 
627
            }
 
628
            mx = my = 0;
 
629
            break;
 
630
          }
 
631
 
 
632
          dx = ((int)event.xmotion.x - mwx);
 
633
          dy = ((int)event.xmotion.y - mwy);
 
634
                                        mx += dx;
 
635
                                        my += dy;
 
636
 
 
637
          mwx = event.xmotion.x;
 
638
          mwy = event.xmotion.y;
 
639
          dowarp = qtrue;
 
640
        }
 
641
      }
 
642
      break;
 
643
 
 
644
    case ButtonPress:
 
645
                  t = Sys_XTimeToSysTime(event.xkey.time);
 
646
      if (event.xbutton.button == 4)
 
647
      {
 
648
        Sys_QueEvent( t, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );
 
649
      } else if (event.xbutton.button == 5)
 
650
      {
 
651
        Sys_QueEvent( t, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );
 
652
      } else
 
653
      {
 
654
        // NOTE TTimo there seems to be a weird mapping for K_MOUSE1 K_MOUSE2 K_MOUSE3 ..
 
655
        b=-1;
 
656
        if (event.xbutton.button == 1)
 
657
        {
 
658
          b = 0; // K_MOUSE1
 
659
        } else if (event.xbutton.button == 2)
 
660
        {
 
661
          b = 2; // K_MOUSE3
 
662
        } else if (event.xbutton.button == 3)
 
663
        {
 
664
          b = 1; // K_MOUSE2
 
665
        } else if (event.xbutton.button == 6)
 
666
        {
 
667
          b = 3; // K_MOUSE4
 
668
        } else if (event.xbutton.button == 7)
 
669
        {
 
670
          b = 4; // K_MOUSE5
 
671
        };
 
672
 
 
673
        Sys_QueEvent( t, SE_KEY, K_MOUSE1 + b, qtrue, 0, NULL );
 
674
      }
 
675
      break;
 
676
 
 
677
    case ButtonRelease:
 
678
                  t = Sys_XTimeToSysTime(event.xkey.time);
 
679
      if (event.xbutton.button == 4)
 
680
      {
 
681
        Sys_QueEvent( t, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );
 
682
      } else if (event.xbutton.button == 5)
 
683
      {
 
684
        Sys_QueEvent( t, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );
 
685
      } else
 
686
      {
 
687
        b=-1;
 
688
        if (event.xbutton.button == 1)
 
689
        {
 
690
          b = 0;
 
691
        } else if (event.xbutton.button == 2)
 
692
        {
 
693
          b = 2;
 
694
        } else if (event.xbutton.button == 3)
 
695
        {
 
696
          b = 1;
 
697
        } else if (event.xbutton.button == 6)
 
698
        {
 
699
          b = 3; // K_MOUSE4
 
700
        } else if (event.xbutton.button == 7)
 
701
        {
 
702
          b = 4; // K_MOUSE5
 
703
        };
 
704
        Sys_QueEvent( t, SE_KEY, K_MOUSE1 + b, qfalse, 0, NULL );
 
705
      }
 
706
      break;
 
707
 
 
708
    case CreateNotify :
 
709
      win_x = event.xcreatewindow.x;
 
710
      win_y = event.xcreatewindow.y;
 
711
      break;
 
712
 
 
713
    case ConfigureNotify :
 
714
      win_x = event.xconfigure.x;
 
715
      win_y = event.xconfigure.y;
 
716
      break;
 
717
    }
 
718
  }
 
719
 
 
720
  if (dowarp)
 
721
  {
 
722
    XWarpPointer(dpy,None,win,0,0,0,0, 
 
723
                 (glConfig.vidWidth/2),(glConfig.vidHeight/2));
 
724
  }
 
725
}
 
726
 
 
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
 
729
void KBD_Init(void)
 
730
{
 
731
}
 
732
 
 
733
void KBD_Close(void)
 
734
{
 
735
}
 
736
 
 
737
void IN_ActivateMouse( void ) 
 
738
{
 
739
  if (!mouse_avail || !dpy || !win)
 
740
    return;
 
741
 
 
742
  if (!mouse_active)
 
743
  {
 
744
                if (!in_nograb->value)
 
745
      install_grabs();
 
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;
 
749
  }
 
750
}
 
751
 
 
752
void IN_DeactivateMouse( void ) 
 
753
{
 
754
  if (!mouse_avail || !dpy || !win)
 
755
    return;
 
756
 
 
757
  if (mouse_active)
 
758
  {
 
759
                if (!in_nograb->value)
 
760
      uninstall_grabs();
 
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;
 
764
  }
 
765
}
 
766
/*****************************************************************************/
 
767
 
 
768
/*
 
769
** GLimp_SetGamma
 
770
**
 
771
** This routine should only be called if glConfig.deviceSupportsGamma is TRUE
 
772
*/
 
773
void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] )
 
774
{
 
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
 
777
#ifdef HAVE_XF86DGA
 
778
  float g = Cvar_Get("r_gamma", "1.0", 0)->value;
 
779
  XF86VidModeGamma gamma;
 
780
  assert(glConfig.deviceSupportsGamma);
 
781
  gamma.red = g;
 
782
  gamma.green = g;
 
783
  gamma.blue = g;
 
784
  XF86VidModeSetGamma(dpy, scrnum, &gamma);
 
785
#endif /* HAVE_XF86DGA */
 
786
}
 
787
 
 
788
/*
 
789
** GLimp_Shutdown
 
790
**
 
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.
 
795
**
 
796
*/
 
797
void GLimp_Shutdown( void )
 
798
{
 
799
  if (!ctx || !dpy)
 
800
    return;
 
801
  IN_DeactivateMouse();
 
802
  // bk001206 - replaced with H2/Fakk2 solution
 
803
  // XAutoRepeatOn(dpy);
 
804
  // autorepeaton = qfalse; // bk001130 - from cvs1.17 (mkv)
 
805
  if (dpy)
 
806
  {
 
807
    if (ctx)
 
808
      qglXDestroyContext(dpy, ctx);
 
809
    if (win)
 
810
      XDestroyWindow(dpy, win);
 
811
#ifdef HAVE_XF86DGA
 
812
    if (vidmode_active)
 
813
      XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]);
 
814
    if (glConfig.deviceSupportsGamma)
 
815
    {
 
816
      XF86VidModeSetGamma(dpy, scrnum, &vidmode_InitialGamma);
 
817
    }
 
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 )
 
823
    XCloseDisplay(dpy);
 
824
  }
 
825
  vidmode_active = qfalse;
 
826
  dpy = NULL;
 
827
  win = 0;
 
828
  ctx = NULL;
 
829
 
 
830
  memset( &glConfig, 0, sizeof( glConfig ) );
 
831
  memset( &glState, 0, sizeof( glState ) );
 
832
 
 
833
  QGL_Shutdown();
 
834
}
 
835
 
 
836
/*
 
837
** GLimp_LogComment
 
838
*/
 
839
void GLimp_LogComment( char *comment ) 
 
840
{
 
841
  if ( glw_state.log_fp )
 
842
  {
 
843
    fprintf( glw_state.log_fp, "%s", comment );
 
844
  }
 
845
}
 
846
 
 
847
/*
 
848
** GLW_StartDriverAndSetMode
 
849
*/
 
850
// bk001204 - prototype needed
 
851
int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen );
 
852
static qboolean GLW_StartDriverAndSetMode( const char *drivername, 
 
853
                                           int mode, 
 
854
                                           qboolean fullscreen )
 
855
{
 
856
  rserr_t err;
 
857
 
 
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" ) )
 
861
  {
 
862
    ri.Cvar_Set( "r_fullscreen", "0" );
 
863
    r_fullscreen->modified = qfalse;
 
864
    fullscreen = qfalse;
 
865
  }
 
866
#endif
 
867
        
 
868
        if (fullscreen && in_nograb->value)
 
869
        {
 
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;
 
873
    fullscreen = qfalse;                
 
874
        }
 
875
 
 
876
  err = GLW_SetMode( drivername, mode, fullscreen );
 
877
 
 
878
  switch ( err )
 
879
  {
 
880
  case RSERR_INVALID_FULLSCREEN:
 
881
    ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" );
 
882
    return qfalse;
 
883
  case RSERR_INVALID_MODE:
 
884
    ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode );
 
885
    return qfalse;
 
886
  default:
 
887
    break;
 
888
  }
 
889
  return qtrue;
 
890
}
 
891
 
 
892
/*
 
893
** GLW_SetMode
 
894
*/
 
895
int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen )
 
896
{
 
897
  int attrib[] = {
 
898
    GLX_RGBA,         // 0
 
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
 
905
    None
 
906
  };
 
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
 
913
  Window root;
 
914
  XVisualInfo *visinfo;
 
915
  XSetWindowAttributes attr;
 
916
  XSizeHints sizehints;
 
917
  unsigned long mask;
 
918
  int colorbits, depthbits, stencilbits;
 
919
  int tcolorbits, tdepthbits, tstencilbits;
 
920
  int dga_MajorVersion, dga_MinorVersion;
 
921
  int actualWidth, actualHeight;
 
922
  int i;
 
923
  const char*   glstring; // bk001130 - from cvs1.17 (mkv)
 
924
 
 
925
  ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");
 
926
 
 
927
  ri.Printf (PRINT_ALL, "...setting mode %d:", mode );
 
928
 
 
929
  if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) )
 
930
  {
 
931
    ri.Printf( PRINT_ALL, " invalid mode\n" );
 
932
    return RSERR_INVALID_MODE;
 
933
  }
 
934
  ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);
 
935
 
 
936
  if (!(dpy = XOpenDisplay(NULL)))
 
937
  {
 
938
    fprintf(stderr, "Error couldn't open the X display\n");
 
939
    return RSERR_INVALID_MODE;
 
940
  }
 
941
  
 
942
  scrnum = DefaultScreen(dpy);
 
943
  root = RootWindow(dpy, scrnum);
 
944
 
 
945
  actualWidth = glConfig.vidWidth;
 
946
  actualHeight = glConfig.vidHeight;
 
947
 
 
948
  // Get video mode list
 
949
#ifdef HAVE_XF86DGA
 
950
  if (!XF86VidModeQueryVersion(dpy, &vidmode_MajorVersion, &vidmode_MinorVersion))
 
951
  {
 
952
#endif /* HAVE_XF86DGA */
 
953
    vidmode_ext = qfalse;
 
954
#ifdef HAVE_XF86DGA
 
955
  } else
 
956
  {
 
957
    ri.Printf(PRINT_ALL, "Using XFree86-VidModeExtension Version %d.%d\n",
 
958
              vidmode_MajorVersion, vidmode_MinorVersion);
 
959
    vidmode_ext = qtrue;
 
960
  }
 
961
#endif /* HAVE_XF86DGA */
 
962
 
 
963
  // Check for DGA      
 
964
  dga_MajorVersion = 0, dga_MinorVersion = 0;
 
965
#ifdef HAVE_XF86DGA
 
966
  if (in_dgamouse->value)
 
967
  {
 
968
    if (!XF86DGAQueryVersion(dpy, &dga_MajorVersion, &dga_MinorVersion))
 
969
    {
 
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" );
 
973
    } else
 
974
    {
 
975
      ri.Printf( PRINT_ALL, "XF86DGA Mouse (Version %d.%d) initialized\n",
 
976
                 dga_MajorVersion, dga_MinorVersion);
 
977
    }
 
978
  }
 
979
#endif /* HAVE_XF86DGA */
 
980
 
 
981
#ifdef HAVE_XF86DGA
 
982
  if (vidmode_ext)
 
983
  {
 
984
    int best_fit, best_dist, dist, x, y;
 
985
 
 
986
    XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
 
987
 
 
988
    // Are we going fullscreen?  If so, let's change video mode
 
989
    if (fullscreen)
 
990
    {
 
991
      best_dist = 9999999;
 
992
      best_fit = -1;
 
993
 
 
994
      for (i = 0; i < num_vidmodes; i++)
 
995
      {
 
996
        if (glConfig.vidWidth > vidmodes[i]->hdisplay ||
 
997
            glConfig.vidHeight > vidmodes[i]->vdisplay)
 
998
          continue;
 
999
 
 
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)
 
1004
        {
 
1005
          best_dist = dist;
 
1006
          best_fit = i;
 
1007
        }
 
1008
      }
 
1009
 
 
1010
      if (best_fit != -1)
 
1011
      {
 
1012
        actualWidth = vidmodes[best_fit]->hdisplay;
 
1013
        actualHeight = vidmodes[best_fit]->vdisplay;
 
1014
 
 
1015
        // change to the mode
 
1016
        XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
 
1017
        vidmode_active = qtrue;
 
1018
 
 
1019
        // Move the viewport to top left
 
1020
        XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
 
1021
 
 
1022
        ri.Printf(PRINT_ALL, "XFree86-VidModeExtension Activated at %dx%d\n",
 
1023
                  actualWidth, actualHeight);
 
1024
 
 
1025
      } else
 
1026
      {
 
1027
        fullscreen = 0;
 
1028
        ri.Printf(PRINT_ALL, "XFree86-VidModeExtension: No acceptable modes found\n");
 
1029
      }
 
1030
    } else
 
1031
    {
 
1032
      ri.Printf(PRINT_ALL, "XFree86-VidModeExtension:  Ignored on non-fullscreen/Voodoo\n");
 
1033
    }
 
1034
  }
 
1035
#endif /* HAVE_XF86DGA */
 
1036
 
 
1037
 
 
1038
  if (!r_colorbits->value)
 
1039
    colorbits = 24;
 
1040
  else
 
1041
    colorbits = r_colorbits->value;
 
1042
 
 
1043
  if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
 
1044
    colorbits = 16;
 
1045
 
 
1046
  if (!r_depthbits->value)
 
1047
    depthbits = 24;
 
1048
  else
 
1049
    depthbits = r_depthbits->value;
 
1050
  stencilbits = r_stencilbits->value;
 
1051
 
 
1052
  for (i = 0; i < 16; i++)
 
1053
  {
 
1054
    // 0 - default
 
1055
    // 1 - minus colorbits
 
1056
    // 2 - minus depthbits
 
1057
    // 3 - minus stencil
 
1058
    if ((i % 4) == 0 && i)
 
1059
    {
 
1060
      // one pass, reduce
 
1061
      switch (i / 4)
 
1062
      {
 
1063
      case 2 :
 
1064
        if (colorbits == 24)
 
1065
          colorbits = 16;
 
1066
        break;
 
1067
      case 1 :
 
1068
        if (depthbits == 24)
 
1069
          depthbits = 16;
 
1070
        else if (depthbits == 16)
 
1071
          depthbits = 8;
 
1072
      case 3 :
 
1073
        if (stencilbits == 24)
 
1074
          stencilbits = 16;
 
1075
        else if (stencilbits == 16)
 
1076
          stencilbits = 8;
 
1077
      }
 
1078
    }
 
1079
 
 
1080
    tcolorbits = colorbits;
 
1081
    tdepthbits = depthbits;
 
1082
    tstencilbits = stencilbits;
 
1083
 
 
1084
    if ((i % 4) == 3)
 
1085
    { // reduce colorbits
 
1086
      if (tcolorbits == 24)
 
1087
        tcolorbits = 16;
 
1088
    }
 
1089
 
 
1090
    if ((i % 4) == 2)
 
1091
    { // reduce depthbits
 
1092
      if (tdepthbits == 24)
 
1093
        tdepthbits = 16;
 
1094
      else if (tdepthbits == 16)
 
1095
        tdepthbits = 8;
 
1096
    }
 
1097
 
 
1098
    if ((i % 4) == 1)
 
1099
    { // reduce stencilbits
 
1100
      if (tstencilbits == 24)
 
1101
        tstencilbits = 16;
 
1102
      else if (tstencilbits == 16)
 
1103
        tstencilbits = 8;
 
1104
      else
 
1105
        tstencilbits = 0;
 
1106
    }
 
1107
 
 
1108
    if (tcolorbits == 24)
 
1109
    {
 
1110
      attrib[ATTR_RED_IDX] = 8;
 
1111
      attrib[ATTR_GREEN_IDX] = 8;
 
1112
      attrib[ATTR_BLUE_IDX] = 8;
 
1113
    } else
 
1114
    {
 
1115
      // must be 16 bit
 
1116
      attrib[ATTR_RED_IDX] = 4;
 
1117
      attrib[ATTR_GREEN_IDX] = 4;
 
1118
      attrib[ATTR_BLUE_IDX] = 4;
 
1119
    }
 
1120
 
 
1121
    attrib[ATTR_DEPTH_IDX] = tdepthbits; // default to 24 depth
 
1122
    attrib[ATTR_STENCIL_IDX] = tstencilbits;
 
1123
 
 
1124
    visinfo = qglXChooseVisual(dpy, scrnum, attrib);
 
1125
    if (!visinfo)
 
1126
    {
 
1127
      continue;
 
1128
    }
 
1129
 
 
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]);
 
1133
 
 
1134
    glConfig.colorBits = tcolorbits;
 
1135
    glConfig.depthBits = tdepthbits;
 
1136
    glConfig.stencilBits = tstencilbits;
 
1137
    break;
 
1138
  }
 
1139
 
 
1140
  if (!visinfo)
 
1141
  {
 
1142
    ri.Printf( PRINT_ALL, "Couldn't get a visual\n" );
 
1143
    return RSERR_INVALID_MODE;
 
1144
  }
 
1145
 
 
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;
 
1151
  if (vidmode_active)
 
1152
  {
 
1153
    mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | 
 
1154
           CWEventMask | CWOverrideRedirect;
 
1155
    attr.override_redirect = True;
 
1156
    attr.backing_store = NotUseful;
 
1157
    attr.save_under = False;
 
1158
  } else
 
1159
    mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
 
1160
 
 
1161
  win = XCreateWindow(dpy, root, 0, 0, 
 
1162
                      actualWidth, actualHeight, 
 
1163
                      0, visinfo->depth, InputOutput,
 
1164
                      visinfo->visual, mask, &attr);
 
1165
 
 
1166
  XStoreName( dpy, win, CLIENT_WINDOW_TITLE );
 
1167
 
 
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;
 
1172
 
 
1173
  XSetWMNormalHints( dpy, win, &sizehints );
 
1174
 
 
1175
  XMapWindow( dpy, win );
 
1176
 
 
1177
  if (vidmode_active)
 
1178
    XMoveWindow(dpy, win, 0, 0);
 
1179
 
 
1180
  XFlush(dpy);
 
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)
 
1184
 
 
1185
  /* GH: Free the visinfo after we're done with it */
 
1186
  XFree( visinfo );
 
1187
 
 
1188
  qglXMakeCurrent(dpy, win, ctx);
 
1189
 
 
1190
  // bk001130 - from cvs1.17 (mkv)
 
1191
  glstring = (char *)qglGetString (GL_RENDERER);
 
1192
  ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glstring );
 
1193
 
 
1194
  // bk010122 - new software token (Indirect)
 
1195
  if ( !Q_stricmp( glstring, "Mesa X11")
 
1196
       || !Q_stricmp( glstring, "Mesa GLX Indirect") )
 
1197
  {
 
1198
    if ( !r_allowSoftwareGL->integer )
 
1199
    {
 
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");
 
1207
      GLimp_Shutdown( );
 
1208
      return RSERR_INVALID_MODE;
 
1209
    } else
 
1210
    {
 
1211
      ri.Printf( PRINT_ALL, "...using software Mesa (r_allowSoftwareGL==1).\n" );
 
1212
    }
 
1213
  }
 
1214
 
 
1215
  return RSERR_OK;
 
1216
}
 
1217
 
 
1218
/*
 
1219
** GLW_InitExtensions
 
1220
*/
 
1221
static void GLW_InitExtensions( void )
 
1222
{
 
1223
  if ( !r_allowExtensions->integer )
 
1224
  {
 
1225
    ri.Printf( PRINT_ALL, "*** IGNORING OPENGL EXTENSIONS ***\n" );
 
1226
    return;
 
1227
  }
 
1228
 
 
1229
  ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" );
 
1230
 
 
1231
  // GL_S3_s3tc
 
1232
  if ( Q_stristr( glConfig.extensions_string, "GL_S3_s3tc" ) )
 
1233
  {
 
1234
    if ( r_ext_compressed_textures->value )
 
1235
    {
 
1236
      glConfig.textureCompression = TC_S3TC;
 
1237
      ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" );
 
1238
    } else
 
1239
    {
 
1240
      glConfig.textureCompression = TC_NONE;
 
1241
      ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" );
 
1242
    }
 
1243
  } else
 
1244
  {
 
1245
    glConfig.textureCompression = TC_NONE;
 
1246
    ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" );
 
1247
  }
 
1248
 
 
1249
  // GL_EXT_texture_env_add
 
1250
  glConfig.textureEnvAddAvailable = qfalse;
 
1251
  if ( Q_stristr( glConfig.extensions_string, "EXT_texture_env_add" ) )
 
1252
  {
 
1253
    if ( r_ext_texture_env_add->integer )
 
1254
    {
 
1255
      glConfig.textureEnvAddAvailable = qtrue;
 
1256
      ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" );
 
1257
    } else
 
1258
    {
 
1259
      glConfig.textureEnvAddAvailable = qfalse;
 
1260
      ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" );
 
1261
    }
 
1262
  } else
 
1263
  {
 
1264
    ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" );
 
1265
  }
 
1266
 
 
1267
  // GL_ARB_multitexture
 
1268
  qglMultiTexCoord2fARB = NULL;
 
1269
  qglActiveTextureARB = NULL;
 
1270
  qglClientActiveTextureARB = NULL;
 
1271
  if ( Q_stristr( glConfig.extensions_string, "GL_ARB_multitexture" ) )
 
1272
  {
 
1273
    if ( r_ext_multitexture->value )
 
1274
    {
 
1275
      qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) dlsym( glw_state.OpenGLLib, "glMultiTexCoord2fARB" );
 
1276
      qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glActiveTextureARB" );
 
1277
      qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glClientActiveTextureARB" );
 
1278
 
 
1279
      if ( qglActiveTextureARB )
 
1280
      {
 
1281
        GLint glint = 0;
 
1282
        qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glint );
 
1283
        glConfig.maxActiveTextures = (int) glint;
 
1284
 
 
1285
        if ( glConfig.maxActiveTextures > 1 )
 
1286
        {
 
1287
          ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" );
 
1288
        } else
 
1289
        {
 
1290
          qglMultiTexCoord2fARB = NULL;
 
1291
          qglActiveTextureARB = NULL;
 
1292
          qglClientActiveTextureARB = NULL;
 
1293
          ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" );
 
1294
        }
 
1295
      }
 
1296
    } else
 
1297
    {
 
1298
      ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" );
 
1299
    }
 
1300
  } else
 
1301
  {
 
1302
    ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" );
 
1303
  }
 
1304
 
 
1305
  // GL_EXT_compiled_vertex_array
 
1306
  if ( Q_stristr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) )
 
1307
  {
 
1308
    if ( r_ext_compiled_vertex_array->value )
 
1309
    {
 
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)
 
1314
      {
 
1315
        ri.Error (ERR_FATAL, "bad getprocaddress");
 
1316
      }
 
1317
    } else
 
1318
    {
 
1319
      ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" );
 
1320
    }
 
1321
  } else
 
1322
  {
 
1323
    ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" );
 
1324
  }
 
1325
 
 
1326
  textureFilterAnisotropic = qfalse;
 
1327
  if ( strstr( glConfig.extensions_string, "GL_EXT_texture_filter_anisotropic" ) )
 
1328
  {
 
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" );
 
1333
        maxAnisotropy = 0;
 
1334
      }
 
1335
      else
 
1336
      {
 
1337
        ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic (max: %i)\n", maxAnisotropy );
 
1338
        textureFilterAnisotropic = qtrue;
 
1339
      }
 
1340
    }
 
1341
    else
 
1342
    {
 
1343
      ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" );
 
1344
    }
 
1345
  }
 
1346
  else
 
1347
  {
 
1348
    ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" );
 
1349
  }
 
1350
}
 
1351
 
 
1352
static void GLW_InitGamma(void)
 
1353
{
 
1354
  /* Minimum extension version required */
 
1355
  #define GAMMA_MINMAJOR 2
 
1356
  #define GAMMA_MINMINOR 0
 
1357
  
 
1358
  glConfig.deviceSupportsGamma = qfalse;
 
1359
 
 
1360
#ifdef HAVE_XF86DGA
 
1361
  if (vidmode_ext)
 
1362
  {
 
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");
 
1366
      return;
 
1367
    }
 
1368
    XF86VidModeGetGamma(dpy, scrnum, &vidmode_InitialGamma);
 
1369
    ri.Printf( PRINT_ALL, "XF86 Gamma extension initialized\n");
 
1370
    glConfig.deviceSupportsGamma = qtrue;
 
1371
  }
 
1372
#endif /* HAVE_XF86DGA */
 
1373
}
 
1374
 
 
1375
/*
 
1376
** GLW_LoadOpenGL
 
1377
**
 
1378
** GLimp_win.c internal function that that attempts to load and use 
 
1379
** a specific OpenGL DLL.
 
1380
*/
 
1381
static qboolean GLW_LoadOpenGL( const char *name )
 
1382
{
 
1383
  qboolean fullscreen;
 
1384
 
 
1385
  ri.Printf( PRINT_ALL, "...loading %s: ", name );
 
1386
 
 
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");
 
1391
 
 
1392
  // Mesa VooDoo hacks
 
1393
  putenv("MESA_GLX_FX=fullscreen\n");
 
1394
 
 
1395
  // load the QGL layer
 
1396
  if ( QGL_Init( name ) )
 
1397
  {
 
1398
    fullscreen = r_fullscreen->integer;
 
1399
 
 
1400
    // create the window and set up the context
 
1401
    if ( !GLW_StartDriverAndSetMode( name, r_mode->integer, fullscreen ) )
 
1402
    {
 
1403
      if (r_mode->integer != 3)
 
1404
      {
 
1405
        if ( !GLW_StartDriverAndSetMode( name, 3, fullscreen ) )
 
1406
        {
 
1407
          goto fail;
 
1408
        }
 
1409
      } else
 
1410
        goto fail;
 
1411
    }
 
1412
 
 
1413
    return qtrue;
 
1414
  } else
 
1415
  {
 
1416
    ri.Printf( PRINT_ALL, "failed\n" );
 
1417
  }
 
1418
  fail:
 
1419
 
 
1420
  QGL_Shutdown();
 
1421
 
 
1422
  return qfalse;
 
1423
}
 
1424
 
 
1425
/*
 
1426
** XErrorHandler
 
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)
 
1431
*/
 
1432
int qXErrorHandler(Display *dpy, XErrorEvent *ev)
 
1433
{
 
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);
 
1440
  return 0;
 
1441
}
 
1442
 
 
1443
/*
 
1444
** GLimp_Init
 
1445
**
 
1446
** This routine is responsible for initializing the OS specific portions
 
1447
** of OpenGL.  
 
1448
*/
 
1449
void GLimp_Init( void )
 
1450
{
 
1451
  qboolean attemptedlibGL = qfalse;
 
1452
  qboolean attempted3Dfx = qfalse;
 
1453
  qboolean success = qfalse;
 
1454
  char  buf[1024];
 
1455
  cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE );
 
1456
 
 
1457
  // guarded, as this is only relevant to SMP renderer thread
 
1458
#ifdef SMP
 
1459
  if (!XInitThreads())
 
1460
  {
 
1461
    Com_Printf("GLimp_Init() - XInitThreads() failed, disabling r_smp\n");
 
1462
    ri.Cvar_Set( "r_smp", "0" );
 
1463
  }
 
1464
#endif
 
1465
 
 
1466
  r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH );
 
1467
 
 
1468
  r_previousglDriver = ri.Cvar_Get( "r_previousglDriver", "", CVAR_ROM );
 
1469
 
 
1470
  InitSig();
 
1471
 
 
1472
  IN_Init();   // rcg08312005 moved into glimp.
 
1473
 
 
1474
  // Hack here so that if the UI 
 
1475
  if ( *r_previousglDriver->string )
 
1476
  {
 
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 );
 
1480
  }
 
1481
  
 
1482
  // set up our custom error handler for X failures
 
1483
  XSetErrorHandler(&qXErrorHandler);
 
1484
 
 
1485
  //
 
1486
  // load and initialize the specific OpenGL driver
 
1487
  //
 
1488
  if ( !GLW_LoadOpenGL( r_glDriver->string ) )
 
1489
  {
 
1490
    if ( !Q_stricmp( r_glDriver->string, OPENGL_DRIVER_NAME ) )
 
1491
    {
 
1492
      attemptedlibGL = qtrue;
 
1493
    } else if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
 
1494
    {
 
1495
      attempted3Dfx = qtrue;
 
1496
    }
 
1497
 
 
1498
    #if 0
 
1499
    // TTimo
 
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 )
 
1503
    {
 
1504
      attempted3Dfx = qtrue;
 
1505
      if ( GLW_LoadOpenGL( _3DFX_DRIVER_NAME ) )
 
1506
      {
 
1507
        ri.Cvar_Set( "r_glDriver", _3DFX_DRIVER_NAME );
 
1508
        r_glDriver->modified = qfalse;
 
1509
        success = qtrue;
 
1510
      }
 
1511
    }
 
1512
    #endif
 
1513
 
 
1514
    // try ICD before trying 3Dfx standalone driver
 
1515
    if ( !attemptedlibGL && !success )
 
1516
    {
 
1517
      attemptedlibGL = qtrue;
 
1518
      if ( GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) )
 
1519
      {
 
1520
        ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME );
 
1521
        r_glDriver->modified = qfalse;
 
1522
        success = qtrue;
 
1523
      }
 
1524
    }
 
1525
 
 
1526
    if (!success)
 
1527
      ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" );
 
1528
 
 
1529
  }
 
1530
 
 
1531
  // Save it in case the UI stomps it
 
1532
  ri.Cvar_Set( "r_previousglDriver", r_glDriver->string );
 
1533
 
 
1534
  // This values force the UI to disable driver selection
 
1535
  glConfig.driverType = GLDRV_ICD;
 
1536
  glConfig.hardwareType = GLHW_GENERIC;
 
1537
 
 
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 ) );
 
1545
 
 
1546
  //
 
1547
  // chipset specific configuration
 
1548
  //
 
1549
  strcpy( buf, glConfig.renderer_string );
 
1550
  strlwr( buf );
 
1551
 
 
1552
  //
 
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.
 
1556
  //
 
1557
  if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) )
 
1558
  {
 
1559
    glConfig.hardwareType = GLHW_GENERIC;
 
1560
 
 
1561
    ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );
 
1562
 
 
1563
    // VOODOO GRAPHICS w/ 2MB
 
1564
    if ( Q_stristr( buf, "voodoo graphics/1 tmu/2 mb" ) )
 
1565
    {
 
1566
      ri.Cvar_Set( "r_picmip", "2" );
 
1567
      ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
 
1568
    } else
 
1569
    {
 
1570
      ri.Cvar_Set( "r_picmip", "1" );
 
1571
 
 
1572
      if ( Q_stristr( buf, "rage 128" ) || Q_stristr( buf, "rage128" ) )
 
1573
      {
 
1574
        ri.Cvar_Set( "r_finish", "0" );
 
1575
      }
 
1576
      // Savage3D and Savage4 should always have trilinear enabled
 
1577
      else if ( Q_stristr( buf, "savage3d" ) || Q_stristr( buf, "s3 savage4" ) )
 
1578
      {
 
1579
        ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
 
1580
      }
 
1581
    }
 
1582
  }
 
1583
 
 
1584
  //
 
1585
  // this is where hardware specific workarounds that should be
 
1586
  // detected/initialized every startup should go.
 
1587
  //
 
1588
  if ( Q_stristr( buf, "banshee" ) || Q_stristr( buf, "Voodoo_Graphics" ) )
 
1589
  {
 
1590
    glConfig.hardwareType = GLHW_3DFX_2D3D;
 
1591
  } else if ( Q_stristr( buf, "rage pro" ) || Q_stristr( buf, "RagePro" ) )
 
1592
  {
 
1593
    glConfig.hardwareType = GLHW_RAGEPRO;
 
1594
  } else if ( Q_stristr( buf, "permedia2" ) )
 
1595
  {
 
1596
    glConfig.hardwareType = GLHW_PERMEDIA2;
 
1597
  } else if ( Q_stristr( buf, "riva 128" ) )
 
1598
  {
 
1599
    glConfig.hardwareType = GLHW_RIVA128;
 
1600
  } else if ( Q_stristr( buf, "riva tnt " ) )
 
1601
  {
 
1602
  }
 
1603
 
 
1604
  ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string );
 
1605
 
 
1606
  // initialize extensions
 
1607
  GLW_InitExtensions();
 
1608
  GLW_InitGamma();
 
1609
 
 
1610
  InitSig(); // not clear why this is at begin & end of function
 
1611
 
 
1612
  return;
 
1613
}
 
1614
 
 
1615
 
 
1616
/*
 
1617
** GLimp_EndFrame
 
1618
** 
 
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.
 
1622
*/
 
1623
void GLimp_EndFrame (void)
 
1624
{
 
1625
  // don't flip if drawing to front buffer
 
1626
  if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 )
 
1627
  {
 
1628
    qglXSwapBuffers(dpy, win);
 
1629
  }
 
1630
 
 
1631
  // check logging
 
1632
  QGL_EnableLogging( (qboolean)r_logFile->integer ); // bk001205 - was ->value
 
1633
}
 
1634
 
 
1635
#ifdef SMP
 
1636
/*
 
1637
===========================================================
 
1638
 
 
1639
SMP acceleration
 
1640
 
 
1641
===========================================================
 
1642
*/
 
1643
 
 
1644
static pthread_mutex_t  smpMutex = PTHREAD_MUTEX_INITIALIZER;
 
1645
 
 
1646
static pthread_cond_t           renderCommandsEvent = PTHREAD_COND_INITIALIZER;
 
1647
static pthread_cond_t           renderCompletedEvent = PTHREAD_COND_INITIALIZER;
 
1648
 
 
1649
static void (*glimpRenderThread)( void );
 
1650
 
 
1651
static void *GLimp_RenderThreadWrapper( void *arg )
 
1652
{
 
1653
        Com_Printf( "Render thread starting\n" );
 
1654
 
 
1655
  glimpRenderThread();
 
1656
 
 
1657
        qglXMakeCurrent( dpy, None, NULL );
 
1658
 
 
1659
        Com_Printf( "Render thread terminating\n" );
 
1660
 
 
1661
        return arg;
 
1662
}
 
1663
 
 
1664
qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
 
1665
{
 
1666
        pthread_t renderThread;
 
1667
        int ret;
 
1668
 
 
1669
        pthread_mutex_init( &smpMutex, NULL );
 
1670
 
 
1671
        pthread_cond_init( &renderCommandsEvent, NULL );
 
1672
        pthread_cond_init( &renderCompletedEvent, NULL );
 
1673
 
 
1674
  glimpRenderThread = function;
 
1675
 
 
1676
        ret = pthread_create( &renderThread,
 
1677
                                                  NULL,                 // attributes
 
1678
                                                  GLimp_RenderThreadWrapper,
 
1679
                                                  NULL );               // argument
 
1680
        if ( ret ) {
 
1681
                ri.Printf( PRINT_ALL, "pthread_create returned %d: %s", ret, strerror( ret ) );
 
1682
    return qfalse;
 
1683
        } else {
 
1684
                ret = pthread_detach( renderThread );
 
1685
                if ( ret ) {
 
1686
                        ri.Printf( PRINT_ALL, "pthread_detach returned %d: %s", ret, strerror( ret ) );
 
1687
                }
 
1688
  }
 
1689
 
 
1690
  return qtrue;
 
1691
}
 
1692
 
 
1693
static volatile void    *smpData = NULL;
 
1694
static volatile qboolean smpDataReady;
 
1695
 
 
1696
void *GLimp_RendererSleep( void )
 
1697
{
 
1698
        void  *data;
 
1699
 
 
1700
        qglXMakeCurrent( dpy, None, NULL );
 
1701
 
 
1702
        pthread_mutex_lock( &smpMutex );
 
1703
        {
 
1704
                smpData = NULL;
 
1705
                smpDataReady = qfalse;
 
1706
 
 
1707
                // after this, the front end can exit GLimp_FrontEndSleep
 
1708
                pthread_cond_signal( &renderCompletedEvent );
 
1709
 
 
1710
                while ( !smpDataReady ) {
 
1711
                        pthread_cond_wait( &renderCommandsEvent, &smpMutex );
 
1712
                }
 
1713
 
 
1714
                data = (void *)smpData;
 
1715
        }
 
1716
        pthread_mutex_unlock( &smpMutex );
 
1717
 
 
1718
        qglXMakeCurrent( dpy, win, ctx );
 
1719
 
 
1720
  return data;
 
1721
}
 
1722
 
 
1723
void GLimp_FrontEndSleep( void )
 
1724
{
 
1725
        pthread_mutex_lock( &smpMutex );
 
1726
        {
 
1727
                while ( smpData ) {
 
1728
                        pthread_cond_wait( &renderCompletedEvent, &smpMutex );
 
1729
                }
 
1730
        }
 
1731
        pthread_mutex_unlock( &smpMutex );
 
1732
 
 
1733
        qglXMakeCurrent( dpy, win, ctx );
 
1734
}
 
1735
 
 
1736
void GLimp_WakeRenderer( void *data )
 
1737
{
 
1738
        qglXMakeCurrent( dpy, None, NULL );
 
1739
 
 
1740
        pthread_mutex_lock( &smpMutex );
 
1741
        {
 
1742
                assert( smpData == NULL );
 
1743
                smpData = data;
 
1744
                smpDataReady = qtrue;
 
1745
 
 
1746
                // after this, the renderer can continue through GLimp_RendererSleep
 
1747
                pthread_cond_signal( &renderCommandsEvent );
 
1748
        }
 
1749
        pthread_mutex_unlock( &smpMutex );
 
1750
}
 
1751
 
 
1752
#else
 
1753
 
 
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");
 
1757
  return qfalse;
 
1758
}
 
1759
void *GLimp_RendererSleep( void ) {
 
1760
  return NULL;
 
1761
}
 
1762
void GLimp_FrontEndSleep( void ) {}
 
1763
void GLimp_WakeRenderer( void *data ) {}
 
1764
 
 
1765
#endif
 
1766
 
 
1767
/*****************************************************************************/
 
1768
/* MOUSE                                                                     */
 
1769
/*****************************************************************************/
 
1770
 
 
1771
void IN_Init(void) {
 
1772
        Com_Printf ("\n------- Input Initialization -------\n");
 
1773
  // mouse variables
 
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);
 
1777
        
 
1778
        // turn on-off sub-frame timing of X events
 
1779
        in_subframe = Cvar_Get ("in_subframe", "1", CVAR_ARCHIVE);
 
1780
        
 
1781
        // developer feature, allows to break without loosing mouse pointer
 
1782
        in_nograb = Cvar_Get ("in_nograb", "0", 0);
 
1783
 
 
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
 
1789
 
 
1790
  Cvar_Set( "cl_platformSensitivity", "2.0" );
 
1791
 
 
1792
  if (in_mouse->value)
 
1793
    mouse_avail = qtrue;
 
1794
  else
 
1795
    mouse_avail = qfalse;
 
1796
 
 
1797
  IN_StartupJoystick( ); // bk001130 - from cvs1.17 (mkv)
 
1798
        Com_Printf ("------------------------------------\n");
 
1799
}
 
1800
 
 
1801
void IN_Shutdown(void)
 
1802
{
 
1803
  mouse_avail = qfalse;
 
1804
}
 
1805
 
 
1806
void IN_Frame (void) {
 
1807
 
 
1808
  // bk001130 - from cvs 1.17 (mkv)
 
1809
  IN_JoyMove(); // FIXME: disable if on desktop?
 
1810
 
 
1811
  if ( cls.keyCatchers & KEYCATCH_CONSOLE )
 
1812
  {
 
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 ) )
 
1818
    {
 
1819
      IN_DeactivateMouse ();
 
1820
      return;
 
1821
    }
 
1822
  }
 
1823
 
 
1824
  IN_ActivateMouse();
 
1825
}
 
1826
 
 
1827
void IN_Activate(void)
 
1828
{
 
1829
}
 
1830
 
 
1831
// bk001130 - cvs1.17 joystick code (mkv) was here, no linux_joystick.c
 
1832
 
 
1833
void Sys_SendKeyEvents (void) {
 
1834
  // XEvent event; // bk001204 - unused
 
1835
 
 
1836
  if (!dpy)
 
1837
    return;
 
1838
  HandleEvents();
 
1839
}
 
1840
 
 
1841
 
 
1842
// bk010216 - added stubs for non-Linux UNIXes here
 
1843
// FIXME - use NO_JOYSTICK or something else generic
 
1844
 
 
1845
#if (defined( __FreeBSD__ ) || defined( __sun)) // rb010123
 
1846
void IN_StartupJoystick( void ) {}
 
1847
void IN_JoyMove( void ) {}
 
1848
#endif
 
1849
 
 
1850
#endif  // !USE_SDL_VIDEO
 
1851