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 <asm/io.h>
29#include <dlfcn.h>
30
31/*#include "vga.h" */
32#include "vgakeyboard.h"
33#include "vgamouse.h"
34
35#include "quakedef.h"
36#include "GL/fxmesa.h"
37
38#define WARP_WIDTH              320
39#define WARP_HEIGHT             200
40
41static fxMesaContext fc = NULL;
42#define stringify(m) { #m, m }
43
44unsigned short	d_8to16table[256];
45unsigned	d_8to24table[256];
46unsigned char d_15to8table[65536];
47
48int num_shades=32;
49
50struct
51{
52	char *name;
53	int num;
54} mice[] =
55{
56	stringify(MOUSE_MICROSOFT),
57	stringify(MOUSE_MOUSESYSTEMS),
58	stringify(MOUSE_MMSERIES),
59	stringify(MOUSE_LOGITECH),
60	stringify(MOUSE_BUSMOUSE),
61	stringify(MOUSE_PS2),
62};
63
64static unsigned char scantokey[128];
65
66int num_mice = sizeof (mice) / sizeof(mice[0]);
67
68int	d_con_indirect = 0;
69
70int		svgalib_inited=0;
71int		UseMouse = 1;
72int		UseKeyboard = 1;
73
74int		mouserate = MOUSE_DEFAULTSAMPLERATE;
75
76cvar_t		vid_mode = {"vid_mode","5",false};
77cvar_t		vid_redrawfull = {"vid_redrawfull","0",false};
78cvar_t		vid_waitforrefresh = {"vid_waitforrefresh","0",true};
79
80char	*framebuffer_ptr;
81
82cvar_t  mouse_button_commands[3] =
83{
84    {"mouse1","+attack"},
85    {"mouse2","+strafe"},
86    {"mouse3","+forward"},
87};
88
89int     mouse_buttons;
90int     mouse_buttonstate;
91int     mouse_oldbuttonstate;
92float   mouse_x, mouse_y;
93float	old_mouse_x, old_mouse_y;
94int		mx, my;
95
96cvar_t	m_filter = {"m_filter","1"};
97
98int scr_width, scr_height;
99
100/*-----------------------------------------------------------------------*/
101
102//int		texture_mode = GL_NEAREST;
103//int		texture_mode = GL_NEAREST_MIPMAP_NEAREST;
104//int		texture_mode = GL_NEAREST_MIPMAP_LINEAR;
105int		texture_mode = GL_LINEAR;
106//int		texture_mode = GL_LINEAR_MIPMAP_NEAREST;
107//int		texture_mode = GL_LINEAR_MIPMAP_LINEAR;
108
109int		texture_extension_number = 1;
110
111float		gldepthmin, gldepthmax;
112
113cvar_t	gl_ztrick = {"gl_ztrick","1"};
114
115const char *gl_vendor;
116const char *gl_renderer;
117const char *gl_version;
118const char *gl_extensions;
119
120void (*qgl3DfxSetPaletteEXT) (GLuint *);
121void (*qglColorTableEXT) (int, int, int, int, int, const void *);
122
123static float vid_gamma = 1.0;
124
125qboolean is8bit = false;
126qboolean isPermedia = false;
127qboolean gl_mtexable = false;
128
129/*-----------------------------------------------------------------------*/
130void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
131{
132}
133
134void D_EndDirectRect (int x, int y, int width, int height)
135{
136}
137
138int matchmouse(int mouse, char *name)
139{
140	int i;
141	for (i=0 ; i<num_mice ; i++)
142		if (!strcmp(mice[i].name, name))
143			return i;
144	return mouse;
145}
146
147#if 0
148
149void vtswitch(int newconsole)
150{
151
152	int fd;
153	struct vt_stat x;
154
155// switch consoles and wait until reactivated
156	fd = open("/dev/console", O_RDONLY);
157	ioctl(fd, VT_GETSTATE, &x);
158	ioctl(fd, VT_ACTIVATE, newconsole);
159	ioctl(fd, VT_WAITACTIVE, x.v_active);
160	close(fd);
161
162}
163
164#endif
165
166void keyhandler(int scancode, int state)
167{
168
169	int sc;
170
171	sc = scancode & 0x7f;
172
173	Key_Event(scantokey[sc], state == KEY_EVENTPRESS);
174
175}
176
177void VID_Shutdown(void)
178{
179	if (!fc)
180		return;
181
182	fxMesaDestroyContext(fc);
183
184	if (UseKeyboard)
185		keyboard_close();
186}
187
188void signal_handler(int sig)
189{
190	printf("Received signal %d, exiting...\n", sig);
191	Sys_Quit();
192	exit(0);
193}
194
195void InitSig(void)
196{
197	signal(SIGHUP, signal_handler);
198	signal(SIGINT, signal_handler);
199	signal(SIGQUIT, signal_handler);
200	signal(SIGILL, signal_handler);
201	signal(SIGTRAP, signal_handler);
202	signal(SIGIOT, signal_handler);
203	signal(SIGBUS, signal_handler);
204	signal(SIGFPE, signal_handler);
205	signal(SIGSEGV, signal_handler);
206	signal(SIGTERM, signal_handler);
207}
208
209void VID_ShiftPalette(unsigned char *p)
210{
211//	VID_SetPalette(p);
212}
213
214void	VID_SetPalette (unsigned char *palette)
215{
216	byte	*pal;
217	unsigned r,g,b;
218	unsigned v;
219	int     r1,g1,b1;
220	int		j,k,l,m;
221	unsigned short i;
222	unsigned	*table;
223	FILE *f;
224	char s[255];
225	int dist, bestdist;
226	static qboolean palflag = false;
227
228//
229// 8 8 8 encoding
230//
231	pal = palette;
232	table = d_8to24table;
233	for (i=0 ; i<256 ; i++)
234	{
235		r = pal[0];
236		g = pal[1];
237		b = pal[2];
238		pal += 3;
239
240		v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
241		*table++ = v;
242	}
243	d_8to24table[255] &= 0xffffff;	// 255 is transparent
244
245	// JACK: 3D distance calcs - k is last closest, l is the distance.
246	for (i=0; i < (1<<15); i++) {
247		/* Maps
248		000000000000000
249		000000000011111 = Red  = 0x1F
250		000001111100000 = Blue = 0x03E0
251		111110000000000 = Grn  = 0x7C00
252		*/
253		r = ((i & 0x1F) << 3)+4;
254		g = ((i & 0x03E0) >> 2)+4;
255		b = ((i & 0x7C00) >> 7)+4;
256		pal = (unsigned char *)d_8to24table;
257		for (v=0,k=0,bestdist=10000*10000; v<256; v++,pal+=4) {
258			r1 = (int)r - (int)pal[0];
259			g1 = (int)g - (int)pal[1];
260			b1 = (int)b - (int)pal[2];
261			dist = (r1*r1)+(g1*g1)+(b1*b1);
262			if (dist < bestdist) {
263				k=v;
264				bestdist = dist;
265			}
266		}
267		d_15to8table[i]=k;
268	}
269}
270
271void CheckMultiTextureExtensions(void)
272{
273	void *prjobj;
274
275	if (strstr(gl_extensions, "GL_SGIS_multitexture ") && !COM_CheckParm("-nomtex")) {
276		Con_Printf("Found GL_SGIS_multitexture...\n");
277
278		if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL) {
279			Con_Printf("Unable to open symbol list for main program.\n");
280			return;
281		}
282
283		qglMTexCoord2fSGIS = (void *) dlsym(prjobj, "glMTexCoord2fSGIS");
284		qglSelectTextureSGIS = (void *) dlsym(prjobj, "glSelectTextureSGIS");
285
286		if (qglMTexCoord2fSGIS && qglSelectTextureSGIS) {
287			Con_Printf("Multitexture extensions found.\n");
288			gl_mtexable = true;
289		} else
290			Con_Printf("Symbol not found, disabled.\n");
291
292		dlclose(prjobj);
293	}
294}
295
296/*
297===============
298GL_Init
299===============
300*/
301void GL_Init (void)
302{
303	gl_vendor = glGetString (GL_VENDOR);
304	Con_Printf ("GL_VENDOR: %s\n", gl_vendor);
305	gl_renderer = glGetString (GL_RENDERER);
306	Con_Printf ("GL_RENDERER: %s\n", gl_renderer);
307
308	gl_version = glGetString (GL_VERSION);
309	Con_Printf ("GL_VERSION: %s\n", gl_version);
310	gl_extensions = glGetString (GL_EXTENSIONS);
311	Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions);
312
313//	Con_Printf ("%s %s\n", gl_renderer, gl_version);
314
315	CheckMultiTextureExtensions ();
316
317	glClearColor (1,0,0,0);
318	glCullFace(GL_FRONT);
319	glEnable(GL_TEXTURE_2D);
320
321	glEnable(GL_ALPHA_TEST);
322	glAlphaFunc(GL_GREATER, 0.666);
323
324	glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
325	glShadeModel (GL_FLAT);
326
327	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
328	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
329	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
330	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
331
332	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
333
334//	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
335	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
336}
337
338/*
339=================
340GL_BeginRendering
341
342=================
343*/
344void GL_BeginRendering (int *x, int *y, int *width, int *height)
345{
346	extern cvar_t gl_clear;
347
348	*x = *y = 0;
349	*width = scr_width;
350	*height = scr_height;
351
352//    if (!wglMakeCurrent( maindc, baseRC ))
353//		Sys_Error ("wglMakeCurrent failed");
354
355//	glViewport (*x, *y, *width, *height);
356}
357
358
359void GL_EndRendering (void)
360{
361	glFlush();
362	fxMesaSwapBuffers();
363}
364
365void Init_KBD(void)
366{
367	int i;
368
369	if (COM_CheckParm("-nokbd")) UseKeyboard = 0;
370
371	if (UseKeyboard)
372	{
373		for (i=0 ; i<128 ; i++)
374			scantokey[i] = ' ';
375
376		scantokey[42] = K_SHIFT;
377		scantokey[54] = K_SHIFT;
378		scantokey[72] = K_UPARROW;
379		scantokey[103] = K_UPARROW;
380		scantokey[80] = K_DOWNARROW;
381		scantokey[108] = K_DOWNARROW;
382		scantokey[75] = K_LEFTARROW;
383		scantokey[105] = K_LEFTARROW;
384		scantokey[77] = K_RIGHTARROW;
385		scantokey[106] = K_RIGHTARROW;
386		scantokey[29] = K_CTRL;
387		scantokey[97] = K_CTRL;
388		scantokey[56] = K_ALT;
389		scantokey[100] = K_ALT;
390//		scantokey[58] = JK_CAPS;
391//		scantokey[69] = JK_NUM_LOCK;
392		scantokey[71] = K_HOME;
393		scantokey[73] = K_PGUP;
394		scantokey[79] = K_END;
395		scantokey[81] = K_PGDN;
396		scantokey[82] = K_INS;
397		scantokey[83] = K_DEL;
398		scantokey[1 ] = K_ESCAPE;
399		scantokey[28] = K_ENTER;
400		scantokey[15] = K_TAB;
401		scantokey[14] = K_BACKSPACE;
402		scantokey[119] = K_PAUSE;
403		scantokey[57] = ' ';
404
405		scantokey[102] = K_HOME;
406		scantokey[104] = K_PGUP;
407		scantokey[107] = K_END;
408		scantokey[109] = K_PGDN;
409		scantokey[110] = K_INS;
410		scantokey[111] = K_DEL;
411
412		scantokey[2] = '1';
413		scantokey[3] = '2';
414		scantokey[4] = '3';
415		scantokey[5] = '4';
416		scantokey[6] = '5';
417		scantokey[7] = '6';
418		scantokey[8] = '7';
419		scantokey[9] = '8';
420		scantokey[10] = '9';
421		scantokey[11] = '0';
422		scantokey[12] = '-';
423		scantokey[13] = '=';
424		scantokey[41] = '`';
425		scantokey[26] = '[';
426		scantokey[27] = ']';
427		scantokey[39] = ';';
428		scantokey[40] = '\'';
429		scantokey[51] = ',';
430		scantokey[52] = '.';
431		scantokey[53] = '/';
432		scantokey[43] = '\\';
433
434		scantokey[59] = K_F1;
435		scantokey[60] = K_F2;
436		scantokey[61] = K_F3;
437		scantokey[62] = K_F4;
438		scantokey[63] = K_F5;
439		scantokey[64] = K_F6;
440		scantokey[65] = K_F7;
441		scantokey[66] = K_F8;
442		scantokey[67] = K_F9;
443		scantokey[68] = K_F10;
444		scantokey[87] = K_F11;
445		scantokey[88] = K_F12;
446		scantokey[30] = 'a';
447		scantokey[48] = 'b';
448		scantokey[46] = 'c';
449		scantokey[32] = 'd';
450		scantokey[18] = 'e';
451		scantokey[33] = 'f';
452		scantokey[34] = 'g';
453		scantokey[35] = 'h';
454		scantokey[23] = 'i';
455		scantokey[36] = 'j';
456		scantokey[37] = 'k';
457		scantokey[38] = 'l';
458		scantokey[50] = 'm';
459		scantokey[49] = 'n';
460		scantokey[24] = 'o';
461		scantokey[25] = 'p';
462		scantokey[16] = 'q';
463		scantokey[19] = 'r';
464		scantokey[31] = 's';
465		scantokey[20] = 't';
466		scantokey[22] = 'u';
467		scantokey[47] = 'v';
468		scantokey[17] = 'w';
469		scantokey[45] = 'x';
470		scantokey[21] = 'y';
471		scantokey[44] = 'z';
472
473		scantokey[78] = '+';
474		scantokey[74] = '-';
475
476		if (keyboard_init())
477			Sys_Error("keyboard_init() failed");
478		keyboard_seteventhandler(keyhandler);
479	}
480}
481
482#define NUM_RESOLUTIONS 16
483
484static int resolutions[NUM_RESOLUTIONS][3]={
485	320,200,  GR_RESOLUTION_320x200,
486	320,240,  GR_RESOLUTION_320x240,
487	400,256,  GR_RESOLUTION_400x256,
488	400,300,  GR_RESOLUTION_400x300,
489	512,384,  GR_RESOLUTION_512x384,
490	640,200,  GR_RESOLUTION_640x200,
491	640,350,  GR_RESOLUTION_640x350,
492	640,400,  GR_RESOLUTION_640x400,
493	640,480,  GR_RESOLUTION_640x480,
494	800,600,  GR_RESOLUTION_800x600,
495	960,720,  GR_RESOLUTION_960x720,
496	856,480,  GR_RESOLUTION_856x480,
497	512,256,  GR_RESOLUTION_512x256,
498	1024,768, GR_RESOLUTION_1024x768,
499	1280,1024,GR_RESOLUTION_1280x1024,
500	1600,1200,GR_RESOLUTION_1600x1200
501};
502
503int findres(int *width, int *height)
504{
505	int i;
506
507	for(i=0;i<NUM_RESOLUTIONS;i++)
508		if((*width<=resolutions[i][0]) && (*height<=resolutions[i][1])) {
509			*width = resolutions[i][0];
510			*height = resolutions[i][1];
511			return resolutions[i][2];
512		}
513
514	*width = 640;
515	*height = 480;
516	return GR_RESOLUTION_640x480;
517}
518
519qboolean VID_Is8bit(void)
520{
521	return is8bit;
522}
523
524void VID_Init8bitPalette(void)
525{
526	// Check for 8bit Extensions and initialize them.
527	int i;
528	void *prjobj;
529
530	if (COM_CheckParm("-no8bit"))
531		return;
532
533	if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL) {
534		Con_Printf("Unable to open symbol list for main program.\n");
535		return;
536	}
537
538	if (strstr(gl_extensions, "3DFX_set_global_palette") &&
539		(qgl3DfxSetPaletteEXT = dlsym(prjobj, "gl3DfxSetPaletteEXT")) != NULL) {
540		GLubyte table[256][4];
541		char *oldpal;
542
543		Con_SafePrintf("... Using 3DFX_set_global_palette\n");
544		glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
545		oldpal = (char *) d_8to24table; //d_8to24table3dfx;
546		for (i=0;i<256;i++) {
547			table[i][2] = *oldpal++;
548			table[i][1] = *oldpal++;
549			table[i][0] = *oldpal++;
550			table[i][3] = 255;
551			oldpal++;
552		}
553		qgl3DfxSetPaletteEXT((GLuint *)table);
554		is8bit = true;
555
556	} else if (strstr(gl_extensions, "GL_EXT_shared_texture_palette") &&
557		(qglColorTableEXT = dlsym(prjobj, "glColorTableEXT")) != NULL) {
558		char thePalette[256*3];
559		char *oldPalette, *newPalette;
560
561		Con_SafePrintf("... Using GL_EXT_shared_texture_palette\n");
562		glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
563		oldPalette = (char *) d_8to24table; //d_8to24table3dfx;
564		newPalette = thePalette;
565		for (i=0;i<256;i++) {
566			*newPalette++ = *oldPalette++;
567			*newPalette++ = *oldPalette++;
568			*newPalette++ = *oldPalette++;
569			oldPalette++;
570		}
571		qglColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, (void *) thePalette);
572		is8bit = true;
573
574	}
575
576	dlclose(prjobj);
577}
578
579static void Check_Gamma (unsigned char *pal)
580{
581	float	f, inf;
582	unsigned char	palette[768];
583	int		i;
584
585	if ((i = COM_CheckParm("-gamma")) == 0) {
586		if ((gl_renderer && strstr(gl_renderer, "Voodoo")) ||
587			(gl_vendor && strstr(gl_vendor, "3Dfx")))
588			vid_gamma = 1;
589		else
590			vid_gamma = 0.7; // default to 0.7 on non-3dfx hardware
591	} else
592		vid_gamma = Q_atof(com_argv[i+1]);
593
594	for (i=0 ; i<768 ; i++)
595	{
596		f = pow ( (pal[i]+1)/256.0 , vid_gamma );
597		inf = f*255 + 0.5;
598		if (inf < 0)
599			inf = 0;
600		if (inf > 255)
601			inf = 255;
602		palette[i] = inf;
603	}
604
605	memcpy (pal, palette, sizeof(palette));
606}
607
608void VID_Init(unsigned char *palette)
609{
610	int i;
611	GLint attribs[32];
612	char	gldir[MAX_OSPATH];
613	int width = 640, height = 480;
614
615	Init_KBD();
616
617	Cvar_RegisterVariable (&vid_mode);
618	Cvar_RegisterVariable (&vid_redrawfull);
619	Cvar_RegisterVariable (&vid_waitforrefresh);
620	Cvar_RegisterVariable (&gl_ztrick);
621
622	vid.maxwarpwidth = WARP_WIDTH;
623	vid.maxwarpheight = WARP_HEIGHT;
624	vid.colormap = host_colormap;
625	vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
626
627// interpret command-line params
628
629// set vid parameters
630	attribs[0] = FXMESA_DOUBLEBUFFER;
631	attribs[1] = FXMESA_ALPHA_SIZE;
632	attribs[2] = 1;
633	attribs[3] = FXMESA_DEPTH_SIZE;
634	attribs[4] = 1;
635	attribs[5] = FXMESA_NONE;
636
637	if ((i = COM_CheckParm("-width")) != 0)
638		width = atoi(com_argv[i+1]);
639	if ((i = COM_CheckParm("-height")) != 0)
640		height = atoi(com_argv[i+1]);
641
642	if ((i = COM_CheckParm("-conwidth")) != 0)
643		vid.conwidth = Q_atoi(com_argv[i+1]);
644	else
645		vid.conwidth = 640;
646
647	vid.conwidth &= 0xfff8; // make it a multiple of eight
648
649	if (vid.conwidth < 320)
650		vid.conwidth = 320;
651
652	// pick a conheight that matches with correct aspect
653	vid.conheight = vid.conwidth*3 / 4;
654
655	if ((i = COM_CheckParm("-conheight")) != 0)
656		vid.conheight = Q_atoi(com_argv[i+1]);
657	if (vid.conheight < 200)
658		vid.conheight = 200;
659
660	fc = fxMesaCreateContext(0, findres(&width, &height), GR_REFRESH_75Hz,
661		attribs);
662	if (!fc)
663		Sys_Error("Unable to create 3DFX context.\n");
664
665	InitSig(); // trap evil signals
666
667	scr_width = width;
668	scr_height = height;
669
670	fxMesaMakeCurrent(fc);
671
672	if (vid.conheight > height)
673		vid.conheight = height;
674	if (vid.conwidth > width)
675		vid.conwidth = width;
676	vid.width = vid.conwidth;
677	vid.height = vid.conheight;
678
679	vid.aspect = ((float)vid.height / (float)vid.width) *
680				(320.0 / 240.0);
681	vid.numpages = 2;
682
683	GL_Init();
684
685	sprintf (gldir, "%s/glquake", com_gamedir);
686	Sys_mkdir (gldir);
687
688	Check_Gamma(palette);
689	VID_SetPalette(palette);
690
691	// Check for 3DFX Extensions and initialize them.
692	VID_Init8bitPalette();
693
694	Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height);
695
696	vid.recalc_refdef = 1;				// force a surface cache flush
697}
698
699void Sys_SendKeyEvents(void)
700{
701	if (UseKeyboard)
702		while (keyboard_update());
703}
704
705void Force_CenterView_f (void)
706{
707	cl.viewangles[PITCH] = 0;
708}
709
710
711void mousehandler(int buttonstate, int dx, int dy)
712{
713	mouse_buttonstate = buttonstate;
714	mx += dx;
715	my += dy;
716}
717
718void IN_Init(void)
719{
720
721	int mtype;
722	char *mousedev;
723	int mouserate;
724
725	if (UseMouse)
726	{
727
728		Cvar_RegisterVariable (&mouse_button_commands[0]);
729		Cvar_RegisterVariable (&mouse_button_commands[1]);
730		Cvar_RegisterVariable (&mouse_button_commands[2]);
731		Cmd_AddCommand ("force_centerview", Force_CenterView_f);
732
733		mouse_buttons = 3;
734
735		mtype = vga_getmousetype();
736
737		mousedev = "/dev/mouse";
738		if (getenv("MOUSEDEV")) mousedev = getenv("MOUSEDEV");
739		if (COM_CheckParm("-mdev"))
740			mousedev = com_argv[COM_CheckParm("-mdev")+1];
741
742		mouserate = 1200;
743		if (getenv("MOUSERATE")) mouserate = atoi(getenv("MOUSERATE"));
744		if (COM_CheckParm("-mrate"))
745			mouserate = atoi(com_argv[COM_CheckParm("-mrate")+1]);
746
747		if (mouse_init(mousedev, mtype, mouserate))
748		{
749			Con_Printf("No mouse found\n");
750			UseMouse = 0;
751		}
752		else
753			mouse_seteventhandler(mousehandler);
754
755	}
756
757}
758
759void IN_Shutdown(void)
760{
761	if (UseMouse)
762		mouse_close();
763}
764
765/*
766===========
767IN_Commands
768===========
769*/
770void IN_Commands (void)
771{
772	if (UseMouse && cls.state != ca_dedicated)
773	{
774		// poll mouse values
775		while (mouse_update())
776			;
777
778		// perform button actions
779		if ((mouse_buttonstate & MOUSE_LEFTBUTTON) &&
780			!(mouse_oldbuttonstate & MOUSE_LEFTBUTTON))
781			Key_Event (K_MOUSE1, true);
782		else if (!(mouse_buttonstate & MOUSE_LEFTBUTTON) &&
783			(mouse_oldbuttonstate & MOUSE_LEFTBUTTON))
784			Key_Event (K_MOUSE1, false);
785
786		if ((mouse_buttonstate & MOUSE_RIGHTBUTTON) &&
787			!(mouse_oldbuttonstate & MOUSE_RIGHTBUTTON))
788			Key_Event (K_MOUSE2, true);
789		else if (!(mouse_buttonstate & MOUSE_RIGHTBUTTON) &&
790			(mouse_oldbuttonstate & MOUSE_RIGHTBUTTON))
791			Key_Event (K_MOUSE2, false);
792
793		if ((mouse_buttonstate & MOUSE_MIDDLEBUTTON) &&
794			!(mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON))
795			Key_Event (K_MOUSE3, true);
796		else if (!(mouse_buttonstate & MOUSE_MIDDLEBUTTON) &&
797			(mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON))
798			Key_Event (K_MOUSE3, false);
799
800		mouse_oldbuttonstate = mouse_buttonstate;
801	}
802}
803
804/*
805===========
806IN_Move
807===========
808*/
809void IN_MouseMove (usercmd_t *cmd)
810{
811	if (!UseMouse)
812		return;
813
814	// poll mouse values
815	while (mouse_update())
816		;
817
818	if (m_filter.value)
819	{
820		mouse_x = (mx + old_mouse_x) * 0.5;
821		mouse_y = (my + old_mouse_y) * 0.5;
822	}
823	else
824	{
825		mouse_x = mx;
826		mouse_y = my;
827	}
828	old_mouse_x = mx;
829	old_mouse_y = my;
830	mx = my = 0; // clear for next update
831
832	mouse_x *= sensitivity.value;
833	mouse_y *= sensitivity.value;
834
835// add mouse X/Y movement to cmd
836	if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
837		cmd->sidemove += m_side.value * mouse_x;
838	else
839		cl.viewangles[YAW] -= m_yaw.value * mouse_x;
840
841	if (in_mlook.state & 1)
842		V_StopPitchDrift ();
843
844	if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
845	{
846		cl.viewangles[PITCH] += m_pitch.value * mouse_y;
847		if (cl.viewangles[PITCH] > 80)
848			cl.viewangles[PITCH] = 80;
849		if (cl.viewangles[PITCH] < -70)
850			cl.viewangles[PITCH] = -70;
851	}
852	else
853	{
854		if ((in_strafe.state & 1) && noclip_anglehack)
855			cmd->upmove -= m_forward.value * mouse_y;
856		else
857			cmd->forwardmove -= m_forward.value * mouse_y;
858	}
859}
860
861void IN_Move (usercmd_t *cmd)
862{
863	IN_MouseMove(cmd);
864}
865
866
867