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#include <asm/io.h>
28
29//#include <X11/cursorfont.h>
30#include <X11/Xlib.h>
31#include <X11/Xutil.h>
32#include <X11/Xatom.h>
33#include <X11/keysym.h>
34
35#include "GL/gl.h"
36#include "GL/glx.h"
37
38#include "quakedef.h"
39
40#define WARP_WIDTH              320
41#define WARP_HEIGHT             200
42
43static Display *dpy = NULL;
44static Window win;
45static GLXContext ctx = NULL;
46
47unsigned short d_8to16table[256];
48unsigned int d_8to24table[256];
49unsigned char d_15to8table[65536];
50
51static qboolean usedga = false;
52
53#define stringify(m) { #m, m }
54
55cvar_t vid_mode = {"vid_mode","0",false};
56
57cvar_t  mouse_button_commands[3] =
58{
59    {"mouse1","+attack"},
60    {"mouse2","+strafe"},
61    {"mouse3","+forward"},
62};
63
64static int mouse_buttons=3;
65static int mouse_buttonstate;
66static int mouse_oldbuttonstate;
67static float mouse_x, mouse_y;
68static float p_mouse_x, p_mouse_y;
69static float old_mouse_x, old_mouse_y;
70
71cvar_t _windowed_mouse = {"_windowed_mouse", "1", true};
72cvar_t m_filter = {"m_filter","0"};
73static float old_windowed_mouse;
74
75static int scr_width, scr_height;
76
77#define KEY_MASK (KeyPressMask | KeyReleaseMask)
78#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
79		    PointerMotionMask | ButtonMotionMask)
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
101qboolean is8bit = false;
102qboolean isPermedia = false;
103qboolean gl_mtexable = false;
104
105/*-----------------------------------------------------------------------*/
106void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
107{
108}
109
110void D_EndDirectRect (int x, int y, int width, int height)
111{
112}
113
114/*
115=================
116VID_Gamma_f
117
118Keybinding command
119=================
120*/
121void VID_Gamma_f (void)
122{
123	float	gamma, f, inf;
124	unsigned char	palette[768];
125	int		i;
126
127	if (Cmd_Argc () == 2)
128	{
129		gamma = Q_atof (Cmd_Argv(1));
130
131		for (i=0 ; i<768 ; i++)
132		{
133			f = pow ( (host_basepal[i]+1)/256.0 , gamma );
134			inf = f*255 + 0.5;
135			if (inf < 0)
136				inf = 0;
137			if (inf > 255)
138				inf = 255;
139			palette[i] = inf;
140		}
141
142		VID_SetPalette (palette);
143
144		vid.recalc_refdef = 1;				// force a surface cache flush
145	}
146}
147
148void VID_Shutdown(void)
149{
150	if (!ctx)
151		return;
152
153	XUngrabPointer(dpy,CurrentTime);
154	XUngrabKeyboard(dpy,CurrentTime);
155
156	glXDestroyContext(dpy,ctx);
157
158#ifdef USE_DGA
159	if (usedga)
160		XF86DGADirectVideo(dpy,DefaultScreen(dpy),0);
161#endif
162}
163
164int XLateKey(XKeyEvent *ev)
165{
166
167	int key;
168	char buf[64];
169	KeySym keysym;
170
171	key = 0;
172
173	XLookupString(ev, buf, sizeof buf, &keysym, 0);
174
175	switch(keysym)
176	{
177		case XK_KP_Page_Up:
178		case XK_Page_Up:	 key = K_PGUP; break;
179
180		case XK_KP_Page_Down:
181		case XK_Page_Down:	 key = K_PGDN; break;
182
183		case XK_KP_Home:
184		case XK_Home:	 key = K_HOME; break;
185
186		case XK_KP_End:
187		case XK_End:	 key = K_END; break;
188
189		case XK_KP_Left:
190		case XK_Left:	 key = K_LEFTARROW; break;
191
192		case XK_KP_Right:
193		case XK_Right:	key = K_RIGHTARROW;		break;
194
195		case XK_KP_Down:
196		case XK_Down:	 key = K_DOWNARROW; break;
197
198		case XK_KP_Up:
199		case XK_Up:		 key = K_UPARROW;	 break;
200
201		case XK_Escape: key = K_ESCAPE;		break;
202
203		case XK_KP_Enter:
204		case XK_Return: key = K_ENTER;		 break;
205
206		case XK_Tab:		key = K_TAB;			 break;
207
208		case XK_F1:		 key = K_F1;				break;
209
210		case XK_F2:		 key = K_F2;				break;
211
212		case XK_F3:		 key = K_F3;				break;
213
214		case XK_F4:		 key = K_F4;				break;
215
216		case XK_F5:		 key = K_F5;				break;
217
218		case XK_F6:		 key = K_F6;				break;
219
220		case XK_F7:		 key = K_F7;				break;
221
222		case XK_F8:		 key = K_F8;				break;
223
224		case XK_F9:		 key = K_F9;				break;
225
226		case XK_F10:		key = K_F10;			 break;
227
228		case XK_F11:		key = K_F11;			 break;
229
230		case XK_F12:		key = K_F12;			 break;
231
232		case XK_BackSpace: key = K_BACKSPACE; break;
233
234		case XK_KP_Delete:
235		case XK_Delete: key = K_DEL; break;
236
237		case XK_Pause:	key = K_PAUSE;		 break;
238
239		case XK_Shift_L:
240		case XK_Shift_R:	key = K_SHIFT;		break;
241
242		case XK_Execute:
243		case XK_Control_L:
244		case XK_Control_R:	key = K_CTRL;		 break;
245
246		case XK_Alt_L:
247		case XK_Meta_L:
248		case XK_Alt_R:
249		case XK_Meta_R: key = K_ALT;			break;
250
251		case XK_KP_Begin: key = K_AUX30;	break;
252
253		case XK_Insert:
254		case XK_KP_Insert: key = K_INS; break;
255
256		case XK_KP_Multiply: key = '*'; break;
257		case XK_KP_Add: key = '+'; break;
258		case XK_KP_Subtract: key = '-'; break;
259		case XK_KP_Divide: key = '/'; break;
260
261#if 0
262		case 0x021: key = '1';break;/* [!] */
263		case 0x040: key = '2';break;/* [@] */
264		case 0x023: key = '3';break;/* [#] */
265		case 0x024: key = '4';break;/* [$] */
266		case 0x025: key = '5';break;/* [%] */
267		case 0x05e: key = '6';break;/* [^] */
268		case 0x026: key = '7';break;/* [&] */
269		case 0x02a: key = '8';break;/* [*] */
270		case 0x028: key = '9';;break;/* [(] */
271		case 0x029: key = '0';break;/* [)] */
272		case 0x05f: key = '-';break;/* [_] */
273		case 0x02b: key = '=';break;/* [+] */
274		case 0x07c: key = '\'';break;/* [|] */
275		case 0x07d: key = '[';break;/* [}] */
276		case 0x07b: key = ']';break;/* [{] */
277		case 0x022: key = '\'';break;/* ["] */
278		case 0x03a: key = ';';break;/* [:] */
279		case 0x03f: key = '/';break;/* [?] */
280		case 0x03e: key = '.';break;/* [>] */
281		case 0x03c: key = ',';break;/* [<] */
282#endif
283
284		default:
285			key = *(unsigned char*)buf;
286			if (key >= 'A' && key <= 'Z')
287				key = key - 'A' + 'a';
288//			fprintf(stdout, "case 0x0%x: key = ___;break;/* [%c] */\n", keysym);
289			break;
290	}
291
292	return key;
293}
294
295struct
296{
297	int key;
298	int down;
299} keyq[64];
300int keyq_head=0;
301int keyq_tail=0;
302
303int config_notify=0;
304int config_notify_width;
305int config_notify_height;
306
307qboolean Keyboard_Update(void)
308{
309	XEvent x_event;
310
311	if(!XCheckMaskEvent(dpy,KEY_MASK,&x_event))
312		return false;
313
314	switch(x_event.type) {
315	case KeyPress:
316		keyq[keyq_head].key = XLateKey(&x_event.xkey);
317		keyq[keyq_head].down = true;
318		keyq_head = (keyq_head + 1) & 63;
319		break;
320	case KeyRelease:
321		keyq[keyq_head].key = XLateKey(&x_event.xkey);
322		keyq[keyq_head].down = false;
323		keyq_head = (keyq_head + 1) & 63;
324		break;
325	}
326
327	return true;
328}
329
330qboolean Mouse_Update(void)
331{
332	XEvent x_event;
333	int b;
334
335	if(!XCheckMaskEvent(dpy,MOUSE_MASK,&x_event))
336		return false;
337
338	switch(x_event.type) {
339	case MotionNotify:
340		if (usedga) {
341			mouse_x += x_event.xmotion.x_root;
342			mouse_y += x_event.xmotion.y_root;
343		} else if (_windowed_mouse.value) {
344			mouse_x += (float) ((int)x_event.xmotion.x - (int)(scr_width/2));
345			mouse_y += (float) ((int)x_event.xmotion.y - (int)(scr_height/2));
346
347			/* move the mouse to the window center again */
348			XSelectInput(dpy,win, (KEY_MASK | MOUSE_MASK) & ~PointerMotionMask);
349			XWarpPointer(dpy,None,win,0,0,0,0, (scr_width/2),(scr_height/2));
350			XSelectInput(dpy,win, KEY_MASK | MOUSE_MASK);
351		} else {
352			mouse_x = (float) (x_event.xmotion.x-p_mouse_x);
353			mouse_y = (float) (x_event.xmotion.y-p_mouse_y);
354			p_mouse_x=x_event.xmotion.x;
355			p_mouse_y=x_event.xmotion.y;
356		}
357		break;
358
359	case ButtonPress:
360		b=-1;
361		if (x_event.xbutton.button == 1)
362			b = 0;
363		else if (x_event.xbutton.button == 2)
364			b = 2;
365		else if (x_event.xbutton.button == 3)
366			b = 1;
367		if (b>=0)
368			mouse_buttonstate |= 1<<b;
369		break;
370
371	case ButtonRelease:
372		b=-1;
373		if (x_event.xbutton.button == 1)
374			b = 0;
375		else if (x_event.xbutton.button == 2)
376			b = 2;
377		else if (x_event.xbutton.button == 3)
378			b = 1;
379		if (b>=0)
380			mouse_buttonstate &= ~(1<<b);
381		break;
382	}
383
384	if (old_windowed_mouse != _windowed_mouse.value) {
385		old_windowed_mouse = _windowed_mouse.value;
386
387		if (!_windowed_mouse.value) {
388			/* ungrab the pointer */
389			Con_Printf("Releasing mouse.\n");
390
391			XUngrabPointer(dpy,CurrentTime);
392			XUngrabKeyboard(dpy,CurrentTime);
393		} else {
394			/* grab the pointer */
395			Con_Printf("Grabbing mouse.\n");
396
397			XGrabPointer(dpy,win,False,MOUSE_MASK,GrabModeAsync,
398				GrabModeAsync,win,None,CurrentTime);
399			XWarpPointer(dpy,None,win, 0,0,0,0, scr_width/2, scr_height/2);
400			XGrabKeyboard(dpy,win,
401				False,
402				GrabModeAsync,GrabModeAsync,
403				CurrentTime);
404
405			//XSync(dpy,True);
406		}
407	}
408	return true;
409}
410
411void signal_handler(int sig)
412{
413	printf("Received signal %d, exiting...\n", sig);
414	VID_Shutdown();
415	exit(0);
416}
417
418void InitSig(void)
419{
420	signal(SIGHUP, signal_handler);
421	signal(SIGQUIT, signal_handler);
422	signal(SIGILL, signal_handler);
423	signal(SIGTRAP, signal_handler);
424	signal(SIGIOT, signal_handler);
425	signal(SIGBUS, signal_handler);
426	signal(SIGFPE, signal_handler);
427	signal(SIGSEGV, signal_handler);
428	signal(SIGTERM, signal_handler);
429}
430
431void VID_ShiftPalette(unsigned char *p)
432{
433	VID_SetPalette(p);
434}
435
436void	VID_SetPalette (unsigned char *palette)
437{
438	byte	*pal;
439	unsigned short r,g,b;
440	int     v;
441	int     r1,g1,b1;
442	int		k;
443	unsigned short i;
444	unsigned	*table;
445	FILE *f;
446	char s[255];
447	float dist, bestdist;
448	static qboolean palflag = false;
449
450//
451// 8 8 8 encoding
452//
453	pal = palette;
454	table = d_8to24table;
455	for (i=0 ; i<256 ; i++)
456	{
457		r = pal[0];
458		g = pal[1];
459		b = pal[2];
460		pal += 3;
461
462//		v = (255<<24) + (r<<16) + (g<<8) + (b<<0);
463//		v = (255<<0) + (r<<8) + (g<<16) + (b<<24);
464		v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
465		*table++ = v;
466	}
467	d_8to24table[255] &= 0xffffff;	// 255 is transparent
468
469	// JACK: 3D distance calcs - k is last closest, l is the distance.
470	// FIXME: Precalculate this and cache to disk.
471	if (palflag)
472		return;
473	palflag = true;
474
475	COM_FOpenFile("glquake/15to8.pal", &f);
476	if (f) {
477		fread(d_15to8table, 1<<15, 1, f);
478		fclose(f);
479	} else {
480		for (i=0; i < (1<<15); i++) {
481			/* Maps
482 			000000000000000
483 			000000000011111 = Red  = 0x1F
484 			000001111100000 = Blue = 0x03E0
485 			111110000000000 = Grn  = 0x7C00
486 			*/
487 			r = ((i & 0x1F) << 3)+4;
488 			g = ((i & 0x03E0) >> 2)+4;
489 			b = ((i & 0x7C00) >> 7)+4;
490			pal = (unsigned char *)d_8to24table;
491			for (v=0,k=0,bestdist=10000.0; v<256; v++,pal+=4) {
492 				r1 = (int)r - (int)pal[0];
493 				g1 = (int)g - (int)pal[1];
494 				b1 = (int)b - (int)pal[2];
495				dist = sqrt(((r1*r1)+(g1*g1)+(b1*b1)));
496				if (dist < bestdist) {
497					k=v;
498					bestdist = dist;
499				}
500			}
501			d_15to8table[i]=k;
502		}
503		sprintf(s, "%s/glquake", com_gamedir);
504 		Sys_mkdir (s);
505		sprintf(s, "%s/glquake/15to8.pal", com_gamedir);
506		if ((f = fopen(s, "wb")) != NULL) {
507			fwrite(d_15to8table, 1<<15, 1, f);
508			fclose(f);
509		}
510	}
511}
512
513/*
514===============
515GL_Init
516===============
517*/
518void GL_Init (void)
519{
520	gl_vendor = glGetString (GL_VENDOR);
521	Con_Printf ("GL_VENDOR: %s\n", gl_vendor);
522	gl_renderer = glGetString (GL_RENDERER);
523	Con_Printf ("GL_RENDERER: %s\n", gl_renderer);
524
525	gl_version = glGetString (GL_VERSION);
526	Con_Printf ("GL_VERSION: %s\n", gl_version);
527	gl_extensions = glGetString (GL_EXTENSIONS);
528	Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions);
529
530//	Con_Printf ("%s %s\n", gl_renderer, gl_version);
531
532	glClearColor (1,0,0,0);
533	glCullFace(GL_FRONT);
534	glEnable(GL_TEXTURE_2D);
535
536	glEnable(GL_ALPHA_TEST);
537	glAlphaFunc(GL_GREATER, 0.666);
538
539	glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
540	glShadeModel (GL_FLAT);
541
542	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
543	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
544	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
545	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
546
547	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
548
549//	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
550	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
551}
552
553/*
554=================
555GL_BeginRendering
556
557=================
558*/
559void GL_BeginRendering (int *x, int *y, int *width, int *height)
560{
561	extern cvar_t gl_clear;
562
563	*x = *y = 0;
564	*width = scr_width;
565	*height = scr_height;
566
567//    if (!wglMakeCurrent( maindc, baseRC ))
568//		Sys_Error ("wglMakeCurrent failed");
569
570//	glViewport (*x, *y, *width, *height);
571}
572
573
574void GL_EndRendering (void)
575{
576	glFlush();
577	glXSwapBuffers(dpy,win);
578}
579
580qboolean VID_Is8bit(void)
581{
582	return is8bit;
583}
584
585#ifdef GL_EXT_SHARED
586void VID_Init8bitPalette()
587{
588	// Check for 8bit Extensions and initialize them.
589	int i;
590	char thePalette[256*3];
591	char *oldPalette, *newPalette;
592
593	if (strstr(gl_extensions, "GL_EXT_shared_texture_palette") == NULL)
594		return;
595
596	Con_SafePrintf("8-bit GL extensions enabled.\n");
597	glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
598	oldPalette = (char *) d_8to24table; //d_8to24table3dfx;
599	newPalette = thePalette;
600	for (i=0;i<256;i++) {
601		*newPalette++ = *oldPalette++;
602		*newPalette++ = *oldPalette++;
603		*newPalette++ = *oldPalette++;
604		oldPalette++;
605	}
606	glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, (void *) thePalette);
607	is8bit = true;
608}
609
610#else
611extern void gl3DfxSetPaletteEXT(GLuint *pal);
612
613void VID_Init8bitPalette(void)
614{
615	// Check for 8bit Extensions and initialize them.
616	int i;
617	GLubyte table[256][4];
618	char *oldpal;
619
620	if (strstr(gl_extensions, "3DFX_set_global_palette") == NULL)
621		return;
622
623	Con_SafePrintf("8-bit GL extensions enabled.\n");
624	glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
625	oldpal = (char *) d_8to24table; //d_8to24table3dfx;
626	for (i=0;i<256;i++) {
627		table[i][2] = *oldpal++;
628		table[i][1] = *oldpal++;
629		table[i][0] = *oldpal++;
630		table[i][3] = 255;
631		oldpal++;
632	}
633	gl3DfxSetPaletteEXT((GLuint *)table);
634	is8bit = true;
635}
636#endif
637
638void VID_Init(unsigned char *palette)
639{
640	int i;
641	char	gldir[MAX_OSPATH];
642	int width = 640, height = 480;
643	int attrib[] = {
644		GLX_RGBA,
645		GLX_RED_SIZE, 1,
646		GLX_GREEN_SIZE, 1,
647		GLX_BLUE_SIZE, 1,
648		GLX_DOUBLEBUFFER,
649		GLX_DEPTH_SIZE, 1,
650		None };
651	int scrnum;
652	XSetWindowAttributes attr;
653	unsigned long mask;
654	Window root;
655	XVisualInfo *visinfo;
656
657	S_Init();
658
659	Cvar_RegisterVariable (&vid_mode);
660	Cvar_RegisterVariable (&gl_ztrick);
661
662	vid.maxwarpwidth = WARP_WIDTH;
663	vid.maxwarpheight = WARP_HEIGHT;
664	vid.colormap = host_colormap;
665	vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
666
667// interpret command-line params
668
669// set vid parameters
670
671	if ((i = COM_CheckParm("-width")) != 0)
672		width = atoi(com_argv[i+1]);
673	if ((i = COM_CheckParm("-height")) != 0)
674		height = atoi(com_argv[i+1]);
675
676	if ((i = COM_CheckParm("-conwidth")) != 0)
677		vid.conwidth = Q_atoi(com_argv[i+1]);
678	else
679		vid.conwidth = 640;
680
681	vid.conwidth &= 0xfff8; // make it a multiple of eight
682
683	if (vid.conwidth < 320)
684		vid.conwidth = 320;
685
686	// pick a conheight that matches with correct aspect
687	vid.conheight = vid.conwidth*3 / 4;
688
689	if ((i = COM_CheckParm("-conheight")) != 0)
690		vid.conheight = Q_atoi(com_argv[i+1]);
691	if (vid.conheight < 200)
692		vid.conheight = 200;
693
694	if (!(dpy = XOpenDisplay(NULL))) {
695		fprintf(stderr, "Error couldn't open the X display\n");
696		exit(1);
697	}
698
699	scrnum = DefaultScreen(dpy);
700	root = RootWindow(dpy, scrnum);
701
702	visinfo=glXChooseVisual(dpy,scrnum,attrib);
703	if (!visinfo) {
704		fprintf(stderr, "Error couldn't get an RGB, Double-buffered, Depth visual\n");
705		exit(1);
706	}
707
708	/* window attributes */
709	attr.background_pixel=0;
710	attr.border_pixel=0;
711	attr.colormap=XCreateColormap(dpy,root,visinfo->visual,AllocNone);
712	attr.event_mask=KEY_MASK|MOUSE_MASK|VisibilityChangeMask;
713	mask=CWBackPixel|CWBorderPixel|CWColormap|CWEventMask;
714
715	win=XCreateWindow(dpy,root,0,0,width,height,
716			0,visinfo->depth,InputOutput,
717			visinfo->visual,mask,&attr);
718	XMapWindow(dpy,win);
719
720	XMoveWindow(dpy,win,0,0);
721
722	XFlush(dpy);
723
724	if (COM_CheckParm("-window"))
725		putenv("MESA_GLX_FX=window");
726	else
727		putenv("MESA_GLX_FX=fullscreen");
728
729	ctx = glXCreateContext(dpy,visinfo,NULL,True);
730
731	if (!ctx) {
732		fprintf(stderr, "Unable to create glX context.\n");
733		exit(1);
734	}
735
736	glXMakeCurrent(dpy,win,ctx);
737
738	scr_width = width;
739	scr_height = height;
740
741	if (vid.conheight > height)
742		vid.conheight = height;
743	if (vid.conwidth > width)
744		vid.conwidth = width;
745	vid.width = vid.conwidth;
746	vid.height = vid.conheight;
747
748	vid.aspect = ((float)vid.height / (float)vid.width) *
749				(320.0 / 240.0);
750	vid.numpages = 2;
751
752	InitSig(); // trap evil signals
753
754	GL_Init();
755
756	sprintf (gldir, "%s/glquake", com_gamedir);
757	Sys_mkdir (gldir);
758
759	VID_SetPalette(palette);
760
761	// Check for 3DFX Extensions and initialize them.
762	VID_Init8bitPalette();
763
764	Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height);
765
766	vid.recalc_refdef = 1;				// force a surface cache flush
767}
768
769void Sys_SendKeyEvents(void)
770{
771	if (dpy)
772	{
773		while (Keyboard_Update())
774			;
775
776		while (keyq_head != keyq_tail)
777		{
778			Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down);
779			keyq_tail = (keyq_tail + 1) & 63;
780		}
781	}
782}
783
784void Force_CenterView_f (void)
785{
786	cl.viewangles[PITCH] = 0;
787}
788
789
790void IN_Init(void)
791{
792	Cvar_RegisterVariable (&_windowed_mouse);
793	Cvar_RegisterVariable (&m_filter);
794	Cvar_RegisterVariable (&mouse_button_commands[0]);
795	Cvar_RegisterVariable (&mouse_button_commands[1]);
796	Cvar_RegisterVariable (&mouse_button_commands[2]);
797	Cmd_AddCommand ("force_centerview", Force_CenterView_f);
798}
799
800void IN_Shutdown(void)
801{
802}
803
804/*
805===========
806IN_Commands
807===========
808*/
809void IN_Commands (void)
810{
811	int i;
812
813	for (i=0 ; i<mouse_buttons ; i++) {
814		if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
815			Key_Event (K_MOUSE1 + i, true);
816
817		if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
818			Key_Event (K_MOUSE1 + i, false);
819	}
820
821	mouse_oldbuttonstate = mouse_buttonstate;
822}
823
824/*
825===========
826IN_Move
827===========
828*/
829void IN_Move (usercmd_t *cmd)
830{
831	while (Mouse_Update())
832		;
833
834	if (m_filter.value) {
835		mouse_x = (mouse_x + old_mouse_x) * 0.5;
836		mouse_y = (mouse_y + old_mouse_y) * 0.5;
837	}
838
839	old_mouse_x = mouse_x;
840	old_mouse_y = mouse_y;
841
842	mouse_x *= sensitivity.value;
843	mouse_y *= sensitivity.value;
844
845	if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
846		cmd->sidemove += m_side.value * mouse_x;
847	else
848		cl.viewangles[YAW] -= m_yaw.value * mouse_x;
849	if (in_mlook.state & 1)
850		V_StopPitchDrift ();
851
852	if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) {
853		cl.viewangles[PITCH] += m_pitch.value * mouse_y;
854		if (cl.viewangles[PITCH] > 80)
855			cl.viewangles[PITCH] = 80;
856		if (cl.viewangles[PITCH] < -70)
857			cl.viewangles[PITCH] = -70;
858	} else {
859		if ((in_strafe.state & 1) && noclip_anglehack)
860			cmd->upmove -= m_forward.value * mouse_y;
861		else
862			cmd->forwardmove -= m_forward.value * mouse_y;
863	}
864	mouse_x = mouse_y = 0.0;
865}
866
867
868void	VID_LockBuffer (void) {}
869void	VID_UnlockBuffer (void) {}
870
871