]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - vid_glx.c
16e012ab16a410e11117551ca53af04a90ba1993
[xonotic/darkplaces.git] / vid_glx.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 #include <termios.h>
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <sys/vt.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <signal.h>
27
28 #include <dlfcn.h>
29
30 #include "quakedef.h"
31
32 #include <GL/glx.h>
33
34 #include <X11/keysym.h>
35 #include <X11/cursorfont.h>
36
37 #include <X11/extensions/xf86dga.h>
38 #include <X11/extensions/xf86vmode.h>
39
40 #define WARP_WIDTH              320
41 #define WARP_HEIGHT             200
42
43 static Display *dpy = NULL;
44 static int scrnum;
45 static Window win;
46 static GLXContext ctx = NULL;
47
48 #define KEY_MASK (KeyPressMask | KeyReleaseMask)
49 #define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
50                     PointerMotionMask | ButtonMotionMask )
51 #define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask )
52
53
54 unsigned short  d_8to16table[256];
55 unsigned                d_8to24table[256];
56 unsigned char   d_15to8table[65536];
57
58 cvar_t  vid_mode = {"vid_mode","0",false};
59  
60 viddef_t        vid;                            // global video state
61
62 static qboolean        mouse_avail;
63 static qboolean        mouse_active;
64 static int   mx, my;
65 static int      old_mouse_x, old_mouse_y;
66
67 static cvar_t in_mouse = {"in_mouse", "1", false};
68 static cvar_t in_dgamouse = {"in_dgamouse", "1", false};
69 static cvar_t m_filter = {"m_filter", "0"};
70
71 qboolean dgamouse = false;
72 qboolean vidmode_ext = false;
73
74 static int win_x, win_y;
75
76 static int scr_width, scr_height;
77
78 static XF86VidModeModeInfo **vidmodes;
79 //static int default_dotclock_vidmode;
80 static int num_vidmodes;
81 static qboolean vidmode_active = false;
82
83 /*-----------------------------------------------------------------------*/
84
85 int             texture_extension_number = 1;
86
87 float           gldepthmin, gldepthmax;
88
89 const char *gl_vendor;
90 const char *gl_renderer;
91 const char *gl_version;
92 const char *gl_extensions;
93
94 void (*qglColorTableEXT) (int, int, int, int, int, const void*);
95 void (*qgl3DfxSetPaletteEXT) (GLuint *);
96 void (*qglMTexCoord2f) (GLenum, GLfloat, GLfloat);
97 void (*qglSelectTexture) (GLenum);
98
99 //static float vid_gamma = 1.0;
100
101 // LordHavoc: ARB multitexture support
102 int gl_mtex_enum = 0;
103
104 // LordHavoc: in GLX these are never set, simply provided to make the rest of the code work
105 qboolean is8bit = false;
106 qboolean isPermedia = false;
107 qboolean isATI = false;
108 qboolean isG200 = false;
109 qboolean isRagePro = false;
110 qboolean gl_mtexable = false;
111 qboolean gl_arrays = false;
112
113 /*-----------------------------------------------------------------------*/
114 void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
115 {
116 }
117
118 void D_EndDirectRect (int x, int y, int width, int height)
119 {
120 }
121
122 static int XLateKey(XKeyEvent *ev)
123 {
124
125         int key;
126         char buf[64];
127         KeySym keysym;
128
129         key = 0;
130
131         XLookupString(ev, buf, sizeof buf, &keysym, 0);
132
133         switch(keysym)
134         {
135                 case XK_KP_Page_Up:      
136                 case XK_Page_Up:         key = K_PGUP; break;
137
138                 case XK_KP_Page_Down: 
139                 case XK_Page_Down:       key = K_PGDN; break;
140
141                 case XK_KP_Home: 
142                 case XK_Home:    key = K_HOME; break;
143
144                 case XK_KP_End:  
145                 case XK_End:     key = K_END; break;
146
147                 case XK_KP_Left: 
148                 case XK_Left:    key = K_LEFTARROW; break;
149
150                 case XK_KP_Right: 
151                 case XK_Right:  key = K_RIGHTARROW;             break;
152
153                 case XK_KP_Down: 
154                 case XK_Down:    key = K_DOWNARROW; break;
155
156                 case XK_KP_Up:   
157                 case XK_Up:              key = K_UPARROW;        break;
158
159                 case XK_Escape: key = K_ESCAPE;         break;
160
161                 case XK_KP_Enter: 
162                 case XK_Return: key = K_ENTER;           break;
163
164                 case XK_Tab:            key = K_TAB;                     break;
165
166                 case XK_F1:              key = K_F1;                            break;
167
168                 case XK_F2:              key = K_F2;                            break;
169
170                 case XK_F3:              key = K_F3;                            break;
171
172                 case XK_F4:              key = K_F4;                            break;
173
174                 case XK_F5:              key = K_F5;                            break;
175
176                 case XK_F6:              key = K_F6;                            break;
177
178                 case XK_F7:              key = K_F7;                            break;
179
180                 case XK_F8:              key = K_F8;                            break;
181
182                 case XK_F9:              key = K_F9;                            break;
183
184                 case XK_F10:            key = K_F10;                     break;
185
186                 case XK_F11:            key = K_F11;                     break;
187
188                 case XK_F12:            key = K_F12;                     break;
189
190                 case XK_BackSpace: key = K_BACKSPACE; break;
191
192                 case XK_KP_Delete: 
193                 case XK_Delete: key = K_DEL; break;
194
195                 case XK_Pause:  key = K_PAUSE;           break;
196
197                 case XK_Shift_L:
198                 case XK_Shift_R:        key = K_SHIFT;          break;
199
200                 case XK_Execute: 
201                 case XK_Control_L: 
202                 case XK_Control_R:      key = K_CTRL;            break;
203
204                 case XK_Alt_L:  
205                 case XK_Meta_L: 
206                 case XK_Alt_R:  
207                 case XK_Meta_R: key = K_ALT;                    break;
208
209                 case XK_KP_Begin: key = '5';    break;
210
211                 case XK_KP_Insert: 
212                 case XK_Insert:key = K_INS; break;
213
214                 case XK_KP_Multiply: key = '*'; break;
215                 case XK_KP_Add:  key = '+'; break;
216                 case XK_KP_Subtract: key = '-'; break;
217                 case XK_KP_Divide: key = '/'; break;
218
219 #if 0
220                 case 0x021: key = '1';break;/* [!] */
221                 case 0x040: key = '2';break;/* [@] */
222                 case 0x023: key = '3';break;/* [#] */
223                 case 0x024: key = '4';break;/* [$] */
224                 case 0x025: key = '5';break;/* [%] */
225                 case 0x05e: key = '6';break;/* [^] */
226                 case 0x026: key = '7';break;/* [&] */
227                 case 0x02a: key = '8';break;/* [*] */
228                 case 0x028: key = '9';;break;/* [(] */
229                 case 0x029: key = '0';break;/* [)] */
230                 case 0x05f: key = '-';break;/* [_] */
231                 case 0x02b: key = '=';break;/* [+] */
232                 case 0x07c: key = '\'';break;/* [|] */
233                 case 0x07d: key = '[';break;/* [}] */
234                 case 0x07b: key = ']';break;/* [{] */
235                 case 0x022: key = '\'';break;/* ["] */
236                 case 0x03a: key = ';';break;/* [:] */
237                 case 0x03f: key = '/';break;/* [?] */
238                 case 0x03e: key = '.';break;/* [>] */
239                 case 0x03c: key = ',';break;/* [<] */
240 #endif
241
242                 default:
243                         key = *(unsigned char*)buf;
244                         if (key >= 'A' && key <= 'Z')
245                                 key = key - 'A' + 'a';
246                         break;
247         } 
248
249         return key;
250 }
251
252 static Cursor CreateNullCursor(Display *display, Window root)
253 {
254     Pixmap cursormask; 
255     XGCValues xgc;
256     GC gc;
257     XColor dummycolour;
258     Cursor cursor;
259
260     cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
261     xgc.function = GXclear;
262     gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
263     XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
264     dummycolour.pixel = 0;
265     dummycolour.red = 0;
266     dummycolour.flags = 04;
267     cursor = XCreatePixmapCursor(display, cursormask, cursormask,
268           &dummycolour,&dummycolour, 0,0);
269     XFreePixmap(display,cursormask);
270     XFreeGC(display,gc);
271     return cursor;
272 }
273
274 static void install_grabs(void)
275 {
276
277 // inviso cursor
278         XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
279
280         XGrabPointer(dpy, win,
281                                  True,
282                                  0,
283                                  GrabModeAsync, GrabModeAsync,
284                                  win,
285                                  None,
286                                  CurrentTime);
287
288         if (in_dgamouse.value) {
289                 int MajorVersion, MinorVersion;
290
291                 if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) { 
292                         // unable to query, probalby not supported
293                         Con_Printf( "Failed to detect XF86DGA Mouse\n" );
294                         in_dgamouse.value = 0;
295                 } else {
296                         dgamouse = true;
297                         XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
298                         XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
299                 }
300         } else {
301                 XWarpPointer(dpy, None, win,
302                                          0, 0, 0, 0,
303                                          vid.width / 2, vid.height / 2);
304         }
305
306         XGrabKeyboard(dpy, win,
307                                   False,
308                                   GrabModeAsync, GrabModeAsync,
309                                   CurrentTime);
310
311         mouse_active = true;
312
313 //      XSync(dpy, True);
314 }
315
316 static void uninstall_grabs(void)
317 {
318         if (!dpy || !win)
319                 return;
320
321         if (dgamouse) {
322                 dgamouse = false;
323                 XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
324         }
325
326         XUngrabPointer(dpy, CurrentTime);
327         XUngrabKeyboard(dpy, CurrentTime);
328
329 // inviso cursor
330         XUndefineCursor(dpy, win);
331
332         mouse_active = false;
333 }
334
335 static void HandleEvents(void)
336 {
337         XEvent event;
338 //      KeySym ks;
339         int b;
340         qboolean dowarp = false;
341         int mwx = vid.width/2;
342         int mwy = vid.height/2;
343
344         if (!dpy)
345                 return;
346
347         while (XPending(dpy)) {
348                 XNextEvent(dpy, &event);
349
350                 switch (event.type) {
351                 case KeyPress:
352                 case KeyRelease:
353                         Key_Event(XLateKey(&event.xkey), event.type == KeyPress);
354                         break;
355
356                 case MotionNotify:
357                         if (mouse_active) {
358                                 if (dgamouse) {
359                                         mx += (event.xmotion.x + win_x) * 2;
360                                         my += (event.xmotion.y + win_y) * 2;
361                                 } 
362                                 else 
363                                 {
364                                         mx += ((int)event.xmotion.x - mwx) * 2;
365                                         my += ((int)event.xmotion.y - mwy) * 2;
366                                         mwx = event.xmotion.x;
367                                         mwy = event.xmotion.y;
368
369                                         if (mx || my)
370                                                 dowarp = true;
371                                 }
372                         }
373                         break;
374
375                         break;
376
377                 case ButtonPress:
378                         b=-1;
379                         if (event.xbutton.button == 1)
380                                 b = 0;
381                         else if (event.xbutton.button == 2)
382                                 b = 2;
383                         else if (event.xbutton.button == 3)
384                                 b = 1;
385                         if (b>=0)
386                                 Key_Event(K_MOUSE1 + b, true);
387                         break;
388
389                 case ButtonRelease:
390                         b=-1;
391                         if (event.xbutton.button == 1)
392                                 b = 0;
393                         else if (event.xbutton.button == 2)
394                                 b = 2;
395                         else if (event.xbutton.button == 3)
396                                 b = 1;
397                         if (b>=0)
398                                 Key_Event(K_MOUSE1 + b, false);
399                         break;
400
401                 case CreateNotify :
402                         win_x = event.xcreatewindow.x;
403                         win_y = event.xcreatewindow.y;
404                         break;
405
406                 case ConfigureNotify :
407                         win_x = event.xconfigure.x;
408                         win_y = event.xconfigure.y;
409                         break;
410                 }
411         }
412
413         if (dowarp) {
414                 /* move the mouse to the window center again */
415                 XWarpPointer(dpy, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2);
416         }
417
418 }
419
420 static void IN_DeactivateMouse( void ) 
421 {
422         if (!mouse_avail || !dpy || !win)
423                 return;
424
425         if (mouse_active) {
426                 uninstall_grabs();
427                 mouse_active = false;
428         }
429 }
430
431 static void IN_ActivateMouse( void ) 
432 {
433         if (!mouse_avail || !dpy || !win)
434                 return;
435
436         if (!mouse_active) {
437                 mx = my = 0; // don't spazz
438                 install_grabs();
439                 mouse_active = true;
440         }
441 }
442
443
444 void VID_Shutdown(void)
445 {
446         if (!ctx || !dpy)
447                 return;
448         IN_DeactivateMouse();
449         if (dpy) {
450                 if (ctx)
451                         glXDestroyContext(dpy, ctx);
452                 if (win)
453                         XDestroyWindow(dpy, win);
454                 if (vidmode_active)
455                         XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]);
456                 XCloseDisplay(dpy);
457         }
458         vidmode_active = false;
459         dpy = NULL;
460         win = 0;
461         ctx = NULL;
462 }
463
464 void signal_handler(int sig)
465 {
466         printf("Received signal %d, exiting...\n", sig);
467         Sys_Quit();
468         exit(0);
469 }
470
471 void InitSig(void)
472 {
473         signal(SIGHUP, signal_handler);
474         signal(SIGINT, signal_handler);
475         signal(SIGQUIT, signal_handler);
476         signal(SIGILL, signal_handler);
477         signal(SIGTRAP, signal_handler);
478         signal(SIGIOT, signal_handler);
479         signal(SIGBUS, signal_handler);
480         signal(SIGFPE, signal_handler);
481         signal(SIGSEGV, signal_handler);
482         signal(SIGTERM, signal_handler);
483 }
484
485 /*
486 void (*qglVertexPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
487 void (*qglColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
488 void (*qglTexCoordPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
489 void (*qglArrayElement)(GLint i);
490 void (*qglDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
491 void (*qglMTexCoord2f)(GLenum, GLfloat, GLfloat);
492 void (*qglSelectTexture)(GLenum);
493 void (*glColorTableEXT)(int, int, int, int, int, const void*);
494
495 void CheckVertexArrays (void)
496 {
497         void *prjobj;
498         if (COM_CheckParm("-novertex"))
499         {
500                 Con_Printf("...vertex array support disabled\n");
501                 return;
502         }
503         if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL)
504         {
505                 Con_Printf("Unable to open symbol list for main program.\n");
506                 return;
507         }
508         qglMTexCoord2fSGIS = (void *) dlsym(prjobj, "glMTexCoord2fSGIS");
509         if ((qglArrayElement = (void *) dlsym(prjobj, "glArrayElement"))
510          && (qglColorPointer = (void *) dlsym(prjobj, "glColorPointer"))
511 //       && (qglDrawArrays = (void *) dlsym(prjobj, "glDrawArrays"))
512          && (qglDrawElements = (void *) dlsym(prjobj, "glDrawElements"))
513 //       && (qglInterleavedArrays = (void *) dlsym(prjobj, "glInterleavedArrays"))
514          && (qglTexCoordPointer = (void *) dlsym(prjobj, "glTexCoordPointer"))
515          && (qglVertexPointer = (void *) dlsym(prjobj, "glVertexPointer"))
516                 )
517         {
518                 Con_Printf("...vertex array support detected\n");
519                 gl_arrays = true;
520                 dlclose(prjobj);
521                 return;
522         }
523
524         Con_Printf("...vertex array support disabled (not detected - get a better driver)\n");
525         dlclose(prjobj);
526 }
527 */
528
529 void CheckMultiTexture(void) 
530 {
531         void *prjobj;
532         qglMTexCoord2f = NULL;
533         qglSelectTexture = NULL;
534         // Check to see if multitexture is disabled
535         if (COM_CheckParm("-nomtex"))
536         {
537                 Con_Printf("...multitexture disabled\n");
538                 return;
539         }
540         if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL)
541         {
542                 Con_Printf("Unable to open symbol list for main program.\n");
543                 return;
544         }
545         // Test for ARB_multitexture
546         if (!COM_CheckParm("-SGISmtex") && strstr(gl_extensions, "GL_ARB_multitexture "))
547         {
548                 Con_Printf("...using GL_ARB_multitexture\n");
549                 qglMTexCoord2f = (void *) dlsym(prjobj, "glMultiTexCoord2fARB");
550                 qglSelectTexture = (void *) dlsym(prjobj, "glActiveTextureARB");
551                 gl_mtexable = true;
552                 gl_mtex_enum = GL_TEXTURE0_ARB;
553         }
554         else if (strstr(gl_extensions, "GL_SGIS_multitexture ")) // Test for SGIS_multitexture (if ARB_multitexture not found)
555         {
556                 Con_Printf("...using GL_SGIS_multitexture\n");
557                 qglMTexCoord2f = (void *) dlsym(prjobj, "glMTexCoord2fSGIS");
558                 qglSelectTexture = (void *) dlsym(prjobj, "glSelectTextureSGIS");
559                 gl_mtexable = true;
560                 gl_mtex_enum = TEXTURE0_SGIS;
561         }
562         if (!gl_mtexable)
563                 Con_Printf("...multitexture disabled (not detected)\n");
564         dlclose(prjobj);
565 }
566
567 /*
568 ===============
569 GL_Init
570 ===============
571 */
572 extern char *QSG_EXTENSIONS;
573 void GL_Init (void)
574 {
575         gl_vendor = glGetString (GL_VENDOR);
576         Con_Printf ("GL_VENDOR: %s\n", gl_vendor);
577         gl_renderer = glGetString (GL_RENDERER);
578         Con_Printf ("GL_RENDERER: %s\n", gl_renderer);
579
580         gl_version = glGetString (GL_VERSION);
581         Con_Printf ("GL_VERSION: %s\n", gl_version);
582         gl_extensions = glGetString (GL_EXTENSIONS);
583         Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions);
584
585 //      Con_Printf ("%s %s\n", gl_renderer, gl_version);
586
587         CheckMultiTexture();
588 //      CheckVertexArrays();
589
590         // LordHavoc: report supported extensions
591         Con_Printf ("\nQSG extensions: %s\n", QSG_EXTENSIONS);
592
593         glCullFace(GL_FRONT);
594         glAlphaFunc(GL_GREATER, 0.5);
595 }
596
597 /*
598 =================
599 GL_BeginRendering
600
601 =================
602 */
603 void GL_BeginRendering (int *x, int *y, int *width, int *height)
604 {
605         *x = *y = 0;
606         *width = scr_width;
607         *height = scr_height;
608
609 //    if (!wglMakeCurrent( maindc, baseRC ))
610 //              Sys_Error ("wglMakeCurrent failed");
611
612 //      glViewport (*x, *y, *width, *height);
613 }
614
615
616 void GL_EndRendering (void)
617 {
618         if (!r_render.value)
619                 return;
620         glFlush();
621         glXSwapBuffers(dpy, win);
622 }
623
624 qboolean VID_Is8bit(void)
625 {
626         return is8bit;
627 }
628
629 void VID_Init8bitPalette(void) 
630 {
631         // Check for 8bit Extensions and initialize them.
632         int i;
633         void *prjobj;
634
635         if (!COM_CheckParm("-8bit"))
636                 return;
637         if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL)
638         {
639                 Con_Printf("Unable to open symbol list for main program.\n");
640                 return;
641         }
642
643         if (strstr(gl_extensions, "3DFX_set_global_palette") && (qgl3DfxSetPaletteEXT = dlsym(prjobj, "gl3DfxSetPaletteEXT")) != NULL)
644         {
645                 GLubyte table[256][4];
646                 char *oldpal;
647
648                 Con_SafePrintf("8-bit GL extensions enabled.\n");
649                 glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
650                 oldpal = (char *) d_8to24table; //d_8to24table3dfx;
651                 for (i=0;i<256;i++)
652                 {
653                         table[i][2] = *oldpal++;
654                         table[i][1] = *oldpal++;
655                         table[i][0] = *oldpal++;
656                         table[i][3] = 255;
657                         oldpal++;
658                 }
659                 qgl3DfxSetPaletteEXT((GLuint *)table);
660                 is8bit = true;
661
662         }
663         else if (strstr(gl_extensions, "GL_EXT_shared_texture_palette") && (qglColorTableEXT = dlsym(prjobj, "glColorTableEXT")) != NULL)
664         {
665                 char thePalette[256*3];
666                 char *oldPalette, *newPalette;
667
668                 Con_SafePrintf("8-bit GL extensions enabled.\n");
669                 glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
670                 oldPalette = (char *) d_8to24table; //d_8to24table3dfx;
671                 newPalette = thePalette;
672                 for (i=0;i<256;i++)
673                 {
674                         *newPalette++ = *oldPalette++;
675                         *newPalette++ = *oldPalette++;
676                         *newPalette++ = *oldPalette++;
677                         oldPalette++;
678                 }
679                 qglColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, (void *) thePalette);
680                 is8bit = true;
681         }
682         
683         dlclose(prjobj);
684 }
685
686 extern void Check_Gamma (unsigned char *pal);
687 void VID_Setup15to8Palette ();
688
689 void VID_Init(unsigned char *palette)
690 {
691         int i;
692         int attrib[] = {
693                 GLX_RGBA,
694                 GLX_RED_SIZE, 1,
695                 GLX_GREEN_SIZE, 1,
696                 GLX_BLUE_SIZE, 1,
697                 GLX_DOUBLEBUFFER,
698                 GLX_DEPTH_SIZE, 1,
699                 None
700         };
701 //      char    gldir[MAX_OSPATH];
702         int width = 640, height = 480;
703         XSetWindowAttributes attr;
704         unsigned long mask;
705         Window root;
706         XVisualInfo *visinfo;
707         qboolean fullscreen = true;
708         int MajorVersion, MinorVersion;
709         int actualWidth, actualHeight;
710
711         Cvar_RegisterVariable (&vid_mode);
712         Cvar_RegisterVariable (&in_mouse);
713         Cvar_RegisterVariable (&in_dgamouse);
714         Cvar_RegisterVariable (&m_filter);
715         
716 // interpret command-line params
717
718 // set vid parameters
719         if ((i = COM_CheckParm("-window")) != 0)
720                 fullscreen = false;
721
722         if ((i = COM_CheckParm("-width")) != 0)
723                 width = atoi(com_argv[i+1]);
724
725         if ((i = COM_CheckParm("-height")) != 0)
726                 height = atoi(com_argv[i+1]);
727
728         if ((i = COM_CheckParm("-conwidth")) != 0)
729                 vid.conwidth = atoi(com_argv[i+1]);
730         else
731                 vid.conwidth = 640;
732
733         vid.conwidth &= 0xfff8; // make it a multiple of eight
734
735         if (vid.conwidth < 320)
736                 vid.conwidth = 320;
737
738         // pick a conheight that matches with correct aspect
739         vid.conheight = vid.conwidth*3 / 4;
740
741         if ((i = COM_CheckParm("-conheight")) != 0)
742                 vid.conheight = atoi(com_argv[i+1]);
743         if (vid.conheight < 200)
744                 vid.conheight = 200;
745
746         if (!(dpy = XOpenDisplay(NULL))) {
747                 fprintf(stderr, "Error couldn't open the X display\n");
748                 exit(1);
749         }
750
751         scrnum = DefaultScreen(dpy);
752         root = RootWindow(dpy, scrnum);
753
754         // Get video mode list
755         MajorVersion = MinorVersion = 0;
756         if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion)) { 
757                 vidmode_ext = false;
758         } else {
759                 Con_Printf("Using XFree86-VidModeExtension Version %d.%d\n", MajorVersion, MinorVersion);
760                 vidmode_ext = true;
761         }
762
763         visinfo = glXChooseVisual(dpy, scrnum, attrib);
764         if (!visinfo) {
765                 fprintf(stderr, "qkHack: Error couldn't get an RGB, Double-buffered, Depth visual\n");
766                 exit(1);
767         }
768
769         if (vidmode_ext) {
770                 int best_fit, best_dist, dist, x, y;
771                 
772                 XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
773
774                 // Are we going fullscreen?  If so, let's change video mode
775                 if (fullscreen) {
776                         best_dist = 9999999;
777                         best_fit = -1;
778
779                         for (i = 0; i < num_vidmodes; i++) {
780                                 if (width > vidmodes[i]->hdisplay ||
781                                         height > vidmodes[i]->vdisplay)
782                                         continue;
783
784                                 x = width - vidmodes[i]->hdisplay;
785                                 y = height - vidmodes[i]->vdisplay;
786                                 dist = (x * x) + (y * y);
787                                 if (dist < best_dist) {
788                                         best_dist = dist;
789                                         best_fit = i;
790                                 }
791                         }
792
793                         if (best_fit != -1) {
794                                 actualWidth = vidmodes[best_fit]->hdisplay;
795                                 actualHeight = vidmodes[best_fit]->vdisplay;
796
797                                 // change to the mode
798                                 XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
799                                 vidmode_active = true;
800
801                                 // Move the viewport to top left
802                                 XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
803                         } else
804                                 fullscreen = 0;
805                 }
806         }
807
808         /* window attributes */
809         attr.background_pixel = 0;
810         attr.border_pixel = 0;
811         attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
812         attr.event_mask = X_MASK;
813         if (vidmode_active) {
814                 mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | 
815                         CWEventMask | CWOverrideRedirect;
816                 attr.override_redirect = True;
817                 attr.backing_store = NotUseful;
818                 attr.save_under = False;
819         } else
820                 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
821
822         win = XCreateWindow(dpy, root, 0, 0, width, height,
823                                                 0, visinfo->depth, InputOutput,
824                                                 visinfo->visual, mask, &attr);
825         XMapWindow(dpy, win);
826
827         if (vidmode_active) {
828                 XMoveWindow(dpy, win, 0, 0);
829                 XRaiseWindow(dpy, win);
830                 XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
831                 XFlush(dpy);
832                 // Move the viewport to top left
833                 XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
834         }
835
836         XFlush(dpy);
837
838         ctx = glXCreateContext(dpy, visinfo, NULL, True);
839
840         glXMakeCurrent(dpy, win, ctx);
841
842         scr_width = width;
843         scr_height = height;
844
845         if (vid.conheight > height)
846                 vid.conheight = height;
847         if (vid.conwidth > width)
848                 vid.conwidth = width;
849         vid.width = vid.conwidth;
850         vid.height = vid.conheight;
851
852         vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
853
854         InitSig(); // trap evil signals
855
856         GL_Init();
857
858 //      sprintf (gldir, "%s/glquake", com_gamedir);
859 //      Sys_mkdir (gldir);
860
861         VID_SetPalette(palette);
862
863         Check_Gamma(palette);
864
865         VID_Init8bitPalette();
866
867         if (is8bit) // LordHavoc: avoid calculating 15to8 table if it won't be used
868                 VID_Setup15to8Palette ();
869
870         Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height);
871
872         vid.recalc_refdef = 1;                          // force a surface cache flush
873 }
874
875 void Sys_SendKeyEvents(void)
876 {
877         HandleEvents();
878 }
879
880 void Force_CenterView_f (void)
881 {
882         cl.viewangles[PITCH] = 0;
883 }
884
885 void IN_Init(void)
886 {
887 }
888
889 void IN_Shutdown(void)
890 {
891 }
892
893 /*
894 ===========
895 IN_Commands
896 ===========
897 */
898 void IN_Commands (void)
899 {
900         if (!dpy || !win)
901                 return;
902
903         if (vidmode_active || key_dest == key_game)
904                 IN_ActivateMouse();
905         else
906                 IN_DeactivateMouse ();
907 }
908
909 /*
910 ===========
911 IN_Move
912 ===========
913 */
914 void IN_MouseMove (usercmd_t *cmd)
915 {
916         if (!mouse_avail)
917                 return;
918    
919         if (m_filter.value)
920         {
921                 mx = (mx + old_mouse_x) * 0.5;
922                 my = (my + old_mouse_y) * 0.5;
923         }
924         old_mouse_x = mx;
925         old_mouse_y = my;
926
927         mx *= sensitivity.value;
928         my *= sensitivity.value;
929
930 // add mouse X/Y movement to cmd
931         if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
932                 cmd->sidemove += m_side.value * mx;
933         else
934                 cl.viewangles[YAW] -= m_yaw.value * mx;
935         
936         if (in_mlook.state & 1)
937                 V_StopPitchDrift ();
938                 
939         if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
940         {
941                 cl.viewangles[PITCH] += m_pitch.value * my;
942                 if (cl.viewangles[PITCH] > 80)
943                         cl.viewangles[PITCH] = 80;
944                 if (cl.viewangles[PITCH] < -70)
945                         cl.viewangles[PITCH] = -70;
946         }
947         else
948         {
949                 if ((in_strafe.state & 1) && noclip_anglehack)
950                         cmd->upmove -= m_forward.value * my;
951                 else
952                         cmd->forwardmove -= m_forward.value * my;
953         }
954         mx = my = 0;
955 }
956
957 void IN_Move (usercmd_t *cmd)
958 {
959         IN_MouseMove(cmd);
960 }
961
962