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