implemented r_render and r_upload cvar options for CPU profiling (not hardware bound...
[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         if (!r_render.value)
626                 return;
627         glFlush();
628         glXSwapBuffers(dpy, win);
629 }
630
631 qboolean VID_Is8bit(void)
632 {
633         return is8bit;
634 }
635
636 void VID_Init8bitPalette(void) 
637 {
638         // Check for 8bit Extensions and initialize them.
639         int i;
640         void *prjobj;
641
642         if (!COM_CheckParm("-8bit"))
643                 return;
644         if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL)
645         {
646                 Con_Printf("Unable to open symbol list for main program.\n");
647                 return;
648         }
649
650         if (strstr(gl_extensions, "3DFX_set_global_palette") && (qgl3DfxSetPaletteEXT = dlsym(prjobj, "gl3DfxSetPaletteEXT")) != NULL)
651         {
652                 GLubyte table[256][4];
653                 char *oldpal;
654
655                 Con_SafePrintf("8-bit GL extensions enabled.\n");
656                 glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
657                 oldpal = (char *) d_8to24table; //d_8to24table3dfx;
658                 for (i=0;i<256;i++)
659                 {
660                         table[i][2] = *oldpal++;
661                         table[i][1] = *oldpal++;
662                         table[i][0] = *oldpal++;
663                         table[i][3] = 255;
664                         oldpal++;
665                 }
666                 qgl3DfxSetPaletteEXT((GLuint *)table);
667                 is8bit = true;
668
669         }
670         else if (strstr(gl_extensions, "GL_EXT_shared_texture_palette") && (qglColorTableEXT = dlsym(prjobj, "glColorTableEXT")) != NULL)
671         {
672                 char thePalette[256*3];
673                 char *oldPalette, *newPalette;
674
675                 Con_SafePrintf("8-bit GL extensions enabled.\n");
676                 glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
677                 oldPalette = (char *) d_8to24table; //d_8to24table3dfx;
678                 newPalette = thePalette;
679                 for (i=0;i<256;i++)
680                 {
681                         *newPalette++ = *oldPalette++;
682                         *newPalette++ = *oldPalette++;
683                         *newPalette++ = *oldPalette++;
684                         oldPalette++;
685                 }
686                 qglColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, (void *) thePalette);
687                 is8bit = true;
688         }
689         
690         dlclose(prjobj);
691 }
692
693 extern void Check_Gamma (unsigned char *pal);
694 void VID_Setup15to8Palette ();
695
696 void VID_Init(unsigned char *palette)
697 {
698         int i;
699         int attrib[] = {
700                 GLX_RGBA,
701                 GLX_RED_SIZE, 1,
702                 GLX_GREEN_SIZE, 1,
703                 GLX_BLUE_SIZE, 1,
704                 GLX_DOUBLEBUFFER,
705                 GLX_DEPTH_SIZE, 1,
706                 None
707         };
708 //      char    gldir[MAX_OSPATH];
709         int width = 640, height = 480;
710         XSetWindowAttributes attr;
711         unsigned long mask;
712         Window root;
713         XVisualInfo *visinfo;
714         qboolean fullscreen = true;
715         int MajorVersion, MinorVersion;
716         int actualWidth, actualHeight;
717
718         Cvar_RegisterVariable (&vid_mode);
719         Cvar_RegisterVariable (&in_mouse);
720         Cvar_RegisterVariable (&in_dgamouse);
721         Cvar_RegisterVariable (&m_filter);
722         
723 // interpret command-line params
724
725 // set vid parameters
726         if ((i = COM_CheckParm("-window")) != 0)
727                 fullscreen = false;
728
729         if ((i = COM_CheckParm("-width")) != 0)
730                 width = atoi(com_argv[i+1]);
731
732         if ((i = COM_CheckParm("-height")) != 0)
733                 height = atoi(com_argv[i+1]);
734
735         if ((i = COM_CheckParm("-conwidth")) != 0)
736                 vid.conwidth = atoi(com_argv[i+1]);
737         else
738                 vid.conwidth = 640;
739
740         vid.conwidth &= 0xfff8; // make it a multiple of eight
741
742         if (vid.conwidth < 320)
743                 vid.conwidth = 320;
744
745         // pick a conheight that matches with correct aspect
746         vid.conheight = vid.conwidth*3 / 4;
747
748         if ((i = COM_CheckParm("-conheight")) != 0)
749                 vid.conheight = atoi(com_argv[i+1]);
750         if (vid.conheight < 200)
751                 vid.conheight = 200;
752
753         if (!(dpy = XOpenDisplay(NULL))) {
754                 fprintf(stderr, "Error couldn't open the X display\n");
755                 exit(1);
756         }
757
758         scrnum = DefaultScreen(dpy);
759         root = RootWindow(dpy, scrnum);
760
761         // Get video mode list
762         MajorVersion = MinorVersion = 0;
763         if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion)) { 
764                 vidmode_ext = false;
765         } else {
766                 Con_Printf("Using XFree86-VidModeExtension Version %d.%d\n", MajorVersion, MinorVersion);
767                 vidmode_ext = true;
768         }
769
770         visinfo = glXChooseVisual(dpy, scrnum, attrib);
771         if (!visinfo) {
772                 fprintf(stderr, "qkHack: Error couldn't get an RGB, Double-buffered, Depth visual\n");
773                 exit(1);
774         }
775
776         if (vidmode_ext) {
777                 int best_fit, best_dist, dist, x, y;
778                 
779                 XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
780
781                 // Are we going fullscreen?  If so, let's change video mode
782                 if (fullscreen) {
783                         best_dist = 9999999;
784                         best_fit = -1;
785
786                         for (i = 0; i < num_vidmodes; i++) {
787                                 if (width > vidmodes[i]->hdisplay ||
788                                         height > vidmodes[i]->vdisplay)
789                                         continue;
790
791                                 x = width - vidmodes[i]->hdisplay;
792                                 y = height - vidmodes[i]->vdisplay;
793                                 dist = (x * x) + (y * y);
794                                 if (dist < best_dist) {
795                                         best_dist = dist;
796                                         best_fit = i;
797                                 }
798                         }
799
800                         if (best_fit != -1) {
801                                 actualWidth = vidmodes[best_fit]->hdisplay;
802                                 actualHeight = vidmodes[best_fit]->vdisplay;
803
804                                 // change to the mode
805                                 XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
806                                 vidmode_active = true;
807
808                                 // Move the viewport to top left
809                                 XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
810                         } else
811                                 fullscreen = 0;
812                 }
813         }
814
815         /* window attributes */
816         attr.background_pixel = 0;
817         attr.border_pixel = 0;
818         attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
819         attr.event_mask = X_MASK;
820         if (vidmode_active) {
821                 mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | 
822                         CWEventMask | CWOverrideRedirect;
823                 attr.override_redirect = True;
824                 attr.backing_store = NotUseful;
825                 attr.save_under = False;
826         } else
827                 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
828
829         win = XCreateWindow(dpy, root, 0, 0, width, height,
830                                                 0, visinfo->depth, InputOutput,
831                                                 visinfo->visual, mask, &attr);
832         XMapWindow(dpy, win);
833
834         if (vidmode_active) {
835                 XMoveWindow(dpy, win, 0, 0);
836                 XRaiseWindow(dpy, win);
837                 XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
838                 XFlush(dpy);
839                 // Move the viewport to top left
840                 XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
841         }
842
843         XFlush(dpy);
844
845         ctx = glXCreateContext(dpy, visinfo, NULL, True);
846
847         glXMakeCurrent(dpy, win, ctx);
848
849         scr_width = width;
850         scr_height = height;
851
852         if (vid.conheight > height)
853                 vid.conheight = height;
854         if (vid.conwidth > width)
855                 vid.conwidth = width;
856         vid.width = vid.conwidth;
857         vid.height = vid.conheight;
858
859         vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
860
861         InitSig(); // trap evil signals
862
863         GL_Init();
864
865 //      sprintf (gldir, "%s/glquake", com_gamedir);
866 //      Sys_mkdir (gldir);
867
868         VID_SetPalette(palette);
869
870         Check_Gamma(palette);
871
872         VID_Init8bitPalette();
873
874         if (is8bit) // LordHavoc: avoid calculating 15to8 table if it won't be used
875                 VID_Setup15to8Palette ();
876
877         Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height);
878
879         vid.recalc_refdef = 1;                          // force a surface cache flush
880 }
881
882 void Sys_SendKeyEvents(void)
883 {
884         HandleEvents();
885 }
886
887 void Force_CenterView_f (void)
888 {
889         cl.viewangles[PITCH] = 0;
890 }
891
892 void IN_Init(void)
893 {
894 }
895
896 void IN_Shutdown(void)
897 {
898 }
899
900 /*
901 ===========
902 IN_Commands
903 ===========
904 */
905 void IN_Commands (void)
906 {
907         if (!dpy || !win)
908                 return;
909
910         if (vidmode_active || key_dest == key_game)
911                 IN_ActivateMouse();
912         else
913                 IN_DeactivateMouse ();
914 }
915
916 /*
917 ===========
918 IN_Move
919 ===========
920 */
921 void IN_MouseMove (usercmd_t *cmd)
922 {
923         if (!mouse_avail)
924                 return;
925    
926         if (m_filter.value)
927         {
928                 mx = (mx + old_mouse_x) * 0.5;
929                 my = (my + old_mouse_y) * 0.5;
930         }
931         old_mouse_x = mx;
932         old_mouse_y = my;
933
934         mx *= sensitivity.value;
935         my *= sensitivity.value;
936
937 // add mouse X/Y movement to cmd
938         if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
939                 cmd->sidemove += m_side.value * mx;
940         else
941                 cl.viewangles[YAW] -= m_yaw.value * mx;
942         
943         if (in_mlook.state & 1)
944                 V_StopPitchDrift ();
945                 
946         if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
947         {
948                 cl.viewangles[PITCH] += m_pitch.value * my;
949                 if (cl.viewangles[PITCH] > 80)
950                         cl.viewangles[PITCH] = 80;
951                 if (cl.viewangles[PITCH] < -70)
952                         cl.viewangles[PITCH] = -70;
953         }
954         else
955         {
956                 if ((in_strafe.state & 1) && noclip_anglehack)
957                         cmd->upmove -= m_forward.value * my;
958                 else
959                         cmd->forwardmove -= m_forward.value * my;
960         }
961         mx = my = 0;
962 }
963
964 void IN_Move (usercmd_t *cmd)
965 {
966         IN_MouseMove(cmd);
967 }
968
969