Home | History | Annotate | Download | only in WinQuake
      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_sunxil.c -- uses X to setup windows and XIL to copy images (scaled as needed)
     21 // 		   to screen
     22 
     23 #define _BSD
     24 #define BYTE_DEFINED 1
     25 
     26 #include <sys/time.h>
     27 #include <sys/types.h>
     28 #include <errno.h>
     29 #include <thread.h>
     30 #include <unistd.h>
     31 #include <signal.h>
     32 #include <stdlib.h>
     33 #include <stdio.h>
     34 #include <string.h>
     35 #include <sys/ipc.h>
     36 #include <sys/shm.h>
     37 #include <X11/Xlib.h>
     38 #include <X11/Xutil.h>
     39 #include <X11/Xatom.h>
     40 #include <X11/keysym.h>
     41 #include <xil/xil.h>
     42 
     43 #include "quakedef.h"
     44 #include "d_local.h"
     45 
     46 #define MIN_WIDTH 320
     47 #define MIN_HEIGHT 200
     48 
     49 cvar_t		_windowed_mouse = {"_windowed_mouse","0", true};
     50 cvar_t		m_filter = {"m_filter","0", true};
     51 float old_windowed_mouse;
     52 
     53 // The following X property format is defined in Motif 1.1's
     54 // Xm/MwmUtils.h, but QUAKE should not depend on that header
     55 // file. Note: Motif 1.2 expanded this structure with
     56 // uninteresting fields (to QUAKE) so just stick with the
     57 // smaller Motif 1.1 structure.
     58 
     59 #define MWM_HINTS_DECORATIONS   2
     60 typedef struct
     61 {
     62 	long flags;
     63 	long functions;
     64 	long decorations;
     65 	long input_mode;
     66 } MotifWmHints;
     67 
     68 #define MAX_COLUMN_SIZE	11
     69 
     70 #define MAX_MODEDESCS	(MAX_COLUMN_SIZE*3)
     71 
     72 typedef struct
     73 {
     74     int		modenum;
     75     int		iscur;
     76     char	desc[256];
     77 } modedesc_t;
     78 
     79 extern void M_Menu_Options_f (void);
     80 extern void M_Print (int cx, int cy, char *str);
     81 extern void M_PrintWhite (int cx, int cy, char *str);
     82 extern void M_DrawCharacter (int cx, int line, int num);
     83 extern void M_DrawTransPic (int x, int y, qpic_t *pic);
     84 extern void M_DrawPic (int x, int y, qpic_t *pic);
     85 
     86 extern int sb_updates;
     87 
     88 qboolean        mouse_avail;
     89 int             mouse_buttons=3;
     90 int             mouse_oldbuttonstate;
     91 int             mouse_buttonstate;
     92 float   mouse_x, mouse_y;
     93 float   old_mouse_x, old_mouse_y;
     94 int p_mouse_x;
     95 int p_mouse_y;
     96 
     97 typedef struct
     98 {
     99 	int input;
    100 	int output;
    101 } keymap_t;
    102 
    103 viddef_t vid; // global video state
    104 unsigned short       d_8to16table[256];
    105 
    106 int		num_shades=32;
    107 
    108 int	d_con_indirect = 0;
    109 
    110 int		vid_buffersize;
    111 
    112 #define STD_EVENT_MASK \
    113 ( \
    114 	StructureNotifyMask | \
    115 	KeyPressMask | \
    116 	KeyReleaseMask | \
    117 	ButtonPressMask | \
    118 	ButtonReleaseMask | \
    119 	ExposureMask | \
    120 	PointerMotionMask | \
    121 	FocusChangeMask \
    122 )
    123 
    124 int		VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar;
    125 byte	*VGA_pagebase;
    126 
    127 qboolean			x_fullscreen = true;
    128 Display				*x_disp = NULL;
    129 int				x_screen, x_screen_width, x_screen_height;
    130 int				x_center_width, x_center_height;
    131 int				x_std_event_mask = STD_EVENT_MASK;
    132 Window				x_win, x_root_win;
    133 qboolean			x_focus = true;
    134 int				global_dx, global_dy;
    135 
    136 
    137 static Colormap			x_cmap;
    138 static GC			x_gc;
    139 static Visual			*x_vis;
    140 static XVisualInfo		*x_visinfo;
    141 static Atom			aHints = NULL;
    142 static Atom			aWMDelete = NULL;
    143 
    144 static qboolean			oktodraw = false;
    145 static qboolean			X11_active = false;
    146 
    147 
    148 static int verbose=1;
    149 
    150 static byte current_palette[768];
    151 
    152 cvar_t pixel_multiply = {"pixel_multiply", "2", true};
    153 int current_pixel_multiply = 2;
    154 
    155 #define PM(a) (int)((current_pixel_multiply)?((a)*current_pixel_multiply):(a))
    156 #define MP(a) (int)((current_pixel_multiply)?((a)/current_pixel_multiply):(a))
    157 
    158 static int 				render_pipeline[2];
    159 static XilSystemState 			state;
    160 static XilImage				display_image  = NULL;
    161 static XilImage				quake_image  = NULL;
    162 static int				use_mt = 0;
    163 static int				count_frames = 0;
    164 
    165 /*
    166 ================
    167 D_BeginDirectRect
    168 ================
    169 */
    170 void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
    171 {
    172 // direct drawing of the "accessing disk" icon isn't supported under Nextstep
    173 }
    174 
    175 
    176 /*
    177 ================
    178 D_EndDirectRect
    179 ================
    180 */
    181 void D_EndDirectRect (int x, int y, int width, int height)
    182 {
    183 // direct drawing of the "accessing disk" icon isnt supported under Nextstep
    184 }
    185 
    186 
    187 /*
    188 =================
    189 VID_Gamma_f
    190 
    191 Keybinding command
    192 =================
    193 */
    194 
    195 byte vid_gamma[256];
    196 
    197 void VID_Gamma_f (void)
    198 {
    199 
    200 	float	g, f, inf;
    201 	int		i;
    202 
    203 	if (Cmd_Argc () == 2) {
    204 		g = Q_atof (Cmd_Argv(1));
    205 
    206 		for (i=0 ; i<255 ; i++)	{
    207 			f = pow ((i+1)/256.0, g);
    208 			inf = f*255 + 0.5;
    209 			if (inf < 0)
    210 				inf = 0;
    211 			if (inf > 255)
    212 				inf = 255;
    213 			vid_gamma[i] = inf;
    214 		}
    215 
    216 		VID_SetPalette (current_palette);
    217 
    218 		vid.recalc_refdef = 1;				// force a surface cache flush
    219 	}
    220 
    221 }
    222 
    223 qboolean CheckPixelMultiply (void)
    224 {
    225 	int m;
    226 	int w, h;
    227 	XWindowAttributes wattr;
    228 	XWindowChanges chg;
    229 	unsigned int value_mask;
    230 	int old_pixel;
    231 
    232 	if ((m = (int)pixel_multiply.value) != current_pixel_multiply) {
    233 		if (m < 1)
    234 			m = 1;
    235 		if (m > 4)
    236 			m = 4;
    237 
    238 		old_pixel = current_pixel_multiply;
    239 		current_pixel_multiply = m;
    240 		Cvar_SetValue("pixel_multiply", m);
    241 
    242 		if(XGetWindowAttributes(x_disp, x_win, & wattr) == 0)
    243 			return true; // ???
    244 
    245 		memset(&chg, 0, sizeof(chg));
    246 		chg.width = wattr.width/old_pixel * current_pixel_multiply;
    247 		chg.height = wattr.height/old_pixel * current_pixel_multiply;
    248 
    249 		if (chg.width < MIN_WIDTH*current_pixel_multiply)
    250 			chg.width = MIN_WIDTH*current_pixel_multiply;
    251 		if (chg.height < MIN_HEIGHT*current_pixel_multiply)
    252 			chg.height = MIN_HEIGHT*current_pixel_multiply;
    253 
    254 		XConfigureWindow(x_disp, x_win, CWWidth | CWHeight, &chg);
    255 
    256 		vid.width = MP(wattr.width) & ~3;
    257 		vid.height = MP(wattr.height);
    258 
    259 		if (vid.width < 320)
    260 			vid.width = 320;
    261 		if (vid.height < 200)
    262 			vid.height = 200;
    263 		VID_ResetFramebuffer();
    264 
    265 		return true;
    266 	}
    267 	return false;
    268 }
    269 
    270 // ========================================================================
    271 // Tragic death handler
    272 // ========================================================================
    273 
    274 void TragicDeath(int signal_num)
    275 {
    276 	//XAutoRepeatOn(x_disp);
    277 	XCloseDisplay(x_disp);
    278 	Sys_Error("This death brought to you by the number %d\n", signal_num);
    279 }
    280 
    281 // ========================================================================
    282 // makes a null cursor
    283 // ========================================================================
    284 
    285 static Cursor CreateNullCursor(Display *display, Window root)
    286 {
    287 	Pixmap cursormask;
    288 	XGCValues xgc;
    289 	GC gc;
    290 	XColor dummycolour;
    291 	Cursor cursor;
    292 
    293 	cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
    294 	xgc.function = GXclear;
    295 	gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
    296 	XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
    297 	dummycolour.pixel = 0;
    298 	dummycolour.red = 0;
    299 	dummycolour.flags = 04;
    300 	cursor = XCreatePixmapCursor(display, cursormask, cursormask,
    301 				     &dummycolour,&dummycolour, 0,0);
    302 	XFreePixmap(display,cursormask);
    303 	XFreeGC(display,gc);
    304 	return cursor;
    305 }
    306 
    307 
    308 void VID_MenuDraw( void )
    309 {
    310 	qpic_t		*p;
    311     char		*ptr;
    312     int			i, j, column, row, dup;
    313     char		temp[100];
    314 
    315     p = Draw_CachePic ("gfx/vidmodes.lmp");
    316     M_DrawPic ( (320-p->width)/2, 4, p);
    317 	M_Print (4*8, 36 + MAX_COLUMN_SIZE * 8 + 8, "Video mode switching unavailable");
    318 	M_Print (9*8, 36 + MAX_COLUMN_SIZE * 8 + 8*6, "Press any key...");
    319 }
    320 
    321 void VID_MenuKey( int key ) { M_Menu_Options_f (); }
    322 
    323 // Called at startup to set up translation tables, takes 256 8 bit RGB values
    324 // the palette data will go away after the call, so it must be copied off if
    325 // the video driver will need it again
    326 
    327 byte	surfcache[1024*1024];
    328 
    329 //
    330 // VID_SetWindowTitle - set the window and icon titles
    331 //
    332 
    333 void VID_SetWindowTitle( Window win, char *pszName )
    334 {
    335 	XTextProperty	textprop;
    336 	XWMHints		*wmHints;
    337 
    338     // Setup ICCCM properties
    339     textprop.value = (unsigned char *)pszName;
    340     textprop.encoding = XA_STRING;
    341     textprop.format = 8;
    342     textprop.nitems = strlen(pszName);
    343     wmHints = XAllocWMHints();
    344     wmHints->initial_state = NormalState;
    345     wmHints->flags = StateHint;
    346     XSetWMProperties( x_disp, win, &textprop, &textprop,
    347 					  // Only put WM_COMMAND property on first window.
    348 					  com_argv, com_argc, NULL, NULL, NULL );
    349     XFree( wmHints );
    350 
    351     aWMDelete = XInternAtom( x_disp, "WM_DELETE_WINDOW", False );
    352     XSetWMProtocols( x_disp, win, &aWMDelete, 1 );
    353 }
    354 
    355 //
    356 // VID_FullScreen - open the window in full screen mode
    357 //
    358 
    359 qboolean VID_FullScreen( Window win )
    360 {
    361 	MotifWmHints    hints;
    362 	XWindowChanges  changes;
    363 
    364 	aHints = XInternAtom( x_disp, "_MOTIF_WM_HINTS", 0 );
    365 	if (aHints == None) {
    366 		Con_Printf( "Could not intern X atom for _MOTIF_WM_HINTS." );
    367 		return( false );
    368     }
    369 
    370 	hints.flags = MWM_HINTS_DECORATIONS;
    371 	hints.decorations = 0; // Absolutely no decorations.
    372 	XChangeProperty( x_disp, win, aHints, aHints, 32, PropModeReplace, (unsigned char *)&hints, 4 );
    373 
    374 	changes.x = 0;
    375 	changes.y = 0;
    376 	changes.width = x_screen_width;
    377 	changes.height = x_screen_height;
    378 	changes.stack_mode = TopIf;
    379 	XConfigureWindow( x_disp, win, CWX | CWY | CWWidth | CWHeight | CWStackMode, &changes);
    380 	return( true );
    381 }
    382 
    383 void	VID_Init (unsigned char *palette)
    384 {
    385 
    386 	int pnum, i;
    387 	XVisualInfo template;
    388 	int num_visuals;
    389 	int template_mask;
    390 	int w, h;
    391 
    392 	int desired_width=320, desired_height=200;
    393 
    394 	Cmd_AddCommand ("gamma", VID_Gamma_f);
    395 
    396 	Cvar_RegisterVariable (&pixel_multiply);
    397 
    398 	if (pipe(render_pipeline) < 0)
    399 		Sys_Error("VID_Init: pipe");
    400 
    401 	for (i=0 ; i<256 ; i++)
    402 		vid_gamma[i] = i;
    403 
    404 	vid.width = 320;
    405 	vid.height = 200;
    406 	vid.aspect = 1.0;
    407 	vid.numpages = 2;
    408 	vid.colormap = host_colormap;
    409 	vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
    410 	//vid.cbits = VID_CBITS;
    411 	//vid.grades = VID_GRADES;
    412 
    413 	srandom(getpid());
    414 
    415 	verbose = COM_CheckParm("-verbose");
    416 	count_frames = COM_CheckParm("-count_frames");
    417 
    418 //
    419 // open the display
    420 //
    421 	x_disp = XOpenDisplay(0);
    422 
    423 	if (!x_disp) {
    424 		if (getenv("DISPLAY"))
    425 			Sys_Error("VID: Could not open display [%s]\n",
    426 				getenv("DISPLAY"));
    427 		else
    428 			Sys_Error("VID: Could not open local display\n");
    429 	}
    430 
    431 	x_screen = DefaultScreen( x_disp );
    432 	x_screen_width = WidthOfScreen( ScreenOfDisplay( x_disp, x_screen ) );
    433 	x_screen_height = HeightOfScreen( ScreenOfDisplay( x_disp, x_screen ) );
    434 
    435 	x_center_width  = x_screen_width/2;
    436 
    437 	x_center_height = x_screen_height/2;
    438 
    439 	Con_Printf( "Using screen %d: %dx%d\n", x_screen, x_screen_width, x_screen_height );
    440 
    441 	x_root_win = DefaultRootWindow( x_disp);
    442 
    443 	//XAutoRepeatOff(x_disp);
    444 
    445 // for debugging only
    446 	if (verbose)
    447 		XSynchronize(x_disp, True);
    448 
    449 //
    450 // check for command-line window size
    451 //
    452 	if ((pnum=COM_CheckParm("-winsize"))) {
    453 		if (pnum >= com_argc-2)
    454 			Sys_Error("VID: -winsize <width> <height>\n");
    455 		desired_width = Q_atoi(com_argv[pnum+1]);
    456 		desired_height = Q_atoi(com_argv[pnum+2]);
    457 		if (desired_width < 1 || desired_height < 1)
    458 			Sys_Error("VID: Bad window width/height\n");
    459 	}
    460 
    461 	template_mask = VisualScreenMask; // make sure we get the right one
    462 	template.screen = x_screen;
    463 //
    464 // specify a visual id
    465 //
    466 	if ((pnum=COM_CheckParm("-visualid"))) {
    467 		if (pnum >= com_argc-1)
    468 			Sys_Error("VID: -visualid <id#>\n");
    469 		template.visualid = Q_atoi(com_argv[pnum+1]);
    470 		template_mask |= VisualIDMask;
    471 	} else	{
    472 		// If not specified, find an 8 bit visual since others don't work
    473 //		template.depth = 8;
    474 //		template_mask |= VisualDepthMask;
    475 		int screen;
    476 		screen = XDefaultScreen(x_disp);
    477 		template.visualid =
    478 			XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
    479 		template_mask = VisualIDMask;
    480 	}
    481 //
    482 // pick a visual- warn if more than one was available
    483 //
    484 	x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals);
    485 	if (num_visuals > 1) {
    486 		printf("Found more than one visual id at depth %d:\n", template.depth);
    487 		for (i=0 ; i<num_visuals ; i++)
    488 			printf("	-visualid %d\n", (int)(x_visinfo[i].visualid));
    489 	}
    490 	else if (num_visuals == 0) {
    491 		if (template_mask == VisualIDMask)
    492 			Sys_Error("VID: Bad visual id %d\n", template.visualid);
    493 		else
    494 			Sys_Error("VID: No visuals at depth %d\n", template.depth);
    495 	}
    496 
    497 	if (verbose) {
    498 		printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
    499 		printf("	screen %d\n", x_visinfo->screen);
    500 		printf("	red_mask 0x%x\n", (int)(x_visinfo->red_mask));
    501 		printf("	green_mask 0x%x\n", (int)(x_visinfo->green_mask));
    502 		printf("	blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
    503 		printf("	colormap_size %d\n", x_visinfo->colormap_size);
    504 		printf("	bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
    505 	}
    506 
    507 	x_vis = x_visinfo->visual;
    508 //
    509 // See if we're going to do pixel multiply
    510 //
    511 	if (pixel_multiply.value < 1 || pixel_multiply.value > 4)
    512 		Cvar_SetValue("pixel_multiply", 2);
    513 	current_pixel_multiply = pixel_multiply.value;
    514 
    515 	w = 320*current_pixel_multiply; // minimum width
    516 	h = 200*current_pixel_multiply; // minimum height
    517 	if (desired_width < w)
    518 		desired_width = w;
    519 	if (desired_height < h)
    520 		desired_height = h;
    521 
    522 	vid.width = MP(desired_width);
    523 	vid.height = MP(desired_height);
    524 
    525 	//
    526 	// patch things up so game doesn't fail if window is too small
    527 	//
    528 
    529 	if (vid.width < 320)
    530 		vid.width = 320;
    531 	if (vid.height < 200)
    532 		vid.height = 200;
    533 
    534 //
    535 // see if we're going to use threads
    536 //
    537 	if(((sysconf(_SC_NPROCESSORS_ONLN) > 1) || COM_CheckParm("-mt")) &&
    538 		(COM_CheckParm("-no_mt") == 0)) {
    539 		use_mt = 1;
    540 		printf("VID: Using multiple threads!\n");
    541 	}
    542 
    543 // setup attributes for main window
    544 	{
    545 		int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
    546 		XSetWindowAttributes attribs;
    547 		Colormap tmpcmap;
    548 
    549 		tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
    550 			x_visinfo->screen), x_vis, AllocNone);
    551 
    552 		attribs.event_mask = x_std_event_mask;
    553 		attribs.border_pixel = 0;
    554 		attribs.colormap = tmpcmap;
    555 
    556 // create the main window
    557 		x_win = XCreateWindow(	x_disp,
    558 			XRootWindow(x_disp, x_visinfo->screen),
    559 			0, 0,	// x, y
    560 			desired_width, desired_height,
    561 			0, // borderwidth
    562 			x_visinfo->depth,
    563 			InputOutput,
    564 			x_vis,
    565 			attribmask,
    566 			&attribs );
    567 
    568 		if (x_visinfo->class != TrueColor)
    569 			XFreeColormap(x_disp, tmpcmap);
    570 
    571 	}
    572 
    573 	if (x_visinfo->depth == 8) {
    574 
    575 	// create and upload the palette
    576 		if (x_visinfo->class == PseudoColor) {
    577 			x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
    578 			VID_SetPalette(palette);
    579 			XSetWindowColormap(x_disp, x_win, x_cmap);
    580 		}
    581 
    582 	}
    583 
    584 	VID_SetWindowTitle( x_win, "Quake" );
    585 
    586 // inviso cursor
    587 	XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
    588 
    589 // create the GC
    590 	{
    591 		XGCValues xgcvalues;
    592 		int valuemask = GCGraphicsExposures;
    593 		xgcvalues.graphics_exposures = False;
    594 		x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
    595 	}
    596 
    597 // map the window
    598 	XMapWindow(x_disp, x_win);
    599 	XSync(x_disp, True) ;        /* wait for map */
    600 //
    601 // wait for first exposure event
    602 //
    603 	{
    604 		XEvent event;
    605 		do{
    606 			XNextEvent(x_disp, &event);
    607 			if (event.type == Expose && !event.xexpose.count)
    608 				oktodraw = true;
    609 		} while (!oktodraw);
    610 	}
    611 //
    612 // initialize XIL
    613 //
    614 
    615 	state = xil_open();
    616 
    617 	if(state == NULL) {
    618 		//
    619 		//  XIL's default error handler will print an error msg on stderr
    620 		//
    621 		Sys_Error("xil_open failed\n");
    622 	}
    623 
    624 	X11_active = true;
    625 
    626 	VID_ResetFramebuffer();
    627 
    628 	D_InitCaches (surfcache, sizeof(surfcache));
    629 
    630 	vid_menudrawfn = VID_MenuDraw;
    631 	vid_menukeyfn = VID_MenuKey;
    632 }
    633 
    634 VID_ResetFramebuffer()
    635 {
    636 	XilMemoryStorage storage;
    637 
    638 	if (use_mt) {
    639 		VID_ResetFramebuffer_MT();
    640 		return;
    641 	}
    642 
    643 //printf("VID_ResetFramebuffer: vid.width %d, vid.height %d\n", vid.width, vid.height);
    644 
    645 	xil_destroy(display_image);
    646 
    647 	xil_destroy(quake_image);
    648 
    649 	display_image = xil_create_from_window(state, x_disp, x_win);
    650 	quake_image = xil_create(state, vid.width, vid.height, 1, XIL_BYTE);
    651 
    652 	xil_export(quake_image);
    653 
    654 	if (xil_get_memory_storage(quake_image, &storage) == FALSE)
    655 		Sys_Error("xil_get_memory_storage");
    656 
    657 	xil_import(quake_image, TRUE);
    658 	xil_export(quake_image);
    659 
    660 	if (xil_get_memory_storage(quake_image, &storage) == FALSE)
    661 		Sys_Error("xil_get_memory_storage");
    662 
    663 	vid.rowbytes = storage.byte.scanline_stride;
    664 	vid.buffer =   storage.byte.data;
    665 	vid.conbuffer = vid.buffer;
    666 	vid.conrowbytes = vid.rowbytes;
    667 	vid.conwidth = vid.width;
    668 	vid.conheight = vid.height;
    669 
    670 	vid.maxwarpwidth = WARP_WIDTH;
    671 	vid.maxwarpheight = WARP_HEIGHT;
    672 	vid.recalc_refdef = 1;				// force a surface cache flush
    673 
    674 	free(d_pzbuffer);
    675 
    676 	d_pzbuffer = malloc(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer));
    677         //Hunk_HighAllocName(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer),"zbuff");
    678 }
    679 
    680 VID_ResetFramebuffer_MT()
    681 {
    682 	XilMemoryStorage storage;
    683 	XilImage drain_renderpipeline();
    684 	XilImage old_display_image;
    685 
    686 	void * update_thread();
    687 
    688 	printf("VID_ResetFramebuffer: vid.width %d, vid.height %d\n", vid.width, vid.height);
    689 
    690 	old_display_image = display_image;
    691 
    692 	display_image = xil_create_from_window(state, x_disp, x_win);
    693 
    694 	if (quake_image == NULL)
    695 		if (thr_create(NULL, NULL, update_thread, NULL, THR_NEW_LWP, NULL) != 0)
    696 			Sys_Error("VID: thr_create");
    697 
    698 	quake_image = drain_renderpipeline(quake_image);
    699 
    700 	xil_destroy(old_display_image);
    701 
    702 	free(d_pzbuffer);
    703 
    704 	d_pzbuffer = malloc(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer));
    705 }
    706 
    707 void VID_ShiftPalette(unsigned char *p)
    708 {
    709 	VID_SetPalette(p);
    710 }
    711 
    712 void VID_SetPalette(unsigned char *palette)
    713 {
    714 
    715 	int i;
    716 	XColor colors[256];
    717 
    718 	if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) {
    719 			if (palette != current_palette)
    720 				memcpy(current_palette, palette, 768);
    721 			for (i=0 ; i<256 ; i++)
    722 				{
    723 					colors[i].pixel = i;
    724 					colors[i].flags = DoRed|DoGreen|DoBlue;
    725 					colors[i].red = vid_gamma[palette[i*3]] * 257;
    726 					colors[i].green = vid_gamma[palette[i*3+1]] * 257;
    727 					colors[i].blue = vid_gamma[palette[i*3+2]] * 257;
    728 				}
    729 			XStoreColors(x_disp, x_cmap, colors, 256);
    730 		}
    731 
    732 }
    733 
    734 // Called at shutdown
    735 
    736 void	VID_Shutdown (void)
    737 {
    738 	X11_active = false;
    739 	Con_Printf("VID_Shutdown\n");
    740 	//XAutoRepeatOn(x_disp);
    741 	xil_destroy(display_image);
    742 	xil_destroy(quake_image);
    743 	display_image = NULL;
    744 	quake_image = NULL;
    745 	XCloseDisplay(x_disp);
    746 }
    747 
    748 int XLateKey(XKeyEvent *ev)
    749 {
    750 
    751 	int key;
    752 	char buf[64];
    753 	KeySym keysym;
    754 
    755 	XLookupString(ev, buf, sizeof buf, &keysym, 0);
    756 
    757 	switch(keysym) {
    758 		case XK_Page_Up:	 key = K_PGUP; break;
    759 		case XK_Page_Down:	 key = K_PGDN; break;
    760 		case XK_Home:	 key = K_HOME; break;
    761 		case XK_End:	 key = K_END; break;
    762 		case XK_Left:	 key = K_LEFTARROW; break;
    763 		case XK_Right:	key = K_RIGHTARROW;		break;
    764 		case XK_Down:	 key = K_DOWNARROW; break;
    765 		case XK_Up:		 key = K_UPARROW;	 break;
    766 		case XK_Escape: key = K_ESCAPE;		break;
    767 		case XK_Return: key = K_ENTER;		 break;
    768 		case XK_Tab:		key = K_TAB;			 break;
    769 		case XK_Help:
    770 		case XK_F1:		 key = K_F1;				break;
    771 		case XK_F2:		 key = K_F2;				break;
    772 		case XK_F3:		 key = K_F3;				break;
    773 		case XK_F4:		 key = K_F4;				break;
    774 		case XK_F5:		 key = K_F5;				break;
    775 		case XK_F6:		 key = K_F6;				break;
    776 		case XK_F7:		 key = K_F7;				break;
    777 		case XK_F8:		 key = K_F8;				break;
    778 		case XK_F9:		 key = K_F9;				break;
    779 		case XK_F10:		key = K_F10;			 break;
    780 		case XK_F11:		key = K_F11;			 break;
    781 		case XK_F12:		key = K_F12;			 break;
    782 		case XK_BackSpace:
    783 		case XK_Delete: key = K_BACKSPACE; break;
    784 		case XK_Pause:	key = K_PAUSE;		 break;
    785 		case XK_Shift_L:
    786 		case XK_Shift_R:		key = K_SHIFT;		break;
    787 		case XK_Control_L:
    788 		case XK_Control_R:	key = K_CTRL;		 break;
    789 		case XK_Alt_L:
    790 		case XK_Meta_L:
    791 		case XK_Alt_R:
    792 		case XK_Meta_R: key = K_ALT;			break;
    793 			// various other keys on the keyboard
    794 				   case XK_F27: key = K_HOME; break;
    795 		case XK_F29: key = K_PGUP; break;
    796 		case XK_F33: key = K_END; break;
    797 		case XK_F35: key = K_PGDN; break;
    798 		case XK_Insert:
    799 		case XK_KP_Insert: key = K_INS; break;
    800 		case XK_F24: key = '-'; break;
    801 		case XK_KP_Add: key = '+'; break;
    802 		case XK_KP_Subtract: key = '-'; break;
    803 		case XK_F25: key = '/'; break;
    804 		case XK_F26: key = '*'; break;
    805 
    806 		default:
    807 			key = (unsigned char)*buf;
    808 			break;
    809 		}
    810 
    811 	return key;
    812 
    813 }
    814 
    815 struct {
    816 	int key;
    817 	int down;
    818 } keyq[64];
    819 
    820 int keyq_head=0;
    821 int keyq_tail=0;
    822 
    823 int config_notify=0;
    824 int config_notify_width;
    825 int config_notify_height;
    826 
    827 void GetEvent(void)
    828 {
    829 	XEvent x_event;
    830 	int b;
    831 
    832 	XNextEvent(x_disp, &x_event);
    833 	switch(x_event.type) {
    834 		case KeyPress:
    835 			Key_Event(XLateKey(&x_event.xkey), true);
    836 			break;
    837 		case KeyRelease:
    838 			Key_Event(XLateKey(&x_event.xkey), false);
    839 			break;
    840 
    841 		case MotionNotify:
    842 
    843 			if (_windowed_mouse.value) {
    844 				mouse_x = (float) ((int)x_event.xmotion.x - (int)(vid.width/2));
    845 				mouse_y = (float) ((int)x_event.xmotion.y - (int)(vid.height/2));
    846 	//printf("m: x=%d,y=%d, mx=%3.2f,my=%3.2f\n",
    847 	//	x_event.xmotion.x, x_event.xmotion.y, mouse_x, mouse_y);
    848 
    849 				/* move the mouse to the window center again */
    850 				XSelectInput( x_disp, x_win, x_std_event_mask & ~PointerMotionMask );
    851 				XWarpPointer(x_disp,None,x_win,0,0,0,0,
    852 					(vid.width/2),(vid.height/2));
    853 				XSelectInput( x_disp, x_win, x_std_event_mask );
    854 			} else {
    855 				mouse_x = (float) (x_event.xmotion.x-p_mouse_x);
    856 				mouse_y = (float) (x_event.xmotion.y-p_mouse_y);
    857 				p_mouse_x=x_event.xmotion.x;
    858 				p_mouse_y=x_event.xmotion.y;
    859 			}
    860 			break;
    861 
    862 		case ButtonPress:
    863 			b=-1;
    864 			if (x_event.xbutton.button == 1)
    865 				b = 0;
    866 			else if (x_event.xbutton.button == 2)
    867 				b = 2;
    868 			else if (x_event.xbutton.button == 3)
    869 				b = 1;
    870 			if (b>=0)
    871 				mouse_buttonstate |= 1<<b;
    872 			break;
    873 
    874 		case ButtonRelease:
    875 			b=-1;
    876 			if (x_event.xbutton.button == 1)
    877 				b = 0;
    878 			else if (x_event.xbutton.button == 2)
    879 				b = 2;
    880 			else if (x_event.xbutton.button == 3)
    881 				b = 1;
    882 			if (b>=0)
    883 				mouse_buttonstate &= ~(1<<b);
    884 			break;
    885 
    886 		case ConfigureNotify:
    887 			//			printf("config notify\n");
    888 			config_notify_width = x_event.xconfigure.width;
    889 			config_notify_height = x_event.xconfigure.height;
    890 			config_notify = 1;
    891 			sb_updates = 0;
    892 			break;
    893 		case Expose:
    894 			sb_updates = 0;
    895 			break;
    896 		case ClientMessage:
    897 			if (x_event.xclient.data.l[0] == aWMDelete) Host_Quit_f();
    898 			break;
    899 #if 0
    900 		case FocusIn:
    901 			printf("FocusIn...\n");
    902 			x_focus = true;
    903 			break;
    904 		case FocusOut:
    905 			printf("FocusOut...\n");
    906 			x_focus = false;
    907 			break;
    908 #endif
    909 	}
    910 
    911 	if (old_windowed_mouse != _windowed_mouse.value) {
    912 		old_windowed_mouse = _windowed_mouse.value;
    913 
    914 		if (!_windowed_mouse.value) {
    915 			/* ungrab the pointer */
    916 			XUngrabPointer(x_disp,CurrentTime);
    917 		} else {
    918 			/* grab the pointer */
    919 			XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
    920 				GrabModeAsync,x_win,None,CurrentTime);
    921 		}
    922 	}
    923 }
    924 
    925 // flushes the given rectangles from the view buffer to the screen
    926 
    927 void
    928 VID_Update (vrect_t *rects)
    929 {
    930 	void VID_Update_MT(vrect_t *);
    931 
    932 
    933 	if (count_frames) {
    934 		static int count;
    935 		static long long s;
    936 		long long gethrtime();
    937 
    938 		if (count == 0)
    939 			s = gethrtime();
    940 
    941 		if (count++ == 200) {
    942 			long long n = gethrtime();
    943 			count = 1;
    944 			printf("%lf frames/secs\n", 200.0/((double)(n-s) / 1e9));
    945 			s = n;
    946 		}
    947 	}
    948 
    949 	if (use_mt) {
    950 		VID_Update_MT(rects);
    951 		return;
    952 	}
    953 
    954 	// if the window changes dimension, skip this frame
    955 
    956 	if (config_notify) {
    957 		int w, h;
    958 		XWindowChanges chg;
    959 		unsigned int value_mask;
    960 
    961 		w = 320*current_pixel_multiply; // minimum width
    962 		h = 200*current_pixel_multiply; // minimum height
    963 
    964 		if (config_notify_width < w || config_notify_height < h) {
    965 			// We must resize the window
    966 			memset(&chg, 0, sizeof(chg));
    967 			value_mask = 0;
    968 			if (config_notify_width < w) {
    969 				config_notify_width = chg.width = w;
    970 				value_mask |= CWWidth;
    971 			}
    972 			if (config_notify_height < h) {
    973 				config_notify_height = chg.height = h;
    974 				value_mask |= CWHeight;
    975 			}
    976 			if (value_mask)
    977 				XConfigureWindow(x_disp, x_win, value_mask, &chg);
    978 		}
    979 
    980 		config_notify = 0;
    981 
    982 		vid.width = MP(config_notify_width) & ~3;
    983 		vid.height = MP(config_notify_height);
    984 
    985 		if (vid.width < 320)
    986 			vid.width = 320;
    987 		if (vid.height < 200)
    988 			vid.height = 200;
    989 
    990 		VID_ResetFramebuffer();
    991 
    992 		return;
    993 	}
    994 	// if pixel multiply changed, skip this frame
    995 	if (CheckPixelMultiply())
    996 		return;
    997 
    998 	while (rects) { // I've never seen more than one rect?
    999 		XilMemoryStorage storage;
   1000 
   1001 		xil_import(quake_image, TRUE); // let xil control the image
   1002 
   1003 		if (current_pixel_multiply < 2)
   1004 			xil_copy(quake_image, display_image);
   1005 		else
   1006 			xil_scale(quake_image, display_image, "nearest",
   1007 				  (float)current_pixel_multiply, (float)current_pixel_multiply);
   1008 
   1009 		xil_export(quake_image);  // back to quake
   1010 
   1011 		if (xil_get_memory_storage(quake_image, &storage) == FALSE)
   1012 			Sys_Error("xil_get_memory_storage");
   1013 
   1014 		vid.buffer =   storage.byte.data;
   1015 		vid.conbuffer = vid.buffer;
   1016 
   1017 		rects = rects->pnext;
   1018 	}
   1019 }
   1020 
   1021 void
   1022 VID_Update_MT (vrect_t *rects)
   1023 {
   1024 	XilImage sched_update();
   1025 
   1026 	// if the window changes dimension, skip this frame
   1027 
   1028 	if (config_notify) {
   1029 		int w, h;
   1030 		XWindowChanges chg;
   1031 		unsigned int value_mask;
   1032 
   1033 		w = 320*current_pixel_multiply; // minimum width
   1034 		h = 200*current_pixel_multiply; // minimum height
   1035 
   1036 		if (config_notify_width < w || config_notify_height < h) {
   1037 			// We must resize the window
   1038 			memset(&chg, 0, sizeof(chg));
   1039 			value_mask = 0;
   1040 			if (config_notify_width < w) {
   1041 				config_notify_width = chg.width = w;
   1042 				value_mask |= CWWidth;
   1043 			}
   1044 			if (config_notify_height < h) {
   1045 				config_notify_height = chg.height = h;
   1046 				value_mask |= CWHeight;
   1047 			}
   1048 			if (value_mask)
   1049 				XConfigureWindow(x_disp, x_win, value_mask, &chg);
   1050 		}
   1051 
   1052 		config_notify = 0;
   1053 
   1054 		vid.width = MP(config_notify_width) & ~3;
   1055 		vid.height = MP(config_notify_height);
   1056 
   1057 		if (vid.width < 320)
   1058 			vid.width = 320;
   1059 		if (vid.height < 200)
   1060 			vid.height = 200;
   1061 
   1062 		VID_ResetFramebuffer_MT();
   1063 
   1064 		return;
   1065 	}
   1066 	// if pixel multiply changed, skip this frame
   1067 	if (CheckPixelMultiply())
   1068 		return;
   1069 
   1070 	quake_image = sched_update(quake_image);
   1071 }
   1072 
   1073 XilImage
   1074 drain_renderpipeline(XilImage old)
   1075 {
   1076 	XilImage new;
   1077 
   1078 	XilMemoryStorage storage;
   1079 
   1080 	if (old)
   1081 		if (read(render_pipeline[1], &new, sizeof(new)) != sizeof (new)) {
   1082 			Sys_Error("drain_renderpipeline: read");
   1083 			xil_destroy(new);
   1084 		}
   1085 
   1086 	xil_destroy(old);
   1087 
   1088 
   1089 	new = xil_create(state, vid.width, vid.height, 1, XIL_BYTE);
   1090 
   1091 	if (write(render_pipeline[0], &new, sizeof (new)) != sizeof(new))
   1092 		Sys_Error("drain_renderpipeline: write");
   1093 
   1094 	new = xil_create(state, vid.width, vid.height, 1, XIL_BYTE);
   1095 
   1096 	xil_export(new);
   1097 
   1098 	if (xil_get_memory_storage(new, &storage) == FALSE)
   1099 		Sys_Error("xil_get_memory_storage");
   1100 
   1101 	vid.rowbytes = storage.byte.scanline_stride;
   1102 	vid.buffer =   storage.byte.data;
   1103 	vid.conbuffer = vid.buffer;
   1104 	vid.conrowbytes = vid.rowbytes;
   1105 	vid.conwidth = vid.width;
   1106 	vid.conheight = vid.height;
   1107 
   1108 	vid.maxwarpwidth = WARP_WIDTH;
   1109 	vid.maxwarpheight = WARP_HEIGHT;
   1110 	vid.recalc_refdef = 1;				// force a surface cache flush
   1111 
   1112 	return(new);
   1113 
   1114 }
   1115 
   1116 XilImage
   1117 sched_update(XilImage image)
   1118 {
   1119 	XilImage new;
   1120 	XilMemoryStorage storage;
   1121 
   1122 	if (write(render_pipeline[1], &image, sizeof(image)) != sizeof (image))
   1123 		Sys_Error("sched_update:write");
   1124 
   1125 	if (read(render_pipeline[1], &new, sizeof(new)) != sizeof (new))
   1126 		Sys_Error("sched_update:read");
   1127 
   1128 	xil_export(new);
   1129 
   1130 	if (xil_get_memory_storage(new, &storage) == FALSE)
   1131 		Sys_Error("xil_get_memory_storage");
   1132 
   1133 	vid.buffer =   storage.byte.data;
   1134 	vid.conbuffer = vid.buffer;
   1135 
   1136 	return (new);
   1137 }
   1138 
   1139 void *update_thread()
   1140 {
   1141 	XilImage image;
   1142 
   1143 	if (!X11_active)
   1144 		return;
   1145 
   1146 	while (read(render_pipeline[0], &image, sizeof (image)) == sizeof(image)) {
   1147 
   1148 		xil_import(image, TRUE); // let xil control the image
   1149 
   1150 		if (!display_image)
   1151 			return;
   1152 
   1153 		if (current_pixel_multiply < 2)
   1154 			xil_copy(image, display_image);
   1155 		else
   1156 			xil_scale(image, display_image, "nearest",
   1157 				  (float)current_pixel_multiply, (float)current_pixel_multiply);
   1158 
   1159 		if (write(render_pipeline[0], &image, sizeof (image)) != sizeof(image))
   1160 			Sys_Error("update_thread: write");
   1161 	}
   1162 }
   1163 
   1164 
   1165 static int dither;
   1166 
   1167 void VID_DitherOn(void)
   1168 {
   1169 	if (dither == 0) {
   1170 		vid.recalc_refdef = 1;
   1171 		dither = 1;
   1172 	}
   1173 }
   1174 
   1175 void VID_DitherOff(void)
   1176 {
   1177 	if (dither) {
   1178 		vid.recalc_refdef = 1;
   1179 		dither = 0;
   1180 	}
   1181 }
   1182 
   1183 void VID_SetDefaultMode( void )
   1184 {
   1185 }
   1186 
   1187 int I_OpenWindow(void)
   1188 {
   1189 	return 0;
   1190 }
   1191 
   1192 void I_EraseWindow(int window)
   1193 {
   1194 
   1195 }
   1196 
   1197 void I_DrawCircle(int window, int x, int y, int r)
   1198 {
   1199 }
   1200 
   1201 void I_DisplayWindow(int window)
   1202 {
   1203 }
   1204 
   1205 void Sys_SendKeyEvents(void)
   1206 {
   1207 	// get events from x server
   1208 		   if (x_disp) {
   1209 				   while (XPending(x_disp)) GetEvent();
   1210 				   while (keyq_head != keyq_tail) {
   1211 						   Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down);
   1212 						   keyq_tail = (keyq_tail + 1) & 63;
   1213 					   }
   1214 			   }
   1215 }
   1216 
   1217 void IN_Init (void)
   1218 {
   1219 	Cvar_RegisterVariable (&_windowed_mouse);
   1220 	Cvar_RegisterVariable (&m_filter);
   1221    if ( COM_CheckParm ("-nomouse") )
   1222      return;
   1223    mouse_x = mouse_y = 0.0;
   1224    mouse_avail = 1;
   1225 }
   1226 
   1227 void IN_Shutdown (void)
   1228 {
   1229    mouse_avail = 0;
   1230 }
   1231 
   1232 void IN_Commands (void)
   1233 {
   1234 	int i;
   1235 
   1236 	if (!mouse_avail) return;
   1237 
   1238 	for (i=0 ; i<mouse_buttons ; i++) {
   1239 		if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
   1240 			Key_Event (K_MOUSE1 + i, true);
   1241 
   1242 		if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
   1243 			Key_Event (K_MOUSE1 + i, false);
   1244 	}
   1245 	mouse_oldbuttonstate = mouse_buttonstate;
   1246 }
   1247 
   1248 void IN_Move (usercmd_t *cmd)
   1249 {
   1250 	if (!mouse_avail)
   1251 		return;
   1252 
   1253 	if (m_filter.value) {
   1254 		mouse_x = (mouse_x + old_mouse_x) * 0.5;
   1255 		mouse_y = (mouse_y + old_mouse_y) * 0.5;
   1256 	}
   1257 
   1258 	old_mouse_x = mouse_x;
   1259 	old_mouse_y = mouse_y;
   1260 
   1261 	mouse_x *= sensitivity.value;
   1262 	mouse_y *= sensitivity.value;
   1263 
   1264 	if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
   1265 		cmd->sidemove += m_side.value * mouse_x;
   1266 	else
   1267 		cl.viewangles[YAW] -= m_yaw.value * mouse_x;
   1268 	if (in_mlook.state & 1)
   1269 		V_StopPitchDrift ();
   1270 
   1271 	if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) {
   1272 		cl.viewangles[PITCH] += m_pitch.value * mouse_y;
   1273 		if (cl.viewangles[PITCH] > 80)
   1274 			cl.viewangles[PITCH] = 80;
   1275 		if (cl.viewangles[PITCH] < -70)
   1276 			cl.viewangles[PITCH] = -70;
   1277 	} else {
   1278 		if ((in_strafe.state & 1) && noclip_anglehack)
   1279 			cmd->upmove -= m_forward.value * mouse_y;
   1280 		else
   1281 			cmd->forwardmove -= m_forward.value * mouse_y;
   1282 	}
   1283 	mouse_x = mouse_y = 0.0;
   1284 }
   1285 
   1286 //void VID_UnlockBuffer(void) { }
   1287 //void VID_LockBuffer(void) { }
   1288 
   1289