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