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
30#include "vga.h"
31#include "vgakeyboard.h"
32#include "vgamouse.h"
33
34#include "quakedef.h"
35#include "d_local.h"
36
37#define stringify(m) { #m, m }
38
39unsigned short       d_8to16table[256];
40static byte		*vid_surfcache;
41static int		VID_highhunkmark;
42
43int num_modes;
44vga_modeinfo *modes;
45int current_mode;
46
47int num_shades=32;
48
49struct
50{
51	char *name;
52	int num;
53} mice[] =
54{
55	stringify(MOUSE_MICROSOFT),
56	stringify(MOUSE_MOUSESYSTEMS),
57	stringify(MOUSE_MMSERIES),
58	stringify(MOUSE_LOGITECH),
59	stringify(MOUSE_BUSMOUSE),
60	stringify(MOUSE_PS2),
61};
62
63static unsigned char scantokey[128];
64static byte vid_current_palette[768];
65
66int num_mice = sizeof (mice) / sizeof(mice[0]);
67
68int	d_con_indirect = 0;
69
70int		svgalib_inited=0;
71int		UseMouse = 1;
72int		UseDisplay = 1;
73int		UseKeyboard = 1;
74
75int		mouserate = MOUSE_DEFAULTSAMPLERATE;
76
77cvar_t		vid_mode = {"vid_mode","5",false};
78cvar_t		vid_redrawfull = {"vid_redrawfull","0",false};
79cvar_t		vid_waitforrefresh = {"vid_waitforrefresh","0",true};
80
81char	*framebuffer_ptr;
82
83cvar_t  mouse_button_commands[3] =
84{
85    {"mouse1","+attack"},
86    {"mouse2","+strafe"},
87    {"mouse3","+forward"},
88};
89
90int     mouse_buttons;
91int     mouse_buttonstate;
92int     mouse_oldbuttonstate;
93float   mouse_x, mouse_y;
94float	old_mouse_x, old_mouse_y;
95int		mx, my;
96
97cvar_t	m_filter = {"m_filter","0"};
98
99static byte     backingbuf[48*24];
100
101int		VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar;
102byte	*VGA_pagebase;
103
104void VGA_UpdatePlanarScreen (void *srcbuffer);
105
106void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
107{
108	int i, j, k, plane, reps, repshift, offset, vidpage, off;
109
110	if (!svgalib_inited || !vid.direct || !vga_oktowrite()) return;
111
112	if (vid.aspect > 1.5)
113	{
114		reps = 2;
115		repshift = 1;
116	} else {
117		reps = 1;
118		repshift = 0;
119	}
120
121	vidpage = 0;
122	vga_setpage(0);
123
124	if (VGA_planar)
125	{
126		for (plane=0 ; plane<4 ; plane++)
127		{
128		// select the correct plane for reading and writing
129			outb(0x02, 0x3C4);
130			outb(1 << plane, 0x3C5);
131			outb(4, 0x3CE);
132			outb(plane, 0x3CF);
133
134			for (i=0 ; i<(height << repshift) ; i += reps)
135			{
136				for (k=0 ; k<reps ; k++)
137				{
138					for (j=0 ; j<(width >> 2) ; j++)
139					{
140						backingbuf[(i + k) * 24 + (j << 2) + plane] =
141								vid.direct[(y + i + k) * VGA_rowbytes +
142								(x >> 2) + j];
143						vid.direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
144								pbitmap[(i >> repshift) * 24 +
145								(j << 2) + plane];
146					}
147				}
148			}
149		}
150	} else {
151		for (i=0 ; i<(height << repshift) ; i += reps)
152		{
153			for (j=0 ; j<reps ; j++)
154			{
155				offset = x + ((y << repshift) + i + j) * vid.rowbytes;
156				off = offset % 0x10000;
157				if ((offset / 0x10000) != vidpage) {
158					vidpage=offset / 0x10000;
159					vga_setpage(vidpage);
160				}
161				memcpy (&backingbuf[(i + j) * 24],
162						vid.direct + off, width);
163				memcpy (vid.direct + off,
164						&pbitmap[(i >> repshift)*width], width);
165			}
166		}
167	}
168}
169
170void D_EndDirectRect (int x, int y, int width, int height)
171{
172	int i, j, k, plane, reps, repshift, offset, vidpage, off;
173
174	if (!svgalib_inited || !vid.direct || !vga_oktowrite()) return;
175
176	if (vid.aspect > 1.5)
177	{
178		reps = 2;
179		repshift = 1;
180	} else {
181		reps = 1;
182		repshift = 0;
183	}
184
185	vidpage = 0;
186	vga_setpage(0);
187
188	if (VGA_planar)
189	{
190		for (plane=0 ; plane<4 ; plane++)
191		{
192		// select the correct plane for writing
193			outb(2, 0x3C4);
194			outb(1 << plane, 0x3C5);
195			outb(4, 0x3CE);
196			outb(plane, 0x3CF);
197
198			for (i=0 ; i<(height << repshift) ; i += reps)
199			{
200				for (k=0 ; k<reps ; k++)
201				{
202					for (j=0 ; j<(width >> 2) ; j++)
203					{
204						vid.direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
205								backingbuf[(i + k) * 24 + (j << 2) + plane];
206					}
207				}
208			}
209		}
210	} else {
211		for (i=0 ; i<(height << repshift) ; i += reps)
212		{
213			for (j=0 ; j<reps ; j++)
214			{
215				offset = x + ((y << repshift) + i + j) * vid.rowbytes;
216				off = offset % 0x10000;
217				if ((offset / 0x10000) != vidpage) {
218					vidpage=offset / 0x10000;
219					vga_setpage(vidpage);
220				}
221				memcpy (vid.direct + off,
222						&backingbuf[(i +j)*24],
223						width);
224			}
225		}
226	}
227}
228
229/*
230=================
231VID_Gamma_f
232
233Keybinding command
234=================
235*/
236void VID_Gamma_f (void)
237{
238	float	gamma, f, inf;
239	unsigned char	palette[768];
240	int		i;
241
242	if (Cmd_Argc () == 2)
243	{
244		gamma = Q_atof (Cmd_Argv(1));
245
246		for (i=0 ; i<768 ; i++)
247		{
248			f = pow ( (host_basepal[i]+1)/256.0 , gamma );
249			inf = f*255 + 0.5;
250			if (inf < 0)
251				inf = 0;
252			if (inf > 255)
253				inf = 255;
254			palette[i] = inf;
255		}
256
257		VID_SetPalette (palette);
258
259		vid.recalc_refdef = 1;				// force a surface cache flush
260	}
261}
262
263void VID_DescribeMode_f (void)
264{
265	int modenum;
266
267	modenum = Q_atoi (Cmd_Argv(1));
268	if ((modenum >= num_modes) || (modenum < 0 ) || !modes[modenum].width)
269		Con_Printf("Invalid video mode: %d!\n",modenum);
270	Con_Printf("%d: %d x %d - ",modenum,modes[modenum].width,modes[modenum].height);
271	if (modes[modenum].bytesperpixel == 0)
272		Con_Printf("ModeX\n");
273	else
274		Con_Printf("%d bpp\n", modes[modenum].bytesperpixel<<3);
275}
276
277void VID_DescribeModes_f (void)
278{
279	int i;
280
281	for (i=0;i<num_modes;i++)
282		if (modes[i].width) {
283			Con_Printf("%d: %d x %d - ", i, modes[i].width,modes[i].height);
284			if (modes[i].bytesperpixel == 0)
285				Con_Printf("ModeX\n");
286			else
287				Con_Printf("%d bpp\n", modes[i].bytesperpixel<<3);
288		}
289}
290
291/*
292================
293VID_NumModes
294================
295*/
296int VID_NumModes ()
297{
298	int i,i1=0;
299
300	for (i=0;i<num_modes;i++)
301		i1+=(modes[i].width?1:0);
302	return (i1);
303}
304
305void VID_NumModes_f (void)
306{
307	Con_Printf("%d modes\n",VID_NumModes());
308}
309
310void VID_Debug_f (void)
311{
312	Con_Printf("mode: %d\n",current_mode);
313	Con_Printf("height x width: %d x %d\n",vid.height,vid.width);
314	Con_Printf("bpp: %d\n",modes[current_mode].bytesperpixel*8);
315	Con_Printf("vid.aspect: %f\n",vid.aspect);
316}
317
318
319
320void VID_InitModes(void)
321{
322
323	int i;
324
325// get complete information on all modes
326
327	num_modes = vga_lastmodenumber()+1;
328	modes = Z_Malloc(num_modes * sizeof(vga_modeinfo));
329	for (i=0 ; i<num_modes ; i++)
330	{
331		if (vga_hasmode(i))
332			Q_memcpy(&modes[i], vga_getmodeinfo(i), sizeof (vga_modeinfo));
333		else
334			modes[i].width = 0; // means not available
335	}
336
337// filter for modes i don't support
338
339	for (i=0 ; i<num_modes ; i++)
340	{
341		if (modes[i].bytesperpixel != 1 && modes[i].colors != 256)
342			modes[i].width = 0;
343	}
344
345}
346
347int get_mode(char *name, int width, int height, int depth)
348{
349
350	int i;
351	int ok, match;
352
353	match = (!!width) + (!!height)*2 + (!!depth)*4;
354
355	if (name)
356	{
357		i = vga_getmodenumber(name);
358		if (!modes[i].width)
359		{
360			Sys_Printf("Mode [%s] not supported\n", name);
361			i = G320x200x256;
362		}
363	}
364	else
365	{
366		for (i=0 ; i<num_modes ; i++)
367			if (modes[i].width)
368			{
369				ok = (modes[i].width == width)
370					+ (modes[i].height == height)*2
371					+ (modes[i].bytesperpixel == depth/8)*4;
372				if ((ok & match) == ok)
373					break;
374			}
375		if (i==num_modes)
376		{
377			Sys_Printf("Mode %dx%d (%d bits) not supported\n",
378				width, height, depth);
379			i = G320x200x256;
380		}
381	}
382
383	return i;
384
385}
386
387int matchmouse(int mouse, char *name)
388{
389	int i;
390	for (i=0 ; i<num_mice ; i++)
391		if (!strcmp(mice[i].name, name))
392			return i;
393	return mouse;
394}
395
396#if 0
397
398void vtswitch(int newconsole)
399{
400
401	int fd;
402	struct vt_stat x;
403
404// switch consoles and wait until reactivated
405	fd = open("/dev/console", O_RDONLY);
406	ioctl(fd, VT_GETSTATE, &x);
407	ioctl(fd, VT_ACTIVATE, newconsole);
408	ioctl(fd, VT_WAITACTIVE, x.v_active);
409	close(fd);
410
411}
412
413#endif
414
415void keyhandler(int scancode, int state)
416{
417
418	int sc;
419
420	sc = scancode & 0x7f;
421//	Con_Printf("scancode=%x (%d%s)\n", scancode, sc, scancode&0x80?"+128":"");
422	Key_Event(scantokey[sc], state == KEY_EVENTPRESS);
423
424}
425
426void VID_Shutdown(void)
427{
428
429	if (!svgalib_inited) return;
430
431//	printf("shutdown graphics called\n");
432	if (UseKeyboard)
433		keyboard_close();
434	if (UseDisplay)
435		vga_setmode(TEXT);
436//	printf("shutdown graphics finished\n");
437
438	svgalib_inited = 0;
439
440}
441
442void VID_ShiftPalette(unsigned char *p)
443{
444	VID_SetPalette(p);
445}
446
447void VID_SetPalette(byte *palette)
448{
449
450	static int tmppal[256*3];
451	int *tp;
452	int i;
453
454	if (!svgalib_inited)
455		return;
456
457	memcpy(vid_current_palette, palette, sizeof(vid_current_palette));
458
459	if (vga_getcolors() == 256)
460	{
461
462		tp = tmppal;
463		for (i=256*3 ; i ; i--)
464			*(tp++) = *(palette++) >> 2;
465
466		if (UseDisplay && vga_oktowrite())
467			vga_setpalvec(0, 256, tmppal);
468
469	}
470}
471
472int VID_SetMode (int modenum, unsigned char *palette)
473{
474	int bsize, zsize, tsize;
475
476	if ((modenum >= num_modes) || (modenum < 0) || !modes[modenum].width)
477	{
478		Cvar_SetValue ("vid_mode", (float)current_mode);
479
480		Con_Printf("No such video mode: %d\n",modenum);
481
482		return 0;
483	}
484
485	Cvar_SetValue ("vid_mode", (float)modenum);
486
487	current_mode=modenum;
488
489	vid.width = modes[current_mode].width;
490	vid.height = modes[current_mode].height;
491
492	VGA_width = modes[current_mode].width;
493	VGA_height = modes[current_mode].height;
494	VGA_planar = modes[current_mode].bytesperpixel == 0;
495	VGA_rowbytes = modes[current_mode].linewidth;
496	vid.rowbytes = modes[current_mode].linewidth;
497	if (VGA_planar) {
498		VGA_bufferrowbytes = modes[current_mode].linewidth * 4;
499		vid.rowbytes = modes[current_mode].linewidth*4;
500	}
501
502	vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
503	vid.colormap = (pixel_t *) host_colormap;
504	vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
505	vid.conrowbytes = vid.rowbytes;
506	vid.conwidth = vid.width;
507	vid.conheight = vid.height;
508	vid.numpages = 1;
509
510	vid.maxwarpwidth = WARP_WIDTH;
511	vid.maxwarpheight = WARP_HEIGHT;
512
513	// alloc zbuffer and surface cache
514	if (d_pzbuffer) {
515		D_FlushCaches();
516		Hunk_FreeToHighMark (VID_highhunkmark);
517		d_pzbuffer = NULL;
518		vid_surfcache = NULL;
519	}
520
521	bsize = vid.rowbytes * vid.height;
522	tsize = D_SurfaceCacheForRes (vid.width, vid.height);
523	zsize = vid.width * vid.height * sizeof(*d_pzbuffer);
524
525	VID_highhunkmark = Hunk_HighMark ();
526
527	d_pzbuffer = Hunk_HighAllocName (bsize+tsize+zsize, "video");
528
529	vid_surfcache = ((byte *)d_pzbuffer) + zsize;
530
531	vid.conbuffer = vid.buffer = (pixel_t *)(((byte *)d_pzbuffer) + zsize + tsize);
532
533	D_InitCaches (vid_surfcache, tsize);
534
535// get goin'
536
537	vga_setmode(current_mode);
538	VID_SetPalette(palette);
539
540	VGA_pagebase = vid.direct = framebuffer_ptr = (char *) vga_getgraphmem();
541//		if (vga_setlinearaddressing()>0)
542//			framebuffer_ptr = (char *) vga_getgraphmem();
543	if (!framebuffer_ptr)
544		Sys_Error("This mode isn't hapnin'\n");
545
546	vga_setpage(0);
547
548	svgalib_inited=1;
549
550	vid.recalc_refdef = 1;				// force a surface cache flush
551
552	return 0;
553}
554
555void VID_Init(unsigned char *palette)
556{
557
558	int i;
559	int w, h, d;
560
561	if (svgalib_inited)
562		return;
563
564//	Cmd_AddCommand ("gamma", VID_Gamma_f);
565
566	if (UseDisplay)
567	{
568		vga_init();
569
570		VID_InitModes();
571
572		Cvar_RegisterVariable (&vid_mode);
573		Cvar_RegisterVariable (&vid_redrawfull);
574		Cvar_RegisterVariable (&vid_waitforrefresh);
575
576		Cmd_AddCommand("vid_nummodes", VID_NumModes_f);
577		Cmd_AddCommand("vid_describemode", VID_DescribeMode_f);
578		Cmd_AddCommand("vid_describemodes", VID_DescribeModes_f);
579		Cmd_AddCommand("vid_debug", VID_Debug_f);
580
581	// interpret command-line params
582
583		w = h = d = 0;
584		if (getenv("GSVGAMODE"))
585			current_mode = get_mode(getenv("GSVGAMODE"), w, h, d);
586		else if (COM_CheckParm("-mode"))
587			current_mode = get_mode(com_argv[COM_CheckParm("-mode")+1], w, h, d);
588		else if (COM_CheckParm("-w") || COM_CheckParm("-h")
589			|| COM_CheckParm("-d"))
590		{
591			if (COM_CheckParm("-w"))
592				w = Q_atoi(com_argv[COM_CheckParm("-w")+1]);
593			if (COM_CheckParm("-h"))
594				h = Q_atoi(com_argv[COM_CheckParm("-h")+1]);
595			if (COM_CheckParm("-d"))
596				d = Q_atoi(com_argv[COM_CheckParm("-d")+1]);
597			current_mode = get_mode(0, w, h, d);
598		}
599		else
600			current_mode = G320x200x256;
601
602	// set vid parameters
603		VID_SetMode(current_mode, palette);
604
605		VID_SetPalette(palette);
606
607		// we do want to run in the background when switched away
608		vga_runinbackground(1);
609	}
610
611	if (COM_CheckParm("-nokbd")) UseKeyboard = 0;
612
613	if (UseKeyboard)
614	{
615		for (i=0 ; i<128 ; i++)
616			scantokey[i] = ' ';
617
618		scantokey[42] = K_SHIFT;
619		scantokey[54] = K_SHIFT;
620		scantokey[72] = K_UPARROW;
621		scantokey[103] = K_UPARROW;
622		scantokey[80] = K_DOWNARROW;
623		scantokey[108] = K_DOWNARROW;
624		scantokey[75] = K_LEFTARROW;
625		scantokey[105] = K_LEFTARROW;
626		scantokey[77] = K_RIGHTARROW;
627		scantokey[106] = K_RIGHTARROW;
628		scantokey[29] = K_CTRL;
629		scantokey[97] = K_CTRL;
630		scantokey[56] = K_ALT;
631		scantokey[100] = K_ALT;
632//		scantokey[58] = JK_CAPS;
633//		scantokey[69] = JK_NUM_LOCK;
634		scantokey[71] = K_HOME;
635		scantokey[73] = K_PGUP;
636		scantokey[79] = K_END;
637		scantokey[81] = K_PGDN;
638		scantokey[82] = K_INS;
639		scantokey[83] = K_DEL;
640		scantokey[1 ] = K_ESCAPE;
641		scantokey[28] = K_ENTER;
642		scantokey[15] = K_TAB;
643		scantokey[14] = K_BACKSPACE;
644		scantokey[119] = K_PAUSE;
645    	scantokey[57] = ' ';
646
647		scantokey[102] = K_HOME;
648		scantokey[104] = K_PGUP;
649		scantokey[107] = K_END;
650		scantokey[109] = K_PGDN;
651		scantokey[110] = K_INS;
652		scantokey[111] = K_DEL;
653
654		scantokey[2] = '1';
655		scantokey[3] = '2';
656		scantokey[4] = '3';
657		scantokey[5] = '4';
658		scantokey[6] = '5';
659		scantokey[7] = '6';
660		scantokey[8] = '7';
661		scantokey[9] = '8';
662		scantokey[10] = '9';
663		scantokey[11] = '0';
664		scantokey[12] = '-';
665		scantokey[13] = '=';
666		scantokey[41] = '`';
667		scantokey[26] = '[';
668		scantokey[27] = ']';
669		scantokey[39] = ';';
670		scantokey[40] = '\'';
671		scantokey[51] = ',';
672		scantokey[52] = '.';
673		scantokey[53] = '/';
674		scantokey[43] = '\\';
675
676		scantokey[59] = K_F1;
677		scantokey[60] = K_F2;
678		scantokey[61] = K_F3;
679		scantokey[62] = K_F4;
680		scantokey[63] = K_F5;
681		scantokey[64] = K_F6;
682		scantokey[65] = K_F7;
683		scantokey[66] = K_F8;
684		scantokey[67] = K_F9;
685		scantokey[68] = K_F10;
686		scantokey[87] = K_F11;
687		scantokey[88] = K_F12;
688		scantokey[30] = 'a';
689		scantokey[48] = 'b';
690		scantokey[46] = 'c';
691        scantokey[32] = 'd';
692        scantokey[18] = 'e';
693        scantokey[33] = 'f';
694        scantokey[34] = 'g';
695        scantokey[35] = 'h';
696        scantokey[23] = 'i';
697        scantokey[36] = 'j';
698        scantokey[37] = 'k';
699        scantokey[38] = 'l';
700        scantokey[50] = 'm';
701        scantokey[49] = 'n';
702        scantokey[24] = 'o';
703        scantokey[25] = 'p';
704        scantokey[16] = 'q';
705        scantokey[19] = 'r';
706        scantokey[31] = 's';
707        scantokey[20] = 't';
708        scantokey[22] = 'u';
709        scantokey[47] = 'v';
710        scantokey[17] = 'w';
711        scantokey[45] = 'x';
712        scantokey[21] = 'y';
713        scantokey[44] = 'z';
714
715		if (keyboard_init())
716			Sys_Error("keyboard_init() failed");
717		keyboard_seteventhandler(keyhandler);
718	}
719
720}
721
722void VID_Update(vrect_t *rects)
723{
724	if (!svgalib_inited)
725		return;
726
727	if (!vga_oktowrite())
728		return; // can't update screen if it's not active
729
730	if (vid_waitforrefresh.value)
731		vga_waitretrace();
732
733	if (VGA_planar)
734		VGA_UpdatePlanarScreen (vid.buffer);
735
736	else if (vid_redrawfull.value) {
737		int total = vid.rowbytes * vid.height;
738		int offset;
739
740		for (offset=0;offset<total;offset+=0x10000) {
741			vga_setpage(offset/0x10000);
742			memcpy(framebuffer_ptr,
743					vid.buffer + offset,
744					((total-offset>0x10000)?0x10000:(total-offset)));
745		}
746	} else {
747		int ycount;
748		int offset;
749		int vidpage=0;
750
751		vga_setpage(0);
752
753		while (rects)
754		{
755			ycount = rects->height;
756			offset = rects->y * vid.rowbytes + rects->x;
757			while (ycount--)
758			{
759				register int i = offset % 0x10000;
760
761				if ((offset / 0x10000) != vidpage) {
762					vidpage=offset / 0x10000;
763					vga_setpage(vidpage);
764				}
765				if (rects->width + i > 0x10000) {
766					memcpy(framebuffer_ptr + i,
767							vid.buffer + offset,
768							0x10000 - i);
769					vga_setpage(++vidpage);
770					memcpy(framebuffer_ptr,
771							vid.buffer + offset + 0x10000 - i,
772							rects->width - 0x10000 + i);
773				} else
774					memcpy(framebuffer_ptr + i,
775							vid.buffer + offset,
776							rects->width);
777				offset += vid.rowbytes;
778			}
779
780			rects = rects->pnext;
781		}
782	}
783
784	if (vid_mode.value != current_mode)
785		VID_SetMode ((int)vid_mode.value, vid_current_palette);
786}
787
788static int dither;
789
790void VID_DitherOn(void)
791{
792    if (dither == 0)
793    {
794//		R_ViewChanged (&vrect, sb_lines, vid.aspect);
795        dither = 1;
796    }
797}
798
799void VID_DitherOff(void)
800{
801    if (dither)
802    {
803//		R_ViewChanged (&vrect, sb_lines, vid.aspect);
804        dither = 0;
805    }
806}
807
808void Sys_SendKeyEvents(void)
809{
810	if (!svgalib_inited)
811		return;
812
813	if (UseKeyboard)
814		while (keyboard_update());
815}
816
817void Force_CenterView_f (void)
818{
819	cl.viewangles[PITCH] = 0;
820}
821
822
823void mousehandler(int buttonstate, int dx, int dy)
824{
825	mouse_buttonstate = buttonstate;
826	mx += dx;
827	my += dy;
828}
829
830void IN_Init(void)
831{
832
833	int mtype;
834	char *mousedev;
835	int mouserate;
836
837	if (UseMouse)
838	{
839
840		Cvar_RegisterVariable (&mouse_button_commands[0]);
841		Cvar_RegisterVariable (&mouse_button_commands[1]);
842		Cvar_RegisterVariable (&mouse_button_commands[2]);
843		Cvar_RegisterVariable (&m_filter);
844		Cmd_AddCommand ("force_centerview", Force_CenterView_f);
845
846		mouse_buttons = 3;
847
848		mtype = vga_getmousetype();
849
850		mousedev = "/dev/mouse";
851		if (getenv("MOUSEDEV")) mousedev = getenv("MOUSEDEV");
852		if (COM_CheckParm("-mdev"))
853			mousedev = com_argv[COM_CheckParm("-mdev")+1];
854
855		mouserate = 1200;
856		if (getenv("MOUSERATE")) mouserate = atoi(getenv("MOUSERATE"));
857		if (COM_CheckParm("-mrate"))
858			mouserate = atoi(com_argv[COM_CheckParm("-mrate")+1]);
859
860//		printf("Mouse: dev=%s,type=%s,speed=%d\n",
861//			mousedev, mice[mtype].name, mouserate);
862		if (mouse_init(mousedev, mtype, mouserate))
863		{
864			Con_Printf("No mouse found\n");
865			UseMouse = 0;
866		}
867		else
868			mouse_seteventhandler(mousehandler);
869
870	}
871
872}
873
874void IN_Shutdown(void)
875{
876	if (UseMouse)
877		mouse_close();
878}
879
880/*
881===========
882IN_Commands
883===========
884*/
885void IN_Commands (void)
886{
887	if (UseMouse && cls.state != ca_dedicated)
888	{
889		// poll mouse values
890		while (mouse_update())
891			;
892
893		// perform button actions
894		if ((mouse_buttonstate & MOUSE_LEFTBUTTON) &&
895			!(mouse_oldbuttonstate & MOUSE_LEFTBUTTON))
896			Key_Event (K_MOUSE1, true);
897		else if (!(mouse_buttonstate & MOUSE_LEFTBUTTON) &&
898			(mouse_oldbuttonstate & MOUSE_LEFTBUTTON))
899			Key_Event (K_MOUSE1, false);
900
901		if ((mouse_buttonstate & MOUSE_RIGHTBUTTON) &&
902			!(mouse_oldbuttonstate & MOUSE_RIGHTBUTTON))
903			Key_Event (K_MOUSE2, true);
904		else if (!(mouse_buttonstate & MOUSE_RIGHTBUTTON) &&
905			(mouse_oldbuttonstate & MOUSE_RIGHTBUTTON))
906			Key_Event (K_MOUSE2, false);
907
908		if ((mouse_buttonstate & MOUSE_MIDDLEBUTTON) &&
909			!(mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON))
910			Key_Event (K_MOUSE3, true);
911		else if (!(mouse_buttonstate & MOUSE_MIDDLEBUTTON) &&
912			(mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON))
913			Key_Event (K_MOUSE3, false);
914
915		mouse_oldbuttonstate = mouse_buttonstate;
916	}
917}
918
919/*
920===========
921IN_Move
922===========
923*/
924void IN_MouseMove (usercmd_t *cmd)
925{
926	if (!UseMouse)
927		return;
928
929	// poll mouse values
930	while (mouse_update())
931		;
932
933	if (m_filter.value)
934	{
935		mouse_x = (mx + old_mouse_x) * 0.5;
936		mouse_y = (my + old_mouse_y) * 0.5;
937	}
938	else
939	{
940		mouse_x = mx;
941		mouse_y = my;
942	}
943	old_mouse_x = mx;
944	old_mouse_y = my;
945	mx = my = 0; // clear for next update
946
947	mouse_x *= sensitivity.value;
948	mouse_y *= sensitivity.value;
949
950// add mouse X/Y movement to cmd
951	if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
952		cmd->sidemove += m_side.value * mouse_x;
953	else
954		cl.viewangles[YAW] -= m_yaw.value * mouse_x;
955
956	if (in_mlook.state & 1)
957		V_StopPitchDrift ();
958
959	if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
960	{
961		cl.viewangles[PITCH] += m_pitch.value * mouse_y;
962		if (cl.viewangles[PITCH] > 80)
963			cl.viewangles[PITCH] = 80;
964		if (cl.viewangles[PITCH] < -70)
965			cl.viewangles[PITCH] = -70;
966	}
967	else
968	{
969		if ((in_strafe.state & 1) && noclip_anglehack)
970			cmd->upmove -= m_forward.value * mouse_y;
971		else
972			cmd->forwardmove -= m_forward.value * mouse_y;
973	}
974}
975
976void IN_Move (usercmd_t *cmd)
977{
978	IN_MouseMove(cmd);
979}
980
981
982/*
983================
984VID_ModeInfo
985================
986*/
987char *VID_ModeInfo (int modenum)
988{
989	static char	*badmodestr = "Bad mode number";
990	static char modestr[40];
991
992	if (modenum == 0)
993	{
994		sprintf (modestr, "%d x %d, %d bpp",
995				 vid.width, vid.height, modes[current_mode].bytesperpixel*8);
996		return (modestr);
997	}
998	else
999	{
1000		return (badmodestr);
1001	}
1002}
1003
1004