Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 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
// vid_x.c -- general x video driver
21
 
22
#define _BSD
23
 
24
 
25
#include 
26
#include 
27
#include 
28
#include 
29
#include 
30
#include 
31
#include 
32
#include 
33
#include 
34
#include 
35
#include 
36
#include 
37
#include 
38
#include 
39
#include 
40
 
41
#include "quakedef.h"
42
#include "d_local.h"
43
 
44
cvar_t		_windowed_mouse = {"_windowed_mouse","0", true};
45
cvar_t		m_filter = {"m_filter","0", true};
46
float old_windowed_mouse;
47
 
48
qboolean        mouse_avail;
49
int             mouse_buttons=3;
50
int             mouse_oldbuttonstate;
51
int             mouse_buttonstate;
52
float   mouse_x, mouse_y;
53
float   old_mouse_x, old_mouse_y;
54
int p_mouse_x;
55
int p_mouse_y;
56
int ignorenext;
57
int bits_per_pixel;
58
 
59
typedef struct
60
{
61
	int input;
62
	int output;
63
} keymap_t;
64
 
65
viddef_t vid; // global video state
66
unsigned short d_8to16table[256];
67
 
68
int		num_shades=32;
69
 
70
int	d_con_indirect = 0;
71
 
72
int		vid_buffersize;
73
 
74
static qboolean			doShm;
75
static Display			*x_disp;
76
static Colormap			x_cmap;
77
static Window			x_win;
78
static GC				x_gc;
79
static Visual			*x_vis;
80
static XVisualInfo		*x_visinfo;
81
//static XImage			*x_image;
82
 
83
static int				x_shmeventtype;
84
//static XShmSegmentInfo	x_shminfo;
85
 
86
static qboolean			oktodraw = false;
87
 
88
int XShmQueryExtension(Display *);
89
int XShmGetEventBase(Display *);
90
 
91
int current_framebuffer;
92
static XImage			*x_framebuffer[2] = { 0, 0 };
93
static XShmSegmentInfo	x_shminfo[2];
94
 
95
static int verbose=0;
96
 
97
static byte current_palette[768];
98
 
99
static long X11_highhunkmark;
100
static long X11_buffersize;
101
 
102
int vid_surfcachesize;
103
void *vid_surfcache;
104
 
105
void (*vid_menudrawfn)(void);
106
void (*vid_menukeyfn)(int key);
107
void VID_MenuKey (int key);
108
 
109
typedef unsigned short PIXEL16;
110
typedef unsigned long PIXEL24;
111
static PIXEL16 st2d_8to16table[256];
112
static PIXEL24 st2d_8to24table[256];
113
static int shiftmask_fl=0;
114
static long r_shift,g_shift,b_shift;
115
static unsigned long r_mask,g_mask,b_mask;
116
 
