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