117
void shiftmask_init()
118
{
119
    unsigned int x;
120
    r_mask=x_vis->red_mask;
121
    g_mask=x_vis->green_mask;
122
    b_mask=x_vis->blue_mask;
123
    for(r_shift=-8,x=1;x
124
    for(g_shift=-8,x=1;x
125
    for(b_shift=-8,x=1;x
126
    shiftmask_fl=1;
127
}
128
 
129
PIXEL16 xlib_rgb16(int r,int g,int b)
130
{
131
    PIXEL16 p;
132
    if(shiftmask_fl==0) shiftmask_init();
133
    p=0;
134
 
135
    if(r_shift>0) {
136
        p=(r<<(r_shift))&r_mask;
137
    } else if(r_shift<0) {
138
        p=(r>>(-r_shift))&r_mask;
139
    } else p|=(r&r_mask);
140
 
141
    if(g_shift>0) {
142
        p|=(g<<(g_shift))&g_mask;
143
    } else if(g_shift<0) {
144
        p|=(g>>(-g_shift))&g_mask;
145
    } else p|=(g&g_mask);
146
 
147
    if(b_shift>0) {
148
        p|=(b<<(b_shift))&b_mask;
149
    } else if(b_shift<0) {
150
        p|=(b>>(-b_shift))&b_mask;
151
    } else p|=(b&b_mask);
152
 
153
    return p;
154
}
155
 
156
PIXEL24 xlib_rgb24(int r,int g,int b)
157
{
158
    PIXEL24 p;
159
    if(shiftmask_fl==0) shiftmask_init();
160
    p=0;
161
 
162
    if(r_shift>0) {
163
        p=(r<<(r_shift))&r_mask;
164
    } else if(r_shift<0) {
165
        p=(r>>(-r_shift))&r_mask;
166
    } else p|=(r&r_mask);
167
 
168
    if(g_shift>0) {
169
        p|=(g<<(g_shift))&g_mask;
170
    } else if(g_shift<0) {
171
        p|=(g>>(-g_shift))&g_mask;
172
    } else p|=(g&g_mask);
173
 
174
    if(b_shift>0) {
175
        p|=(b<<(b_shift))&b_mask;
176
    } else if(b_shift<0) {
177
        p|=(b>>(-b_shift))&b_mask;
178
    } else p|=(b&b_mask);
179
 
180
    return p;
181
}
182
 
183
void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
184
{
185
	int xi,yi;
186
	unsigned char *src;
187
	PIXEL16 *dest;
188
	register int count, n;
189
 
190
	if( (x<0)||(y<0) )return;
191
 
192
	for (yi = y; yi < (y+height); yi++) {
193
		src = &framebuf->data [yi * framebuf->bytes_per_line];
194
 
195
		// Duff's Device
196
		count = width;
197
		n = (count + 7) / 8;
198
		dest = ((PIXEL16 *)src) + x+width - 1;
199
		src += x+width - 1;
200
 
201
		switch (count % 8) {
202
		case 0:	do {	*dest-- = st2d_8to16table[*src--];
203
		case 7:			*dest-- = st2d_8to16table[*src--];
204
		case 6:			*dest-- = st2d_8to16table[*src--];
205
		case 5:			*dest-- = st2d_8to16table[*src--];
206
		case 4:			*dest-- = st2d_8to16table[*src--];
207
		case 3:			*dest-- = st2d_8to16table[*src--];
208
		case 2:			*dest-- = st2d_8to16table[*src--];
209
		case 1:			*dest-- = st2d_8to16table[*src--];
210
				} while (--n > 0);
211
		}
212
 
213
//		for(xi = (x+width-1); xi >= x; xi--) {
214
//			dest[xi] = st2d_8to16table[src[xi]];
215
//		}
216
	}
217
}
218
 
219
void st3_fixup( XImage *framebuf, int x, int y, int width, int height)
220
{
221
	int xi,yi;
222
	unsigned char *src;
223
	PIXEL24 *dest;
224
	register int count, n;
225
 
226
	if( (x<0)||(y<0) )return;
227
 
228
	for (yi = y; yi < (y+height); yi++) {
229
		src = &framebuf->data [yi * framebuf->bytes_per_line];
230
 
231
		// Duff's Device
232
		count = width;
233
		n = (count + 7) / 8;
234
		dest = ((PIXEL24 *)src) + x+width - 1;
235
		src += x+width - 1;
236
 
237
		switch (count % 8) {
238
		case 0:	do {	*dest-- = st2d_8to24table[*src--];
239
		case 7:			*dest-- = st2d_8to24table[*src--];
240
		case 6:			*dest-- = st2d_8to24table[*src--];
241
		case 5:			*dest-- = st2d_8to24table[*src--];
242
		case 4:			*dest-- = st2d_8to24table[*src--];
243
		case 3:			*dest-- = st2d_8to24table[*src--];
244
		case 2:			*dest-- = st2d_8to24table[*src--];
245
		case 1:			*dest-- = st2d_8to24table[*src--];
246
				} while (--n > 0);
247
		}
248
 
249
//		for(xi = (x+width-1); xi >= x; xi--) {
250
//			dest[xi] = st2d_8to16table[src[xi]];
251
//		}
252
	}
253
}
254
 
255
 
256
// ========================================================================
257
// Tragic death handler
258
// ========================================================================
259
 
260
void TragicDeath(int signal_num)
261
{
262
	XAutoRepeatOn(x_disp);
263
	XCloseDisplay(x_disp);
264
	Sys_Error("This death brought to you by the number %d\n", signal_num);
265
}
266
 
267
// ========================================================================
268
// makes a null cursor
269
// ========================================================================
270
 
271
static Cursor CreateNullCursor(Display *display, Window root)
272
{
273
    Pixmap cursormask;
274
    XGCValues xgc;
275
    GC gc;
276
    XColor dummycolour;
277
    Cursor cursor;
278
 
279
    cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
280
    xgc.function = GXclear;
281
    gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
282
    XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
283
    dummycolour.pixel = 0;
284
    dummycolour.red = 0;
285
    dummycolour.flags = 04;
286
    cursor = XCreatePixmapCursor(display, cursormask, cursormask,
287
          &dummycolour,&dummycolour, 0,0);
288
    XFreePixmap(display,cursormask);
289
    XFreeGC(display,gc);
290
    return cursor;
291
}
292
 
293
void ResetFrameBuffer(void)
294
{
295
	int mem;
296
	int pwidth;
297
 
298
	if (x_framebuffer[0])
299
	{
300
		free(x_framebuffer[0]->data);
301
		free(x_framebuffer[0]);
302
	}
303
 
304
	if (d_pzbuffer)
305
	{
306
		D_FlushCaches ();
307
		Hunk_FreeToHighMark (X11_highhunkmark);
308
		d_pzbuffer = NULL;
309
	}
310
	X11_highhunkmark = Hunk_HighMark ();
311
 
312
// alloc an extra line in case we want to wrap, and allocate the z-buffer
313
	X11_buffersize = vid.width * vid.height * sizeof (*d_pzbuffer);
314
 
315
	vid_surfcachesize = D_SurfaceCacheForRes (vid.width, vid.height);
316
 
317
	X11_buffersize += vid_surfcachesize;
318
 
319
	d_pzbuffer = Hunk_HighAllocName (X11_buffersize, "video");
320
	if (d_pzbuffer == NULL)
321
		Sys_Error ("Not enough memory for video mode\n");
322
 
323
	vid_surfcache = (byte *) d_pzbuffer
324
		+ vid.width * vid.height * sizeof (*d_pzbuffer);
325
 
326
	D_InitCaches(vid_surfcache, vid_surfcachesize);
327
 
328
	pwidth = x_visinfo->depth / 8;
329
	if (pwidth == 3) pwidth = 4;
330
	mem = ((vid.width*pwidth+7)&~7) * vid.height;
331
 
332
	x_framebuffer[0] = XCreateImage(	x_disp,
333
		x_vis,
334
		x_visinfo->depth,
335
		ZPixmap,
336
		0,
337
		malloc(mem),
338
		vid.width, vid.height,
339
		32,
340
		0);
341
 
342
	if (!x_framebuffer[0])
343
		Sys_Error("VID: XCreateImage failed\n");
344
 
345
	vid.buffer = (byte*) (x_framebuffer[0]);
346
	vid.conbuffer = vid.buffer;
347
 
348
}
349
 
350
void ResetSharedFrameBuffers(void)
351
{
352
 
353
	int size;
354
	int key;
355
	int minsize = getpagesize();
356
	int frm;
357
 
358
	if (d_pzbuffer)
359
	{
360
		D_FlushCaches ();
361
		Hunk_FreeToHighMark (X11_highhunkmark);
362
		d_pzbuffer = NULL;
363
	}
364
 
365
	X11_highhunkmark = Hunk_HighMark ();
366
 
367
// alloc an extra line in case we want to wrap, and allocate the z-buffer
368
	X11_buffersize = vid.width * vid.height * sizeof (*d_pzbuffer);
369
 
370
	vid_surfcachesize = D_SurfaceCacheForRes (vid.width, vid.height);
371
 
372
	X11_buffersize += vid_surfcachesize;
373
 
374
	d_pzbuffer = Hunk_HighAllocName (X11_buffersize, "video");
375
	if (d_pzbuffer == NULL)
376
		Sys_Error ("Not enough memory for video mode\n");
377
 
378
	vid_surfcache = (byte *) d_pzbuffer
379
		+ vid.width * vid.height * sizeof (*d_pzbuffer);
380
 
381
	D_InitCaches(vid_surfcache, vid_surfcachesize);
382
 
383
	for (frm=0 ; frm<2 ; frm++)
384
	{
385
 
386
	// free up old frame buffer memory
387
 
388
		if (x_framebuffer[frm])
389
		{
390
			XShmDetach(x_disp, &x_shminfo[frm]);
391
			free(x_framebuffer[frm]);
392
			shmdt(x_shminfo[frm].shmaddr);
393
		}
394
 
395
	// create the image
396
 
397
		x_framebuffer[frm] = XShmCreateImage(	x_disp,
398
						x_vis,
399
						x_visinfo->depth,
400
						ZPixmap,
401
						0,
402
						&x_shminfo[frm],
403
						vid.width,
404
						vid.height );
405
 
406
	// grab shared memory
407
 
408
		size = x_framebuffer[frm]->bytes_per_line
409
			* x_framebuffer[frm]->height;
410
		if (size < minsize)
411
			Sys_Error("VID: Window must use at least %d bytes\n", minsize);
412
 
413
		key = random();
414
		x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
415
		if (x_shminfo[frm].shmid==-1)
416
			Sys_Error("VID: Could not get any shared memory\n");
417
 
418
		// attach to the shared memory segment
419
		x_shminfo[frm].shmaddr =
420
			(void *) shmat(x_shminfo[frm].shmid, 0, 0);
421
 
422
		printf("VID: shared memory id=%d, addr=0x%lx\n", x_shminfo[frm].shmid,
423
			(long) x_shminfo[frm].shmaddr);
424
 
425
		x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
426
 
427
	// get the X server to attach to it
428
 
429
		if (!XShmAttach(x_disp, &x_shminfo[frm]))
430
			Sys_Error("VID: XShmAttach() failed\n");
431
		XSync(x_disp, 0);
432
		shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
433
 
434
	}
435
 
436
}
437
 
438
// Called at startup to set up translation tables, takes 256 8 bit RGB values
439
// the palette data will go away after the call, so it must be copied off if
440
// the video driver will need it again
441
 
442
void	VID_Init (unsigned char *palette)
443
{
444
 
445
   int pnum, i;
446
   XVisualInfo template;
447
   int num_visuals;
448
   int template_mask;
449
 
450
   ignorenext=0;
451
   vid.width = 320;
452
   vid.height = 200;
453
   vid.maxwarpwidth = WARP_WIDTH;
454
   vid.maxwarpheight = WARP_HEIGHT;
455
   vid.numpages = 2;
456
   vid.colormap = host_colormap;
457
   //	vid.cbits = VID_CBITS;
458
   //	vid.grades = VID_GRADES;
459
   vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
460
 
461
	srandom(getpid());
462
 
463
	verbose=COM_CheckParm("-verbose");
464
 
465
// open the display
466
	x_disp = XOpenDisplay(0);
467
	if (!x_disp)
468
	{
469
		if (getenv("DISPLAY"))
470
			Sys_Error("VID: Could not open display [%s]\n",
471
				getenv("DISPLAY"));
472
		else
473
			Sys_Error("VID: Could not open local display\n");
474
	}
475
 
476
// catch signals so i can turn on auto-repeat
477
 
478
	{
479
		struct sigaction sa;
480
		sigaction(SIGINT, 0, &sa);
481
		sa.sa_handler = TragicDeath;
482
		sigaction(SIGINT, &sa, 0);
483
		sigaction(SIGTERM, &sa, 0);
484
	}
485
 
486
	XAutoRepeatOff(x_disp);
487
 
488
// for debugging only
489
	XSynchronize(x_disp, True);
490
 
491
// check for command-line window size
492
	if ((pnum=COM_CheckParm("-winsize")))
493
	{
494
		if (pnum >= com_argc-2)
495
			Sys_Error("VID: -winsize  \n");
496
		vid.width = Q_atoi(com_argv[pnum+1]);
497
		vid.height = Q_atoi(com_argv[pnum+2]);
498
		if (!vid.width || !vid.height)
499
			Sys_Error("VID: Bad window width/height\n");
500
	}
501
	if ((pnum=COM_CheckParm("-width"))) {
502
		if (pnum >= com_argc-1)
503
			Sys_Error("VID: -width \n");
504
		vid.width = Q_atoi(com_argv[pnum+1]);
505
		if (!vid.width)
506
			Sys_Error("VID: Bad window width\n");
507
	}
508
	if ((pnum=COM_CheckParm("-height"))) {
509
		if (pnum >= com_argc-1)
510
			Sys_Error("VID: -height \n");
511
		vid.height = Q_atoi(com_argv[pnum+1]);
512
		if (!vid.height)
513
			Sys_Error("VID: Bad window height\n");
514
	}
515
 
516
	template_mask = 0;
517
 
518
// specify a visual id
519
	if ((pnum=COM_CheckParm("-visualid")))
520
	{
521
		if (pnum >= com_argc-1)
522
			Sys_Error("VID: -visualid \n");
523
		template.visualid = Q_atoi(com_argv[pnum+1]);
524
		template_mask = VisualIDMask;
525
	}
526
 
527
// If not specified, use default visual
528
	else
529
	{
530
		int screen;
531
		screen = XDefaultScreen(x_disp);
532
		template.visualid =
533
			XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
534
		template_mask = VisualIDMask;
535
	}
536
 
537
// pick a visual- warn if more than one was available
538
	x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals);
539
	if (num_visuals > 1)
540
	{
541
		printf("Found more than one visual id at depth %d:\n", template.depth);
542
		for (i=0 ; i
543
			printf("	-visualid %d\n", (int)(x_visinfo[i].visualid));
544
	}
545
	else if (num_visuals == 0)
546
	{
547
		if (template_mask == VisualIDMask)
548
			Sys_Error("VID: Bad visual id %d\n", template.visualid);
549
		else
550
			Sys_Error("VID: No visuals at depth %d\n", template.depth);
551
	}
552
 
553
	if (verbose)
554
	{
555
		printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
556
		printf("	screen %d\n", x_visinfo->screen);
557
		printf("	red_mask 0x%x\n", (int)(x_visinfo->red_mask));
558
		printf("	green_mask 0x%x\n", (int)(x_visinfo->green_mask));
559
		printf("	blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
560
		printf("	colormap_size %d\n", x_visinfo->colormap_size);
561
		printf("	bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
562
	}
563
 
564
	x_vis = x_visinfo->visual;
565
 
566
// setup attributes for main window
567
	{
568
	   int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
569
	   XSetWindowAttributes attribs;
570
	   Colormap tmpcmap;
571
 
572
	   tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
573
							 x_visinfo->screen), x_vis, AllocNone);
574
 
575
           attribs.event_mask = StructureNotifyMask | KeyPressMask
576
	     | KeyReleaseMask | ExposureMask | PointerMotionMask |
577
	     ButtonPressMask | ButtonReleaseMask;
578
	   attribs.border_pixel = 0;
579
	   attribs.colormap = tmpcmap;
580
 
581
// create the main window
582
		x_win = XCreateWindow(	x_disp,
583
			XRootWindow(x_disp, x_visinfo->screen),
584
			0, 0,	// x, y
585
			vid.width, vid.height,
586
			0, // borderwidth
587
			x_visinfo->depth,
588
			InputOutput,
589
			x_vis,
590
			attribmask,
591
			&attribs );
592
		XStoreName( x_disp,x_win,"xquake");
593
 
594
 
595
		if (x_visinfo->class != TrueColor)
596
			XFreeColormap(x_disp, tmpcmap);
597
	}
598
 
599
	if (x_visinfo->depth == 8)
600
	{
601
		// create and upload the palette
602
		if (x_visinfo->class == PseudoColor)
603
		{
604
			x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
605
			VID_SetPalette(palette);
606
			XSetWindowColormap(x_disp, x_win, x_cmap);
607
		}
608
	}
609
 
610
// inviso cursor
611
	XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
612
 
613
// create the GC
614
	{
615
		XGCValues xgcvalues;
616
		int valuemask = GCGraphicsExposures;
617
		xgcvalues.graphics_exposures = False;
618
		x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
619
	}
620
 
621
// map the window
622
	XMapWindow(x_disp, x_win);
623
 
624
// wait for first exposure event
625
	{
626
		XEvent event;
627
		do
628
		{
629
			XNextEvent(x_disp, &event);
630
			if (event.type == Expose && !event.xexpose.count)
631
				oktodraw = true;
632
		} while (!oktodraw);
633
	}
634
// now safe to draw
635
 
636
// even if MITSHM is available, make sure it's a local connection
637
	if (XShmQueryExtension(x_disp))
638
	{
639
		char *displayname;
640
		doShm = true;
641
		displayname = (char *) getenv("DISPLAY");
642
		if (displayname)
643
		{
644
			char *d = displayname;
645
			while (*d && (*d != ':')) d++;
646
			if (*d) *d = 0;
647
			if (!(!strcasecmp(displayname, "unix") || !*displayname))
648
				doShm = false;
649
		}
650
	}
651
 
652
	if (doShm)
653
	{
654
		x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion;
655
		ResetSharedFrameBuffers();
656
	}
657
	else
658
		ResetFrameBuffer();
659
 
660
	current_framebuffer = 0;
661
	vid.rowbytes = x_framebuffer[0]->bytes_per_line;
662
	vid.buffer = x_framebuffer[0]->data;
663
	vid.direct = 0;
664
	vid.conbuffer = x_framebuffer[0]->data;
665
	vid.conrowbytes = vid.rowbytes;
666
	vid.conwidth = vid.width;
667
	vid.conheight = vid.height;
668
	vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
669
 
670
//	XSynchronize(x_disp, False);
671
 
672
}
673
 
674
void VID_ShiftPalette(unsigned char *p)
675
{
676
	VID_SetPalette(p);
677
}
678
 
679
 
680
 
681
void VID_SetPalette(unsigned char *palette)
682
{
683
 
684
	int i;
685
	XColor colors[256];
686
 
687
	for(i=0;i<256;i++) {
688
		st2d_8to16table[i]= xlib_rgb16(palette[i*3], palette[i*3+1],palette[i*3+2]);
689
		st2d_8to24table[i]= xlib_rgb24(palette[i*3], palette[i*3+1],palette[i*3+2]);
690
	}
691
 
692
	if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
693
	{
694
		if (palette != current_palette)
695
			memcpy(current_palette, palette, 768);
696
		for (i=0 ; i<256 ; i++)
697
		{
698
			colors[i].pixel = i;
699
			colors[i].flags = DoRed|DoGreen|DoBlue;
700
			colors[i].red = palette[i*3] * 257;
701
			colors[i].green = palette[i*3+1] * 257;
702
			colors[i].blue = palette[i*3+2] * 257;
703
		}
704
		XStoreColors(x_disp, x_cmap, colors, 256);
705
	}
706
 
707
}
708
 
709
// Called at shutdown
710
 
711
void	VID_Shutdown (void)
712
{
713
	Con_Printf("VID_Shutdown\n");
714
	XAutoRepeatOn(x_disp);
715
	XCloseDisplay(x_disp);
716
}
717
 
718
int XLateKey(XKeyEvent *ev)
719
{
720
 
721
	int key;
722
	char buf[64];
723
	KeySym keysym;
724
 
725
	key = 0;
726
 
727
	XLookupString(ev, buf, sizeof buf, &keysym, 0);
728
 
729
	switch(keysym)
730
	{
731
		case XK_KP_Page_Up:
732
		case XK_Page_Up:	 key = K_PGUP; break;
733
 
734
		case XK_KP_Page_Down:
735
		case XK_Page_Down:	 key = K_PGDN; break;
736
 
737
		case XK_KP_Home:
738
		case XK_Home:	 key = K_HOME; break;
739
 
740
		case XK_KP_End:
741
		case XK_End:	 key = K_END; break;
742
 
743
		case XK_KP_Left:
744
		case XK_Left:	 key = K_LEFTARROW; break;
745
 
746
		case XK_KP_Right:
747
		case XK_Right:	key = K_RIGHTARROW;		break;
748
 
749
		case XK_KP_Down:
750
		case XK_Down:	 key = K_DOWNARROW; break;
751
 
752
		case XK_KP_Up:
753
		case XK_Up:		 key = K_UPARROW;	 break;
754
 
755
		case XK_Escape: key = K_ESCAPE;		break;
756
 
757
		case XK_KP_Enter:
758
		case XK_Return: key = K_ENTER;		 break;
759
 
760
		case XK_Tab:		key = K_TAB;			 break;
761
 
762
		case XK_F1:		 key = K_F1;				break;
763
 
764
		case XK_F2:		 key = K_F2;				break;
765
 
766
		case XK_F3:		 key = K_F3;				break;
767
 
768
		case XK_F4:		 key = K_F4;				break;
769
 
770
		case XK_F5:		 key = K_F5;				break;
771
 
772
		case XK_F6:		 key = K_F6;				break;
773
 
774
		case XK_F7:		 key = K_F7;				break;
775
 
776
		case XK_F8:		 key = K_F8;				break;
777
 
778
		case XK_F9:		 key = K_F9;				break;
779
 
780
		case XK_F10:		key = K_F10;			 break;
781
 
782
		case XK_F11:		key = K_F11;			 break;
783
 
784
		case XK_F12:		key = K_F12;			 break;
785
 
786
		case XK_BackSpace: key = K_BACKSPACE; break;
787
 
788
		case XK_KP_Delete:
789
		case XK_Delete: key = K_DEL; break;
790
 
791
		case XK_Pause:	key = K_PAUSE;		 break;
792
 
793
		case XK_Shift_L:
794
		case XK_Shift_R:	key = K_SHIFT;		break;
795
 
796
		case XK_Execute:
797
		case XK_Control_L:
798
		case XK_Control_R:	key = K_CTRL;		 break;
799
 
800
		case XK_Alt_L:
801
		case XK_Meta_L:
802
		case XK_Alt_R:
803
		case XK_Meta_R: key = K_ALT;			break;
804
 
805
		case XK_KP_Begin: key = K_AUX30;	break;
806
 
807
		case XK_Insert:
808
		case XK_KP_Insert: key = K_INS; break;
809
 
810
		case XK_KP_Multiply: key = '*'; break;
811
		case XK_KP_Add: key = '+'; break;
812
		case XK_KP_Subtract: key = '-'; break;
813
		case XK_KP_Divide: key = '/'; break;
814
 
815
#if 0
816
		case 0x021: key = '1';break;/* [!] */
817
		case 0x040: key = '2';break;/* [@] */
818
		case 0x023: key = '3';break;/* [#] */
819
		case 0x024: key = '4';break;/* [$] */
820
		case 0x025: key = '5';break;/* [%] */
821
		case 0x05e: key = '6';break;/* [^] */
822
		case 0x026: key = '7';break;/* [&] */
823
		case 0x02a: key = '8';break;/* [*] */
824
		case 0x028: key = '9';;break;/* [(] */
825
		case 0x029: key = '0';break;/* [)] */
826
		case 0x05f: key = '-';break;/* [_] */
827
		case 0x02b: key = '=';break;/* [+] */
828
		case 0x07c: key = '\'';break;/* [|] */
829
		case 0x07d: key = '[';break;/* [}] */
830
		case 0x07b: key = ']';break;/* [{] */
831
		case 0x022: key = '\'';break;/* ["] */
832
		case 0x03a: key = ';';break;/* [:] */
833
		case 0x03f: key = '/';break;/* [?] */
834
		case 0x03e: key = '.';break;/* [>] */
835
		case 0x03c: key = ',';break;/* [<] */
836
#endif
837
 
838
		default:
839
			key = *(unsigned char*)buf;
840
			if (key >= 'A' && key <= 'Z')
841
				key = key - 'A' + 'a';
842
//			fprintf(stdout, "case 0x0%x: key = ___;break;/* [%c] */\n", keysym);
843
			break;
844
	}
845
 
846
	return key;
847
}
848
 
849
struct
850
{
851
	int key;
852
	int down;
853
} keyq[64];
854
int keyq_head=0;
855
int keyq_tail=0;
856
 
857
int config_notify=0;
858
int config_notify_width;
859
int config_notify_height;
860
 
861
void GetEvent(void)
862
{
863
	XEvent x_event;
864
	int b;
865
 
866
	XNextEvent(x_disp, &x_event);
867
	switch(x_event.type) {
868
	case KeyPress:
869
		keyq[keyq_head].key = XLateKey(&x_event.xkey);
870
		keyq[keyq_head].down = true;
871
		keyq_head = (keyq_head + 1) & 63;
872
		break;
873
	case KeyRelease:
874
		keyq[keyq_head].key = XLateKey(&x_event.xkey);
875
		keyq[keyq_head].down = false;
876
		keyq_head = (keyq_head + 1) & 63;
877
		break;
878
 
879
	case MotionNotify:
880
		if (_windowed_mouse.value) {
881
			mouse_x = (float) ((int)x_event.xmotion.x - (int)(vid.width/2));
882
			mouse_y = (float) ((int)x_event.xmotion.y - (int)(vid.height/2));
883
//printf("m: x=%d,y=%d, mx=%3.2f,my=%3.2f\n",
884
//	x_event.xmotion.x, x_event.xmotion.y, mouse_x, mouse_y);
885
 
886
			/* move the mouse to the window center again */
887
			XSelectInput(x_disp,x_win,StructureNotifyMask|KeyPressMask
888
				|KeyReleaseMask|ExposureMask
889
				|ButtonPressMask
890
				|ButtonReleaseMask);
891
			XWarpPointer(x_disp,None,x_win,0,0,0,0,
892
				(vid.width/2),(vid.height/2));
893
			XSelectInput(x_disp,x_win,StructureNotifyMask|KeyPressMask
894
				|KeyReleaseMask|ExposureMask
895
				|PointerMotionMask|ButtonPressMask
896
				|ButtonReleaseMask);
897
		} else {
898
			mouse_x = (float) (x_event.xmotion.x-p_mouse_x);
899
			mouse_y = (float) (x_event.xmotion.y-p_mouse_y);
900
			p_mouse_x=x_event.xmotion.x;
901
			p_mouse_y=x_event.xmotion.y;
902
		}
903
		break;
904
 
905
	case ButtonPress:
906
		b=-1;
907
		if (x_event.xbutton.button == 1)
908
			b = 0;
909
		else if (x_event.xbutton.button == 2)
910
			b = 2;
911
		else if (x_event.xbutton.button == 3)
912
			b = 1;
913
		if (b>=0)
914
			mouse_buttonstate |= 1<
915
		break;
916
 
917
	case ButtonRelease:
918
		b=-1;
919
		if (x_event.xbutton.button == 1)
920
			b = 0;
921
		else if (x_event.xbutton.button == 2)
922
			b = 2;
923
		else if (x_event.xbutton.button == 3)
924
			b = 1;
925
		if (b>=0)
926
			mouse_buttonstate &= ~(1<
927
		break;
928
 
929
	case ConfigureNotify:
930
//printf("config notify\n");
931
		config_notify_width = x_event.xconfigure.width;
932
		config_notify_height = x_event.xconfigure.height;
933
		config_notify = 1;
934
		break;
935
 
936
	default:
937
		if (doShm && x_event.type == x_shmeventtype)
938
			oktodraw = true;
939
	}
940
 
941
	if (old_windowed_mouse != _windowed_mouse.value) {
942
		old_windowed_mouse = _windowed_mouse.value;
943
 
944
		if (!_windowed_mouse.value) {
945
			/* ungrab the pointer */
946
			XUngrabPointer(x_disp,CurrentTime);
947
		} else {
948
			/* grab the pointer */
949
			XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
950
				GrabModeAsync,x_win,None,CurrentTime);
951
		}
952
	}
953
}
954
 
955
// flushes the given rectangles from the view buffer to the screen
956
 
957
void	VID_Update (vrect_t *rects)
958
{
959
	vrect_t full;
960
 
961
// if the window changes dimension, skip this frame
962
 
963
	if (config_notify)
964
	{
965
		fprintf(stderr, "config notify\n");
966
		config_notify = 0;
967
		vid.width = config_notify_width & ~7;
968
		vid.height = config_notify_height;
969
		if (doShm)
970
			ResetSharedFrameBuffers();
971
		else
972
			ResetFrameBuffer();
973
		vid.rowbytes = x_framebuffer[0]->bytes_per_line;
974
		vid.buffer = x_framebuffer[current_framebuffer]->data;
975
		vid.conbuffer = vid.buffer;
976
		vid.conwidth = vid.width;
977
		vid.conheight = vid.height;
978
		vid.conrowbytes = vid.rowbytes;
979
		vid.recalc_refdef = 1;				// force a surface cache flush
980
		Con_CheckResize();
981
		Con_Clear_f();
982
		return;
983
	}
984
 
985
	// force full update if not 8bit
986
	if (x_visinfo->depth != 8) {
987
		extern int scr_fullupdate;
988
 
989
		scr_fullupdate = 0;
990
	}
991
 
992
 
993
	if (doShm)
994
	{
995
 
996
		while (rects)
997
		{
998
			if (x_visinfo->depth == 16)
999
				st2_fixup( x_framebuffer[current_framebuffer],
1000
					rects->x, rects->y, rects->width,
1001
					rects->height);
1002
			else if (x_visinfo->depth == 24)
1003
				st3_fixup( x_framebuffer[current_framebuffer],
1004
					rects->x, rects->y, rects->width,
1005
					rects->height);
1006
			if (!XShmPutImage(x_disp, x_win, x_gc,
1007
				x_framebuffer[current_framebuffer], rects->x, rects->y,
1008
				rects->x, rects->y, rects->width, rects->height, True))
1009
					Sys_Error("VID_Update: XShmPutImage failed\n");
1010
			oktodraw = false;
1011
			while (!oktodraw) GetEvent();
1012
			rects = rects->pnext;
1013
		}
1014
		current_framebuffer = !current_framebuffer;
1015
		vid.buffer = x_framebuffer[current_framebuffer]->data;
1016
		vid.conbuffer = vid.buffer;
1017
		XSync(x_disp, False);
1018
	}
1019
	else
1020
	{
1021
		while (rects)
1022
		{
1023
			if (x_visinfo->depth == 16)
1024
				st2_fixup( x_framebuffer[current_framebuffer],
1025
					rects->x, rects->y, rects->width,
1026
					rects->height);
1027
			else if (x_visinfo->depth == 24)
1028
				st3_fixup( x_framebuffer[current_framebuffer],
1029
					rects->x, rects->y, rects->width,
1030
					rects->height);
1031
			XPutImage(x_disp, x_win, x_gc, x_framebuffer[0], rects->x,
1032
				rects->y, rects->x, rects->y, rects->width, rects->height);
1033
			rects = rects->pnext;
1034
		}
1035
		XSync(x_disp, False);
1036
	}
1037
 
1038
}
1039
 
1040
static int dither;
1041
 
1042
void VID_DitherOn(void)
1043
{
1044
    if (dither == 0)
1045
    {
1046
		vid.recalc_refdef = 1;
1047
        dither = 1;
1048
    }
1049
}
1050
 
1051
void VID_DitherOff(void)
1052
{
1053
    if (dither)
1054
    {
1055
		vid.recalc_refdef = 1;
1056
        dither = 0;
1057
    }
1058
}
1059
 
1060
int Sys_OpenWindow(void)
1061
{
1062
	return 0;
1063
}
1064
 
1065
void Sys_EraseWindow(int window)
1066
{
1067
}
1068
 
1069
void Sys_DrawCircle(int window, int x, int y, int r)
1070
{
1071
}
1072
 
1073
void Sys_DisplayWindow(int window)
1074
{
1075
}
1076
 
1077
void Sys_SendKeyEvents(void)
1078
{
1079
// get events from x server
1080
	if (x_disp)
1081
	{
1082
		while (XPending(x_disp)) GetEvent();
1083
		while (keyq_head != keyq_tail)
1084
		{
1085
			Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down);
1086
			keyq_tail = (keyq_tail + 1) & 63;
1087
		}
1088
	}
1089
}
1090
 
1091
#if 0
1092
char *Sys_ConsoleInput (void)
1093
{
1094
 
1095
	static char	text[256];
1096
	int		len;
1097
	fd_set  readfds;
1098
	int		ready;
1099
	struct timeval timeout;
1100
 
1101
	timeout.tv_sec = 0;
1102
	timeout.tv_usec = 0;
1103
	FD_ZERO(&readfds);
1104
	FD_SET(0, &readfds);
1105
	ready = select(1, &readfds, 0, 0, &timeout);
1106
 
1107
	if (ready>0)
1108
	{
1109
		len = read (0, text, sizeof(text));
1110
		if (len >= 1)
1111
		{
1112
			text[len-1] = 0;	// rip off the /n and terminate
1113
			return text;
1114
		}
1115
	}
1116
 
1117
	return 0;
1118
 
1119
}
1120
#endif
1121
 
1122
void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
1123
{
1124
// direct drawing of the "accessing disk" icon isn't supported under Linux
1125
}
1126
 
1127
void D_EndDirectRect (int x, int y, int width, int height)
1128
{
1129
// direct drawing of the "accessing disk" icon isn't supported under Linux
1130
}
1131
 
1132
void IN_Init (void)
1133
{
1134
	Cvar_RegisterVariable (&_windowed_mouse);
1135
	Cvar_RegisterVariable (&m_filter);
1136
   if ( COM_CheckParm ("-nomouse") )
1137
     return;
1138
   mouse_x = mouse_y = 0.0;
1139
   mouse_avail = 1;
1140
}
1141
 
1142
void IN_Shutdown (void)
1143
{
1144
   mouse_avail = 0;
1145
}
1146
 
1147
void IN_Commands (void)
1148
{
1149
	int i;
1150
 
1151
	if (!mouse_avail) return;
1152
 
1153
	for (i=0 ; i
1154
		if ( (mouse_buttonstate & (1<
1155
			Key_Event (K_MOUSE1 + i, true);
1156
 
1157
		if ( !(mouse_buttonstate & (1<
1158
			Key_Event (K_MOUSE1 + i, false);
1159
	}
1160
	mouse_oldbuttonstate = mouse_buttonstate;
1161
}
1162
 
1163
void IN_Move (usercmd_t *cmd)
1164
{
1165
	if (!mouse_avail)
1166
		return;
1167
 
1168
	if (m_filter.value) {
1169
		mouse_x = (mouse_x + old_mouse_x) * 0.5;
1170
		mouse_y = (mouse_y + old_mouse_y) * 0.5;
1171
	}
1172
 
1173
	old_mouse_x = mouse_x;
1174
	old_mouse_y = mouse_y;
1175
 
1176
	mouse_x *= sensitivity.value;
1177
	mouse_y *= sensitivity.value;
1178
 
1179
	if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
1180
		cmd->sidemove += m_side.value * mouse_x;
1181
	else
1182
		cl.viewangles[YAW] -= m_yaw.value * mouse_x;
1183
	if (in_mlook.state & 1)
1184
		V_StopPitchDrift ();
1185
 
1186
	if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) {
1187
		cl.viewangles[PITCH] += m_pitch.value * mouse_y;
1188
		if (cl.viewangles[PITCH] > 80)
1189
			cl.viewangles[PITCH] = 80;
1190
		if (cl.viewangles[PITCH] < -70)
1191
			cl.viewangles[PITCH] = -70;
1192
	} else {
1193
		if ((in_strafe.state & 1) && noclip_anglehack)
1194
			cmd->upmove -= m_forward.value * mouse_y;
1195
		else
1196
			cmd->forwardmove -= m_forward.value * mouse_y;
1197
	}
1198
	mouse_x = mouse_y = 0.0;
1199
}