Red and blue quake2

Chris Venter chris at dsp.sun.ac.za
Wed Jan 30 09:41:20 EST 2002


Hi all,

I saw this link <http://www.jfedor.org/red-blue-quake2/>
on www.linuxgames.com on Friday. It creates a stereo software renderer for 
those funky red and blue glasses.

jfedor modified the original id source, which I just manually 
applied to the r0.0.8 release, and created a patch (attached).
I have tested this patch on a clean r0.0.8 source tree and it compiles 
for me. If it doesn't want to patch/compile properly, please tell me.

Thanks for all the cool work guys, I have rediscovered quake2!

PS jfedor mentions he may still do an OpenGL renderer, which may speed 
things up. Any takers?

-- 
Chris Venter :: http://www.dsp.sun.ac.za/~chris
Two fish are in a tank. One says to the other, "I'll drive. You man the guns."
-------------- next part --------------
diff -ur quake2-r0.0.8/Makefile quake2-devel-r0.0.8/Makefile
--- quake2-r0.0.8/Makefile	Wed Jan  9 13:26:31 2002
+++ quake2-devel-r0.0.8/Makefile	Wed Jan 30 15:04:13 2002
@@ -14,7 +14,7 @@
 # game{i386,axp,ppc}.so is automatically built.
 BUILD_SDLQUAKE2=YES	# sdlquake2 executable (uses SDL for cdrom and sound)
 BUILD_SVGA=NO		# SVGAlib driver. Seems to work fine.
-BUILD_X11=NO		# X11 software driver. Works somewhat ok.
+BUILD_X11=YES		# X11 software driver. Works somewhat ok.
 BUILD_GLX=YES		# X11 GLX driver. Works somewhat ok.
 BUILD_FXGL=NO		# FXMesa driver. Not tested. (used only for V1 and V2).
 BUILD_SDL=YES		# SDL software driver. Works fine for some people.
Only in quake2-r0.0.8: Makefile~
Only in quake2-r0.0.8: README.r~
diff -ur quake2-r0.0.8/src/client/cl_scrn.c quake2-devel-r0.0.8/src/client/cl_scrn.c
--- quake2-r0.0.8/src/client/cl_scrn.c	Thu Jan  3 07:10:13 2002
+++ quake2-devel-r0.0.8/src/client/cl_scrn.c	Wed Jan 30 15:18:24 2002
@@ -1,1411 +1,1410 @@
-/*
-Copyright (C) 1997-2001 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-*/
-// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
-
-/*
-
-  full screen console
-  put up loading plaque
-  blanked background with loading plaque
-  blanked background with menu
-  cinematics
-  full screen image for quit and victory
-
-  end of unit intermissions
-
-  */
-
-#include "client.h"
-
-float		scr_con_current;	// aproaches scr_conlines at scr_conspeed
-float		scr_conlines;		// 0.0 to 1.0 lines of console to display
-
-qboolean	scr_initialized;		// ready to draw
-
-int			scr_draw_loading;
-
-vrect_t		scr_vrect;		// position of render window on screen
-
-
-cvar_t		*scr_viewsize;
-cvar_t		*scr_conspeed;
-cvar_t		*scr_centertime;
-cvar_t		*scr_showturtle;
-cvar_t		*scr_showpause;
-cvar_t		*scr_printspeed;
-
-cvar_t		*scr_netgraph;
-cvar_t		*scr_timegraph;
-cvar_t		*scr_debuggraph;
-cvar_t		*scr_graphheight;
-cvar_t		*scr_graphscale;
-cvar_t		*scr_graphshift;
-cvar_t		*scr_drawall;
-
-typedef struct
-{
-	int		x1, y1, x2, y2;
-} dirty_t;
-
-dirty_t		scr_dirty, scr_old_dirty[2];
-
-char		crosshair_pic[MAX_QPATH];
-int			crosshair_width, crosshair_height;
-
-extern cvar_t *cl_drawfps; // FPS hack
-
-void SCR_TimeRefresh_f (void);
-void SCR_Loading_f (void);
-
-
-/*
-===============================================================================
-
-BAR GRAPHS
-
-===============================================================================
-*/
-
-/*
-==============
-CL_AddNetgraph
-
-A new packet was just parsed
-==============
-*/
-void CL_AddNetgraph (void)
-{
-	int		i;
-	int		in;
-	int		ping;
-
-	// if using the debuggraph for something else, don't
-	// add the net lines
-	if (scr_debuggraph->value || scr_timegraph->value)
-		return;
-
-	for (i=0 ; i<cls.netchan.dropped ; i++)
-		SCR_DebugGraph (30, 0x40);
-
-	for (i=0 ; i<cl.surpressCount ; i++)
-		SCR_DebugGraph (30, 0xdf);
-
-	// see what the latency was on this packet
-	in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
-	ping = cls.realtime - cl.cmd_time[in];
-	ping /= 30;
-	if (ping > 30)
-		ping = 30;
-	SCR_DebugGraph (ping, 0xd0);
-}
-
-
-typedef struct
-{
-	float	value;
-	int		color;
-} graphsamp_t;
-
-static	int			current;
-static	graphsamp_t	values[1024];
-
-/*
-==============
-SCR_DebugGraph
-==============
-*/
-void SCR_DebugGraph (float value, int color)
-{
-	values[current&1023].value = value;
-	values[current&1023].color = color;
-	current++;
-}
-
-/*
-==============
-SCR_DrawDebugGraph
-==============
-*/
-void SCR_DrawDebugGraph (void)
-{
-	int		a, x, y, w, i, h;
-	float	v;
-	int		color;
-
-	//
-	// draw the graph
-	//
-	w = scr_vrect.width;
-
-	x = scr_vrect.x;
-	y = scr_vrect.y+scr_vrect.height;
-	re.DrawFill (x, y-scr_graphheight->value,
-		w, scr_graphheight->value, 8);
-
-	for (a=0 ; a<w ; a++)
-	{
-		i = (current-1-a+1024) & 1023;
-		v = values[i].value;
-		color = values[i].color;
-		v = v*scr_graphscale->value + scr_graphshift->value;
-		
-		if (v < 0)
-			v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
-		h = (int)v % (int)scr_graphheight->value;
-		re.DrawFill (x+w-1-a, y - h, 1,	h, color);
-	}
-}
-
-/*
-===============================================================================
-
-CENTER PRINTING
-
-===============================================================================
-*/
-
-char		scr_centerstring[1024];
-float		scr_centertime_start;	// for slow victory printing
-float		scr_centertime_off;
-int			scr_center_lines;
-int			scr_erase_center;
-
-/*
-==============
-SCR_CenterPrint
-
-Called for important messages that should stay in the center of the screen
-for a few moments
-==============
-*/
-void SCR_CenterPrint (char *str)
-{
-	char	*s;
-	char	line[64];
-	int		i, j, l;
-
-	strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
-	scr_centertime_off = scr_centertime->value;
-	scr_centertime_start = cl.time;
-
-	// count the number of lines for centering
-	scr_center_lines = 1;
-	s = str;
-	while (*s)
-	{
-		if (*s == '\n')
-			scr_center_lines++;
-		s++;
-	}
-
-	// echo it to the console
-	Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
-
-	s = str;
-	do	
-	{
-	// scan the width of the line
-		for (l=0 ; l<40 ; l++)
-			if (s[l] == '\n' || !s[l])
-				break;
-		for (i=0 ; i<(40-l)/2 ; i++)
-			line[i] = ' ';
-
-		for (j=0 ; j<l ; j++)
-		{
-			line[i++] = s[j];
-		}
-
-		line[i] = '\n';
-		line[i+1] = 0;
-
-		Com_Printf ("%s", line);
-
-		while (*s && *s != '\n')
-			s++;
-
-		if (!*s)
-			break;
-		s++;		// skip the \n
-	} while (1);
-	Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
-	Con_ClearNotify ();
-}
-
-
-void SCR_DrawCenterString (void)
-{
-	char	*start;
-	int		l;
-	int		j;
-	int		x, y;
-	int		remaining;
-
-// the finale prints the characters one at a time
-	remaining = 9999;
-
-	scr_erase_center = 0;
-	start = scr_centerstring;
-
-	if (scr_center_lines <= 4)
-		y = viddef.height*0.35;
-	else
-		y = 48;
-
-	do	
-	{
-	// scan the width of the line
-		for (l=0 ; l<40 ; l++)
-			if (start[l] == '\n' || !start[l])
-				break;
-		x = (viddef.width - l*8)/2;
-		SCR_AddDirtyPoint (x, y);
-		for (j=0 ; j<l ; j++, x+=8)
-		{
-			re.DrawChar (x, y, start[j]);	
-			if (!remaining--)
-				return;
-		}
-		SCR_AddDirtyPoint (x, y+8);
-			
-		y += 8;
-
-		while (*start && *start != '\n')
-			start++;
-
-		if (!*start)
-			break;
-		start++;		// skip the \n
-	} while (1);
-}
-
-void SCR_CheckDrawCenterString (void)
-{
-	scr_centertime_off -= cls.frametime;
-	
-	if (scr_centertime_off <= 0)
-		return;
-
-	SCR_DrawCenterString ();
-}
-
-//=============================================================================
-
-/*
-=================
-SCR_CalcVrect
-
-Sets scr_vrect, the coordinates of the rendered window
-=================
-*/
-static void SCR_CalcVrect (void)
-{
-	int		size;
-
-	// bound viewsize
-	if (scr_viewsize->value < 40)
-		Cvar_Set ("viewsize","40");
-	if (scr_viewsize->value > 100)
-		Cvar_Set ("viewsize","100");
-
-	size = scr_viewsize->value;
-
-	scr_vrect.width = viddef.width*size/100;
-	scr_vrect.width &= ~7;
-
-	scr_vrect.height = viddef.height*size/100;
-	scr_vrect.height &= ~1;
-
-	scr_vrect.x = (viddef.width - scr_vrect.width)/2;
-	scr_vrect.y = (viddef.height - scr_vrect.height)/2;
-}
-
-
-/*
-=================
-SCR_SizeUp_f
-
-Keybinding command
-=================
-*/
-void SCR_SizeUp_f (void)
-{
-	Cvar_SetValue ("viewsize",scr_viewsize->value+10);
-}
-
-
-/*
-=================
-SCR_SizeDown_f
-
-Keybinding command
-=================
-*/
-void SCR_SizeDown_f (void)
-{
-	Cvar_SetValue ("viewsize",scr_viewsize->value-10);
-}
-
-/*
-=================
-SCR_Sky_f
-
-Set a specific sky and rotation speed
-=================
-*/
-void SCR_Sky_f (void)
-{
-	float	rotate;
-	vec3_t	axis;
-
-	if (Cmd_Argc() < 2)
-	{
-		Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
-		return;
-	}
-	if (Cmd_Argc() > 2)
-		rotate = atof(Cmd_Argv(2));
-	else
-		rotate = 0;
-	if (Cmd_Argc() == 6)
-	{
-		axis[0] = atof(Cmd_Argv(3));
-		axis[1] = atof(Cmd_Argv(4));
-		axis[2] = atof(Cmd_Argv(5));
-	}
-	else
-	{
-		axis[0] = 0;
-		axis[1] = 0;
-		axis[2] = 1;
-	}
-
-	re.SetSky (Cmd_Argv(1), rotate, axis);
-}
-
-//============================================================================
-
-/*
-==================
-SCR_Init
-==================
-*/
-void SCR_Init (void)
-{
-	scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
-	scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
-	scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
-	scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
-	scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
-	scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
-	scr_netgraph = Cvar_Get ("netgraph", "0", 0);
-	scr_timegraph = Cvar_Get ("timegraph", "0", 0);
-	scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
-	scr_graphheight = Cvar_Get ("graphheight", "32", 0);
-	scr_graphscale = Cvar_Get ("graphscale", "1", 0);
-	scr_graphshift = Cvar_Get ("graphshift", "0", 0);
-	scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
-
-//
-// register our commands
-//
-	Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
-	Cmd_AddCommand ("loading",SCR_Loading_f);
-	Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
-	Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
-	Cmd_AddCommand ("sky",SCR_Sky_f);
-
-	scr_initialized = true;
-}
-
-
-/*
-==============
-SCR_DrawNet
-==============
-*/
-void SCR_DrawNet (void)
-{
-	if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged 
-		< CMD_BACKUP-1)
-		return;
-
-	re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
-}
-
-/*
-==============
-SCR_DrawPause
-==============
-*/
-void SCR_DrawPause (void)
-{
-	int		w, h;
-
-	if (!scr_showpause->value)		// turn off for screenshots
-		return;
-
-	if (!cl_paused->value)
-		return;
-
-	re.DrawGetPicSize (&w, &h, "pause");
-	re.DrawPic ((viddef.width-w)/2, viddef.height/2 + 8, "pause");
-}
-
-/*
-==============
-SCR_DrawLoading
-==============
-*/
-void SCR_DrawLoading (void)
-{
-	int		w, h;
-		
-	if (!scr_draw_loading)
-		return;
-
-	scr_draw_loading = false;
-	re.DrawGetPicSize (&w, &h, "loading");
-	re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
-}
-
-//=============================================================================
-
-/*
-==================
-SCR_RunConsole
-
-Scroll it up or down
-==================
-*/
-void SCR_RunConsole (void)
-{
-// decide on the height of the console
-	if (cls.key_dest == key_console)
-		scr_conlines = 0.5;		// half screen
-	else
-		scr_conlines = 0;				// none visible
-	
-	if (scr_conlines < scr_con_current)
-	{
-		scr_con_current -= scr_conspeed->value*cls.frametime;
-		if (scr_conlines > scr_con_current)
-			scr_con_current = scr_conlines;
-
-	}
-	else if (scr_conlines > scr_con_current)
-	{
-		scr_con_current += scr_conspeed->value*cls.frametime;
-		if (scr_conlines < scr_con_current)
-			scr_con_current = scr_conlines;
-	}
-
-}
-
-/*
-==================
-SCR_DrawConsole
-==================
-*/
-void SCR_DrawConsole (void)
-{
-	Con_CheckResize ();
-	
-	if (cls.state == ca_disconnected || cls.state == ca_connecting)
-	{	// forced full screen console
-		Con_DrawConsole (1.0);
-		return;
-	}
-
-	if (cls.state != ca_active || !cl.refresh_prepped)
-	{	// connected, but can't render
-		Con_DrawConsole (0.5);
-		re.DrawFill (0, viddef.height/2, viddef.width, viddef.height/2, 0);
-		return;
-	}
-
-	if (scr_con_current)
-	{
-		Con_DrawConsole (scr_con_current);
-	}
-	else
-	{
-		if (cls.key_dest == key_game || cls.key_dest == key_message)
-			Con_DrawNotify ();	// only draw notify in game
-	}
-}
-
-//=============================================================================
-
-/*
-================
-SCR_BeginLoadingPlaque
-================
-*/
-void SCR_BeginLoadingPlaque (void)
-{
-	S_StopAllSounds ();
-	cl.sound_prepped = false;		// don't play ambients
-	CDAudio_Stop ();
-	if (cls.disable_screen)
-		return;
-	if (developer->value)
-		return;
-	if (cls.state == ca_disconnected)
-		return;	// if at console, don't bring up the plaque
-	if (cls.key_dest == key_console)
-		return;
-	if (cl.cinematictime > 0)
-		scr_draw_loading = 2;	// clear to balack first
-	else
-		scr_draw_loading = 1;
-	SCR_UpdateScreen ();
-	cls.disable_screen = Sys_Milliseconds ();
-	cls.disable_servercount = cl.servercount;
-}
-
-/*
-================
-SCR_EndLoadingPlaque
-================
-*/
-void SCR_EndLoadingPlaque (void)
-{
-	cls.disable_screen = 0;
-	Con_ClearNotify ();
-}
-
-/*
-================
-SCR_Loading_f
-================
-*/
-void SCR_Loading_f (void)
-{
-	SCR_BeginLoadingPlaque ();
-}
-
-/*
-================
-SCR_TimeRefresh_f
-================
-*/
-int entitycmpfnc( const entity_t *a, const entity_t *b )
-{
-	/*
-	** all other models are sorted by model then skin
-	*/
-	if ( a->model == b->model )
-	{
-		return ( ( int ) a->skin - ( int ) b->skin );
-	}
-	else
-	{
-		return ( ( int ) a->model - ( int ) b->model );
-	}
-}
-
-void SCR_TimeRefresh_f (void)
-{
-	int		i;
-	int		start, stop;
-	float	time;
-
-	if ( cls.state != ca_active )
-		return;
-
-	start = Sys_Milliseconds ();
-
-	if (Cmd_Argc() == 2)
-	{	// run without page flipping
-		re.BeginFrame( 0 );
-		for (i=0 ; i<128 ; i++)
-		{
-			cl.refdef.viewangles[1] = i/128.0*360.0;
-			re.RenderFrame (&cl.refdef);
-		}
-		re.EndFrame();
-	}
-	else
-	{
-		for (i=0 ; i<128 ; i++)
-		{
-			cl.refdef.viewangles[1] = i/128.0*360.0;
-
-			re.BeginFrame( 0 );
-			re.RenderFrame (&cl.refdef);
-			re.EndFrame();
-		}
-	}
-
-	stop = Sys_Milliseconds ();
-	time = (stop-start)/1000.0;
-	Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
-}
-
-/*
-=================
-SCR_AddDirtyPoint
-=================
-*/
-void SCR_AddDirtyPoint (int x, int y)
-{
-	if (x < scr_dirty.x1)
-		scr_dirty.x1 = x;
-	if (x > scr_dirty.x2)
-		scr_dirty.x2 = x;
-	if (y < scr_dirty.y1)
-		scr_dirty.y1 = y;
-	if (y > scr_dirty.y2)
-		scr_dirty.y2 = y;
-}
-
-void SCR_DirtyScreen (void)
-{
-	SCR_AddDirtyPoint (0, 0);
-	SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
-}
-
-/*
-==============
-SCR_TileClear
-
-Clear any parts of the tiled background that were drawn on last frame
-==============
-*/
-void SCR_TileClear (void)
-{
-	int		i;
-	int		top, bottom, left, right;
-	dirty_t	clear;
-
-	if (scr_drawall->value)
-		SCR_DirtyScreen ();	// for power vr or broken page flippers...
-
-	if (scr_con_current == 1.0)
-		return;		// full screen console
-	if (scr_viewsize->value == 100)
-		return;		// full screen rendering
-	if (cl.cinematictime > 0)
-		return;		// full screen cinematic
-
-	// erase rect will be the union of the past three frames
-	// so tripple buffering works properly
-	clear = scr_dirty;
-	for (i=0 ; i<2 ; i++)
-	{
-		if (scr_old_dirty[i].x1 < clear.x1)
-			clear.x1 = scr_old_dirty[i].x1;
-		if (scr_old_dirty[i].x2 > clear.x2)
-			clear.x2 = scr_old_dirty[i].x2;
-		if (scr_old_dirty[i].y1 < clear.y1)
-			clear.y1 = scr_old_dirty[i].y1;
-		if (scr_old_dirty[i].y2 > clear.y2)
-			clear.y2 = scr_old_dirty[i].y2;
-	}
-
-	scr_old_dirty[1] = scr_old_dirty[0];
-	scr_old_dirty[0] = scr_dirty;
-
-	scr_dirty.x1 = 9999;
-	scr_dirty.x2 = -9999;
-	scr_dirty.y1 = 9999;
-	scr_dirty.y2 = -9999;
-
-	// don't bother with anything convered by the console)
-	top = scr_con_current*viddef.height;
-	if (top >= clear.y1)
-		clear.y1 = top;
-
-	if (clear.y2 <= clear.y1)
-		return;		// nothing disturbed
-
-	top = scr_vrect.y;
-	bottom = top + scr_vrect.height-1;
-	left = scr_vrect.x;
-	right = left + scr_vrect.width-1;
-
-	if (clear.y1 < top)
-	{	// clear above view screen
-		i = clear.y2 < top-1 ? clear.y2 : top-1;
-		re.DrawTileClear (clear.x1 , clear.y1,
-			clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
-		clear.y1 = top;
-	}
-	if (clear.y2 > bottom)
-	{	// clear below view screen
-		i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
-		re.DrawTileClear (clear.x1, i,
-			clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
-		clear.y2 = bottom;
-	}
-	if (clear.x1 < left)
-	{	// clear left of view screen
-		i = clear.x2 < left-1 ? clear.x2 : left-1;
-		re.DrawTileClear (clear.x1, clear.y1,
-			i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
-		clear.x1 = left;
-	}
-	if (clear.x2 > right)
-	{	// clear left of view screen
-		i = clear.x1 > right+1 ? clear.x1 : right+1;
-		re.DrawTileClear (i, clear.y1,
-			clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
-		clear.x2 = right;
-	}
-
-}
-
-
-//===============================================================
-
-
-#define STAT_MINUS		10	// num frame for '-' stats digit
-char		*sb_nums[2][11] = 
-{
-	{"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
-	"num_6", "num_7", "num_8", "num_9", "num_minus"},
-	{"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
-	"anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
-};
-
-#define	ICON_WIDTH	24
-#define	ICON_HEIGHT	24
-#define	CHAR_WIDTH	16
-#define	ICON_SPACE	8
-
-
-
-/*
-================
-SizeHUDString
-
-Allow embedded \n in the string
-================
-*/
-void SizeHUDString (char *string, int *w, int *h)
-{
-	int		lines, width, current;
-
-	lines = 1;
-	width = 0;
-
-	current = 0;
-	while (*string)
-	{
-		if (*string == '\n')
-		{
-			lines++;
-			current = 0;
-		}
-		else
-		{
-			current++;
-			if (current > width)
-				width = current;
-		}
-		string++;
-	}
-
-	*w = width * 8;
-	*h = lines * 8;
-}
-
-void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
-{
-	int		margin;
-	char	line[1024];
-	int		width;
-	int		i;
-
-	margin = x;
-
-	while (*string)
-	{
-		// scan out one line of text from the string
-		width = 0;
-		while (*string && *string != '\n')
-			line[width++] = *string++;
-		line[width] = 0;
-
-		if (centerwidth)
-			x = margin + (centerwidth - width*8)/2;
-		else
-			x = margin;
-		for (i=0 ; i<width ; i++)
-		{
-			re.DrawChar (x, y, line[i]^xor);
-			x += 8;
-		}
-		if (*string)
-		{
-			string++;	// skip the \n
-			x = margin;
-			y += 8;
-		}
-	}
-}
-
-
-/*
-==============
-SCR_DrawField
-==============
-*/
-void SCR_DrawField (int x, int y, int color, int width, int value)
-{
-	char	num[16], *ptr;
-	int		l;
-	int		frame;
-
-	if (width < 1)
-		return;
-
-	// draw number string
-	if (width > 5)
-		width = 5;
-
-	SCR_AddDirtyPoint (x, y);
-	SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
-
-	Com_sprintf (num, sizeof(num), "%i", value);
-	l = strlen(num);
-	if (l > width)
-		l = width;
-	x += 2 + CHAR_WIDTH*(width - l);
-
-	ptr = num;
-	while (*ptr && l)
-	{
-		if (*ptr == '-')
-			frame = STAT_MINUS;
-		else
-			frame = *ptr -'0';
-
-		re.DrawPic (x,y,sb_nums[color][frame]);
-		x += CHAR_WIDTH;
-		ptr++;
-		l--;
-	}
-}
-
-
-/*
-===============
-SCR_TouchPics
-
-Allows rendering code to cache all needed sbar graphics
-===============
-*/
-void SCR_TouchPics (void)
-{
-	int		i, j;
-
-	for (i=0 ; i<2 ; i++)
-		for (j=0 ; j<11 ; j++)
-			re.RegisterPic (sb_nums[i][j]);
-
-	if (crosshair->value)
-	{
-		if (crosshair->value > 3 || crosshair->value < 0)
-			crosshair->value = 3;
-
-		Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
-		re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
-		if (!crosshair_width)
-			crosshair_pic[0] = 0;
-	}
-}
-
-/*
-================
-SCR_ExecuteLayoutString 
-
-================
-*/
-void SCR_ExecuteLayoutString (char *s)
-{
-	int		x, y;
-	int		value;
-	char	*token;
-	int		width;
-	int		index;
-	clientinfo_t	*ci;
-
-	if (cls.state != ca_active || !cl.refresh_prepped)
-		return;
-
-	if (!s[0])
-		return;
-
-	x = 0;
-	y = 0;
-	width = 3;
-
-	while (s)
-	{
-		token = COM_Parse (&s);
-		if (!strcmp(token, "xl"))
-		{
-			token = COM_Parse (&s);
-			x = atoi(token);
-			continue;
-		}
-		if (!strcmp(token, "xr"))
-		{
-			token = COM_Parse (&s);
-			x = viddef.width + atoi(token);
-			continue;
-		}
-		if (!strcmp(token, "xv"))
-		{
-			token = COM_Parse (&s);
-			x = viddef.width/2 - 160 + atoi(token);
-			continue;
-		}
-
-		if (!strcmp(token, "yt"))
-		{
-			token = COM_Parse (&s);
-			y = atoi(token);
-			continue;
-		}
-		if (!strcmp(token, "yb"))
-		{
-			token = COM_Parse (&s);
-			y = viddef.height + atoi(token);
-			continue;
-		}
-		if (!strcmp(token, "yv"))
-		{
-			token = COM_Parse (&s);
-			y = viddef.height/2 - 120 + atoi(token);
-			continue;
-		}
-
-		if (!strcmp(token, "pic"))
-		{	// draw a pic from a stat number
-			token = COM_Parse (&s);
-			value = cl.frame.playerstate.stats[atoi(token)];
-			if (value >= MAX_IMAGES)
-				Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
-			if (cl.configstrings[CS_IMAGES+value])
-			{
-				SCR_AddDirtyPoint (x, y);
-				SCR_AddDirtyPoint (x+23, y+23);
-				re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
-			}
-			continue;
-		}
-
-		if (!strcmp(token, "client"))
-		{	// draw a deathmatch client block
-			int		score, ping, time;
-
-			token = COM_Parse (&s);
-			x = viddef.width/2 - 160 + atoi(token);
-			token = COM_Parse (&s);
-			y = viddef.height/2 - 120 + atoi(token);
-			SCR_AddDirtyPoint (x, y);
-			SCR_AddDirtyPoint (x+159, y+31);
-
-			token = COM_Parse (&s);
-			value = atoi(token);
-			if (value >= MAX_CLIENTS || value < 0)
-				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
-			ci = &cl.clientinfo[value];
-
-			token = COM_Parse (&s);
-			score = atoi(token);
-
-			token = COM_Parse (&s);
-			ping = atoi(token);
-
-			token = COM_Parse (&s);
-			time = atoi(token);
-
-			DrawAltString (x+32, y, ci->name);
-			DrawString (x+32, y+8,  "Score: ");
-			DrawAltString (x+32+7*8, y+8,  va("%i", score));
-			DrawString (x+32, y+16, va("Ping:  %i", ping));
-			DrawString (x+32, y+24, va("Time:  %i", time));
-
-			if (!ci->icon)
-				ci = &cl.baseclientinfo;
-			re.DrawPic (x, y, ci->iconname);
-			continue;
-		}
-
-		if (!strcmp(token, "ctf"))
-		{	// draw a ctf client block
-			int		score, ping;
-			char	block[80];
-
-			token = COM_Parse (&s);
-			x = viddef.width/2 - 160 + atoi(token);
-			token = COM_Parse (&s);
-			y = viddef.height/2 - 120 + atoi(token);
-			SCR_AddDirtyPoint (x, y);
-			SCR_AddDirtyPoint (x+159, y+31);
-
-			token = COM_Parse (&s);
-			value = atoi(token);
-			if (value >= MAX_CLIENTS || value < 0)
-				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
-			ci = &cl.clientinfo[value];
-
-			token = COM_Parse (&s);
-			score = atoi(token);
-
-			token = COM_Parse (&s);
-			ping = atoi(token);
-			if (ping > 999)
-				ping = 999;
-
-			sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
-
-			if (value == cl.playernum)
-				DrawAltString (x, y, block);
-			else
-				DrawString (x, y, block);
-			continue;
-		}
-
-		if (!strcmp(token, "picn"))
-		{	// draw a pic from a name
-			token = COM_Parse (&s);
-			SCR_AddDirtyPoint (x, y);
-			SCR_AddDirtyPoint (x+23, y+23);
-			re.DrawPic (x, y, token);
-			continue;
-		}
-
-		if (!strcmp(token, "num"))
-		{	// draw a number
-			token = COM_Parse (&s);
-			width = atoi(token);
-			token = COM_Parse (&s);
-			value = cl.frame.playerstate.stats[atoi(token)];
-			SCR_DrawField (x, y, 0, width, value);
-			continue;
-		}
-
-		if (!strcmp(token, "hnum"))
-		{	// health number
-			int		color;
-
-			width = 3;
-			value = cl.frame.playerstate.stats[STAT_HEALTH];
-			if (value > 25)
-				color = 0;	// green
-			else if (value > 0)
-				color = (cl.frame.serverframe>>2) & 1;		// flash
-			else
-				color = 1;
-
-			if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
-				re.DrawPic (x, y, "field_3");
-
-			SCR_DrawField (x, y, color, width, value);
-			continue;
-		}
-
-		if (!strcmp(token, "anum"))
-		{	// ammo number
-			int		color;
-
-			width = 3;
-			value = cl.frame.playerstate.stats[STAT_AMMO];
-			if (value > 5)
-				color = 0;	// green
-			else if (value >= 0)
-				color = (cl.frame.serverframe>>2) & 1;		// flash
-			else
-				continue;	// negative number = don't show
-
-			if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
-				re.DrawPic (x, y, "field_3");
-
-			SCR_DrawField (x, y, color, width, value);
-			continue;
-		}
-
-		if (!strcmp(token, "rnum"))
-		{	// armor number
-			int		color;
-
-			width = 3;
-			value = cl.frame.playerstate.stats[STAT_ARMOR];
-			if (value < 1)
-				continue;
-
-			color = 0;	// green
-
-			if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
-				re.DrawPic (x, y, "field_3");
-
-			SCR_DrawField (x, y, color, width, value);
-			continue;
-		}
-
-
-		if (!strcmp(token, "stat_string"))
-		{
-			token = COM_Parse (&s);
-			index = atoi(token);
-			if (index < 0 || index >= MAX_CONFIGSTRINGS)
-				Com_Error (ERR_DROP, "Bad stat_string index");
-			index = cl.frame.playerstate.stats[index];
-			if (index < 0 || index >= MAX_CONFIGSTRINGS)
-				Com_Error (ERR_DROP, "Bad stat_string index");
-			DrawString (x, y, cl.configstrings[index]);
-			continue;
-		}
-
-		if (!strcmp(token, "cstring"))
-		{
-			token = COM_Parse (&s);
-			DrawHUDString (token, x, y, 320, 0);
-			continue;
-		}
-
-		if (!strcmp(token, "string"))
-		{
-			token = COM_Parse (&s);
-			DrawString (x, y, token);
-			continue;
-		}
-
-		if (!strcmp(token, "cstring2"))
-		{
-			token = COM_Parse (&s);
-			DrawHUDString (token, x, y, 320,0x80);
-			continue;
-		}
-
-		if (!strcmp(token, "string2"))
-		{
-			token = COM_Parse (&s);
-			DrawAltString (x, y, token);
-			continue;
-		}
-
-		if (!strcmp(token, "if"))
-		{	// draw a number
-			token = COM_Parse (&s);
-			value = cl.frame.playerstate.stats[atoi(token)];
-			if (!value)
-			{	// skip to endif
-				while (s && strcmp(token, "endif") )
-				{
-					token = COM_Parse (&s);
-				}
-			}
-
-			continue;
-		}
-
-
-	}
-}
-
-
-/*
-================
-SCR_DrawStats
-
-The status bar is a small layout program that
-is based on the stats array
-================
-*/
-void SCR_DrawStats (void)
-{
-	SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
-}
-
-
-/*
-================
-SCR_DrawLayout
-
-================
-*/
-#define	STAT_LAYOUTS		13
-
-void SCR_DrawLayout (void)
-{
-	if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
-		return;
-	SCR_ExecuteLayoutString (cl.layout);
-}
-
-//=======================================================
-
-/*
-==================
-SCR_UpdateScreen
-
-This is called every frame, and can also be called explicitly to flush
-text to the screen.
-==================
-*/
-void SCR_UpdateScreen (void)
-{
-	int numframes;
-	int i;
-	float separation[2] = { 0, 0 };
-
-	// if the screen is disabled (loading plaque is up, or vid mode changing)
-	// do nothing at all
-	if (cls.disable_screen)
-	{
-		if (Sys_Milliseconds() - cls.disable_screen > 120000)
-		{
-			cls.disable_screen = 0;
-			Com_Printf ("Loading plaque timed out.\n");
-		}
-		return;
-	}
-
-	if (!scr_initialized || !con.initialized)
-		return;				// not initialized yet
-
-	/*
-	** range check cl_camera_separation so we don't inadvertently fry someone's
-	** brain
-	*/
-	if ( cl_stereo_separation->value > 1.0 )
-		Cvar_SetValue( "cl_stereo_separation", 1.0 );
-	else if ( cl_stereo_separation->value < 0 )
-		Cvar_SetValue( "cl_stereo_separation", 0.0 );
-
-	if ( cl_stereo->value )
-	{
-		numframes = 2;
-		separation[0] = -cl_stereo_separation->value / 2;
-		separation[1] =  cl_stereo_separation->value / 2;
-	}		
-	else
-	{
-		separation[0] = 0;
-		separation[1] = 0;
-		numframes = 1;
-	}
-
-	for ( i = 0; i < numframes; i++ )
-	{
-		re.BeginFrame( separation[i] );
-
-		if (scr_draw_loading == 2)
-		{	//  loading plaque over black screen
-			int		w, h;
-
-			re.CinematicSetPalette(NULL);
-			scr_draw_loading = false;
-			re.DrawGetPicSize (&w, &h, "loading");
-			re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
-//			re.EndFrame();
-//			return;
-		} 
-		// if a cinematic is supposed to be running, handle menus
-		// and console specially
-		else if (cl.cinematictime > 0)
-		{
-			if (cls.key_dest == key_menu)
-			{
-				if (cl.cinematicpalette_active)
-				{
-					re.CinematicSetPalette(NULL);
-					cl.cinematicpalette_active = false;
-				}
-				M_Draw ();
-//				re.EndFrame();
-//				return;
-			}
-			else if (cls.key_dest == key_console)
-			{
-				if (cl.cinematicpalette_active)
-				{
-					re.CinematicSetPalette(NULL);
-					cl.cinematicpalette_active = false;
-				}
-				SCR_DrawConsole ();
-//				re.EndFrame();
-//				return;
-			}
-			else
-			{
-				SCR_DrawCinematic();
-//				re.EndFrame();
-//				return;
-			}
-		}
-		else 
-		{
-
-			// make sure the game palette is active
-			if (cl.cinematicpalette_active)
-			{
-				re.CinematicSetPalette(NULL);
-				cl.cinematicpalette_active = false;
-			}
-
-			// do 3D refresh drawing, and then update the screen
-			SCR_CalcVrect ();
-
-			// clear any dirty part of the background
-			SCR_TileClear ();
-
-			V_RenderView ( separation[i] );
-
-			SCR_DrawStats ();
-			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
-				SCR_DrawLayout ();
-			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
-				CL_DrawInventory ();
-
-			SCR_DrawNet ();
-			SCR_CheckDrawCenterString ();
-
-			// FPS counter hack 
-			// http://www.quakesrc.org/?Page=tutorials&What=./tutorials/Quake2/misc/fps.txt
-			if (cl_drawfps->value) {
-				char s[8];
-				sprintf(s,"%3.0ffps", 1/cls.frametime);
-				DrawString(viddef.width-64,0,s);
-			}
-			
-			if (scr_timegraph->value)
-				SCR_DebugGraph (cls.frametime*300, 0);
-
-			if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
-				SCR_DrawDebugGraph ();
-
-			SCR_DrawPause ();
-
-			SCR_DrawConsole ();
-
-			M_Draw ();
-
-			SCR_DrawLoading ();
-		}
-	}
-	re.EndFrame();
-}
+/*

+Copyright (C) 1997-2001 Id Software, Inc.

+

+This program is free software; you can redistribute it and/or

+modify it under the terms of the GNU General Public License

+as published by the Free Software Foundation; either version 2

+of the License, or (at your option) any later version.

+

+This program is distributed in the hope that it will be useful,

+but WITHOUT ANY WARRANTY; without even the implied warranty of

+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

+

+See the GNU General Public License for more details.

+

+You should have received a copy of the GNU General Public License

+along with this program; if not, write to the Free Software

+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

+

+*/

+// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc

+

+/*

+

+  full screen console

+  put up loading plaque

+  blanked background with loading plaque

+  blanked background with menu

+  cinematics

+  full screen image for quit and victory

+

+  end of unit intermissions

+

+  */

+

+#include "client.h"

+

+float		scr_con_current;	// aproaches scr_conlines at scr_conspeed

+float		scr_conlines;		// 0.0 to 1.0 lines of console to display

+

+qboolean	scr_initialized;		// ready to draw

+

+int			scr_draw_loading;

+

+vrect_t		scr_vrect;		// position of render window on screen

+

+

+cvar_t		*scr_viewsize;

+cvar_t		*scr_conspeed;

+cvar_t		*scr_centertime;

+cvar_t		*scr_showturtle;

+cvar_t		*scr_showpause;

+cvar_t		*scr_printspeed;

+

+cvar_t		*scr_netgraph;

+cvar_t		*scr_timegraph;

+cvar_t		*scr_debuggraph;

+cvar_t		*scr_graphheight;

+cvar_t		*scr_graphscale;

+cvar_t		*scr_graphshift;

+cvar_t		*scr_drawall;

+

+typedef struct

+{

+	int		x1, y1, x2, y2;

+} dirty_t;

+

+dirty_t		scr_dirty, scr_old_dirty[2];

+

+char		crosshair_pic[MAX_QPATH];

+int			crosshair_width, crosshair_height;

+

+void SCR_TimeRefresh_f (void);

+void SCR_Loading_f (void);

+

+

+/*

+===============================================================================

+

+BAR GRAPHS

+

+===============================================================================

+*/

+

+/*

+==============

+CL_AddNetgraph

+

+A new packet was just parsed

+==============

+*/

+void CL_AddNetgraph (void)

+{

+	int		i;

+	int		in;

+	int		ping;

+

+	// if using the debuggraph for something else, don't

+	// add the net lines

+	if (scr_debuggraph->value || scr_timegraph->value)

+		return;

+

+	for (i=0 ; i<cls.netchan.dropped ; i++)

+		SCR_DebugGraph (30, 0x40);

+

+	for (i=0 ; i<cl.surpressCount ; i++)

+		SCR_DebugGraph (30, 0xdf);

+

+	// see what the latency was on this packet

+	in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);

+	ping = cls.realtime - cl.cmd_time[in];

+	ping /= 30;

+	if (ping > 30)

+		ping = 30;

+	SCR_DebugGraph (ping, 0xd0);

+}

+

+

+typedef struct

+{

+	float	value;

+	int		color;

+} graphsamp_t;

+

+static	int			current;

+static	graphsamp_t	values[1024];

+

+/*

+==============

+SCR_DebugGraph

+==============

+*/

+void SCR_DebugGraph (float value, int color)

+{

+	values[current&1023].value = value;

+	values[current&1023].color = color;

+	current++;

+}

+

+/*

+==============

+SCR_DrawDebugGraph

+==============

+*/

+void SCR_DrawDebugGraph (void)

+{

+	int		a, x, y, w, i, h;

+	float	v;

+	int		color;

+

+	//

+	// draw the graph

+	//

+	w = scr_vrect.width;

+

+	x = scr_vrect.x;

+	y = scr_vrect.y+scr_vrect.height;

+	re.DrawFill (x, y-scr_graphheight->value,

+		w, scr_graphheight->value, 8);

+

+	for (a=0 ; a<w ; a++)

+	{

+		i = (current-1-a+1024) & 1023;

+		v = values[i].value;

+		color = values[i].color;

+		v = v*scr_graphscale->value + scr_graphshift->value;

+		

+		if (v < 0)

+			v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));

+		h = (int)v % (int)scr_graphheight->value;

+		re.DrawFill (x+w-1-a, y - h, 1,	h, color);

+	}

+}

+

+/*

+===============================================================================

+

+CENTER PRINTING

+

+===============================================================================

+*/

+

+char		scr_centerstring[1024];

+float		scr_centertime_start;	// for slow victory printing

+float		scr_centertime_off;

+int			scr_center_lines;

+int			scr_erase_center;

+

+/*

+==============

+SCR_CenterPrint

+

+Called for important messages that should stay in the center of the screen

+for a few moments

+==============

+*/

+void SCR_CenterPrint (char *str)

+{

+	char	*s;

+	char	line[64];

+	int		i, j, l;

+

+	strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);

+	scr_centertime_off = scr_centertime->value;

+	scr_centertime_start = cl.time;

+

+	// count the number of lines for centering

+	scr_center_lines = 1;

+	s = str;

+	while (*s)

+	{

+		if (*s == '\n')

+			scr_center_lines++;

+		s++;

+	}

+

+	// echo it to the console

+	Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");

+

+	s = str;

+	do	

+	{

+	// scan the width of the line

+		for (l=0 ; l<40 ; l++)

+			if (s[l] == '\n' || !s[l])

+				break;

+		for (i=0 ; i<(40-l)/2 ; i++)

+			line[i] = ' ';

+

+		for (j=0 ; j<l ; j++)

+		{

+			line[i++] = s[j];

+		}

+

+		line[i] = '\n';

+		line[i+1] = 0;

+

+		Com_Printf ("%s", line);

+

+		while (*s && *s != '\n')

+			s++;

+

+		if (!*s)

+			break;

+		s++;		// skip the \n

+	} while (1);

+	Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");

+	Con_ClearNotify ();

+}

+

+

+void SCR_DrawCenterString (void)

+{

+	char	*start;

+	int		l;

+	int		j;

+	int		x, y;

+	int		remaining;

+

+// the finale prints the characters one at a time

+	remaining = 9999;

+

+	scr_erase_center = 0;

+	start = scr_centerstring;

+

+	if (scr_center_lines <= 4)

+		y = viddef.height*0.35;

+	else

+		y = 48;

+

+	do	

+	{

+	// scan the width of the line

+		for (l=0 ; l<40 ; l++)

+			if (start[l] == '\n' || !start[l])

+				break;

+		x = (viddef.width - l*8)/2;

+		SCR_AddDirtyPoint (x, y);

+		for (j=0 ; j<l ; j++, x+=8)

+		{

+			re.DrawChar (x, y, start[j]);	

+			if (!remaining--)

+				return;

+		}

+		SCR_AddDirtyPoint (x, y+8);

+			

+		y += 8;

+

+		while (*start && *start != '\n')

+			start++;

+

+		if (!*start)

+			break;

+		start++;		// skip the \n

+	} while (1);

+}

+

+void SCR_CheckDrawCenterString (void)

+{

+	scr_centertime_off -= cls.frametime;

+	

+	if (scr_centertime_off <= 0)

+		return;

+

+	SCR_DrawCenterString ();

+}

+

+//=============================================================================

+

+/*

+=================

+SCR_CalcVrect

+

+Sets scr_vrect, the coordinates of the rendered window

+=================

+*/

+static void SCR_CalcVrect (void)

+{

+	int		size;

+

+	// bound viewsize

+	if (scr_viewsize->value < 40)

+		Cvar_Set ("viewsize","40");

+	if (scr_viewsize->value > 100)

+		Cvar_Set ("viewsize","100");

+

+	size = scr_viewsize->value;

+

+	scr_vrect.width = viddef.width*size/100;

+	scr_vrect.width &= ~7;

+

+	scr_vrect.height = viddef.height*size/100;

+	scr_vrect.height &= ~1;

+

+	scr_vrect.x = (viddef.width - scr_vrect.width)/2;

+	scr_vrect.y = (viddef.height - scr_vrect.height)/2;

+}

+

+

+/*

+=================

+SCR_SizeUp_f

+

+Keybinding command

+=================

+*/

+void SCR_SizeUp_f (void)

+{

+	Cvar_SetValue ("viewsize",scr_viewsize->value+10);

+}

+

+

+/*

+=================

+SCR_SizeDown_f

+

+Keybinding command

+=================

+*/

+void SCR_SizeDown_f (void)

+{

+	Cvar_SetValue ("viewsize",scr_viewsize->value-10);

+}

+

+/*

+=================

+SCR_Sky_f

+

+Set a specific sky and rotation speed

+=================

+*/

+void SCR_Sky_f (void)

+{

+	float	rotate;

+	vec3_t	axis;

+

+	if (Cmd_Argc() < 2)

+	{

+		Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");

+		return;

+	}

+	if (Cmd_Argc() > 2)

+		rotate = atof(Cmd_Argv(2));

+	else

+		rotate = 0;

+	if (Cmd_Argc() == 6)

+	{

+		axis[0] = atof(Cmd_Argv(3));

+		axis[1] = atof(Cmd_Argv(4));

+		axis[2] = atof(Cmd_Argv(5));

+	}

+	else

+	{

+		axis[0] = 0;

+		axis[1] = 0;

+		axis[2] = 1;

+	}

+

+	re.SetSky (Cmd_Argv(1), rotate, axis);

+}

+

+//============================================================================

+

+/*

+==================

+SCR_Init

+==================

+*/

+void SCR_Init (void)

+{

+	scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);

+	scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);

+	scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);

+	scr_showpause = Cvar_Get ("scr_showpause", "1", 0);

+	scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);

+	scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);

+	scr_netgraph = Cvar_Get ("netgraph", "0", 0);

+	scr_timegraph = Cvar_Get ("timegraph", "0", 0);

+	scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);

+	scr_graphheight = Cvar_Get ("graphheight", "32", 0);

+	scr_graphscale = Cvar_Get ("graphscale", "1", 0);

+	scr_graphshift = Cvar_Get ("graphshift", "0", 0);

+	scr_drawall = Cvar_Get ("scr_drawall", "0", 0);

+

+//

+// register our commands

+//

+	Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);

+	Cmd_AddCommand ("loading",SCR_Loading_f);

+	Cmd_AddCommand ("sizeup",SCR_SizeUp_f);

+	Cmd_AddCommand ("sizedown",SCR_SizeDown_f);

+	Cmd_AddCommand ("sky",SCR_Sky_f);

+

+	scr_initialized = true;

+}

+

+

+/*

+==============

+SCR_DrawNet

+==============

+*/

+void SCR_DrawNet (void)

+{

+	if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged 

+		< CMD_BACKUP-1)

+		return;

+

+	re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");

+}

+

+/*

+==============

+SCR_DrawPause

+==============

+*/

+void SCR_DrawPause (void)

+{

+	int		w, h;

+

+	if (!scr_showpause->value)		// turn off for screenshots

+		return;

+

+	if (!cl_paused->value)

+		return;

+

+	re.DrawGetPicSize (&w, &h, "pause");

+	re.DrawPic ((viddef.width-w)/2, viddef.height/2 + 8, "pause");

+}

+

+/*

+==============

+SCR_DrawLoading

+==============

+*/

+void SCR_DrawLoading (void)

+{

+	int		w, h;

+		

+	if (!scr_draw_loading)

+		return;

+

+	scr_draw_loading = false;

+	re.DrawGetPicSize (&w, &h, "loading");

+	re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");

+}

+

+//=============================================================================

+

+/*

+==================

+SCR_RunConsole

+

+Scroll it up or down

+==================

+*/

+void SCR_RunConsole (void)

+{

+// decide on the height of the console

+	if (cls.key_dest == key_console)

+		scr_conlines = 0.5;		// half screen

+	else

+		scr_conlines = 0;				// none visible

+	

+	if (scr_conlines < scr_con_current)

+	{

+		scr_con_current -= scr_conspeed->value*cls.frametime;

+		if (scr_conlines > scr_con_current)

+			scr_con_current = scr_conlines;

+

+	}

+	else if (scr_conlines > scr_con_current)

+	{

+		scr_con_current += scr_conspeed->value*cls.frametime;

+		if (scr_conlines < scr_con_current)

+			scr_con_current = scr_conlines;

+	}

+

+}

+

+/*

+==================

+SCR_DrawConsole

+==================

+*/

+void SCR_DrawConsole (void)

+{

+	Con_CheckResize ();

+	

+	if (cls.state == ca_disconnected || cls.state == ca_connecting)

+	{	// forced full screen console

+		Con_DrawConsole (1.0);

+		return;

+	}

+

+	if (cls.state != ca_active || !cl.refresh_prepped)

+	{	// connected, but can't render

+		Con_DrawConsole (0.5);

+		re.DrawFill (0, viddef.height/2, viddef.width, viddef.height/2, 0);

+		return;

+	}

+

+	if (scr_con_current)

+	{

+		Con_DrawConsole (scr_con_current);

+	}

+	else

+	{

+		if (cls.key_dest == key_game || cls.key_dest == key_message)

+			Con_DrawNotify ();	// only draw notify in game

+	}

+}

+

+//=============================================================================

+

+/*

+================

+SCR_BeginLoadingPlaque

+================

+*/

+void SCR_BeginLoadingPlaque (void)

+{

+	S_StopAllSounds ();

+	cl.sound_prepped = false;		// don't play ambients

+	CDAudio_Stop ();

+	if (cls.disable_screen)

+		return;

+	if (developer->value)

+		return;

+	if (cls.state == ca_disconnected)

+		return;	// if at console, don't bring up the plaque

+	if (cls.key_dest == key_console)

+		return;

+	if (cl.cinematictime > 0)

+		scr_draw_loading = 2;	// clear to balack first

+	else

+		scr_draw_loading = 1;

+	SCR_UpdateScreen ();

+	cls.disable_screen = Sys_Milliseconds ();

+	cls.disable_servercount = cl.servercount;

+}

+

+/*

+================

+SCR_EndLoadingPlaque

+================

+*/

+void SCR_EndLoadingPlaque (void)

+{

+	cls.disable_screen = 0;

+	Con_ClearNotify ();

+}

+

+/*

+================

+SCR_Loading_f

+================

+*/

+void SCR_Loading_f (void)

+{

+	SCR_BeginLoadingPlaque ();

+}

+

+/*

+================

+SCR_TimeRefresh_f

+================

+*/

+int entitycmpfnc( const entity_t *a, const entity_t *b )

+{

+	/*

+	** all other models are sorted by model then skin

+	*/

+	if ( a->model == b->model )

+	{

+		return ( ( int ) a->skin - ( int ) b->skin );

+	}

+	else

+	{

+		return ( ( int ) a->model - ( int ) b->model );

+	}

+}

+

+void SCR_TimeRefresh_f (void)

+{

+	int		i;

+	int		start, stop;

+	float	time;

+

+	if ( cls.state != ca_active )

+		return;

+

+	start = Sys_Milliseconds ();

+

+	if (Cmd_Argc() == 2)

+	{	// run without page flipping

+		re.BeginFrame( 0 );

+		for (i=0 ; i<128 ; i++)

+		{

+			cl.refdef.viewangles[1] = i/128.0*360.0;

+			re.RenderFrame (&cl.refdef);

+		}

+		re.EndFrame();

+	}

+	else

+	{

+		for (i=0 ; i<128 ; i++)

+		{

+			cl.refdef.viewangles[1] = i/128.0*360.0;

+

+			re.BeginFrame( 0 );

+			re.RenderFrame (&cl.refdef);

+			re.EndFrame();

+		}

+	}

+

+	stop = Sys_Milliseconds ();

+	time = (stop-start)/1000.0;

+	Com_Printf ("%f seconds (%f fps)\n", time, 128/time);

+}

+

+/*

+=================

+SCR_AddDirtyPoint

+=================

+*/

+void SCR_AddDirtyPoint (int x, int y)

+{

+	if (x < scr_dirty.x1)

+		scr_dirty.x1 = x;

+	if (x > scr_dirty.x2)

+		scr_dirty.x2 = x;

+	if (y < scr_dirty.y1)

+		scr_dirty.y1 = y;

+	if (y > scr_dirty.y2)

+		scr_dirty.y2 = y;

+}

+

+void SCR_DirtyScreen (void)

+{

+	SCR_AddDirtyPoint (0, 0);

+	SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);

+}

+

+/*

+==============

+SCR_TileClear

+

+Clear any parts of the tiled background that were drawn on last frame

+==============

+*/

+void SCR_TileClear (void)

+{

+	int		i;

+	int		top, bottom, left, right;

+	dirty_t	clear;

+

+	if (scr_drawall->value)

+		SCR_DirtyScreen ();	// for power vr or broken page flippers...

+

+	if (scr_con_current == 1.0)

+		return;		// full screen console

+	if (scr_viewsize->value == 100)

+		return;		// full screen rendering

+	if (cl.cinematictime > 0)

+		return;		// full screen cinematic

+

+	// erase rect will be the union of the past three frames

+	// so tripple buffering works properly

+	clear = scr_dirty;

+	for (i=0 ; i<2 ; i++)

+	{

+		if (scr_old_dirty[i].x1 < clear.x1)

+			clear.x1 = scr_old_dirty[i].x1;

+		if (scr_old_dirty[i].x2 > clear.x2)

+			clear.x2 = scr_old_dirty[i].x2;

+		if (scr_old_dirty[i].y1 < clear.y1)

+			clear.y1 = scr_old_dirty[i].y1;

+		if (scr_old_dirty[i].y2 > clear.y2)

+			clear.y2 = scr_old_dirty[i].y2;

+	}

+

+	scr_old_dirty[1] = scr_old_dirty[0];

+	scr_old_dirty[0] = scr_dirty;

+

+	scr_dirty.x1 = 9999;

+	scr_dirty.x2 = -9999;

+	scr_dirty.y1 = 9999;

+	scr_dirty.y2 = -9999;

+

+	// don't bother with anything convered by the console)

+	top = scr_con_current*viddef.height;

+	if (top >= clear.y1)

+		clear.y1 = top;

+

+	if (clear.y2 <= clear.y1)

+		return;		// nothing disturbed

+

+	top = scr_vrect.y;

+	bottom = top + scr_vrect.height-1;

+	left = scr_vrect.x;

+	right = left + scr_vrect.width-1;

+

+	if (clear.y1 < top)

+	{	// clear above view screen

+		i = clear.y2 < top-1 ? clear.y2 : top-1;

+		re.DrawTileClear (clear.x1 , clear.y1,

+			clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");

+		clear.y1 = top;

+	}

+	if (clear.y2 > bottom)

+	{	// clear below view screen

+		i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;

+		re.DrawTileClear (clear.x1, i,

+			clear.x2-clear.x1+1, clear.y2-i+1, "backtile");

+		clear.y2 = bottom;

+	}

+	if (clear.x1 < left)

+	{	// clear left of view screen

+		i = clear.x2 < left-1 ? clear.x2 : left-1;

+		re.DrawTileClear (clear.x1, clear.y1,

+			i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");

+		clear.x1 = left;

+	}

+	if (clear.x2 > right)

+	{	// clear left of view screen

+		i = clear.x1 > right+1 ? clear.x1 : right+1;

+		re.DrawTileClear (i, clear.y1,

+			clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");

+		clear.x2 = right;

+	}

+

+}

+

+

+//===============================================================

+

+

+#define STAT_MINUS		10	// num frame for '-' stats digit

+char		*sb_nums[2][11] = 

+{

+	{"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",

+	"num_6", "num_7", "num_8", "num_9", "num_minus"},

+	{"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",

+	"anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}

+};

+

+#define	ICON_WIDTH	24

+#define	ICON_HEIGHT	24

+#define	CHAR_WIDTH	16

+#define	ICON_SPACE	8

+

+

+

+/*

+================

+SizeHUDString

+

+Allow embedded \n in the string

+================

+*/

+void SizeHUDString (char *string, int *w, int *h)

+{

+	int		lines, width, current;

+

+	lines = 1;

+	width = 0;

+

+	current = 0;

+	while (*string)

+	{

+		if (*string == '\n')

+		{

+			lines++;

+			current = 0;

+		}

+		else

+		{

+			current++;

+			if (current > width)

+				width = current;

+		}

+		string++;

+	}

+

+	*w = width * 8;

+	*h = lines * 8;

+}

+

+void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)

+{

+	int		margin;

+	char	line[1024];

+	int		width;

+	int		i;

+

+	margin = x;

+

+	while (*string)

+	{

+		// scan out one line of text from the string

+		width = 0;

+		while (*string && *string != '\n')

+			line[width++] = *string++;

+		line[width] = 0;

+

+		if (centerwidth)

+			x = margin + (centerwidth - width*8)/2;

+		else

+			x = margin;

+		for (i=0 ; i<width ; i++)

+		{

+			re.DrawChar (x, y, line[i]^xor);

+			x += 8;

+		}

+		if (*string)

+		{

+			string++;	// skip the \n

+			x = margin;

+			y += 8;

+		}

+	}

+}

+

+

+/*

+==============

+SCR_DrawField

+==============

+*/

+void SCR_DrawField (int x, int y, int color, int width, int value)

+{

+	char	num[16], *ptr;

+	int		l;

+	int		frame;

+

+	if (width < 1)

+		return;

+

+	// draw number string

+	if (width > 5)

+		width = 5;

+

+	SCR_AddDirtyPoint (x, y);

+	SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);

+

+	Com_sprintf (num, sizeof(num), "%i", value);

+	l = strlen(num);

+	if (l > width)

+		l = width;

+	x += 2 + CHAR_WIDTH*(width - l);

+

+	ptr = num;

+	while (*ptr && l)

+	{

+		if (*ptr == '-')

+			frame = STAT_MINUS;

+		else

+			frame = *ptr -'0';

+

+		re.DrawPic (x,y,sb_nums[color][frame]);

+		x += CHAR_WIDTH;

+		ptr++;

+		l--;

+	}

+}

+

+

+/*

+===============

+SCR_TouchPics

+

+Allows rendering code to cache all needed sbar graphics

+===============

+*/

+void SCR_TouchPics (void)

+{

+	int		i, j;

+

+	for (i=0 ; i<2 ; i++)

+		for (j=0 ; j<11 ; j++)

+			re.RegisterPic (sb_nums[i][j]);

+

+	if (crosshair->value)

+	{

+		if (crosshair->value > 3 || crosshair->value < 0)

+			crosshair->value = 3;

+

+		Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));

+		re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);

+		if (!crosshair_width)

+			crosshair_pic[0] = 0;

+	}

+}

+

+/*

+================

+SCR_ExecuteLayoutString 

+

+================

+*/

+void SCR_ExecuteLayoutString (char *s)

+{

+	int		x, y;

+	int		value;

+	char	*token;

+	int		width;

+	int		index;

+	clientinfo_t	*ci;

+

+	if (cls.state != ca_active || !cl.refresh_prepped)

+		return;

+

+	if (!s[0])

+		return;

+

+	x = 0;

+	y = 0;

+	width = 3;

+

+	while (s)

+	{

+		token = COM_Parse (&s);

+		if (!strcmp(token, "xl"))

+		{

+			token = COM_Parse (&s);

+			x = atoi(token);

+			continue;

+		}

+		if (!strcmp(token, "xr"))

+		{

+			token = COM_Parse (&s);

+			x = viddef.width + atoi(token);

+			continue;

+		}

+		if (!strcmp(token, "xv"))

+		{

+			token = COM_Parse (&s);

+			x = viddef.width/2 - 160 + atoi(token);

+			continue;

+		}

+

+		if (!strcmp(token, "yt"))

+		{

+			token = COM_Parse (&s);

+			y = atoi(token);

+			continue;

+		}

+		if (!strcmp(token, "yb"))

+		{

+			token = COM_Parse (&s);

+			y = viddef.height + atoi(token);

+			continue;

+		}

+		if (!strcmp(token, "yv"))

+		{

+			token = COM_Parse (&s);

+			y = viddef.height/2 - 120 + atoi(token);

+			continue;

+		}

+

+		if (!strcmp(token, "pic"))

+		{	// draw a pic from a stat number

+			token = COM_Parse (&s);

+			value = cl.frame.playerstate.stats[atoi(token)];

+			if (value >= MAX_IMAGES)

+				Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");

+			if (cl.configstrings[CS_IMAGES+value])

+			{

+				SCR_AddDirtyPoint (x, y);

+				SCR_AddDirtyPoint (x+23, y+23);

+				re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);

+			}

+			continue;

+		}

+

+		if (!strcmp(token, "client"))

+		{	// draw a deathmatch client block

+			int		score, ping, time;

+

+			token = COM_Parse (&s);

+			x = viddef.width/2 - 160 + atoi(token);

+			token = COM_Parse (&s);

+			y = viddef.height/2 - 120 + atoi(token);

+			SCR_AddDirtyPoint (x, y);

+			SCR_AddDirtyPoint (x+159, y+31);

+

+			token = COM_Parse (&s);

+			value = atoi(token);

+			if (value >= MAX_CLIENTS || value < 0)

+				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");

+			ci = &cl.clientinfo[value];

+

+			token = COM_Parse (&s);

+			score = atoi(token);

+

+			token = COM_Parse (&s);

+			ping = atoi(token);

+

+			token = COM_Parse (&s);

+			time = atoi(token);

+

+			DrawAltString (x+32, y, ci->name);

+			DrawString (x+32, y+8,  "Score: ");

+			DrawAltString (x+32+7*8, y+8,  va("%i", score));

+			DrawString (x+32, y+16, va("Ping:  %i", ping));

+			DrawString (x+32, y+24, va("Time:  %i", time));

+

+			if (!ci->icon)

+				ci = &cl.baseclientinfo;

+			re.DrawPic (x, y, ci->iconname);

+			continue;

+		}

+

+		if (!strcmp(token, "ctf"))

+		{	// draw a ctf client block

+			int		score, ping;

+			char	block[80];

+

+			token = COM_Parse (&s);

+			x = viddef.width/2 - 160 + atoi(token);

+			token = COM_Parse (&s);

+			y = viddef.height/2 - 120 + atoi(token);

+			SCR_AddDirtyPoint (x, y);

+			SCR_AddDirtyPoint (x+159, y+31);

+

+			token = COM_Parse (&s);

+			value = atoi(token);

+			if (value >= MAX_CLIENTS || value < 0)

+				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");

+			ci = &cl.clientinfo[value];

+

+			token = COM_Parse (&s);

+			score = atoi(token);

+

+			token = COM_Parse (&s);

+			ping = atoi(token);

+			if (ping > 999)

+				ping = 999;

+

+			sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);

+

+			if (value == cl.playernum)

+				DrawAltString (x, y, block);

+			else

+				DrawString (x, y, block);

+			continue;

+		}

+

+		if (!strcmp(token, "picn"))

+		{	// draw a pic from a name

+			token = COM_Parse (&s);

+			SCR_AddDirtyPoint (x, y);

+			SCR_AddDirtyPoint (x+23, y+23);

+			re.DrawPic (x, y, token);

+			continue;

+		}

+

+		if (!strcmp(token, "num"))

+		{	// draw a number

+			token = COM_Parse (&s);

+			width = atoi(token);

+			token = COM_Parse (&s);

+			value = cl.frame.playerstate.stats[atoi(token)];

+			SCR_DrawField (x, y, 0, width, value);

+			continue;

+		}

+

+		if (!strcmp(token, "hnum"))

+		{	// health number

+			int		color;

+

+			width = 3;

+			value = cl.frame.playerstate.stats[STAT_HEALTH];

+			if (value > 25)

+				color = 0;	// green

+			else if (value > 0)

+				color = (cl.frame.serverframe>>2) & 1;		// flash

+			else

+				color = 1;

+

+			if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)

+				re.DrawPic (x, y, "field_3");

+

+			SCR_DrawField (x, y, color, width, value);

+			continue;

+		}

+

+		if (!strcmp(token, "anum"))

+		{	// ammo number

+			int		color;

+

+			width = 3;

+			value = cl.frame.playerstate.stats[STAT_AMMO];

+			if (value > 5)

+				color = 0;	// green

+			else if (value >= 0)

+				color = (cl.frame.serverframe>>2) & 1;		// flash

+			else

+				continue;	// negative number = don't show

+

+			if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)

+				re.DrawPic (x, y, "field_3");

+

+			SCR_DrawField (x, y, color, width, value);

+			continue;

+		}

+

+		if (!strcmp(token, "rnum"))

+		{	// armor number

+			int		color;

+

+			width = 3;

+			value = cl.frame.playerstate.stats[STAT_ARMOR];

+			if (value < 1)

+				continue;

+

+			color = 0;	// green

+

+			if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)

+				re.DrawPic (x, y, "field_3");

+

+			SCR_DrawField (x, y, color, width, value);

+			continue;

+		}

+

+

+		if (!strcmp(token, "stat_string"))

+		{

+			token = COM_Parse (&s);

+			index = atoi(token);

+			if (index < 0 || index >= MAX_CONFIGSTRINGS)

+				Com_Error (ERR_DROP, "Bad stat_string index");

+			index = cl.frame.playerstate.stats[index];

+			if (index < 0 || index >= MAX_CONFIGSTRINGS)

+				Com_Error (ERR_DROP, "Bad stat_string index");

+			DrawString (x, y, cl.configstrings[index]);

+			continue;

+		}

+

+		if (!strcmp(token, "cstring"))

+		{

+			token = COM_Parse (&s);

+			DrawHUDString (token, x, y, 320, 0);

+			continue;

+		}

+

+		if (!strcmp(token, "string"))

+		{

+			token = COM_Parse (&s);

+			DrawString (x, y, token);

+			continue;

+		}

+

+		if (!strcmp(token, "cstring2"))

+		{

+			token = COM_Parse (&s);

+			DrawHUDString (token, x, y, 320,0x80);

+			continue;

+		}

+

+		if (!strcmp(token, "string2"))

+		{

+			token = COM_Parse (&s);

+			DrawAltString (x, y, token);

+			continue;

+		}

+

+		if (!strcmp(token, "if"))

+		{	// draw a number

+			token = COM_Parse (&s);

+			value = cl.frame.playerstate.stats[atoi(token)];

+			if (!value)

+			{	// skip to endif

+				while (s && strcmp(token, "endif") )

+				{

+					token = COM_Parse (&s);

+				}

+			}

+

+			continue;

+		}

+

+

+	}

+}

+

+

+/*

+================

+SCR_DrawStats

+

+The status bar is a small layout program that

+is based on the stats array

+================

+*/

+void SCR_DrawStats (void)

+{

+	SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);

+}

+

+

+/*

+================

+SCR_DrawLayout

+

+================

+*/

+#define	STAT_LAYOUTS		13

+

+void SCR_DrawLayout (void)

+{

+	if (!cl.frame.playerstate.stats[STAT_LAYOUTS])

+		return;

+	SCR_ExecuteLayoutString (cl.layout);

+}

+

+//=======================================================

+

+/*

+==================

+SCR_UpdateScreen

+

+This is called every frame, and can also be called explicitly to flush

+text to the screen.

+==================

+*/

+void SCR_UpdateScreen (void)

+{

+	int numframes;

+	int i;

+	float separation[2] = { 0, 0 };

+

+	// if the screen is disabled (loading plaque is up, or vid mode changing)

+	// do nothing at all

+	if (cls.disable_screen)

+	{

+		if (Sys_Milliseconds() - cls.disable_screen > 120000)

+		{

+			cls.disable_screen = 0;

+			Com_Printf ("Loading plaque timed out.\n");

+		}

+		return;

+	}

+

+	if (!scr_initialized || !con.initialized)

+		return;				// not initialized yet

+

+	/*

+	** range check cl_camera_separation so we don't inadvertently fry someone's

+	** brain

+	*/

+	if ( cl_stereo_separation->value > 10.0 )

+		Cvar_SetValue( "cl_stereo_separation", 10.0 );

+	else if ( cl_stereo_separation->value < 0 )

+		Cvar_SetValue( "cl_stereo_separation", 0.0 );

+

+	if ( !cl_stereo->value )

+		Cvar_SetValue( "cl_stereo", 1 );

+

+	numframes = 2;

+	separation[0] = -cl_stereo_separation->value / 2.0;

+	separation[1] =  cl_stereo_separation->value / 2.0;

+

+/*

+	if ( cl_stereo->value )

+	{

+		numframes = 2;

+		separation[0] = -cl_stereo_separation->value / 2.0;

+		separation[1] =  cl_stereo_separation->value / 2.0;

+	}		

+	else

+	{

+		separation[0] = 0;

+		separation[1] = 0;

+		numframes = 1;

+	}

+*/

+

+	for ( i = 0; i < numframes; i++ )

+	{

+		re.BeginFrame( separation[i] );

+

+		if (scr_draw_loading == 2)

+		{	//  loading plaque over black screen

+			int		w, h;

+

+			re.CinematicSetPalette(NULL);

+			scr_draw_loading = false;

+			re.DrawGetPicSize (&w, &h, "loading");

+			re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");

+//			re.EndFrame();

+//			return;

+		} 

+		// if a cinematic is supposed to be running, handle menus

+		// and console specially

+		else if (cl.cinematictime > 0)

+		{

+			if (cls.key_dest == key_menu)

+			{

+				if (cl.cinematicpalette_active)

+				{

+					re.CinematicSetPalette(NULL);

+					cl.cinematicpalette_active = false;

+				}

+				M_Draw ();

+//				re.EndFrame();

+//				return;

+			}

+			else if (cls.key_dest == key_console)

+			{

+				if (cl.cinematicpalette_active)

+				{

+					re.CinematicSetPalette(NULL);

+					cl.cinematicpalette_active = false;

+				}

+				SCR_DrawConsole ();

+//				re.EndFrame();

+//				return;

+			}

+			else

+			{

+				SCR_DrawCinematic();

+//				re.EndFrame();

+//				return;

+			}

+		}

+		else 

+		{

+

+			// make sure the game palette is active

+			if (cl.cinematicpalette_active)

+			{

+				re.CinematicSetPalette(NULL);

+				cl.cinematicpalette_active = false;

+			}

+

+			// do 3D refresh drawing, and then update the screen

+			SCR_CalcVrect ();

+

+			// clear any dirty part of the background

+			SCR_TileClear ();

+

+			V_RenderView ( separation[i] );

+

+			SCR_DrawStats ();

+			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)

+				SCR_DrawLayout ();

+			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)

+				CL_DrawInventory ();

+

+			SCR_DrawNet ();

+			SCR_CheckDrawCenterString ();

+

+			if (scr_timegraph->value)

+				SCR_DebugGraph (cls.frametime*300, 0);

+

+			if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)

+				SCR_DrawDebugGraph ();

+

+			SCR_DrawPause ();

+

+			SCR_DrawConsole ();

+

+			M_Draw ();

+

+			SCR_DrawLoading ();

+		}

+	}

+	re.EndFrame();

+}

diff -ur quake2-r0.0.8/src/linux/rw_x11.c quake2-devel-r0.0.8/src/linux/rw_x11.c
--- quake2-r0.0.8/src/linux/rw_x11.c	Sat Jan  5 02:35:22 2002
+++ quake2-devel-r0.0.8/src/linux/rw_x11.c	Wed Jan 30 15:03:18 2002
@@ -1,1339 +1,1445 @@
-/*
-Copyright (C) 1997-2001 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-*/
-/*
-** RW_X11.C
-**
-** This file contains ALL Linux specific stuff having to do with the
-** software refresh.  When a port is being made the following functions
-** must be implemented by the port:
-**
-** SWimp_EndFrame
-** SWimp_Init
-** SWimp_InitGraphics
-** SWimp_SetPalette
-** SWimp_Shutdown
-** SWimp_SwitchFullscreen
-*/
-
-#include <ctype.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/mman.h>
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xatom.h>
-#include <X11/keysym.h>
-#include <X11/extensions/XShm.h>
-#include <X11/extensions/xf86dga.h>
-
-#include "../ref_soft/r_local.h"
-#include "../client/keys.h"
-#include "../linux/rw_linux.h"
-
-/*****************************************************************************/
-
-static qboolean			doShm;
-static Display			*dpy;
-static Colormap			x_cmap;
-static Window			win;
-static GC				x_gc;
-static Visual			*x_vis;
-static XVisualInfo		*x_visinfo;
-static int win_x, win_y;
-static Atom wmDeleteWindow;
-
-#define KEY_MASK (KeyPressMask | KeyReleaseMask)
-#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
-		    PointerMotionMask | ButtonMotionMask )
-#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask | ExposureMask )
-
-static int				x_shmeventtype;
-//static XShmSegmentInfo	x_shminfo;
-
-static qboolean			oktodraw = false;
-static qboolean			ignorefirst = false;
-static qboolean			exposureflag = false;
-static qboolean			X11_active = false;
-
-int XShmQueryExtension(Display *);
-int XShmGetEventBase(Display *);
-
-int current_framebuffer;
-static XImage			*x_framebuffer[2] = { 0, 0 };
-static XShmSegmentInfo	x_shminfo[2];
-
-int config_notify=0;
-int config_notify_width;
-int config_notify_height;
-						      
-typedef unsigned short PIXEL16;
-typedef unsigned long PIXEL24;
-static PIXEL16 st2d_8to16table[256];
-static PIXEL24 st2d_8to24table[256];
-static int shiftmask_fl=0;
-static long r_shift,g_shift,b_shift;
-static unsigned long r_mask,g_mask,b_mask;
-
-void shiftmask_init(void)
-{
-    unsigned int x;
-    r_mask=x_vis->red_mask;
-    g_mask=x_vis->green_mask;
-    b_mask=x_vis->blue_mask;
-    for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;
-    for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;
-    for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;
-    shiftmask_fl=1;
-}
-
-PIXEL16 xlib_rgb16(int r,int g,int b)
-{
-    PIXEL16 p;
-    if(shiftmask_fl==0) shiftmask_init();
-    p=0;
-
-    if(r_shift>0) {
-        p=(r<<(r_shift))&r_mask;
-    } else if(r_shift<0) {
-        p=(r>>(-r_shift))&r_mask;
-    } else p|=(r&r_mask);
-
-    if(g_shift>0) {
-        p|=(g<<(g_shift))&g_mask;
-    } else if(g_shift<0) {
-        p|=(g>>(-g_shift))&g_mask;
-    } else p|=(g&g_mask);
-
-    if(b_shift>0) {
-        p|=(b<<(b_shift))&b_mask;
-    } else if(b_shift<0) {
-        p|=(b>>(-b_shift))&b_mask;
-    } else p|=(b&b_mask);
-
-    return p;
-}
-
-PIXEL24 xlib_rgb24(int r,int g,int b)
-{
-    PIXEL24 p;
-    if(shiftmask_fl==0) shiftmask_init();
-    p=0;
-
-    if(r_shift>0) {
-        p=(r<<(r_shift))&r_mask;
-    } else if(r_shift<0) {
-        p=(r>>(-r_shift))&r_mask;
-    } else p|=(r&r_mask);
-
-    if(g_shift>0) {
-        p|=(g<<(g_shift))&g_mask;
-    } else if(g_shift<0) {
-        p|=(g>>(-g_shift))&g_mask;
-    } else p|=(g&g_mask);
-
-    if(b_shift>0) {
-        p|=(b<<(b_shift))&b_mask;
-    } else if(b_shift<0) {
-        p|=(b>>(-b_shift))&b_mask;
-    } else p|=(b&b_mask);
-
-    return p;
-}
-
-
-void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
-{
-	int yi;
-	byte *src;
-	PIXEL16 *dest;
-	register int count, n;
-
-	if( (x<0)||(y<0) )return;
-
-	for (yi = y; yi < (y+height); yi++) {
-		src = (byte *)&framebuf->data [yi * framebuf->bytes_per_line];
-
-		// Duff's Device
-		count = width;
-		n = (count + 7) / 8;
-		dest = ((PIXEL16 *)src) + x+width - 1;
-		src += x+width - 1;
-
-		switch (count % 8) {
-		case 0:	do {	*dest-- = st2d_8to16table[*src--];
-		case 7:			*dest-- = st2d_8to16table[*src--];
-		case 6:			*dest-- = st2d_8to16table[*src--];
-		case 5:			*dest-- = st2d_8to16table[*src--];
-		case 4:			*dest-- = st2d_8to16table[*src--];
-		case 3:			*dest-- = st2d_8to16table[*src--];
-		case 2:			*dest-- = st2d_8to16table[*src--];
-		case 1:			*dest-- = st2d_8to16table[*src--];
-				} while (--n > 0);
-		}
-
-//		for(xi = (x+width-1); xi >= x; xi--) {
-//			dest[xi] = st2d_8to16table[src[xi]];
-//		}
-	}
-}
-
-void st3_fixup( XImage *framebuf, int x, int y, int width, int height)
-{
-	int yi;
-	byte *src;
-	PIXEL24 *dest;
-	register int count, n;
-
-	if( (x<0)||(y<0) )return;
-
-	for (yi = y; yi < (y+height); yi++) {
-		src = (byte *)&framebuf->data [yi * framebuf->bytes_per_line];
-
-		// Duff's Device
-		count = width;
-		n = (count + 7) / 8;
-		dest = ((PIXEL24 *)src) + x+width - 1;
-		src += x+width - 1;
-
-		switch (count % 8) {
-		case 0:	do {	*dest-- = st2d_8to24table[*src--];
-		case 7:			*dest-- = st2d_8to24table[*src--];
-		case 6:			*dest-- = st2d_8to24table[*src--];
-		case 5:			*dest-- = st2d_8to24table[*src--];
-		case 4:			*dest-- = st2d_8to24table[*src--];
-		case 3:			*dest-- = st2d_8to24table[*src--];
-		case 2:			*dest-- = st2d_8to24table[*src--];
-		case 1:			*dest-- = st2d_8to24table[*src--];
-				} while (--n > 0);
-		}
-
-//		for(xi = (x+width-1); xi >= x; xi--) {
-//			dest[xi] = st2d_8to16table[src[xi]];
-//		}
-	}
-}
-
-
-
-// Console variables that we need to access from this module
-
-/*****************************************************************************/
-/* MOUSE                                                                     */
-/*****************************************************************************/
-
-// this is inside the renderer shared lib, so these are called from vid_so
-
-static qboolean	mouse_avail;
-static int		mouse_buttonstate;
-static int		mouse_oldbuttonstate;
-static int		old_mouse_x, old_mouse_y;
-static int		mx, my;
-
-static qboolean mouse_active = false;
-static qboolean dgamouse = false;
-
-static cvar_t	*m_filter;
-static cvar_t	*in_mouse;
-static cvar_t	*in_dgamouse;
-
-static cvar_t	*vid_xpos;			// X coordinate of window position
-static cvar_t	*vid_ypos;			// Y coordinate of window position
-
-static qboolean	mlooking;
-
-// state struct passed in Init
-static in_state_t	*in_state;
-
-static cvar_t *sensitivity;
-static cvar_t *lookstrafe;
-static cvar_t *m_side;
-static cvar_t *m_yaw;
-static cvar_t *m_pitch;
-static cvar_t *m_forward;
-static cvar_t *freelook;
-
-static void Force_CenterView_f (void)
-{
-	in_state->viewangles[PITCH] = 0;
-}
-
-static void RW_IN_MLookDown (void) 
-{ 
-	mlooking = true; 
-}
-
-static void RW_IN_MLookUp (void) 
-{
-	mlooking = false;
-	in_state->IN_CenterView_fp ();
-}
-
-void RW_IN_Init(in_state_t *in_state_p)
-{
-	in_state = in_state_p;
-
-	// mouse variables
-	m_filter = ri.Cvar_Get ("m_filter", "0", 0);
-	in_mouse = ri.Cvar_Get ("in_mouse", "0", CVAR_ARCHIVE);
-	in_dgamouse = ri.Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE);
-	freelook = ri.Cvar_Get( "freelook", "0", 0 );
-	lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);
-	sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);
-	m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);
-	m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);
-	m_forward = ri.Cvar_Get ("m_forward", "1", 0);
-	m_side = ri.Cvar_Get ("m_side", "0.8", 0);
-
-	ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);
-	ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);
-
-	ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);
-
-	mouse_avail = true;
-}
-
-
-/*
-===========
-IN_Commands
-===========
-*/
-void RW_IN_Commands (void)
-{
-	int i;
-   
-	if (!mouse_avail) 
-		return;
-   
-	for (i=0 ; i<3 ; i++) {
-		if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
-			in_state->Key_Event_fp (K_MOUSE1 + i, true);
-
-		if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
-			in_state->Key_Event_fp (K_MOUSE1 + i, false);
-	}
-	mouse_oldbuttonstate = mouse_buttonstate;
-}
-
-/*
-===========
-IN_Move
-===========
-*/
-void RW_IN_Move (usercmd_t *cmd)
-{
-	if (!mouse_avail)
-		return;
-   
-	if (m_filter->value)
-	{
-		mx = (mx + old_mouse_x) * 0.5;
-		my = (my + old_mouse_y) * 0.5;
-	}
-
-	old_mouse_x = mx;
-	old_mouse_y = my;
-
-	mx *= sensitivity->value;
-	my *= sensitivity->value;
-
-// add mouse X/Y movement to cmd
-	if ( (*in_state->in_strafe_state & 1) || 
-		(lookstrafe->value && mlooking ))
-		cmd->sidemove += m_side->value * mx;
-	else
-		in_state->viewangles[YAW] -= m_yaw->value * mx;
-
-	if ( (mlooking || freelook->value) && 
-		!(*in_state->in_strafe_state & 1))
-	{
-		in_state->viewangles[PITCH] += m_pitch->value * my;
-	}
-	else
-	{
-		cmd->forwardmove -= m_forward->value * my;
-	}
-	mx = my = 0;
-}
-
-// ========================================================================
-// makes a null cursor
-// ========================================================================
-
-static Cursor CreateNullCursor(Display *display, Window root)
-{
-    Pixmap cursormask; 
-    XGCValues xgc;
-    GC gc;
-    XColor dummycolour;
-    Cursor cursor;
-
-    cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
-    xgc.function = GXclear;
-    gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
-    XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
-    dummycolour.pixel = 0;
-    dummycolour.red = 0;
-    dummycolour.flags = 04;
-    cursor = XCreatePixmapCursor(display, cursormask, cursormask,
-          &dummycolour,&dummycolour, 0,0);
-    XFreePixmap(display,cursormask);
-    XFreeGC(display,gc);
-    return cursor;
-}
-
-static void install_grabs(void)
-{
-
-// inviso cursor
-	XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
-
-	XGrabPointer(dpy, win,
-				 True,
-				 0,
-				 GrabModeAsync, GrabModeAsync,
-				 win,
-				 None,
-				 CurrentTime);
-
-	if (in_dgamouse->value) {
-		int MajorVersion, MinorVersion;
-
-		if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) { 
-			// unable to query, probalby not supported
-			ri.Con_Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
-			ri.Cvar_Set( "in_dgamouse", "0" );
-		} else {
-			dgamouse = true;
-			XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
-			XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
-		}
-	} else
-		XWarpPointer(dpy, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2);
-
-	XGrabKeyboard(dpy, win,
-				  False,
-				  GrabModeAsync, GrabModeAsync,
-				  CurrentTime);
-
-	mouse_active = true;
-
-	ignorefirst = true;
-
-//	XSync(dpy, True);
-}
-
-static void uninstall_grabs(void)
-{
-	if (!dpy || !win)
-		return;
-
-	if (dgamouse) {
-		dgamouse = false;
-		XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
-	}
-
-	XUngrabPointer(dpy, CurrentTime);
-	XUngrabKeyboard(dpy, CurrentTime);
-
-// inviso cursor
-	XUndefineCursor(dpy, win);
-
-	mouse_active = false;
-}
-
-static void IN_DeactivateMouse( void ) 
-{
-	if (!mouse_avail || !dpy || !win)
-		return;
-
-	if (mouse_active) {
-		uninstall_grabs();
-		mouse_active = false;
-	}
-}
-
-static void IN_ActivateMouse( void ) 
-{
-	if (!mouse_avail || !dpy || !win)
-		return;
-
-	if (!mouse_active) {
-		mx = my = 0; // don't spazz
-		install_grabs();
-		mouse_active = true;
-	}
-}
-
-void RW_IN_Frame (void)
-{
-}
-
-void RW_IN_Activate(qboolean active)
-{
-	if (active)
-		IN_ActivateMouse();
-	else
-		IN_DeactivateMouse();
-}
-
-void RW_IN_Shutdown(void)
-{
-	if (mouse_avail) {
-		RW_IN_Activate (false);
-		
-		mouse_avail = false;
-		
-		ri.Cmd_RemoveCommand ("+mlook");
-		ri.Cmd_RemoveCommand ("-mlook");
-		ri.Cmd_RemoveCommand ("force_centerview");
-	}
-}
-
-/*****************************************************************************/
-
-void ResetFrameBuffer(void)
-{
-	int mem;
-	int pwidth;
-
-	if (x_framebuffer[0])
-	{
-		free(x_framebuffer[0]->data);
-		free(x_framebuffer[0]);
-	}
-
-// alloc an extra line in case we want to wrap, and allocate the z-buffer
-	pwidth = x_visinfo->depth / 8;
-	if (pwidth == 3) pwidth = 4;
-	mem = ((vid.width*pwidth+7)&~7) * vid.height;
-
-	x_framebuffer[0] = XCreateImage(dpy,
-		x_vis,
-		x_visinfo->depth,
-		ZPixmap,
-		0,
-		malloc(mem),
-		vid.width, vid.height,
-		32,
-		0);
-
-	if (!x_framebuffer[0])
-		Sys_Error("VID: XCreateImage failed\n");
-
-	vid.buffer = (byte*) (x_framebuffer[0]);
-}
-
-void ResetSharedFrameBuffers(void)
-{
-	int size;
-	int key;
-	int minsize = getpagesize();
-	int frm;
-
-	for (frm=0 ; frm<2 ; frm++)
-	{
-	// free up old frame buffer memory
-		if (x_framebuffer[frm])
-		{
-			XShmDetach(dpy, &x_shminfo[frm]);
-			free(x_framebuffer[frm]);
-			shmdt(x_shminfo[frm].shmaddr);
-		}
-
-	// create the image
-		x_framebuffer[frm] = XShmCreateImage(	dpy,
-						x_vis,
-						x_visinfo->depth,
-						ZPixmap,
-						0,
-						&x_shminfo[frm],
-						vid.width,
-						vid.height );
-
-	// grab shared memory
-
-		size = x_framebuffer[frm]->bytes_per_line
-			* x_framebuffer[frm]->height;
-		if (size < minsize)
-			Sys_Error("VID: Window must use at least %d bytes\n", minsize);
-
-		key = random();
-		x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
-		if (x_shminfo[frm].shmid==-1)
-			Sys_Error("VID: Could not get any shared memory\n");
-
-		// attach to the shared memory segment
-		x_shminfo[frm].shmaddr =
-			(void *) shmat(x_shminfo[frm].shmid, 0, 0);
-
-		ri.Con_Printf(PRINT_DEVELOPER, "MITSHM shared memory (id=%d, addr=0x%lx)\n", 
-			x_shminfo[frm].shmid, (long) x_shminfo[frm].shmaddr);
-
-		x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
-
-	// get the X server to attach to it
-
-		if (!XShmAttach(dpy, &x_shminfo[frm]))
-			Sys_Error("VID: XShmAttach() failed\n");
-		XSync(dpy, 0);
-		shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
-	}
-
-}
-
-// ========================================================================
-// Tragic death handler
-// ========================================================================
-
-void TragicDeath(int signal_num)
-{
-//	XAutoRepeatOn(dpy);
-	XCloseDisplay(dpy);
-	Sys_Error("This death brought to you by the number %d\n", signal_num);
-}
-
-int XLateKey(XKeyEvent *ev)
-{
-
-	int key;
-	char buf[64];
-	KeySym keysym;
-
-	key = 0;
-
-	XLookupString(ev, buf, sizeof buf, &keysym, 0);
-
-	switch(keysym)
-	{
-		case XK_KP_Page_Up:	 key = K_KP_PGUP; break;
-		case XK_Page_Up:	 key = K_PGUP; break;
-
-		case XK_KP_Page_Down: key = K_KP_PGDN; break;
-		case XK_Page_Down:	 key = K_PGDN; break;
-
-		case XK_KP_Home: key = K_KP_HOME; break;
-		case XK_Home:	 key = K_HOME; break;
-
-		case XK_KP_End:  key = K_KP_END; break;
-		case XK_End:	 key = K_END; break;
-
-		case XK_KP_Left: key = K_KP_LEFTARROW; break;
-		case XK_Left:	 key = K_LEFTARROW; break;
-
-		case XK_KP_Right: key = K_KP_RIGHTARROW; break;
-		case XK_Right:	key = K_RIGHTARROW;		break;
-
-		case XK_KP_Down: key = K_KP_DOWNARROW; break;
-		case XK_Down:	 key = K_DOWNARROW; break;
-
-		case XK_KP_Up:   key = K_KP_UPARROW; break;
-		case XK_Up:		 key = K_UPARROW;	 break;
-
-		case XK_Escape: key = K_ESCAPE;		break;
-
-		case XK_KP_Enter: key = K_KP_ENTER;	break;
-		case XK_Return: key = K_ENTER;		 break;
-
-		case XK_Tab:		key = K_TAB;			 break;
-
-		case XK_F1:		 key = K_F1;				break;
-
-		case XK_F2:		 key = K_F2;				break;
-
-		case XK_F3:		 key = K_F3;				break;
-
-		case XK_F4:		 key = K_F4;				break;
-
-		case XK_F5:		 key = K_F5;				break;
-
-		case XK_F6:		 key = K_F6;				break;
-
-		case XK_F7:		 key = K_F7;				break;
-
-		case XK_F8:		 key = K_F8;				break;
-
-		case XK_F9:		 key = K_F9;				break;
-
-		case XK_F10:		key = K_F10;			 break;
-
-		case XK_F11:		key = K_F11;			 break;
-
-		case XK_F12:		key = K_F12;			 break;
-
-		case XK_BackSpace: key = K_BACKSPACE; break;
-
-		case XK_KP_Delete: key = K_KP_DEL; break;
-		case XK_Delete: key = K_DEL; break;
-
-		case XK_Pause:	key = K_PAUSE;		 break;
-
-		case XK_Shift_L:
-		case XK_Shift_R:	key = K_SHIFT;		break;
-
-		case XK_Execute: 
-		case XK_Control_L: 
-		case XK_Control_R:	key = K_CTRL;		 break;
-
-		case XK_Alt_L:	
-		case XK_Meta_L: 
-		case XK_Alt_R:	
-		case XK_Meta_R: key = K_ALT;			break;
-
-		case XK_KP_Begin: key = K_KP_5;	break;
-
-		case XK_Insert:key = K_INS; break;
-		case XK_KP_Insert: key = K_KP_INS; break;
-
-		case XK_KP_Multiply: key = '*'; break;
-		case XK_KP_Add:  key = K_KP_PLUS; break;
-		case XK_KP_Subtract: key = K_KP_MINUS; break;
-		case XK_KP_Divide: key = K_KP_SLASH; break;
-
-#if 0
-		case 0x021: key = '1';break;/* [!] */
-		case 0x040: key = '2';break;/* [@] */
-		case 0x023: key = '3';break;/* [#] */
-		case 0x024: key = '4';break;/* [$] */
-		case 0x025: key = '5';break;/* [%] */
-		case 0x05e: key = '6';break;/* [^] */
-		case 0x026: key = '7';break;/* [&] */
-		case 0x02a: key = '8';break;/* [*] */
-		case 0x028: key = '9';;break;/* [(] */
-		case 0x029: key = '0';break;/* [)] */
-		case 0x05f: key = '-';break;/* [_] */
-		case 0x02b: key = '=';break;/* [+] */
-		case 0x07c: key = '\'';break;/* [|] */
-		case 0x07d: key = '[';break;/* [}] */
-		case 0x07b: key = ']';break;/* [{] */
-		case 0x022: key = '\'';break;/* ["] */
-		case 0x03a: key = ';';break;/* [:] */
-		case 0x03f: key = '/';break;/* [?] */
-		case 0x03e: key = '.';break;/* [>] */
-		case 0x03c: key = ',';break;/* [<] */
-#endif
-
-		default:
-			key = *(unsigned char*)buf;
-			if (key >= 'A' && key <= 'Z')
-				key = key - 'A' + 'a';
-			if (key >= 1 && key <= 26) /* ctrl+alpha */
-				key = key + 'a' - 1;
-			break;
-	} 
-
-	return key;
-}
-
-void HandleEvents(void)
-{
-	XEvent event;
-	int b;
-	qboolean dowarp = false;
-	int mwx = vid.width/2;
-	int mwy = vid.height/2;
-   
-	while (XPending(dpy)) {
-
-		XNextEvent(dpy, &event);
-
-		switch(event.type) {
-		case KeyPress:
-		case KeyRelease:
-			if (in_state && in_state->Key_Event_fp)
-				in_state->Key_Event_fp (XLateKey(&event.xkey), event.type == KeyPress);
-			break;
-
-		case MotionNotify:
-			if (ignorefirst) {
-				ignorefirst = false;
-				break;
-			}
-
-			if (mouse_active) {
-				if (dgamouse) {
-					mx += (event.xmotion.x + win_x) * 2;
-					my += (event.xmotion.y + win_y) * 2;
-				} 
-				else 
-				{
-					mx += ((int)event.xmotion.x - mwx) * 2;
-					my += ((int)event.xmotion.y - mwy) * 2;
-					mwx = event.xmotion.x;
-					mwy = event.xmotion.y;
-
-					if (mx || my)
-						dowarp = true;
-				}
-			}
-			break;
-
-
-			break;
-
-		case ButtonPress:
-			b=-1;
-			if (event.xbutton.button == 1)
-				b = 0;
-			else if (event.xbutton.button == 2)
-				b = 2;
-			else if (event.xbutton.button == 3)
-				b = 1;
-			if (b>=0)
-				mouse_buttonstate |= 1<<b;
-			break;
-
-		case ButtonRelease:
-			b=-1;
-			if (event.xbutton.button == 1)
-				b = 0;
-			else if (event.xbutton.button == 2)
-				b = 2;
-			else if (event.xbutton.button == 3)
-				b = 1;
-			if (b>=0)
-				mouse_buttonstate &= ~(1<<b);
-			break;
-		
-		case CreateNotify :
-			ri.Cvar_Set( "vid_xpos", va("%d", event.xcreatewindow.x));
-			ri.Cvar_Set( "vid_ypos", va("%d", event.xcreatewindow.y));
-			vid_xpos->modified = false;
-			vid_ypos->modified = false;
-			win_x = event.xcreatewindow.x;
-			win_y = event.xcreatewindow.y;
-			break;
-
-		case ConfigureNotify :
-			ri.Cvar_Set( "vid_xpos", va("%d", event.xcreatewindow.x));
-			ri.Cvar_Set( "vid_ypos", va("%d", event.xcreatewindow.y));
-			vid_xpos->modified = false;
-			vid_ypos->modified = false;
-			win_x = event.xconfigure.x;
-			win_y = event.xconfigure.y;
-			config_notify_width = event.xconfigure.width;
-			config_notify_height = event.xconfigure.height;
-			if (config_notify_width != vid.width ||
-				config_notify_height != vid.height)
-				XMoveResizeWindow(dpy, win, win_x, win_y, vid.width, vid.height);
-			config_notify = 1;
-			break;
-
-		case ClientMessage:
-			if (event.xclient.data.l[0] == wmDeleteWindow)
-				ri.Cmd_ExecuteText(EXEC_NOW, "quit");
-			break;
-		default:
-			if (doShm && event.type == x_shmeventtype)
-				oktodraw = true;
-			if (event.type == Expose && !event.xexpose.count)
-				exposureflag = true;
-		}
-	}
-	   
-	if (dowarp) {
-		/* move the mouse to the window center again */
-		XWarpPointer(dpy,None,win,0,0,0,0, vid.width/2,vid.height/2);
-	}
-}
-
-/*****************************************************************************/
-
-/*
-** SWimp_Init
-**
-** This routine is responsible for initializing the implementation
-** specific stuff in a software rendering subsystem.
-*/
-int SWimp_Init( void *hInstance, void *wndProc )
-{
-
-	vid_xpos = ri.Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
-	vid_ypos = ri.Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
-
-// open the display
-	dpy = XOpenDisplay(NULL);
-	if (!dpy)
-	{
-		if (getenv("DISPLAY"))
-			Sys_Error("VID: Could not open display [%s]\n",
-				getenv("DISPLAY"));
-		else
-			Sys_Error("VID: Could not open local display\n");
-	}
-
-// catch signals so i can turn on auto-repeat
-
-	{
-		struct sigaction sa;
-		sigaction(SIGINT, 0, &sa);
-		sa.sa_handler = TragicDeath;
-		sigaction(SIGINT, &sa, 0);
-		sigaction(SIGTERM, &sa, 0);
-	}
-
-	return true;
-}
-
-/*
-** SWimp_InitGraphics
-**
-** This initializes the software refresh's implementation specific
-** graphics subsystem.  In the case of Windows it creates DIB or
-** DDRAW surfaces.
-**
-** The necessary width and height parameters are grabbed from
-** vid.width and vid.height.
-*/
-static qboolean SWimp_InitGraphics( qboolean fullscreen )
-{
-	int i;
-	XVisualInfo template;
-	int num_visuals;
-	int template_mask;
-	Window root;
-	//int pnum;
-
-	srandom(getpid());
-
-	// free resources in use
-	SWimp_Shutdown ();
-
-	// let the sound and input subsystems know about the new window
-	ri.Vid_NewWindow (vid.width, vid.height);
-
-//	XAutoRepeatOff(dpy);
-
-// for debugging only
-	XSynchronize(dpy, True);
-
-// check for command-line window size
-	template_mask = 0;
-
-#if 0
-// specify a visual id
-	if ((pnum=COM_CheckParm("-visualid")))
-	{
-		if (pnum >= com_argc-1)
-			Sys_Error("VID: -visualid <id#>\n");
-		template.visualid = Q_atoi(com_argv[pnum+1]);
-		template_mask = VisualIDMask;
-	}
-
-// If not specified, use default visual
-	else
-#endif
-	{
-		int screen;
-		screen = XDefaultScreen(dpy);
-		template.visualid =
-			XVisualIDFromVisual(XDefaultVisual(dpy, screen));
-		template_mask = VisualIDMask;
-	}
-
-// pick a visual- warn if more than one was available
-	x_visinfo = XGetVisualInfo(dpy, template_mask, &template, &num_visuals);
-	if (num_visuals > 1)
-	{
-		printf("Found more than one visual id at depth %d:\n", template.depth);
-		for (i=0 ; i<num_visuals ; i++)
-			printf("	-visualid %d\n", (int)(x_visinfo[i].visualid));
-	}
-	else if (num_visuals == 0)
-	{
-		if (template_mask == VisualIDMask)
-			Sys_Error("VID: Bad visual id %d\n", template.visualid);
-		else
-			Sys_Error("VID: No visuals at depth %d\n", template.depth);
-	}
-
-#if 0
-	printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
-	printf("	screen %d\n", x_visinfo->screen);
-	printf("	red_mask 0x%x\n", (int)(x_visinfo->red_mask));
-	printf("	green_mask 0x%x\n", (int)(x_visinfo->green_mask));
-	printf("	blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
-	printf("	colormap_size %d\n", x_visinfo->colormap_size);
-	printf("	bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
-#endif
-
-	x_vis = x_visinfo->visual;
-	root = XRootWindow(dpy, x_visinfo->screen);
-
-// setup attributes for main window
-	{
-	   int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
-	   XSetWindowAttributes attribs;
-	   XSizeHints *sizehints;
-	   XWMHints *wmhints;
-	   Colormap tmpcmap;
-	   
-	   tmpcmap = XCreateColormap(dpy, root, x_vis, AllocNone);
-	   
-	   attribs.event_mask = X_MASK;
-	   attribs.border_pixel = 0;
-	   attribs.colormap = tmpcmap;
-
-// create the main window
-		win = XCreateWindow(dpy, root, (int)vid_xpos->value, (int)vid_ypos->value, 
-			vid.width, vid.height, 0, x_visinfo->depth, InputOutput, x_vis, 
-			attribmask, &attribs );
-		
-		sizehints = XAllocSizeHints();
-		if (sizehints) {
-			sizehints->min_width = vid.width;
-			sizehints->min_height = vid.height;
-			sizehints->max_width = vid.width;
-			sizehints->max_height = vid.height;
-			sizehints->base_width = vid.width;
-			sizehints->base_height = vid.height;
-			
-			sizehints->flags = PMinSize | PMaxSize | PBaseSize;
-		}
-		
-		wmhints = XAllocWMHints();
-		if (wmhints) {
-			#include "q2icon.xbm"
-
-			Pixmap icon_pixmap, icon_mask;
-			unsigned long fg, bg;
-			int i;
-		
-			fg = BlackPixel(dpy, x_visinfo->screen);
-			bg = WhitePixel(dpy, x_visinfo->screen);
-			icon_pixmap = XCreatePixmapFromBitmapData(dpy, win, (char *)q2icon_bits, q2icon_width, q2icon_height, fg, bg, x_visinfo->depth);
-			for (i = 0; i < sizeof(q2icon_bits); i++)
-				q2icon_bits[i] = ~q2icon_bits[i];
-			icon_mask = XCreatePixmapFromBitmapData(dpy, win, (char *)q2icon_bits, q2icon_width, q2icon_height, bg, fg, x_visinfo->depth); 
-		
-			wmhints->flags = IconPixmapHint|IconMaskHint;
-			wmhints->icon_pixmap = icon_pixmap;
-			wmhints->icon_mask = icon_mask;
-		}
-
-		XSetWMProperties(dpy, win, NULL, NULL, NULL, 0,
-			sizehints, wmhints, None);
-		if (sizehints)
-			XFree(sizehints);
-		if (wmhints)
-			XFree(wmhints);
-			
-		XStoreName(dpy, win, "Quake II");
-
-		wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
-		XSetWMProtocols(dpy, win, &wmDeleteWindow, 1);
-		
-		if (x_visinfo->class != TrueColor)
-			XFreeColormap(dpy, tmpcmap);
-	}
-
-	if (x_visinfo->depth == 8)
-	{
-	// create and upload the palette
-		if (x_visinfo->class == PseudoColor)
-		{
-			x_cmap = XCreateColormap(dpy, win, x_vis, AllocAll);
-			XSetWindowColormap(dpy, win, x_cmap);
-		}
-
-	}
-
-// create the GC
-	{
-		XGCValues xgcvalues;
-		int valuemask = GCGraphicsExposures;
-		xgcvalues.graphics_exposures = False;
-		x_gc = XCreateGC(dpy, win, valuemask, &xgcvalues );
-	}
-
-	XMapWindow(dpy, win);
-	XMoveWindow(dpy, win, (int)vid_xpos->value, (int)vid_ypos->value);
-
-// wait for first exposure event
-	{
-		exposureflag = false;
-		do
-		{
-			HandleEvents();
-		} while (!exposureflag);
-	}
-// now safe to draw
-
-// even if MITSHM is available, make sure it's a local connection
-	if (XShmQueryExtension(dpy))
-	{
-		char *displayname;
-		doShm = true;
-		displayname = (char *) getenv("DISPLAY");
-		if (displayname)
-		{
-			char *dptr = strdup(displayname);
-			char *d;
-			
-			d = dptr;
-			while (*d && (*d != ':')) d++;
-			if (*d) *d = 0;
-			if (!(!strcasecmp(displayname, "unix") || !*displayname))
-				doShm = false;
-			
-			free(dptr);
-		}
-	}
-
-	if (doShm)
-	{
-		x_shmeventtype = XShmGetEventBase(dpy) + ShmCompletion;
-		ResetSharedFrameBuffers();
-	}
-	else
-		ResetFrameBuffer();
-
-	current_framebuffer = 0;
-	vid.rowbytes = x_framebuffer[0]->bytes_per_line;
-	vid.buffer = (byte *)x_framebuffer[0]->data;
-
-//	XSynchronize(dpy, False);
-
-	X11_active = true;
-
-	return true;
-}
-
-/*
-** SWimp_EndFrame
-**
-** This does an implementation specific copy from the backbuffer to the
-** front buffer.  In the Win32 case it uses BitBlt or BltFast depending
-** on whether we're using DIB sections/GDI or DDRAW.
-*/
-void SWimp_EndFrame (void)
-{
-// if the window changes dimension, skip this frame
-#if 0
-	if (config_notify)
-	{
-		fprintf(stderr, "config notify\n");
-		config_notify = 0;
-		vid.width = config_notify_width & ~7;
-		vid.height = config_notify_height;
-		if (doShm)
-			ResetSharedFrameBuffers();
-		else
-			ResetFrameBuffer();
-		vid.rowbytes = x_framebuffer[0]->bytes_per_line;
-		vid.buffer = x_framebuffer[current_framebuffer]->data;
-		vid.recalc_refdef = 1;				// force a surface cache flush
-		Con_CheckResize();
-		Con_Clear_f();
-		return;
-	}
-#endif
-
-	if (doShm)
-	{
-		if (x_visinfo->depth == 16)
-			st2_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
-		else if (x_visinfo->depth == 24)
-			st3_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
-		if (!XShmPutImage(dpy, win, x_gc,
-			x_framebuffer[current_framebuffer], 0, 0, 0, 0, vid.width, vid.height, True))
-			Sys_Error("VID_Update: XShmPutImage failed\n");
-		oktodraw = false;
-		while (!oktodraw) 
-			HandleEvents();
-		current_framebuffer = !current_framebuffer;
-		vid.buffer = (byte *)x_framebuffer[current_framebuffer]->data;
-		XSync(dpy, False);
-	}
-	else
-	{
-		if (x_visinfo->depth == 16)
-			st2_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
-		else if (x_visinfo->depth == 24)
-			st3_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
-		XPutImage(dpy, win, x_gc, x_framebuffer[0], 0, 0, 0, 0, vid.width, vid.height);
-		XSync(dpy, False);
-	}
-}
-
-/*
-** SWimp_SetMode
-*/
-rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
-{
-	rserr_t retval = rserr_ok;
-
-	ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
-
-	if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
-	{
-		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
-		return rserr_invalid_mode;
-	}
-
-	ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight);
-
-	if ( !SWimp_InitGraphics( false ) ) {
-		// failed to set a valid mode in windowed mode
-		return rserr_invalid_mode;
-	}
-
-	R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
-
-	return retval;
-}
-
-/*
-** SWimp_SetPalette
-**
-** System specific palette setting routine.  A NULL palette means
-** to use the existing palette.  The palette is expected to be in
-** a padded 4-byte xRGB format.
-*/
-void SWimp_SetPalette( const unsigned char *palette )
-{
-	int i;
-	XColor colors[256];
-
-	if (!X11_active)
-		return;
-
-    if ( !palette )
-        palette = ( const unsigned char * ) sw_state.currentpalette;
- 
-	for(i=0;i<256;i++) {
-		st2d_8to16table[i]= xlib_rgb16(palette[i*4], palette[i*4+1],palette[i*4+2]);
-		st2d_8to24table[i]= xlib_rgb24(palette[i*4], palette[i*4+1],palette[i*4+2]);
-	}
-
-	if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
-	{
-		for (i=0 ; i<256 ; i++)
-		{
-			colors[i].pixel = i;
-			colors[i].flags = DoRed|DoGreen|DoBlue;
-			colors[i].red = palette[i*4] * 257;
-			colors[i].green = palette[i*4+1] * 257;
-			colors[i].blue = palette[i*4+2] * 257;
-		}
-		XStoreColors(dpy, x_cmap, colors, 256);
-	}
-}
-
-/*
-** SWimp_Shutdown
-**
-** System specific graphics subsystem shutdown routine.  Destroys
-** DIBs or DDRAW surfaces as appropriate.
-*/
-void SWimp_Shutdown( void )
-{
-	int i;
-
-	if (!X11_active)
-		return;
-
-	if (doShm) {
-		for (i = 0; i < 2; i++)
-			if (x_framebuffer[i]) {
-				XShmDetach(dpy, &x_shminfo[i]);
-				free(x_framebuffer[i]);
-				shmdt(x_shminfo[i].shmaddr);
-				x_framebuffer[i] = NULL;
-			}
-	} else if (x_framebuffer[0]) {
-		free(x_framebuffer[0]->data);
-		free(x_framebuffer[0]);
-		x_framebuffer[0] = NULL;
-	}
-
-	XDestroyWindow(	dpy, win );
-
-	win = 0;
-	
-//	XAutoRepeatOn(dpy);
-//	XCloseDisplay(dpy);
-
-	X11_active = false;
-}
-
-/*
-** SWimp_AppActivate
-*/
-void SWimp_AppActivate( qboolean active )
-{
-}
-
-//===============================================================================
-
-/*
-================
-Sys_MakeCodeWriteable
-================
-*/
-void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
-{
-
-	int r;
-	unsigned long addr;
-	int psize = getpagesize();
-
-	addr = (startaddr & ~(psize-1)) - psize;
-
-//	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
-//			addr, startaddr+length, length);
-
-	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
-
-	if (r < 0)
-    		Sys_Error("Protection change failed\n");
-
-}
-
-/*****************************************************************************/
-/* KEYBOARD                                                                  */
-/*****************************************************************************/
-
-Key_Event_fp_t Key_Event_fp;
-
-void KBD_Init(Key_Event_fp_t fp)
-{
-	Key_Event_fp = fp;
-}
-
-void KBD_Update(void)
-{
-// get events from x server
-	HandleEvents();
-}
-
-void KBD_Close(void)
-{
-}
-
-
+/*

+Copyright (C) 1997-2001 Id Software, Inc.

+

+This program is free software; you can redistribute it and/or

+modify it under the terms of the GNU General Public License

+as published by the Free Software Foundation; either version 2

+of the License, or (at your option) any later version.

+

+This program is distributed in the hope that it will be useful,

+but WITHOUT ANY WARRANTY; without even the implied warranty of

+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

+

+See the GNU General Public License for more details.

+

+You should have received a copy of the GNU General Public License

+along with this program; if not, write to the Free Software

+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

+

+*/

+/*

+** RW_X11.C

+**

+** This file contains ALL Linux specific stuff having to do with the

+** software refresh.  When a port is being made the following functions

+** must be implemented by the port:

+**

+** SWimp_EndFrame

+** SWimp_Init

+** SWimp_InitGraphics

+** SWimp_SetPalette

+** SWimp_Shutdown

+** SWimp_SwitchFullscreen

+*/

+

+#include <ctype.h>

+#include <sys/time.h>

+#include <sys/types.h>

+#include <unistd.h>

+#include <signal.h>

+#include <stdlib.h>

+#include <stdio.h>

+#include <string.h>

+#include <sys/ipc.h>

+#include <sys/shm.h>

+

+#include <X11/Xlib.h>

+#include <X11/Xutil.h>

+#include <X11/Xatom.h>

+#include <X11/keysym.h>

+#include <X11/extensions/XShm.h>

+#include <X11/extensions/xf86dga.h>

+

+#include "../ref_soft/r_local.h"

+#include "../client/keys.h"

+#include "../linux/rw_linux.h"

+

+/*****************************************************************************/

+

+static qboolean			doShm;

+static Display			*dpy;

+static Colormap			x_cmap;

+static Window			win;

+static GC				x_gc;

+static Visual			*x_vis;

+static XVisualInfo		*x_visinfo;

+static int win_x, win_y;

+

+#define KEY_MASK (KeyPressMask | KeyReleaseMask)

+#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \

+		    PointerMotionMask | ButtonMotionMask )

+#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask | ExposureMask )

+

+static int				x_shmeventtype;

+//static XShmSegmentInfo	x_shminfo;

+

+static qboolean			oktodraw = false;

+static qboolean			ignorefirst = false;

+static qboolean			exposureflag = false;

+static qboolean			X11_active = false;

+

+int XShmQueryExtension(Display *);

+int XShmGetEventBase(Display *);

+

+int current_framebuffer;

+static XImage			*x_framebuffer[2] = { 0, 0 };

+static XShmSegmentInfo	x_shminfo[2];

+

+int config_notify=0;

+int config_notify_width;

+int config_notify_height;

+						      

+typedef unsigned short PIXEL16;

+typedef unsigned long PIXEL24;

+static PIXEL16 st2d_8to16table[256];

+static PIXEL16 st2d_8to16table_s[2][256];

+static PIXEL24 st2d_8to24table[256];

+static PIXEL24 st2d_8to24table_s[2][256];

+static int shiftmask_fl=0;

+static long r_shift,g_shift,b_shift;

+static unsigned long r_mask,g_mask,b_mask;

+

+void shiftmask_init(void)

+{

+    unsigned int x;

+    r_mask=x_vis->red_mask;

+    g_mask=x_vis->green_mask;

+    b_mask=x_vis->blue_mask;

+    for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;

+    for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;

+    for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;

+    shiftmask_fl=1;

+}

+

+PIXEL16 xlib_rgb16(int r,int g,int b)

+{

+    PIXEL16 p;

+    if(shiftmask_fl==0) shiftmask_init();

+    p=0;

+

+    if(r_shift>0) {

+        p=(r<<(r_shift))&r_mask;

+    } else if(r_shift<0) {

+        p=(r>>(-r_shift))&r_mask;

+    } else p|=(r&r_mask);

+

+    if(g_shift>0) {

+        p|=(g<<(g_shift))&g_mask;

+    } else if(g_shift<0) {

+        p|=(g>>(-g_shift))&g_mask;

+    } else p|=(g&g_mask);

+

+    if(b_shift>0) {

+        p|=(b<<(b_shift))&b_mask;

+    } else if(b_shift<0) {

+        p|=(b>>(-b_shift))&b_mask;

+    } else p|=(b&b_mask);

+

+    return p;

+}

+

+PIXEL24 xlib_rgb24(int r,int g,int b)

+{

+    PIXEL24 p;

+    if(shiftmask_fl==0) shiftmask_init();

+    p=0;

+

+    if(r_shift>0) {

+        p=(r<<(r_shift))&r_mask;

+    } else if(r_shift<0) {

+        p=(r>>(-r_shift))&r_mask;

+    } else p|=(r&r_mask);

+

+    if(g_shift>0) {

+        p|=(g<<(g_shift))&g_mask;

+    } else if(g_shift<0) {

+        p|=(g>>(-g_shift))&g_mask;

+    } else p|=(g&g_mask);

+

+    if(b_shift>0) {

+        p|=(b<<(b_shift))&b_mask;

+    } else if(b_shift<0) {

+        p|=(b>>(-b_shift))&b_mask;

+    } else p|=(b&b_mask);

+

+    return p;

+}

+

+

+void st2_fixup( XImage *framebuf, int x, int y, int width, int height)

+{

+	int xi,yi;

+	unsigned char *src;

+	PIXEL16 *dest;

+	register int count, n;

+

+	if( (x<0)||(y<0) )return;

+

+	for (yi = y; yi < (y+height); yi++) {

+		src = &framebuf->data [yi * framebuf->bytes_per_line];

+

+		// Duff's Device

+		count = width;

+		n = (count + 7) / 8;

+		dest = ((PIXEL16 *)src) + x+width - 1;

+		src += x+width - 1;

+

+		switch (count % 8) {

+		case 0:	do {	*dest-- = st2d_8to16table[*src--];

+		case 7:			*dest-- = st2d_8to16table[*src--];

+		case 6:			*dest-- = st2d_8to16table[*src--];

+		case 5:			*dest-- = st2d_8to16table[*src--];

+		case 4:			*dest-- = st2d_8to16table[*src--];

+		case 3:			*dest-- = st2d_8to16table[*src--];

+		case 2:			*dest-- = st2d_8to16table[*src--];

+		case 1:			*dest-- = st2d_8to16table[*src--];

+				} while (--n > 0);

+		}

+

+//		for(xi = (x+width-1); xi >= x; xi--) {

+//			dest[xi] = st2d_8to16table[src[xi]];

+//		}

+	}

+}

+

+void st2_fixup_stereo( XImage *framebuf1, XImage *framebuf2, int x, int y, int width, int height)

+{

+	int xi,yi;

+	unsigned char *src;

+	PIXEL16 *dest;

+	register int count, n;

+

+	if( (x<0)||(y<0) )return;

+

+	for (yi = y; yi < (y+height); yi++) {

+		src = &framebuf1->data [yi * framebuf1->bytes_per_line];

+

+		// Duff's Device

+		count = width;

+		n = (count + 7) / 8;

+		dest = ((PIXEL16 *)src) + x+width - 1;

+		src += x+width - 1;

+

+		switch (count % 8) {

+		case 0:	do {	*dest-- = st2d_8to16table_s[0][*src--];

+		case 7:			*dest-- = st2d_8to16table_s[0][*src--];

+		case 6:			*dest-- = st2d_8to16table_s[0][*src--];

+		case 5:			*dest-- = st2d_8to16table_s[0][*src--];

+		case 4:			*dest-- = st2d_8to16table_s[0][*src--];

+		case 3:			*dest-- = st2d_8to16table_s[0][*src--];

+		case 2:			*dest-- = st2d_8to16table_s[0][*src--];

+		case 1:			*dest-- = st2d_8to16table_s[0][*src--];

+				} while (--n > 0);

+		}

+

+//		for(xi = (x+width-1); xi >= x; xi--) {

+//			dest[xi] = st2d_8to16table[src[xi]];

+//		}

+	}

+

+	for (yi = y; yi < (y+height); yi++) {

+		src = &framebuf1->data [yi * framebuf1->bytes_per_line];

+

+		// Duff's Device

+		count = width;

+		n = (count + 7) / 8;

+		dest = ((PIXEL16 *)src) + x+width - 1;

+		src = &framebuf2->data [yi * framebuf2->bytes_per_line];

+		src += x+width - 1;

+

+		switch (count % 8) {

+		case 0:	do {	*dest-- += st2d_8to16table_s[1][*src--];

+		case 7:			*dest-- += st2d_8to16table_s[1][*src--];

+		case 6:			*dest-- += st2d_8to16table_s[1][*src--];

+		case 5:			*dest-- += st2d_8to16table_s[1][*src--];

+		case 4:			*dest-- += st2d_8to16table_s[1][*src--];

+		case 3:			*dest-- += st2d_8to16table_s[1][*src--];

+		case 2:			*dest-- += st2d_8to16table_s[1][*src--];

+		case 1:			*dest-- += st2d_8to16table_s[1][*src--];

+				} while (--n > 0);

+		}

+

+//		for(xi = (x+width-1); xi >= x; xi--) {

+//			dest[xi] = st2d_8to16table[src[xi]];

+//		}

+	}

+}

+

+void st3_fixup( XImage *framebuf, int x, int y, int width, int height)

+{

+	int xi,yi;

+	unsigned char *src;

+	PIXEL24 *dest;

+	register int count, n;

+

+	if( (x<0)||(y<0) )return;

+

+	for (yi = y; yi < (y+height); yi++) {

+		src = &framebuf->data [yi * framebuf->bytes_per_line];

+

+		// Duff's Device

+		count = width;

+		n = (count + 7) / 8;

+		dest = ((PIXEL24 *)src) + x+width - 1;

+		src += x+width - 1;

+

+		switch (count % 8) {

+		case 0:	do {	*dest-- = st2d_8to24table[*src--];

+		case 7:			*dest-- = st2d_8to24table[*src--];

+		case 6:			*dest-- = st2d_8to24table[*src--];

+		case 5:			*dest-- = st2d_8to24table[*src--];

+		case 4:			*dest-- = st2d_8to24table[*src--];

+		case 3:			*dest-- = st2d_8to24table[*src--];

+		case 2:			*dest-- = st2d_8to24table[*src--];

+		case 1:			*dest-- = st2d_8to24table[*src--];

+				} while (--n > 0);

+		}

+

+//		for(xi = (x+width-1); xi >= x; xi--) {

+//			dest[xi] = st2d_8to16table[src[xi]];

+//		}

+	}

+}

+

+void st3_fixup_stereo( XImage *framebuf1, XImage *framebuf2, int x, int y, int width, int height)

+{

+	int xi,yi;

+	unsigned char *src;

+	PIXEL24 *dest;

+	register int count, n;

+

+	if( (x<0)||(y<0) )return;

+

+	for (yi = y; yi < (y+height); yi++) {

+		src = &framebuf1->data [yi * framebuf1->bytes_per_line];

+

+		// Duff's Device

+		count = width;

+		n = (count + 7) / 8;

+		dest = ((PIXEL24 *)src) + x+width - 1;

+		src += x+width - 1;

+

+		switch (count % 8) {

+		case 0:	do {	*dest-- = st2d_8to24table_s[0][*src--];

+		case 7:			*dest-- = st2d_8to24table_s[0][*src--];

+		case 6:			*dest-- = st2d_8to24table_s[0][*src--];

+		case 5:			*dest-- = st2d_8to24table_s[0][*src--];

+		case 4:			*dest-- = st2d_8to24table_s[0][*src--];

+		case 3:			*dest-- = st2d_8to24table_s[0][*src--];

+		case 2:			*dest-- = st2d_8to24table_s[0][*src--];

+		case 1:			*dest-- = st2d_8to24table_s[0][*src--];

+				} while (--n > 0);

+		}

+

+//		for(xi = (x+width-1); xi >= x; xi--) {

+//			dest[xi] = st2d_8to16table[src[xi]];

+//		}

+	}

+

+	for (yi = y; yi < (y+height); yi++) {

+		src = &framebuf1->data [yi * framebuf1->bytes_per_line];

+

+		// Duff's Device

+		count = width;

+		n = (count + 7) / 8;

+		dest = ((PIXEL24 *)src) + x+width - 1;

+		src = &framebuf2->data [yi * framebuf2->bytes_per_line];

+		src += x+width - 1;

+

+		switch (count % 8) {

+		case 0:	do {	*dest-- += st2d_8to24table_s[1][*src--];

+		case 7:			*dest-- += st2d_8to24table_s[1][*src--];

+		case 6:			*dest-- += st2d_8to24table_s[1][*src--];

+		case 5:			*dest-- += st2d_8to24table_s[1][*src--];

+		case 4:			*dest-- += st2d_8to24table_s[1][*src--];

+		case 3:			*dest-- += st2d_8to24table_s[1][*src--];

+		case 2:			*dest-- += st2d_8to24table_s[1][*src--];

+		case 1:			*dest-- += st2d_8to24table_s[1][*src--];

+				} while (--n > 0);

+		}

+

+//		for(xi = (x+width-1); xi >= x; xi--) {

+//			dest[xi] = st2d_8to16table[src[xi]];

+//		}

+	}

+}

+

+

+

+// Console variables that we need to access from this module

+

+/*****************************************************************************/

+/* MOUSE                                                                     */

+/*****************************************************************************/

+

+// this is inside the renderer shared lib, so these are called from vid_so

+

+static qboolean	mouse_avail;

+static int		mouse_buttonstate;

+static int		mouse_oldbuttonstate;

+static int		old_mouse_x, old_mouse_y;

+static int		mx, my;

+

+static qboolean mouse_active = false;

+static qboolean dgamouse = false;

+

+static cvar_t	*m_filter;

+static cvar_t	*in_mouse;

+static cvar_t	*in_dgamouse;

+

+static cvar_t	*vid_xpos;			// X coordinate of window position

+static cvar_t	*vid_ypos;			// Y coordinate of window position

+

+static qboolean	mlooking;

+

+// state struct passed in Init

+static in_state_t	*in_state;

+

+static cvar_t *sensitivity;

+static cvar_t *lookstrafe;

+static cvar_t *m_side;

+static cvar_t *m_yaw;

+static cvar_t *m_pitch;

+static cvar_t *m_forward;

+static cvar_t *freelook;

+

+static void Force_CenterView_f (void)

+{

+	in_state->viewangles[PITCH] = 0;

+}

+

+static void RW_IN_MLookDown (void) 

+{ 

+	mlooking = true; 

+}

+

+static void RW_IN_MLookUp (void) 

+{

+	mlooking = false;

+	in_state->IN_CenterView_fp ();

+}

+

+void RW_IN_Init(in_state_t *in_state_p)

+{

+	int mtype;

+	int i;

+

+	in_state = in_state_p;

+

+	// mouse variables

+	m_filter = ri.Cvar_Get ("m_filter", "0", 0);

+    in_mouse = ri.Cvar_Get ("in_mouse", "0", CVAR_ARCHIVE);

+    in_dgamouse = ri.Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE);

+	freelook = ri.Cvar_Get( "freelook", "0", 0 );

+	lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);

+	sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);

+	m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);

+	m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);

+	m_forward = ri.Cvar_Get ("m_forward", "1", 0);

+	m_side = ri.Cvar_Get ("m_side", "0.8", 0);

+

+	ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);

+	ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);

+

+	ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);

+

+	mouse_avail = true;

+}

+

+void RW_IN_Shutdown(void)

+{

+	mouse_avail = false;

+}

+

+/*

+===========

+IN_Commands

+===========

+*/

+void RW_IN_Commands (void)

+{

+	int i;

+   

+	if (!mouse_avail) 

+		return;

+   

+	for (i=0 ; i<3 ; i++) {

+		if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )

+			in_state->Key_Event_fp (K_MOUSE1 + i, true);

+

+		if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )

+			in_state->Key_Event_fp (K_MOUSE1 + i, false);

+	}

+	mouse_oldbuttonstate = mouse_buttonstate;

+}

+

+/*

+===========

+IN_Move

+===========

+*/

+void RW_IN_Move (usercmd_t *cmd)

+{

+	if (!mouse_avail)

+		return;

+   

+	if (m_filter->value)

+	{

+		mx = (mx + old_mouse_x) * 0.5;

+		my = (my + old_mouse_y) * 0.5;

+	}

+

+	old_mouse_x = mx;

+	old_mouse_y = my;

+

+	mx *= sensitivity->value;

+	my *= sensitivity->value;

+

+// add mouse X/Y movement to cmd

+	if ( (*in_state->in_strafe_state & 1) || 

+		(lookstrafe->value && mlooking ))

+		cmd->sidemove += m_side->value * mx;

+	else

+		in_state->viewangles[YAW] -= m_yaw->value * mx;

+

+	if ( (mlooking || freelook->value) && 

+		!(*in_state->in_strafe_state & 1))

+	{

+		in_state->viewangles[PITCH] += m_pitch->value * my;

+	}

+	else

+	{

+		cmd->forwardmove -= m_forward->value * my;

+	}

+	mx = my = 0;

+}

+

+// ========================================================================

+// makes a null cursor

+// ========================================================================

+

+static Cursor CreateNullCursor(Display *display, Window root)

+{

+    Pixmap cursormask; 

+    XGCValues xgc;

+    GC gc;

+    XColor dummycolour;

+    Cursor cursor;

+

+    cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);

+    xgc.function = GXclear;

+    gc =  XCreateGC(display, cursormask, GCFunction, &xgc);

+    XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);

+    dummycolour.pixel = 0;

+    dummycolour.red = 0;

+    dummycolour.flags = 04;

+    cursor = XCreatePixmapCursor(display, cursormask, cursormask,

+          &dummycolour,&dummycolour, 0,0);

+    XFreePixmap(display,cursormask);

+    XFreeGC(display,gc);

+    return cursor;

+}

+

+static void install_grabs(void)

+{

+

+// inviso cursor

+	XDefineCursor(dpy, win, CreateNullCursor(dpy, win));

+

+	XGrabPointer(dpy, win,

+				 True,

+				 0,

+				 GrabModeAsync, GrabModeAsync,

+				 win,

+				 None,

+				 CurrentTime);

+

+	if (in_dgamouse->value) {

+		int MajorVersion, MinorVersion;

+

+		if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) { 

+			// unable to query, probalby not supported

+			ri.Con_Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );

+			ri.Cvar_Set( "in_dgamouse", "0" );

+		} else {

+			dgamouse = true;

+			XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);

+			XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);

+		}

+	} else

+		XWarpPointer(dpy, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2);

+

+	XGrabKeyboard(dpy, win,

+				  False,

+				  GrabModeAsync, GrabModeAsync,

+				  CurrentTime);

+

+	mouse_active = true;

+

+	ignorefirst = true;

+

+//	XSync(dpy, True);

+}

+

+static void uninstall_grabs(void)

+{

+	if (!dpy || !win)

+		return;

+

+	if (dgamouse) {

+		dgamouse = false;

+		XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);

+	}

+

+	XUngrabPointer(dpy, CurrentTime);

+	XUngrabKeyboard(dpy, CurrentTime);

+

+// inviso cursor

+	XUndefineCursor(dpy, win);

+

+	mouse_active = false;

+}

+

+static void IN_DeactivateMouse( void ) 

+{

+	if (!mouse_avail || !dpy || !win)

+		return;

+

+	if (mouse_active) {

+		uninstall_grabs();

+		mouse_active = false;

+	}

+}

+

+static void IN_ActivateMouse( void ) 

+{

+	if (!mouse_avail || !dpy || !win)

+		return;

+

+	if (!mouse_active) {

+		mx = my = 0; // don't spazz

+		install_grabs();

+		mouse_active = true;

+	}

+}

+

+void RW_IN_Frame (void)

+{

+}

+

+void RW_IN_Activate(qboolean active)

+{

+	if (active)

+		IN_ActivateMouse();

+	else

+		IN_DeactivateMouse ();

+}

+

+/*****************************************************************************/

+

+void ResetFrameBuffer(void)

+{

+	int mem;

+	int pwidth;

+

+	if (x_framebuffer[0])

+	{

+		free(x_framebuffer[0]->data);

+		free(x_framebuffer[0]);

+	}

+

+	if (x_framebuffer[1])

+	{

+		free(x_framebuffer[1]->data);

+		free(x_framebuffer[1]);

+	}

+

+// alloc an extra line in case we want to wrap, and allocate the z-buffer

+	pwidth = x_visinfo->depth / 8;

+	if (pwidth == 3) pwidth = 4;

+	mem = ((vid.width*pwidth+7)&~7) * vid.height;

+

+	x_framebuffer[0] = XCreateImage(dpy,

+		x_vis,

+		x_visinfo->depth,

+		ZPixmap,

+		0,

+		malloc(mem),

+		vid.width, vid.height,

+		32,

+		0);

+

+	if (!x_framebuffer[0])

+		Sys_Error("VID: XCreateImage failed\n");

+

+	x_framebuffer[1] = XCreateImage(dpy,

+		x_vis,

+		x_visinfo->depth,

+		ZPixmap,

+		0,

+		malloc(mem),

+		vid.width, vid.height,

+		32,

+		0);

+

+	if (!x_framebuffer[1])

+		Sys_Error("VID: XCreateImage failed\n");

+

+	vid.buffer = (byte*) (x_framebuffer[0]->data);

+}

+

+void ResetSharedFrameBuffers(void)

+{

+	int size;

+	int key;

+	int minsize = getpagesize();

+	int frm;

+

+	for (frm=0 ; frm<2 ; frm++)

+	{

+	// free up old frame buffer memory

+		if (x_framebuffer[frm])

+		{

+			XShmDetach(dpy, &x_shminfo[frm]);

+			free(x_framebuffer[frm]);

+			shmdt(x_shminfo[frm].shmaddr);

+		}

+

+	// create the image

+		x_framebuffer[frm] = XShmCreateImage(	dpy,

+						x_vis,

+						x_visinfo->depth,

+						ZPixmap,

+						0,

+						&x_shminfo[frm],

+						vid.width,

+						vid.height );

+

+	// grab shared memory

+

+		size = x_framebuffer[frm]->bytes_per_line

+			* x_framebuffer[frm]->height;

+		if (size < minsize)

+			Sys_Error("VID: Window must use at least %d bytes\n", minsize);

+

+		key = random();

+		x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);

+		if (x_shminfo[frm].shmid==-1)

+			Sys_Error("VID: Could not get any shared memory\n");

+

+		// attach to the shared memory segment

+		x_shminfo[frm].shmaddr =

+			(void *) shmat(x_shminfo[frm].shmid, 0, 0);

+

+		ri.Con_Printf(PRINT_DEVELOPER, "MITSHM shared memory (id=%d, addr=0x%lx)\n", 

+			x_shminfo[frm].shmid, (long) x_shminfo[frm].shmaddr);

+

+		x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;

+

+	// get the X server to attach to it

+

+		if (!XShmAttach(dpy, &x_shminfo[frm]))

+			Sys_Error("VID: XShmAttach() failed\n");

+		XSync(dpy, 0);

+		shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);

+	}

+

+}

+

+// ========================================================================

+// Tragic death handler

+// ========================================================================

+

+void TragicDeath(int signal_num)

+{

+//	XAutoRepeatOn(dpy);

+	XCloseDisplay(dpy);

+	Sys_Error("This death brought to you by the number %d\n", signal_num);

+}

+

+int XLateKey(XKeyEvent *ev)

+{

+

+	int key;

+	char buf[64];

+	KeySym keysym;

+

+	key = 0;

+

+	XLookupString(ev, buf, sizeof buf, &keysym, 0);

+

+	switch(keysym)

+	{

+		case XK_KP_Page_Up:	 key = K_KP_PGUP; break;

+		case XK_Page_Up:	 key = K_PGUP; break;

+

+		case XK_KP_Page_Down: key = K_KP_PGDN; break;

+		case XK_Page_Down:	 key = K_PGDN; break;

+

+		case XK_KP_Home: key = K_KP_HOME; break;

+		case XK_Home:	 key = K_HOME; break;

+

+		case XK_KP_End:  key = K_KP_END; break;

+		case XK_End:	 key = K_END; break;

+

+		case XK_KP_Left: key = K_KP_LEFTARROW; break;

+		case XK_Left:	 key = K_LEFTARROW; break;

+

+		case XK_KP_Right: key = K_KP_RIGHTARROW; break;

+		case XK_Right:	key = K_RIGHTARROW;		break;

+

+		case XK_KP_Down: key = K_KP_DOWNARROW; break;

+		case XK_Down:	 key = K_DOWNARROW; break;

+

+		case XK_KP_Up:   key = K_KP_UPARROW; break;

+		case XK_Up:		 key = K_UPARROW;	 break;

+

+		case XK_Escape: key = K_ESCAPE;		break;

+

+		case XK_KP_Enter: key = K_KP_ENTER;	break;

+		case XK_Return: key = K_ENTER;		 break;

+

+		case XK_Tab:		key = K_TAB;			 break;

+

+		case XK_F1:		 key = K_F1;				break;

+

+		case XK_F2:		 key = K_F2;				break;

+

+		case XK_F3:		 key = K_F3;				break;

+

+		case XK_F4:		 key = K_F4;				break;

+

+		case XK_F5:		 key = K_F5;				break;

+

+		case XK_F6:		 key = K_F6;				break;

+

+		case XK_F7:		 key = K_F7;				break;

+

+		case XK_F8:		 key = K_F8;				break;

+

+		case XK_F9:		 key = K_F9;				break;

+

+		case XK_F10:		key = K_F10;			 break;

+

+		case XK_F11:		key = K_F11;			 break;

+

+		case XK_F12:		key = K_F12;			 break;

+

+		case XK_BackSpace: key = K_BACKSPACE; break;

+

+		case XK_KP_Delete: key = K_KP_DEL; break;

+		case XK_Delete: key = K_DEL; break;

+

+		case XK_Pause:	key = K_PAUSE;		 break;

+

+		case XK_Shift_L:

+		case XK_Shift_R:	key = K_SHIFT;		break;

+

+		case XK_Execute: 

+		case XK_Control_L: 

+		case XK_Control_R:	key = K_CTRL;		 break;

+

+		case XK_Alt_L:	

+		case XK_Meta_L: 

+		case XK_Alt_R:	

+		case XK_Meta_R: key = K_ALT;			break;

+

+		case XK_KP_Begin: key = K_KP_5;	break;

+

+		case XK_Insert:key = K_INS; break;

+		case XK_KP_Insert: key = K_KP_INS; break;

+

+		case XK_KP_Multiply: key = '*'; break;

+		case XK_KP_Add:  key = K_KP_PLUS; break;

+		case XK_KP_Subtract: key = K_KP_MINUS; break;

+		case XK_KP_Divide: key = K_KP_SLASH; break;

+

+#if 0

+		case 0x021: key = '1';break;/* [!] */

+		case 0x040: key = '2';break;/* [@] */

+		case 0x023: key = '3';break;/* [#] */

+		case 0x024: key = '4';break;/* [$] */

+		case 0x025: key = '5';break;/* [%] */

+		case 0x05e: key = '6';break;/* [^] */

+		case 0x026: key = '7';break;/* [&] */

+		case 0x02a: key = '8';break;/* [*] */

+		case 0x028: key = '9';;break;/* [(] */

+		case 0x029: key = '0';break;/* [)] */

+		case 0x05f: key = '-';break;/* [_] */

+		case 0x02b: key = '=';break;/* [+] */

+		case 0x07c: key = '\'';break;/* [|] */

+		case 0x07d: key = '[';break;/* [}] */

+		case 0x07b: key = ']';break;/* [{] */

+		case 0x022: key = '\'';break;/* ["] */

+		case 0x03a: key = ';';break;/* [:] */

+		case 0x03f: key = '/';break;/* [?] */

+		case 0x03e: key = '.';break;/* [>] */

+		case 0x03c: key = ',';break;/* [<] */

+#endif

+

+		default:

+			key = *(unsigned char*)buf;

+			if (key >= 'A' && key <= 'Z')

+				key = key - 'A' + 'a';

+			break;

+	} 

+

+	return key;

+}

+

+void HandleEvents(void)

+{

+	XEvent event;

+	int b;

+	qboolean dowarp = false;

+	int mwx = vid.width/2;

+	int mwy = vid.height/2;

+   

+	while (XPending(dpy)) {

+

+		XNextEvent(dpy, &event);

+

+		switch(event.type) {

+		case KeyPress:

+		case KeyRelease:

+			if (in_state && in_state->Key_Event_fp)

+				in_state->Key_Event_fp (XLateKey(&event.xkey), event.type == KeyPress);

+			break;

+

+		case MotionNotify:

+			if (ignorefirst) {

+				ignorefirst = false;

+				break;

+			}

+

+			if (mouse_active) {

+				if (dgamouse) {

+					mx += (event.xmotion.x + win_x) * 2;

+					my += (event.xmotion.y + win_y) * 2;

+				} 

+				else 

+				{

+					mx += ((int)event.xmotion.x - mwx) * 2;

+					my += ((int)event.xmotion.y - mwy) * 2;

+					mwx = event.xmotion.x;

+					mwy = event.xmotion.y;

+

+					if (mx || my)

+						dowarp = true;

+				}

+			}

+			break;

+

+

+			break;

+

+		case ButtonPress:

+			b=-1;

+			if (event.xbutton.button == 1)

+				b = 0;

+			else if (event.xbutton.button == 2)

+				b = 2;

+			else if (event.xbutton.button == 3)

+				b = 1;

+			if (b>=0)

+				mouse_buttonstate |= 1<<b;

+			break;

+

+		case ButtonRelease:

+			b=-1;

+			if (event.xbutton.button == 1)

+				b = 0;

+			else if (event.xbutton.button == 2)

+				b = 2;

+			else if (event.xbutton.button == 3)

+				b = 1;

+			if (b>=0)

+				mouse_buttonstate &= ~(1<<b);

+			break;

+		

+		case CreateNotify :

+			ri.Cvar_Set( "vid_xpos", va("%d", event.xcreatewindow.x));

+			ri.Cvar_Set( "vid_ypos", va("%d", event.xcreatewindow.y));

+			vid_xpos->modified = false;

+			vid_ypos->modified = false;

+			win_x = event.xcreatewindow.x;

+			win_y = event.xcreatewindow.y;

+			break;

+

+		case ConfigureNotify :

+			ri.Cvar_Set( "vid_xpos", va("%d", event.xcreatewindow.x));

+			ri.Cvar_Set( "vid_ypos", va("%d", event.xcreatewindow.y));

+			vid_xpos->modified = false;

+			vid_ypos->modified = false;

+			win_x = event.xconfigure.x;

+			win_y = event.xconfigure.y;

+			config_notify_width = event.xconfigure.width;

+			config_notify_height = event.xconfigure.height;

+			if (config_notify_width != vid.width ||

+				config_notify_height != vid.height)

+				XMoveResizeWindow(dpy, win, win_x, win_y, vid.width, vid.height);

+			config_notify = 1;

+			break;

+

+		default:

+			if (doShm && event.type == x_shmeventtype)

+				oktodraw = true;

+			if (event.type == Expose && !event.xexpose.count)

+				exposureflag = true;

+		}

+	}

+	   

+	if (dowarp) {

+		/* move the mouse to the window center again */

+		XWarpPointer(dpy,None,win,0,0,0,0, vid.width/2,vid.height/2);

+	}

+}

+

+/*****************************************************************************/

+

+/*

+** SWimp_Init

+**

+** This routine is responsible for initializing the implementation

+** specific stuff in a software rendering subsystem.

+*/

+int SWimp_Init( void *hInstance, void *wndProc )

+{

+

+	vid_xpos = ri.Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);

+	vid_ypos = ri.Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);

+

+// open the display

+	dpy = XOpenDisplay(0);

+	if (!dpy)

+	{

+		if (getenv("DISPLAY"))

+			Sys_Error("VID: Could not open display [%s]\n",

+				getenv("DISPLAY"));

+		else

+			Sys_Error("VID: Could not open local display\n");

+	}

+

+// catch signals so i can turn on auto-repeat

+

+	{

+		struct sigaction sa;

+		sigaction(SIGINT, 0, &sa);

+		sa.sa_handler = TragicDeath;

+		sigaction(SIGINT, &sa, 0);

+		sigaction(SIGTERM, &sa, 0);

+	}

+

+	return true;

+}

+

+/*

+** SWimp_InitGraphics

+**

+** This initializes the software refresh's implementation specific

+** graphics subsystem.  In the case of Windows it creates DIB or

+** DDRAW surfaces.

+**

+** The necessary width and height parameters are grabbed from

+** vid.width and vid.height.

+*/

+static qboolean SWimp_InitGraphics( qboolean fullscreen )

+{

+	int pnum, i;

+	XVisualInfo template;

+	int num_visuals;

+	int template_mask;

+	Window root;

+

+	srandom(getpid());

+

+	// free resources in use

+	SWimp_Shutdown ();

+

+	// let the sound and input subsystems know about the new window

+	ri.Vid_NewWindow (vid.width, vid.height);

+

+//	XAutoRepeatOff(dpy);

+

+// for debugging only

+	XSynchronize(dpy, True);

+

+// check for command-line window size

+	template_mask = 0;

+

+#if 0

+// specify a visual id

+	if ((pnum=COM_CheckParm("-visualid")))

+	{

+		if (pnum >= com_argc-1)

+			Sys_Error("VID: -visualid <id#>\n");

+		template.visualid = Q_atoi(com_argv[pnum+1]);

+		template_mask = VisualIDMask;

+	}

+

+// If not specified, use default visual

+	else

+#endif

+	{

+		int screen;

+		screen = XDefaultScreen(dpy);

+		template.visualid =

+			XVisualIDFromVisual(XDefaultVisual(dpy, screen));

+		template_mask = VisualIDMask;

+	}

+

+// pick a visual- warn if more than one was available

+	x_visinfo = XGetVisualInfo(dpy, template_mask, &template, &num_visuals);

+	if (num_visuals > 1)

+	{

+		printf("Found more than one visual id at depth %d:\n", template.depth);

+		for (i=0 ; i<num_visuals ; i++)

+			printf("	-visualid %d\n", (int)(x_visinfo[i].visualid));

+	}

+	else if (num_visuals == 0)

+	{

+		if (template_mask == VisualIDMask)

+			Sys_Error("VID: Bad visual id %d\n", template.visualid);

+		else

+			Sys_Error("VID: No visuals at depth %d\n", template.depth);

+	}

+

+#if 0

+	printf("Using visualid %d:\n", (int)(x_visinfo->visualid));

+	printf("	screen %d\n", x_visinfo->screen);

+	printf("	red_mask 0x%x\n", (int)(x_visinfo->red_mask));

+	printf("	green_mask 0x%x\n", (int)(x_visinfo->green_mask));

+	printf("	blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));

+	printf("	colormap_size %d\n", x_visinfo->colormap_size);

+	printf("	bits_per_rgb %d\n", x_visinfo->bits_per_rgb);

+#endif

+

+	x_vis = x_visinfo->visual;

+	root = XRootWindow(dpy, x_visinfo->screen);

+

+// setup attributes for main window

+	{

+	   int attribmask = CWEventMask  | CWColormap | CWBorderPixel;

+	   XSetWindowAttributes attribs;

+	   Colormap tmpcmap;

+	   

+	   tmpcmap = XCreateColormap(dpy, root, x_vis, AllocNone);

+	   

+	   attribs.event_mask = X_MASK;

+	   attribs.border_pixel = 0;

+	   attribs.colormap = tmpcmap;

+

+// create the main window

+		win = XCreateWindow(dpy, root, (int)vid_xpos->value, (int)vid_ypos->value, 

+			vid.width, vid.height, 0, x_visinfo->depth, InputOutput, x_vis, 

+			attribmask, &attribs );

+		XStoreName(dpy, win, "Quake II");

+

+		if (x_visinfo->class != TrueColor)

+			XFreeColormap(dpy, tmpcmap);

+	}

+

+	if (x_visinfo->depth == 8)

+	{

+	// create and upload the palette

+		if (x_visinfo->class == PseudoColor)

+		{

+			x_cmap = XCreateColormap(dpy, win, x_vis, AllocAll);

+			XSetWindowColormap(dpy, win, x_cmap);

+		}

+

+	}

+

+// create the GC

+	{

+		XGCValues xgcvalues;

+		int valuemask = GCGraphicsExposures;

+		xgcvalues.graphics_exposures = False;

+		x_gc = XCreateGC(dpy, win, valuemask, &xgcvalues );

+	}

+

+	XMapWindow(dpy, win);

+	XMoveWindow(dpy, win, (int)vid_xpos->value, (int)vid_ypos->value);

+

+// wait for first exposure event

+	{

+		XEvent event;

+		exposureflag = false;

+		do

+		{

+			HandleEvents();

+		} while (!exposureflag);

+	}

+// now safe to draw

+

+// even if MITSHM is available, make sure it's a local connection

+	doShm = false;

+/*

+	if (XShmQueryExtension(dpy))

+	{

+		char *displayname;

+		doShm = true;

+		displayname = (char *) getenv("DISPLAY");

+		if (displayname)

+		{

+			char *d = displayname;

+			while (*d && (*d != ':')) d++;

+			if (*d) *d = 0;

+			if (!(!strcasecmp(displayname, "unix") || !*displayname))

+				doShm = false;

+		}

+	}

+*/

+

+	if (doShm)

+	{

+		x_shmeventtype = XShmGetEventBase(dpy) + ShmCompletion;

+		ResetSharedFrameBuffers();

+	}

+	else

+		ResetFrameBuffer();

+

+	current_framebuffer = 0;

+	vid.rowbytes = x_framebuffer[0]->bytes_per_line;

+	vid.buffer = x_framebuffer[0]->data;

+

+//	XSynchronize(dpy, False);

+

+	X11_active = true;

+

+	return true;

+}

+

+/*

+** SWimp_EndFrame

+**

+** This does an implementation specific copy from the backbuffer to the

+** front buffer.  In the Win32 case it uses BitBlt or BltFast depending

+** on whether we're using DIB sections/GDI or DDRAW.

+*/

+void SWimp_EndFrame (void)

+{

+// if the window changes dimension, skip this frame

+#if 0

+	if (config_notify)

+	{

+		fprintf(stderr, "config notify\n");

+		config_notify = 0;

+		vid.width = config_notify_width & ~7;

+		vid.height = config_notify_height;

+		if (doShm)

+			ResetSharedFrameBuffers();

+		else

+			ResetFrameBuffer();

+		vid.rowbytes = x_framebuffer[0]->bytes_per_line;

+		vid.buffer = x_framebuffer[current_framebuffer]->data;

+		vid.recalc_refdef = 1;				// force a surface cache flush

+		Con_CheckResize();

+		Con_Clear_f();

+		return;

+	}

+#endif

+

+	if (doShm)

+	{

+		if (x_visinfo->depth == 16)

+			st2_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);

+		else if (x_visinfo->depth == 24)

+			st3_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);

+		if (!XShmPutImage(dpy, win, x_gc,

+			x_framebuffer[current_framebuffer], 0, 0, 0, 0, vid.width, vid.height, True))

+			Sys_Error("VID_Update: XShmPutImage failed\n");

+		oktodraw = false;

+		while (!oktodraw) 

+			HandleEvents();

+		current_framebuffer = !current_framebuffer;

+		vid.buffer = x_framebuffer[current_framebuffer]->data;

+		XSync(dpy, False);

+	}

+	else

+	{

+		if (x_visinfo->depth == 16)

+			st2_fixup_stereo( x_framebuffer[0], x_framebuffer[1], 0, 0, vid.width, vid.height);

+		else if (x_visinfo->depth == 24)

+			st3_fixup_stereo( x_framebuffer[0], x_framebuffer[1], 0, 0, vid.width, vid.height);

+		XPutImage(dpy, win, x_gc, x_framebuffer[0], 0, 0, 0, 0, vid.width, vid.height);

+		XSync(dpy, False);

+	}

+}

+

+/*

+** SWimp_SetMode

+*/

+rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )

+{

+	rserr_t retval = rserr_ok;

+

+	ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );

+

+	if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )

+	{

+		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );

+		return rserr_invalid_mode;

+	}

+

+	ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight);

+

+	if ( !SWimp_InitGraphics( false ) ) {

+		// failed to set a valid mode in windowed mode

+		return rserr_invalid_mode;

+	}

+

+	R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );

+

+	return retval;

+}

+

+/*

+** SWimp_SetPalette

+**

+** System specific palette setting routine.  A NULL palette means

+** to use the existing palette.  The palette is expected to be in

+** a padded 4-byte xRGB format.

+*/

+void SWimp_SetPalette( const unsigned char *palette )

+{

+	int i;

+	XColor colors[256];

+	int tmp;

+

+	if (!X11_active)

+		return;

+

+    if ( !palette )

+        palette = ( const unsigned char * ) sw_state.currentpalette;

+ 

+	for(i=0;i<256;i++) {

+		st2d_8to16table[i]= xlib_rgb16(palette[i*4], palette[i*4+1],palette[i*4+2]);

+		st2d_8to24table[i]= xlib_rgb24(palette[i*4], palette[i*4+1],palette[i*4+2]);

+

+		tmp = (30*palette[i*4] + 59*palette[i*4+1] + 11*palette[i*4+2]) / 100;

+		st2d_8to16table_s[0][i] = xlib_rgb16(tmp, 0, 0);

+		st2d_8to16table_s[1][i] = xlib_rgb16(0, 0, tmp);

+		st2d_8to24table_s[0][i] = xlib_rgb24(tmp, 0, 0);

+		st2d_8to24table_s[1][i] = xlib_rgb24(0, 0, tmp);

+	}

+

+	if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)

+	{

+		for (i=0 ; i<256 ; i++)

+		{

+			colors[i].pixel = i;

+			colors[i].flags = DoRed|DoGreen|DoBlue;

+			colors[i].red = palette[i*4] * 257;

+			colors[i].green = palette[i*4+1] * 257;

+			colors[i].blue = palette[i*4+2] * 257;

+		}

+		XStoreColors(dpy, x_cmap, colors, 256);

+	}

+}

+

+/*

+** SWimp_Shutdown

+**

+** System specific graphics subsystem shutdown routine.  Destroys

+** DIBs or DDRAW surfaces as appropriate.

+*/

+void SWimp_Shutdown( void )

+{

+	int i;

+

+	if (!X11_active)

+		return;

+

+	if (doShm) {

+		for (i = 0; i < 2; i++)

+			if (x_framebuffer[i]) {

+				XShmDetach(dpy, &x_shminfo[i]);

+				free(x_framebuffer[i]);

+				shmdt(x_shminfo[i].shmaddr);

+				x_framebuffer[i] = NULL;

+			}

+	} else {

+		if (x_framebuffer[0]) {

+			free(x_framebuffer[0]->data);

+			free(x_framebuffer[0]);

+			x_framebuffer[0] = NULL;

+		}

+		if (x_framebuffer[1]) {

+			free(x_framebuffer[1]->data);

+			free(x_framebuffer[1]);

+			x_framebuffer[1] = NULL;

+		}

+	}

+

+	XDestroyWindow(	dpy, win );

+

+//	XAutoRepeatOn(dpy);

+//	XCloseDisplay(dpy);

+

+	X11_active = false;

+}

+

+/*

+** SWimp_AppActivate

+*/

+void SWimp_AppActivate( qboolean active )

+{

+}

+

+void SetStereoBuffer(int buf)

+{

+	if (x_framebuffer[buf])

+		vid.buffer = (byte*) (x_framebuffer[buf]->data);

+	else

+		printf("SetStereoBuffer: x_framebuffer[%d] is NULL\n", buf);

+}

+

+//===============================================================================

+

+/*

+================

+Sys_MakeCodeWriteable

+================

+*/

+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)

+{

+

+	int r;

+	unsigned long addr;

+	int psize = getpagesize();

+

+	addr = (startaddr & ~(psize-1)) - psize;

+

+//	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,

+//			addr, startaddr+length, length);

+

+	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);

+

+	if (r < 0)

+    		Sys_Error("Protection change failed\n");

+

+}

+

+/*****************************************************************************/

+/* KEYBOARD                                                                  */

+/*****************************************************************************/

+

+Key_Event_fp_t Key_Event_fp;

+

+void KBD_Init(Key_Event_fp_t fp)

+{

+	Key_Event_fp = fp;

+}

+

+void KBD_Update(void)

+{

+// get events from x server

+	HandleEvents();

+}

+

+void KBD_Close(void)

+{

+}

+

+

diff -ur quake2-r0.0.8/src/ref_soft/r_main.c quake2-devel-r0.0.8/src/ref_soft/r_main.c
--- quake2-r0.0.8/src/ref_soft/r_main.c	Thu Jan  3 07:10:14 2002
+++ quake2-devel-r0.0.8/src/ref_soft/r_main.c	Wed Jan 30 15:03:01 2002
@@ -1,1423 +1,1426 @@
-/*
-Copyright (C) 1997-2001 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-*/
-// r_main.c
-
-#include "r_local.h"
-
-viddef_t	vid;
-refimport_t	ri;
-
-unsigned	d_8to24table[256];
-
-entity_t	r_worldentity;
-
-char		skyname[MAX_QPATH];
-float		skyrotate;
-vec3_t		skyaxis;
-image_t		*sky_images[6];
-
-refdef_t	r_newrefdef;
-model_t		*currentmodel;
-
-model_t		*r_worldmodel;
-
-byte		r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
-
-swstate_t sw_state;
-
-void		*colormap;
-vec3_t		viewlightvec;
-alight_t	r_viewlighting = {128, 192, viewlightvec};
-float		r_time1;
-int			r_numallocatededges;
-float		r_aliasuvscale = 1.0;
-int			r_outofsurfaces;
-int			r_outofedges;
-
-qboolean	r_dowarp;
-
-mvertex_t	*r_pcurrentvertbase;
-
-int			c_surf;
-int			r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
-qboolean	r_surfsonstack;
-int			r_clipflags;
-
-//
-// view origin
-//
-vec3_t	vup, base_vup;
-vec3_t	vpn, base_vpn;
-vec3_t	vright, base_vright;
-vec3_t	r_origin;
-
-//
-// screen size info
-//
-oldrefdef_t	r_refdef;
-float		xcenter, ycenter;
-float		xscale, yscale;
-float		xscaleinv, yscaleinv;
-float		xscaleshrink, yscaleshrink;
-float		aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
-
-int		r_screenwidth;
-
-float	verticalFieldOfView;
-float	xOrigin, yOrigin;
-
-mplane_t	screenedge[4];
-
-//
-// refresh flags
-//
-int		r_framecount = 1;	// so frame counts initialized to 0 don't match
-int		r_visframecount;
-int		d_spanpixcount;
-int		r_polycount;
-int		r_drawnpolycount;
-int		r_wholepolycount;
-
-int			*pfrustum_indexes[4];
-int			r_frustum_indexes[4*6];
-
-mleaf_t		*r_viewleaf;
-int			r_viewcluster, r_oldviewcluster;
-
-image_t  	*r_notexture_mip;
-
-float	da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
-float	se_time1, se_time2, de_time1, de_time2;
-
-void R_MarkLeaves (void);
-
-cvar_t	*r_lefthand;
-cvar_t	*sw_aliasstats;
-cvar_t	*sw_allow_modex;
-cvar_t	*sw_clearcolor;
-cvar_t	*sw_drawflat;
-cvar_t	*sw_draworder;
-cvar_t	*sw_maxedges;
-cvar_t	*sw_maxsurfs;
-cvar_t  *sw_mode;
-cvar_t	*sw_reportedgeout;
-cvar_t	*sw_reportsurfout;
-cvar_t  *sw_stipplealpha;
-cvar_t	*sw_surfcacheoverride;
-cvar_t	*sw_waterwarp;
-
-cvar_t	*r_drawworld;
-cvar_t	*r_drawentities;
-cvar_t	*r_dspeeds;
-cvar_t	*r_fullbright;
-cvar_t  *r_lerpmodels;
-cvar_t  *r_novis;
-
-cvar_t	*r_speeds;
-cvar_t	*r_lightlevel;	//FIXME HACK
-
-cvar_t	*vid_fullscreen;
-cvar_t	*vid_gamma;
-
-//PGM
-cvar_t	*sw_lockpvs;
-//PGM
-
-#define	STRINGER(x) "x"
-
-
-#if	!id386
-
-// r_vars.c
-
-// all global and static refresh variables are collected in a contiguous block
-// to avoid cache conflicts.
-
-//-------------------------------------------------------
-// global refresh variables
-//-------------------------------------------------------
-
-// FIXME: make into one big structure, like cl or sv
-// FIXME: do separately for refresh engine and driver
-
-
-// d_vars.c
-
-// all global and static refresh variables are collected in a contiguous block
-// to avoid cache conflicts.
-
-//-------------------------------------------------------
-// global refresh variables
-//-------------------------------------------------------
-
-// FIXME: make into one big structure, like cl or sv
-// FIXME: do separately for refresh engine and driver
-
-float	d_sdivzstepu, d_tdivzstepu, d_zistepu;
-float	d_sdivzstepv, d_tdivzstepv, d_zistepv;
-float	d_sdivzorigin, d_tdivzorigin, d_ziorigin;
-
-fixed16_t	sadjust, tadjust, bbextents, bbextentt;
-
-pixel_t			*cacheblock;
-int				cachewidth;
-pixel_t			*d_viewbuffer;
-short			*d_pzbuffer;
-unsigned int	d_zrowbytes;
-unsigned int	d_zwidth;
-
-
-#endif	// !id386
-
-byte	r_notexture_buffer[1024];
-
-/*
-==================
-R_InitTextures
-==================
-*/
-void	R_InitTextures (void)
-{
-	int		x,y, m;
-	byte	*dest;
-	
-// create a simple checkerboard texture for the default
-	r_notexture_mip = (image_t *)&r_notexture_buffer;
-	
-	r_notexture_mip->width = r_notexture_mip->height = 16;
-	r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)];
-	r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16;
-	r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8;
-	r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4;
-	
-	for (m=0 ; m<4 ; m++)
-	{
-		dest = r_notexture_mip->pixels[m];
-		for (y=0 ; y< (16>>m) ; y++)
-			for (x=0 ; x< (16>>m) ; x++)
-			{
-				if (  (y< (8>>m) ) ^ (x< (8>>m) ) )
-
-					*dest++ = 0;
-				else
-					*dest++ = 0xff;
-			}
-	}	
-}
-
-
-/*
-================
-R_InitTurb
-================
-*/
-void R_InitTurb (void)
-{
-	int		i;
-	
-	for (i=0 ; i<1280 ; i++)
-	{
-		sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
-		intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2;	// AMP2, not 20
-		blanktable[i] = 0;			//PGM
-	}
-}
-
-void R_ImageList_f( void );
-
-void R_Register (void)
-{
-	sw_aliasstats = ri.Cvar_Get ("sw_polymodelstats", "0", 0);
-	sw_allow_modex = ri.Cvar_Get( "sw_allow_modex", "1", CVAR_ARCHIVE );
-	sw_clearcolor = ri.Cvar_Get ("sw_clearcolor", "2", 0);
-	sw_drawflat = ri.Cvar_Get ("sw_drawflat", "0", 0);
-	sw_draworder = ri.Cvar_Get ("sw_draworder", "0", 0);
-	sw_maxedges = ri.Cvar_Get ("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0);
-	sw_maxsurfs = ri.Cvar_Get ("sw_maxsurfs", "0", 0);
-	sw_mipcap = ri.Cvar_Get ("sw_mipcap", "0", 0);
-	sw_mipscale = ri.Cvar_Get ("sw_mipscale", "1", 0);
-	sw_reportedgeout = ri.Cvar_Get ("sw_reportedgeout", "0", 0);
-	sw_reportsurfout = ri.Cvar_Get ("sw_reportsurfout", "0", 0);
-	sw_stipplealpha = ri.Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
-	sw_surfcacheoverride = ri.Cvar_Get ("sw_surfcacheoverride", "0", 0);
-	sw_waterwarp = ri.Cvar_Get ("sw_waterwarp", "1", 0);
-	sw_mode = ri.Cvar_Get( "sw_mode", "0", CVAR_ARCHIVE );
-
-	r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
-	r_speeds = ri.Cvar_Get ("r_speeds", "0", 0);
-	r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0);
-	r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0);
-	r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0);
-	r_dspeeds = ri.Cvar_Get ("r_dspeeds", "0", 0);
-	r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0);
-	r_lerpmodels = ri.Cvar_Get( "r_lerpmodels", "1", 0 );
-	r_novis = ri.Cvar_Get( "r_novis", "0", 0 );
-
-	vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE );
-	vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE );
-
-	ri.Cmd_AddCommand ("modellist", Mod_Modellist_f);
-	ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
-	ri.Cmd_AddCommand( "imagelist", R_ImageList_f );
-
-	sw_mode->modified = true; // force us to do mode specific stuff later
-	vid_gamma->modified = true; // force us to rebuild the gamma table later
-
-//PGM
-	sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0);
-//PGM
-}
-
-void R_UnRegister (void)
-{
-	ri.Cmd_RemoveCommand( "screenshot" );
-	ri.Cmd_RemoveCommand ("modellist");
-	ri.Cmd_RemoveCommand( "imagelist" );
-}
-
-/*
-===============
-R_Init
-===============
-*/
-int R_Init( void *hInstance, void *wndProc )
-{
-	R_InitImages ();
-	Mod_Init ();
-	Draw_InitLocal ();
-	R_InitTextures ();
-
-	R_InitTurb ();
-
-	view_clipplanes[0].leftedge = true;
-	view_clipplanes[1].rightedge = true;
-	view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
-			view_clipplanes[3].leftedge = false;
-	view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
-			view_clipplanes[3].rightedge = false;
-
-	r_refdef.xOrigin = XCENTERING;
-	r_refdef.yOrigin = YCENTERING;
-
-// TODO: collect 386-specific code in one place
-#if	id386
-	Sys_MakeCodeWriteable ((long)R_EdgeCodeStart,
-					     (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart);
-	Sys_SetFPCW ();		// get bit masks for FPCW	(FIXME: is this id386?)
-#endif	// id386
-
-	r_aliasuvscale = 1.0;
-
-	R_Register ();
-	Draw_GetPalette ();
-	if (SWimp_Init( hInstance, wndProc ) == false)
-		return -1;
-
-	// create the window
-	R_BeginFrame( 0 );
-
-	ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");
-
-	return true;
-}
-
-/*
-===============
-R_Shutdown
-===============
-*/
-void R_Shutdown (void)
-{
-	// free z buffer
-	if (d_pzbuffer)
-	{
-		free (d_pzbuffer);
-		d_pzbuffer = NULL;
-	}
-	// free surface cache
-	if (sc_base)
-	{
-		D_FlushCaches ();
-		free (sc_base);
-		sc_base = NULL;
-	}
-
-	// free colormap
-	if (vid.colormap)
-	{
-		free (vid.colormap);
-		vid.colormap = NULL;
-	}
-	R_UnRegister ();
-	Mod_FreeAll ();
-	R_ShutdownImages ();
-
-	SWimp_Shutdown();
-}
-
-/*
-===============
-R_NewMap
-===============
-*/
-void R_NewMap (void)
-{
-	r_viewcluster = -1;
-
-	r_cnumsurfs = sw_maxsurfs->value;
-
-	if (r_cnumsurfs <= MINSURFACES)
-		r_cnumsurfs = MINSURFACES;
-
-	if (r_cnumsurfs > NUMSTACKSURFACES)
-	{
-		surfaces = malloc (r_cnumsurfs * sizeof(surf_t));
-		surface_p = surfaces;
-		surf_max = &surfaces[r_cnumsurfs];
-		r_surfsonstack = false;
-	// surface 0 doesn't really exist; it's just a dummy because index 0
-	// is used to indicate no edge attached to surface
-		surfaces--;
-		R_SurfacePatch ();
-	}
-	else
-	{
-		r_surfsonstack = true;
-	}
-
-	r_maxedgesseen = 0;
-	r_maxsurfsseen = 0;
-
-	r_numallocatededges = sw_maxedges->value;
-
-	if (r_numallocatededges < MINEDGES)
-		r_numallocatededges = MINEDGES;
-
-	if (r_numallocatededges <= NUMSTACKEDGES)
-	{
-		auxedges = NULL;
-	}
-	else
-	{
-		auxedges = malloc (r_numallocatededges * sizeof(edge_t));
-	}
-}
-
-
-/*
-===============
-R_MarkLeaves
-
-Mark the leaves and nodes that are in the PVS for the current
-cluster
-===============
-*/
-void R_MarkLeaves (void)
-{
-	byte	*vis;
-	mnode_t	*node;
-	int		i;
-	mleaf_t	*leaf;
-	int		cluster;
-
-	if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
-		return;
-	
-	// development aid to let you run around and see exactly where
-	// the pvs ends
-	if (sw_lockpvs->value)
-		return;
-
-	r_visframecount++;
-	r_oldviewcluster = r_viewcluster;
-
-	if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
-	{
-		// mark everything
-		for (i=0 ; i<r_worldmodel->numleafs ; i++)
-			r_worldmodel->leafs[i].visframe = r_visframecount;
-		for (i=0 ; i<r_worldmodel->numnodes ; i++)
-			r_worldmodel->nodes[i].visframe = r_visframecount;
-		return;
-	}
-
-	vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
-	
-	for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
-	{
-		cluster = leaf->cluster;
-		if (cluster == -1)
-			continue;
-		if (vis[cluster>>3] & (1<<(cluster&7)))
-		{
-			node = (mnode_t *)leaf;
-			do
-			{
-				if (node->visframe == r_visframecount)
-					break;
-				node->visframe = r_visframecount;
-				node = node->parent;
-			} while (node);
-		}
-	}
-
-#if 0
-	for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
-	{
-		if (vis[i>>3] & (1<<(i&7)))
-		{
-			node = (mnode_t *)&r_worldmodel->leafs[i];	// FIXME: cluster
-			do
-			{
-				if (node->visframe == r_visframecount)
-					break;
-				node->visframe = r_visframecount;
-				node = node->parent;
-			} while (node);
-		}
-	}
-#endif
-}
-
-/*
-** R_DrawNullModel
-**
-** IMPLEMENT THIS!
-*/
-void R_DrawNullModel( void )
-{
-}
-
-/*
-=============
-R_DrawEntitiesOnList
-=============
-*/
-void R_DrawEntitiesOnList (void)
-{
-	int			i;
-	qboolean	translucent_entities = false;
-
-	if (!r_drawentities->value)
-		return;
-
-	// all bmodels have already been drawn by the edge list
-	for (i=0 ; i<r_newrefdef.num_entities ; i++)
-	{
-		currententity = &r_newrefdef.entities[i];
-
-		if ( currententity->flags & RF_TRANSLUCENT )
-		{
-			translucent_entities = true;
-			continue;
-		}
-
-		if ( currententity->flags & RF_BEAM )
-		{
-			modelorg[0] = -r_origin[0];
-			modelorg[1] = -r_origin[1];
-			modelorg[2] = -r_origin[2];
-			VectorCopy( vec3_origin, r_entorigin );
-			R_DrawBeam( currententity );
-		}
-		else
-		{
-			currentmodel = currententity->model;
-			if (!currentmodel)
-			{
-				R_DrawNullModel();
-				continue;
-			}
-			VectorCopy (currententity->origin, r_entorigin);
-			VectorSubtract (r_origin, r_entorigin, modelorg);
-
-			switch (currentmodel->type)
-			{
-			case mod_sprite:
-				R_DrawSprite ();
-				break;
-
-			case mod_alias:
-				R_AliasDrawModel ();
-				break;
-
-			default:
-				break;
-			}
-		}
-	}
-
-	if ( !translucent_entities )
-		return;
-
-	for (i=0 ; i<r_newrefdef.num_entities ; i++)
-	{
-		currententity = &r_newrefdef.entities[i];
-
-		if ( !( currententity->flags & RF_TRANSLUCENT ) )
-			continue;
-
-		if ( currententity->flags & RF_BEAM )
-		{
-			modelorg[0] = -r_origin[0];
-			modelorg[1] = -r_origin[1];
-			modelorg[2] = -r_origin[2];
-			VectorCopy( vec3_origin, r_entorigin );
-			R_DrawBeam( currententity );
-		}
-		else
-		{
-			currentmodel = currententity->model;
-			if (!currentmodel)
-			{
-				R_DrawNullModel();
-				continue;
-			}
-			VectorCopy (currententity->origin, r_entorigin);
-			VectorSubtract (r_origin, r_entorigin, modelorg);
-
-			switch (currentmodel->type)
-			{
-			case mod_sprite:
-				R_DrawSprite ();
-				break;
-
-			case mod_alias:
-				R_AliasDrawModel ();
-				break;
-
-			default:
-				break;
-			}
-		}
-	}
-}
-
-
-/*
-=============
-R_BmodelCheckBBox
-=============
-*/
-int R_BmodelCheckBBox (float *minmaxs)
-{
-	int			i, *pindex, clipflags;
-	vec3_t		acceptpt, rejectpt;
-	float		d;
-
-	clipflags = 0;
-
-	for (i=0 ; i<4 ; i++)
-	{
-	// generate accept and reject points
-	// FIXME: do with fast look-ups or integer tests based on the sign bit
-	// of the floating point values
-
-		pindex = pfrustum_indexes[i];
-
-		rejectpt[0] = minmaxs[pindex[0]];
-		rejectpt[1] = minmaxs[pindex[1]];
-		rejectpt[2] = minmaxs[pindex[2]];
-		
-		d = DotProduct (rejectpt, view_clipplanes[i].normal);
-		d -= view_clipplanes[i].dist;
-
-		if (d <= 0)
-			return BMODEL_FULLY_CLIPPED;
-
-		acceptpt[0] = minmaxs[pindex[3+0]];
-		acceptpt[1] = minmaxs[pindex[3+1]];
-		acceptpt[2] = minmaxs[pindex[3+2]];
-
-		d = DotProduct (acceptpt, view_clipplanes[i].normal);
-		d -= view_clipplanes[i].dist;
-
-		if (d <= 0)
-			clipflags |= (1<<i);
-	}
-
-	return clipflags;
-}
-
-
-/*
-===================
-R_FindTopnode
-
-Find the first node that splits the given box
-===================
-*/
-mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
-{
-	mplane_t	*splitplane;
-	int			sides;
-	mnode_t *node;
-
-	node = r_worldmodel->nodes;
-
-	while (1)
-	{
-		if (node->visframe != r_visframecount)
-			return NULL;		// not visible at all
-		
-		if (node->contents != CONTENTS_NODE)
-		{
-			if (node->contents != CONTENTS_SOLID)
-				return	node; // we've reached a non-solid leaf, so it's
-							//  visible and not BSP clipped
-			return NULL;	// in solid, so not visible
-		}
-		
-		splitplane = node->plane;
-		sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);
-		
-		if (sides == 3)
-			return node;	// this is the splitter
-		
-	// not split yet; recurse down the contacted side
-		if (sides & 1)
-			node = node->children[0];
-		else
-			node = node->children[1];
-	}
-}
-
-
-/*
-=============
-RotatedBBox
-
-Returns an axially aligned box that contains the input box at the given rotation
-=============
-*/
-void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)
-{
-	vec3_t	tmp, v;
-	int		i, j;
-	vec3_t	forward, right, up;
-
-	if (!angles[0] && !angles[1] && !angles[2])
-	{
-		VectorCopy (mins, tmins);
-		VectorCopy (maxs, tmaxs);
-		return;
-	}
-
-	for (i=0 ; i<3 ; i++)
-	{
-		tmins[i] = 99999;
-		tmaxs[i] = -99999;
-	}
-
-	AngleVectors (angles, forward, right, up);
-
-	for ( i = 0; i < 8; i++ )
-	{
-		if ( i & 1 )
-			tmp[0] = mins[0];
-		else
-			tmp[0] = maxs[0];
-
-		if ( i & 2 )
-			tmp[1] = mins[1];
-		else
-			tmp[1] = maxs[1];
-
-		if ( i & 4 )
-			tmp[2] = mins[2];
-		else
-			tmp[2] = maxs[2];
-
-
-		VectorScale (forward, tmp[0], v);
-		VectorMA (v, -tmp[1], right, v);
-		VectorMA (v, tmp[2], up, v);
-
-		for (j=0 ; j<3 ; j++)
-		{
-			if (v[j] < tmins[j])
-				tmins[j] = v[j];
-			if (v[j] > tmaxs[j])
-				tmaxs[j] = v[j];
-		}
-	}
-}
-
-/*
-=============
-R_DrawBEntitiesOnList
-=============
-*/
-void R_DrawBEntitiesOnList (void)
-{
-	int			i, clipflags;
-	vec3_t		oldorigin;
-	vec3_t		mins, maxs;
-	float		minmaxs[6];
-	mnode_t		*topnode;
-
-	if (!r_drawentities->value)
-		return;
-
-	VectorCopy (modelorg, oldorigin);
-	insubmodel = true;
-	r_dlightframecount = r_framecount;
-
-	for (i=0 ; i<r_newrefdef.num_entities ; i++)
-	{
-		currententity = &r_newrefdef.entities[i];
-		currentmodel = currententity->model;
-		if (!currentmodel)
-			continue;
-		if (currentmodel->nummodelsurfaces == 0)
-			continue;	// clip brush only
-		if ( currententity->flags & RF_BEAM )
-			continue;
-		if (currentmodel->type != mod_brush)
-			continue;
-	// see if the bounding box lets us trivially reject, also sets
-	// trivial accept status
-		RotatedBBox (currentmodel->mins, currentmodel->maxs,
-			currententity->angles, mins, maxs);
-		VectorAdd (mins, currententity->origin, minmaxs);
-		VectorAdd (maxs, currententity->origin, (minmaxs+3));
-
-		clipflags = R_BmodelCheckBBox (minmaxs);
-		if (clipflags == BMODEL_FULLY_CLIPPED)
-			continue;	// off the edge of the screen
-
-		topnode = R_FindTopnode (minmaxs, minmaxs+3);
-		if (!topnode)
-			continue;	// no part in a visible leaf
-
-		VectorCopy (currententity->origin, r_entorigin);
-		VectorSubtract (r_origin, r_entorigin, modelorg);
-
-		r_pcurrentvertbase = currentmodel->vertexes;
-
-	// FIXME: stop transforming twice
-		R_RotateBmodel ();
-
-	// calculate dynamic lighting for bmodel
-		R_PushDlights (currentmodel);
-
-		if (topnode->contents == CONTENTS_NODE)
-		{
-		// not a leaf; has to be clipped to the world BSP
-			r_clipflags = clipflags;
-			R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);
-		}
-		else
-		{
-		// falls entirely in one leaf, so we just put all the
-		// edges in the edge list and let 1/z sorting handle
-		// drawing order
-			R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);
-		}
-
-	// put back world rotation and frustum clipping		
-	// FIXME: R_RotateBmodel should just work off base_vxx
-		VectorCopy (base_vpn, vpn);
-		VectorCopy (base_vup, vup);
-		VectorCopy (base_vright, vright);
-		VectorCopy (oldorigin, modelorg);
-		R_TransformFrustum ();
-	}
-
-	insubmodel = false;
-}
-
-
-/*
-================
-R_EdgeDrawing
-================
-*/
-void R_EdgeDrawing (void)
-{
-	edge_t	ledges[NUMSTACKEDGES +
-				((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
-	surf_t	lsurfs[NUMSTACKSURFACES +
-				((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
-
-	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
-		return;
-
-	if (auxedges)
-	{
-		r_edges = auxedges;
-	}
-	else
-	{
-		r_edges =  (edge_t *)
-				(((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
-	}
-
-	if (r_surfsonstack)
-	{
-		surfaces =  (surf_t *)
-				(((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
-		surf_max = &surfaces[r_cnumsurfs];
-	// surface 0 doesn't really exist; it's just a dummy because index 0
-	// is used to indicate no edge attached to surface
-		surfaces--;
-		R_SurfacePatch ();
-	}
-
-	R_BeginEdgeFrame ();
-
-	if (r_dspeeds->value)
-	{
-		rw_time1 = Sys_Milliseconds ();
-	}
-
-	R_RenderWorld ();
-
-	if (r_dspeeds->value)
-	{
-		rw_time2 = Sys_Milliseconds ();
-		db_time1 = rw_time2;
-	}
-
-	R_DrawBEntitiesOnList ();
-
-	if (r_dspeeds->value)
-	{
-		db_time2 = Sys_Milliseconds ();
-		se_time1 = db_time2;
-	}
-
-	R_ScanEdges ();
-}
-
-//=======================================================================
-
-
-/*
-=============
-R_CalcPalette
-
-=============
-*/
-void R_CalcPalette (void)
-{
-	static qboolean modified;
-	byte	palette[256][4], *in, *out;
-	int		i, j;
-	float	alpha, one_minus_alpha;
-	vec3_t	premult;
-	int		v;
-
-	alpha = r_newrefdef.blend[3];
-	if (alpha <= 0)
-	{
-		if (modified)
-		{	// set back to default
-			modified = false;
-			R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
-			return;
-		}
-		return;
-	}
-
-	modified = true;
-	if (alpha > 1)
-		alpha = 1;
-
-	premult[0] = r_newrefdef.blend[0]*alpha*255;
-	premult[1] = r_newrefdef.blend[1]*alpha*255;
-	premult[2] = r_newrefdef.blend[2]*alpha*255;
-
-	one_minus_alpha = (1.0 - alpha);
-
-	in = (byte *)d_8to24table;
-	out = palette[0];
-	for (i=0 ; i<256 ; i++, in+=4, out+=4)
-	{
-		for (j=0 ; j<3 ; j++)
-		{
-			v = premult[j] + one_minus_alpha * in[j];
-			if (v > 255)
-				v = 255;
-			out[j] = v;
-		}
-		out[3] = 255;
-	}
-
-	R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] );
-//	SWimp_SetPalette( palette[0] );
-}
-
-//=======================================================================
-
-void R_SetLightLevel (void)
-{
-	vec3_t		light;
-
-	if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))
-	{
-		r_lightlevel->value = 150.0;
-		return;
-	}
-
-	// save off light value for server to look at (BIG HACK!)
-	R_LightPoint (r_newrefdef.vieworg, light);
-	r_lightlevel->value = 150.0 * light[0];
-}
-
-
-/*
-@@@@@@@@@@@@@@@@
-R_RenderFrame
-
-@@@@@@@@@@@@@@@@
-*/
-void R_RenderFrame (refdef_t *fd)
-{
-	r_newrefdef = *fd;
-
-	if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
-		ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");
-
-	VectorCopy (fd->vieworg, r_refdef.vieworg);
-	VectorCopy (fd->viewangles, r_refdef.viewangles);
-
-	if (r_speeds->value || r_dspeeds->value)
-		r_time1 = Sys_Milliseconds ();
-
-	R_SetupFrame ();
-
-	R_MarkLeaves ();	// done here so we know if we're in water
-
-	R_PushDlights (r_worldmodel);
-
-	R_EdgeDrawing ();
-
-	if (r_dspeeds->value)
-	{
-		se_time2 = Sys_Milliseconds ();
-		de_time1 = se_time2;
-	}
-
-	R_DrawEntitiesOnList ();
-
-	if (r_dspeeds->value)
-	{
-		de_time2 = Sys_Milliseconds ();
-		dp_time1 = Sys_Milliseconds ();
-	}
-
-	R_DrawParticles ();
-
-	if (r_dspeeds->value)
-		dp_time2 = Sys_Milliseconds ();
-
-	R_DrawAlphaSurfaces();
-
-	R_SetLightLevel ();
-
-	if (r_dowarp)
-		D_WarpScreen ();
-
-	if (r_dspeeds->value)
-		da_time1 = Sys_Milliseconds ();
-
-	if (r_dspeeds->value)
-		da_time2 = Sys_Milliseconds ();
-
-	R_CalcPalette ();
-
-	if (sw_aliasstats->value)
-		R_PrintAliasStats ();
-		
-	if (r_speeds->value)
-		R_PrintTimes ();
-
-	if (r_dspeeds->value)
-		R_PrintDSpeeds ();
-
-	if (sw_reportsurfout->value && r_outofsurfaces)
-		ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);
-
-	if (sw_reportedgeout->value && r_outofedges)
-		ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);
-}
-
-/*
-** R_InitGraphics
-*/
-void R_InitGraphics( int width, int height )
-{
-	vid.width  = width;
-	vid.height = height;
-
-	// free z buffer
-	if ( d_pzbuffer )
-	{
-		free( d_pzbuffer );
-		d_pzbuffer = NULL;
-	}
-
-	// free surface cache
-	if ( sc_base )
-	{
-		D_FlushCaches ();
-		free( sc_base );
-		sc_base = NULL;
-	}
-
-	d_pzbuffer = malloc(vid.width*vid.height*2);
-
-	R_InitCaches ();
-
-	R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table );
-}
-
-/*
-** R_BeginFrame
-*/
-void R_BeginFrame( float camera_separation )
-{
-	extern void Draw_BuildGammaTable( void );
-
-	/*
-	** rebuild the gamma correction palette if necessary
-	*/
-	if ( vid_gamma->modified )
-	{
-		Draw_BuildGammaTable();
-		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
-
-		vid_gamma->modified = false;
-	}
-
-	while ( sw_mode->modified || vid_fullscreen->modified )
-	{
-		rserr_t err;
-
-		/*
-		** if this returns rserr_invalid_fullscreen then it set the mode but not as a
-		** fullscreen mode, e.g. 320x200 on a system that doesn't support that res
-		*/
-		if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )
-		{
-			R_InitGraphics( vid.width, vid.height );
-
-			sw_state.prev_mode = sw_mode->value;
-			vid_fullscreen->modified = false;
-			sw_mode->modified = false;
-		}
-		else
-		{
-			if ( err == rserr_invalid_mode )
-			{
-				ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );
-				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );
-			}
-			else if ( err == rserr_invalid_fullscreen )
-			{
-				R_InitGraphics( vid.width, vid.height );
-
-				ri.Cvar_SetValue( "vid_fullscreen", 0);
-				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );
-				sw_state.prev_mode = sw_mode->value;
-//				vid_fullscreen->modified = false;
-//				sw_mode->modified = false;
-			}
-			else
-			{
-				ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );
-			}
-		}
-	}
-}
-
-/*
-** R_GammaCorrectAndSetPalette
-*/
-void R_GammaCorrectAndSetPalette( const unsigned char *palette )
-{
-	int i;
-
-	for ( i = 0; i < 256; i++ )
-	{
-		sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];
-		sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];
-		sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];
-	}
-
-	SWimp_SetPalette( sw_state.currentpalette );
-}
-
-/*
-** R_CinematicSetPalette
-*/
-void R_CinematicSetPalette( const unsigned char *palette )
-{
-	byte palette32[1024];
-	int		i, j, w;
-	int		*d;
-
-	// clear screen to black to avoid any palette flash
-	w = abs(vid.rowbytes)>>2;	// stupid negative pitch win32 stuff...
-	for (i=0 ; i<vid.height ; i++, d+=w)
-	{
-		d = (int *)(vid.buffer + i*vid.rowbytes);
-		for (j=0 ; j<w ; j++)
-			d[j] = 0;
-	}
-	// flush it to the screen
-	SWimp_EndFrame ();
-
-	if ( palette )
-	{
-		for ( i = 0; i < 256; i++ )
-		{
-			palette32[i*4+0] = palette[i*3+0];
-			palette32[i*4+1] = palette[i*3+1];
-			palette32[i*4+2] = palette[i*3+2];
-			palette32[i*4+3] = 0xFF;
-		}
-
-		R_GammaCorrectAndSetPalette( palette32 );
-	}
-	else
-	{
-		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
-	}
-}
-
-/*
-================
-Draw_BuildGammaTable
-================
-*/
-void Draw_BuildGammaTable (void)
-{
-	int		i, inf;
-	float	g;
-
-	g = vid_gamma->value;
-
-	if (g == 1.0)
-	{
-		for (i=0 ; i<256 ; i++)
-			sw_state.gammatable[i] = i;
-		return;
-	}
-	
-	for (i=0 ; i<256 ; i++)
-	{
-		inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
-		if (inf < 0)
-			inf = 0;
-		if (inf > 255)
-			inf = 255;
-		sw_state.gammatable[i] = inf;
-	}
-}
-
-/*
-** R_DrawBeam
-*/
-void R_DrawBeam( entity_t *e )
-{
-#define NUM_BEAM_SEGS 6
-
-	int	i;
-
-	vec3_t perpvec;
-	vec3_t direction, normalized_direction;
-	vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
-	vec3_t oldorigin, origin;
-
-	oldorigin[0] = e->oldorigin[0];
-	oldorigin[1] = e->oldorigin[1];
-	oldorigin[2] = e->oldorigin[2];
-
-	origin[0] = e->origin[0];
-	origin[1] = e->origin[1];
-	origin[2] = e->origin[2];
-
-	normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
-	normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
-	normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
-
-	if ( VectorNormalize( normalized_direction ) == 0 )
-		return;
-
-	PerpendicularVector( perpvec, normalized_direction );
-	VectorScale( perpvec, e->frame / 2, perpvec );
-
-	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
-	{
-		RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
-		VectorAdd( start_points[i], origin, start_points[i] );
-		VectorAdd( start_points[i], direction, end_points[i] );
-	}
-
-	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
-	{
-		R_IMFlatShadedQuad( start_points[i],
-		                    end_points[i],
-							end_points[(i+1)%NUM_BEAM_SEGS],
-							start_points[(i+1)%NUM_BEAM_SEGS],
-							e->skinnum & 0xFF,
-							e->alpha );
-	}
-}
-
-
-//===================================================================
-
-/*
-============
-R_SetSky
-============
-*/
-// 3dstudio environment map names
-char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
-int	r_skysideimage[6] = {5, 2, 4, 1, 0, 3};
-extern	mtexinfo_t		r_skytexinfo[6];
-void R_SetSky (char *name, float rotate, vec3_t axis)
-{
-	int		i;
-	char	pathname[MAX_QPATH];
-
-	strncpy (skyname, name, sizeof(skyname)-1);
-	skyrotate = rotate;
-	VectorCopy (axis, skyaxis);
-
-	for (i=0 ; i<6 ; i++)
-	{
-		Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);
-		r_skytexinfo[i].image = R_FindImage (pathname, it_sky);
-	}
-}
-
-
-/*
-===============
-Draw_GetPalette
-===============
-*/
-void Draw_GetPalette (void)
-{
-	byte	*pal, *out;
-	int		i;
-	int		r, g, b;
-
-	// get the palette and colormap
-	LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);
-	if (!vid.colormap)
-		ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
-	vid.alphamap = vid.colormap + 64*256;
-
-	out = (byte *)d_8to24table;
-	for (i=0 ; i<256 ; i++, out+=4)
-	{
-		r = pal[i*3+0];
-		g = pal[i*3+1];
-		b = pal[i*3+2];
-
-        out[0] = r;
-        out[1] = g;
-        out[2] = b;
-	}
-
-	free (pal);
-}
-
-struct image_s *R_RegisterSkin (char *name);
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-GetRefAPI
-
-@@@@@@@@@@@@@@@@@@@@@
-*/
-refexport_t GetRefAPI (refimport_t rimp)
-{
-	refexport_t	re;
-
-	ri = rimp;
-
-	re.api_version = API_VERSION;
-
-	re.BeginRegistration = R_BeginRegistration;
-    re.RegisterModel = R_RegisterModel;
-    re.RegisterSkin = R_RegisterSkin;
-	re.RegisterPic = Draw_FindPic;
-	re.SetSky = R_SetSky;
-	re.EndRegistration = R_EndRegistration;
-
-	re.RenderFrame = R_RenderFrame;
-
-	re.DrawGetPicSize = Draw_GetPicSize;
-	re.DrawPic = Draw_Pic;
-	re.DrawStretchPic = Draw_StretchPic;
-	re.DrawChar = Draw_Char;
-	re.DrawTileClear = Draw_TileClear;
-	re.DrawFill = Draw_Fill;
-	re.DrawFadeScreen= Draw_FadeScreen;
-
-	re.DrawStretchRaw = Draw_StretchRaw;
-
-	re.Init = R_Init;
-	re.Shutdown = R_Shutdown;
-
-	re.CinematicSetPalette = R_CinematicSetPalette;
-	re.BeginFrame = R_BeginFrame;
-	re.EndFrame = SWimp_EndFrame;
-
-	re.AppActivate = SWimp_AppActivate;
-
-	Swap_Init ();
-
-	return re;
-}
-
-#ifndef REF_HARD_LINKED
-// this is only here so the functions in q_shared.c and q_shwin.c can link
-void Sys_Error (char *error, ...)
-{
-	va_list		argptr;
-	char		text[1024];
-
-	va_start (argptr, error);
-	vsprintf (text, error, argptr);
-	va_end (argptr);
-
-	ri.Sys_Error (ERR_FATAL, "%s", text);
-}
-
-void Com_Printf (char *fmt, ...)
-{
-	va_list		argptr;
-	char		text[1024];
-
-	va_start (argptr, fmt);
-	vsprintf (text, fmt, argptr);
-	va_end (argptr);
-
-	ri.Con_Printf (PRINT_ALL, "%s", text);
-}
-
-#endif
+/*

+Copyright (C) 1997-2001 Id Software, Inc.

+

+This program is free software; you can redistribute it and/or

+modify it under the terms of the GNU General Public License

+as published by the Free Software Foundation; either version 2

+of the License, or (at your option) any later version.

+

+This program is distributed in the hope that it will be useful,

+but WITHOUT ANY WARRANTY; without even the implied warranty of

+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

+

+See the GNU General Public License for more details.

+

+You should have received a copy of the GNU General Public License

+along with this program; if not, write to the Free Software

+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

+

+*/

+// r_main.c

+

+#include "r_local.h"

+

+viddef_t	vid;

+refimport_t	ri;

+

+unsigned	d_8to24table[256];

+

+entity_t	r_worldentity;

+

+char		skyname[MAX_QPATH];

+float		skyrotate;

+vec3_t		skyaxis;

+image_t		*sky_images[6];

+

+refdef_t	r_newrefdef;

+model_t		*currentmodel;

+

+model_t		*r_worldmodel;

+

+byte		r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];

+

+swstate_t sw_state;

+

+void		*colormap;

+vec3_t		viewlightvec;

+alight_t	r_viewlighting = {128, 192, viewlightvec};

+float		r_time1;

+int			r_numallocatededges;

+float		r_aliasuvscale = 1.0;

+int			r_outofsurfaces;

+int			r_outofedges;

+

+qboolean	r_dowarp;

+

+mvertex_t	*r_pcurrentvertbase;

+

+int			c_surf;

+int			r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;

+qboolean	r_surfsonstack;

+int			r_clipflags;

+

+//

+// view origin

+//

+vec3_t	vup, base_vup;

+vec3_t	vpn, base_vpn;

+vec3_t	vright, base_vright;

+vec3_t	r_origin;

+

+//

+// screen size info

+//

+oldrefdef_t	r_refdef;

+float		xcenter, ycenter;

+float		xscale, yscale;

+float		xscaleinv, yscaleinv;

+float		xscaleshrink, yscaleshrink;

+float		aliasxscale, aliasyscale, aliasxcenter, aliasycenter;

+

+int		r_screenwidth;

+

+float	verticalFieldOfView;

+float	xOrigin, yOrigin;

+

+mplane_t	screenedge[4];

+

+//

+// refresh flags

+//

+int		r_framecount = 1;	// so frame counts initialized to 0 don't match

+int		r_visframecount;

+int		d_spanpixcount;

+int		r_polycount;

+int		r_drawnpolycount;

+int		r_wholepolycount;

+

+int			*pfrustum_indexes[4];

+int			r_frustum_indexes[4*6];

+

+mleaf_t		*r_viewleaf;

+int			r_viewcluster, r_oldviewcluster;

+

+image_t  	*r_notexture_mip;

+

+float	da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;

+float	se_time1, se_time2, de_time1, de_time2;

+

+void R_MarkLeaves (void);

+

+cvar_t	*r_lefthand;

+cvar_t	*sw_aliasstats;

+cvar_t	*sw_allow_modex;

+cvar_t	*sw_clearcolor;

+cvar_t	*sw_drawflat;

+cvar_t	*sw_draworder;

+cvar_t	*sw_maxedges;

+cvar_t	*sw_maxsurfs;

+cvar_t  *sw_mode;

+cvar_t	*sw_reportedgeout;

+cvar_t	*sw_reportsurfout;

+cvar_t  *sw_stipplealpha;

+cvar_t	*sw_surfcacheoverride;

+cvar_t	*sw_waterwarp;

+

+cvar_t	*r_drawworld;

+cvar_t	*r_drawentities;

+cvar_t	*r_dspeeds;

+cvar_t	*r_fullbright;

+cvar_t  *r_lerpmodels;

+cvar_t  *r_novis;

+

+cvar_t	*r_speeds;

+cvar_t	*r_lightlevel;	//FIXME HACK

+

+cvar_t	*vid_fullscreen;

+cvar_t	*vid_gamma;

+

+//PGM

+cvar_t	*sw_lockpvs;

+//PGM

+

+#define	STRINGER(x) "x"

+

+

+#if	!id386

+

+// r_vars.c

+

+// all global and static refresh variables are collected in a contiguous block

+// to avoid cache conflicts.

+

+//-------------------------------------------------------

+// global refresh variables

+//-------------------------------------------------------

+

+// FIXME: make into one big structure, like cl or sv

+// FIXME: do separately for refresh engine and driver

+

+

+// d_vars.c

+

+// all global and static refresh variables are collected in a contiguous block

+// to avoid cache conflicts.

+

+//-------------------------------------------------------

+// global refresh variables

+//-------------------------------------------------------

+

+// FIXME: make into one big structure, like cl or sv

+// FIXME: do separately for refresh engine and driver

+

+float	d_sdivzstepu, d_tdivzstepu, d_zistepu;

+float	d_sdivzstepv, d_tdivzstepv, d_zistepv;

+float	d_sdivzorigin, d_tdivzorigin, d_ziorigin;

+

+fixed16_t	sadjust, tadjust, bbextents, bbextentt;

+

+pixel_t			*cacheblock;

+int				cachewidth;

+pixel_t			*d_viewbuffer;

+short			*d_pzbuffer;

+unsigned int	d_zrowbytes;

+unsigned int	d_zwidth;

+

+

+#endif	// !id386

+

+byte	r_notexture_buffer[1024];

+

+/*

+==================

+R_InitTextures

+==================

+*/

+void	R_InitTextures (void)

+{

+	int		x,y, m;

+	byte	*dest;

+	

+// create a simple checkerboard texture for the default

+	r_notexture_mip = (image_t *)&r_notexture_buffer;

+	

+	r_notexture_mip->width = r_notexture_mip->height = 16;

+	r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)];

+	r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16;

+	r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8;

+	r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4;

+	

+	for (m=0 ; m<4 ; m++)

+	{

+		dest = r_notexture_mip->pixels[m];

+		for (y=0 ; y< (16>>m) ; y++)

+			for (x=0 ; x< (16>>m) ; x++)

+			{

+				if (  (y< (8>>m) ) ^ (x< (8>>m) ) )

+

+					*dest++ = 0;

+				else

+					*dest++ = 0xff;

+			}

+	}	

+}

+

+

+/*

+================

+R_InitTurb

+================

+*/

+void R_InitTurb (void)

+{

+	int		i;

+	

+	for (i=0 ; i<1280 ; i++)

+	{

+		sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;

+		intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2;	// AMP2, not 20

+		blanktable[i] = 0;			//PGM

+	}

+}

+

+void R_ImageList_f( void );

+

+void R_Register (void)

+{

+	sw_aliasstats = ri.Cvar_Get ("sw_polymodelstats", "0", 0);

+	sw_allow_modex = ri.Cvar_Get( "sw_allow_modex", "1", CVAR_ARCHIVE );

+	sw_clearcolor = ri.Cvar_Get ("sw_clearcolor", "2", 0);

+	sw_drawflat = ri.Cvar_Get ("sw_drawflat", "0", 0);

+	sw_draworder = ri.Cvar_Get ("sw_draworder", "0", 0);

+	sw_maxedges = ri.Cvar_Get ("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0);

+	sw_maxsurfs = ri.Cvar_Get ("sw_maxsurfs", "0", 0);

+	sw_mipcap = ri.Cvar_Get ("sw_mipcap", "0", 0);

+	sw_mipscale = ri.Cvar_Get ("sw_mipscale", "1", 0);

+	sw_reportedgeout = ri.Cvar_Get ("sw_reportedgeout", "0", 0);

+	sw_reportsurfout = ri.Cvar_Get ("sw_reportsurfout", "0", 0);

+	sw_stipplealpha = ri.Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );

+	sw_surfcacheoverride = ri.Cvar_Get ("sw_surfcacheoverride", "0", 0);

+	sw_waterwarp = ri.Cvar_Get ("sw_waterwarp", "1", 0);

+	sw_mode = ri.Cvar_Get( "sw_mode", "0", CVAR_ARCHIVE );

+

+	r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );

+	r_speeds = ri.Cvar_Get ("r_speeds", "0", 0);

+	r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0);

+	r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0);

+	r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0);

+	r_dspeeds = ri.Cvar_Get ("r_dspeeds", "0", 0);

+	r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0);

+	r_lerpmodels = ri.Cvar_Get( "r_lerpmodels", "1", 0 );

+	r_novis = ri.Cvar_Get( "r_novis", "0", 0 );

+

+	vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE );

+	vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE );

+

+	ri.Cmd_AddCommand ("modellist", Mod_Modellist_f);

+	ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );

+	ri.Cmd_AddCommand( "imagelist", R_ImageList_f );

+

+	sw_mode->modified = true; // force us to do mode specific stuff later

+	vid_gamma->modified = true; // force us to rebuild the gamma table later

+

+//PGM

+	sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0);

+//PGM

+}

+

+void R_UnRegister (void)

+{

+	ri.Cmd_RemoveCommand( "screenshot" );

+	ri.Cmd_RemoveCommand ("modellist");

+	ri.Cmd_RemoveCommand( "imagelist" );

+}

+

+/*

+===============

+R_Init

+===============

+*/

+int R_Init( void *hInstance, void *wndProc )

+{

+	R_InitImages ();

+	Mod_Init ();

+	Draw_InitLocal ();

+	R_InitTextures ();

+

+	R_InitTurb ();

+

+	view_clipplanes[0].leftedge = true;

+	view_clipplanes[1].rightedge = true;

+	view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =

+			view_clipplanes[3].leftedge = false;

+	view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =

+			view_clipplanes[3].rightedge = false;

+

+	r_refdef.xOrigin = XCENTERING;

+	r_refdef.yOrigin = YCENTERING;

+

+// TODO: collect 386-specific code in one place

+#if	id386

+	Sys_MakeCodeWriteable ((long)R_EdgeCodeStart,

+					     (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart);

+	Sys_SetFPCW ();		// get bit masks for FPCW	(FIXME: is this id386?)

+#endif	// id386

+

+	r_aliasuvscale = 1.0;

+

+	R_Register ();

+	Draw_GetPalette ();

+	SWimp_Init( hInstance, wndProc );

+

+	// create the window

+	R_BeginFrame( 0 );

+

+	ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");

+

+	return true;

+}

+

+/*

+===============

+R_Shutdown

+===============

+*/

+void R_Shutdown (void)

+{

+	// free z buffer

+	if (d_pzbuffer)

+	{

+		free (d_pzbuffer);

+		d_pzbuffer = NULL;

+	}

+	// free surface cache

+	if (sc_base)

+	{

+		D_FlushCaches ();

+		free (sc_base);

+		sc_base = NULL;

+	}

+

+	// free colormap

+	if (vid.colormap)

+	{

+		free (vid.colormap);

+		vid.colormap = NULL;

+	}

+	R_UnRegister ();

+	Mod_FreeAll ();

+	R_ShutdownImages ();

+

+	SWimp_Shutdown();

+}

+

+/*

+===============

+R_NewMap

+===============

+*/

+void R_NewMap (void)

+{

+	r_viewcluster = -1;

+

+	r_cnumsurfs = sw_maxsurfs->value;

+

+	if (r_cnumsurfs <= MINSURFACES)

+		r_cnumsurfs = MINSURFACES;

+

+	if (r_cnumsurfs > NUMSTACKSURFACES)

+	{

+		surfaces = malloc (r_cnumsurfs * sizeof(surf_t));

+		surface_p = surfaces;

+		surf_max = &surfaces[r_cnumsurfs];

+		r_surfsonstack = false;

+	// surface 0 doesn't really exist; it's just a dummy because index 0

+	// is used to indicate no edge attached to surface

+		surfaces--;

+		R_SurfacePatch ();

+	}

+	else

+	{

+		r_surfsonstack = true;

+	}

+

+	r_maxedgesseen = 0;

+	r_maxsurfsseen = 0;

+

+	r_numallocatededges = sw_maxedges->value;

+

+	if (r_numallocatededges < MINEDGES)

+		r_numallocatededges = MINEDGES;

+

+	if (r_numallocatededges <= NUMSTACKEDGES)

+	{

+		auxedges = NULL;

+	}

+	else

+	{

+		auxedges = malloc (r_numallocatededges * sizeof(edge_t));

+	}

+}

+

+

+/*

+===============

+R_MarkLeaves

+

+Mark the leaves and nodes that are in the PVS for the current

+cluster

+===============

+*/

+void R_MarkLeaves (void)

+{

+	byte	*vis;

+	mnode_t	*node;

+	int		i;

+	mleaf_t	*leaf;

+	int		cluster;

+

+	if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)

+		return;

+	

+	// development aid to let you run around and see exactly where

+	// the pvs ends

+	if (sw_lockpvs->value)

+		return;

+

+	r_visframecount++;

+	r_oldviewcluster = r_viewcluster;

+

+	if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)

+	{

+		// mark everything

+		for (i=0 ; i<r_worldmodel->numleafs ; i++)

+			r_worldmodel->leafs[i].visframe = r_visframecount;

+		for (i=0 ; i<r_worldmodel->numnodes ; i++)

+			r_worldmodel->nodes[i].visframe = r_visframecount;

+		return;

+	}

+

+	vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);

+	

+	for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)

+	{

+		cluster = leaf->cluster;

+		if (cluster == -1)

+			continue;

+		if (vis[cluster>>3] & (1<<(cluster&7)))

+		{

+			node = (mnode_t *)leaf;

+			do

+			{

+				if (node->visframe == r_visframecount)

+					break;

+				node->visframe = r_visframecount;

+				node = node->parent;

+			} while (node);

+		}

+	}

+

+#if 0

+	for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)

+	{

+		if (vis[i>>3] & (1<<(i&7)))

+		{

+			node = (mnode_t *)&r_worldmodel->leafs[i];	// FIXME: cluster

+			do

+			{

+				if (node->visframe == r_visframecount)

+					break;

+				node->visframe = r_visframecount;

+				node = node->parent;

+			} while (node);

+		}

+	}

+#endif

+}

+

+/*

+** R_DrawNullModel

+**

+** IMPLEMENT THIS!

+*/

+void R_DrawNullModel( void )

+{

+}

+

+/*

+=============

+R_DrawEntitiesOnList

+=============

+*/

+void R_DrawEntitiesOnList (void)

+{

+	int			i;

+	qboolean	translucent_entities = false;

+

+	if (!r_drawentities->value)

+		return;

+

+	// all bmodels have already been drawn by the edge list

+	for (i=0 ; i<r_newrefdef.num_entities ; i++)

+	{

+		currententity = &r_newrefdef.entities[i];

+

+		if ( currententity->flags & RF_TRANSLUCENT )

+		{

+			translucent_entities = true;

+			continue;

+		}

+

+		if ( currententity->flags & RF_BEAM )

+		{

+			modelorg[0] = -r_origin[0];

+			modelorg[1] = -r_origin[1];

+			modelorg[2] = -r_origin[2];

+			VectorCopy( vec3_origin, r_entorigin );

+			R_DrawBeam( currententity );

+		}

+		else

+		{

+			currentmodel = currententity->model;

+			if (!currentmodel)

+			{

+				R_DrawNullModel();

+				continue;

+			}

+			VectorCopy (currententity->origin, r_entorigin);

+			VectorSubtract (r_origin, r_entorigin, modelorg);

+

+			switch (currentmodel->type)

+			{

+			case mod_sprite:

+				R_DrawSprite ();

+				break;

+

+			case mod_alias:

+				R_AliasDrawModel ();

+				break;

+

+			default:

+				break;

+			}

+		}

+	}

+

+	if ( !translucent_entities )

+		return;

+

+	for (i=0 ; i<r_newrefdef.num_entities ; i++)

+	{

+		currententity = &r_newrefdef.entities[i];

+

+		if ( !( currententity->flags & RF_TRANSLUCENT ) )

+			continue;

+

+		if ( currententity->flags & RF_BEAM )

+		{

+			modelorg[0] = -r_origin[0];

+			modelorg[1] = -r_origin[1];

+			modelorg[2] = -r_origin[2];

+			VectorCopy( vec3_origin, r_entorigin );

+			R_DrawBeam( currententity );

+		}

+		else

+		{

+			currentmodel = currententity->model;

+			if (!currentmodel)

+			{

+				R_DrawNullModel();

+				continue;

+			}

+			VectorCopy (currententity->origin, r_entorigin);

+			VectorSubtract (r_origin, r_entorigin, modelorg);

+

+			switch (currentmodel->type)

+			{

+			case mod_sprite:

+				R_DrawSprite ();

+				break;

+

+			case mod_alias:

+				R_AliasDrawModel ();

+				break;

+

+			default:

+				break;

+			}

+		}

+	}

+}

+

+

+/*

+=============

+R_BmodelCheckBBox

+=============

+*/

+int R_BmodelCheckBBox (float *minmaxs)

+{

+	int			i, *pindex, clipflags;

+	vec3_t		acceptpt, rejectpt;

+	float		d;

+

+	clipflags = 0;

+

+	for (i=0 ; i<4 ; i++)

+	{

+	// generate accept and reject points

+	// FIXME: do with fast look-ups or integer tests based on the sign bit

+	// of the floating point values

+

+		pindex = pfrustum_indexes[i];

+

+		rejectpt[0] = minmaxs[pindex[0]];

+		rejectpt[1] = minmaxs[pindex[1]];

+		rejectpt[2] = minmaxs[pindex[2]];

+		

+		d = DotProduct (rejectpt, view_clipplanes[i].normal);

+		d -= view_clipplanes[i].dist;

+

+		if (d <= 0)

+			return BMODEL_FULLY_CLIPPED;

+

+		acceptpt[0] = minmaxs[pindex[3+0]];

+		acceptpt[1] = minmaxs[pindex[3+1]];

+		acceptpt[2] = minmaxs[pindex[3+2]];

+

+		d = DotProduct (acceptpt, view_clipplanes[i].normal);

+		d -= view_clipplanes[i].dist;

+

+		if (d <= 0)

+			clipflags |= (1<<i);

+	}

+

+	return clipflags;

+}

+

+

+/*

+===================

+R_FindTopnode

+

+Find the first node that splits the given box

+===================

+*/

+mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)

+{

+	mplane_t	*splitplane;

+	int			sides;

+	mnode_t *node;

+

+	node = r_worldmodel->nodes;

+

+	while (1)

+	{

+		if (node->visframe != r_visframecount)

+			return NULL;		// not visible at all

+		

+		if (node->contents != CONTENTS_NODE)

+		{

+			if (node->contents != CONTENTS_SOLID)

+				return	node; // we've reached a non-solid leaf, so it's

+							//  visible and not BSP clipped

+			return NULL;	// in solid, so not visible

+		}

+		

+		splitplane = node->plane;

+		sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);

+		

+		if (sides == 3)

+			return node;	// this is the splitter

+		

+	// not split yet; recurse down the contacted side

+		if (sides & 1)

+			node = node->children[0];

+		else

+			node = node->children[1];

+	}

+}

+

+

+/*

+=============

+RotatedBBox

+

+Returns an axially aligned box that contains the input box at the given rotation

+=============

+*/

+void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)

+{

+	vec3_t	tmp, v;

+	int		i, j;

+	vec3_t	forward, right, up;

+

+	if (!angles[0] && !angles[1] && !angles[2])

+	{

+		VectorCopy (mins, tmins);

+		VectorCopy (maxs, tmaxs);

+		return;

+	}

+

+	for (i=0 ; i<3 ; i++)

+	{

+		tmins[i] = 99999;

+		tmaxs[i] = -99999;

+	}

+

+	AngleVectors (angles, forward, right, up);

+

+	for ( i = 0; i < 8; i++ )

+	{

+		if ( i & 1 )

+			tmp[0] = mins[0];

+		else

+			tmp[0] = maxs[0];

+

+		if ( i & 2 )

+			tmp[1] = mins[1];

+		else

+			tmp[1] = maxs[1];

+

+		if ( i & 4 )

+			tmp[2] = mins[2];

+		else

+			tmp[2] = maxs[2];

+

+

+		VectorScale (forward, tmp[0], v);

+		VectorMA (v, -tmp[1], right, v);

+		VectorMA (v, tmp[2], up, v);

+

+		for (j=0 ; j<3 ; j++)

+		{

+			if (v[j] < tmins[j])

+				tmins[j] = v[j];

+			if (v[j] > tmaxs[j])

+				tmaxs[j] = v[j];

+		}

+	}

+}

+

+/*

+=============

+R_DrawBEntitiesOnList

+=============

+*/

+void R_DrawBEntitiesOnList (void)

+{

+	int			i, clipflags;

+	vec3_t		oldorigin;

+	vec3_t		mins, maxs;

+	float		minmaxs[6];

+	mnode_t		*topnode;

+

+	if (!r_drawentities->value)

+		return;

+

+	VectorCopy (modelorg, oldorigin);

+	insubmodel = true;

+	r_dlightframecount = r_framecount;

+

+	for (i=0 ; i<r_newrefdef.num_entities ; i++)

+	{

+		currententity = &r_newrefdef.entities[i];

+		currentmodel = currententity->model;

+		if (!currentmodel)

+			continue;

+		if (currentmodel->nummodelsurfaces == 0)

+			continue;	// clip brush only

+		if ( currententity->flags & RF_BEAM )

+			continue;

+		if (currentmodel->type != mod_brush)

+			continue;

+	// see if the bounding box lets us trivially reject, also sets

+	// trivial accept status

+		RotatedBBox (currentmodel->mins, currentmodel->maxs,

+			currententity->angles, mins, maxs);

+		VectorAdd (mins, currententity->origin, minmaxs);

+		VectorAdd (maxs, currententity->origin, (minmaxs+3));

+

+		clipflags = R_BmodelCheckBBox (minmaxs);

+		if (clipflags == BMODEL_FULLY_CLIPPED)

+			continue;	// off the edge of the screen

+

+		topnode = R_FindTopnode (minmaxs, minmaxs+3);

+		if (!topnode)

+			continue;	// no part in a visible leaf

+

+		VectorCopy (currententity->origin, r_entorigin);

+		VectorSubtract (r_origin, r_entorigin, modelorg);

+

+		r_pcurrentvertbase = currentmodel->vertexes;

+

+	// FIXME: stop transforming twice

+		R_RotateBmodel ();

+

+	// calculate dynamic lighting for bmodel

+		R_PushDlights (currentmodel);

+

+		if (topnode->contents == CONTENTS_NODE)

+		{

+		// not a leaf; has to be clipped to the world BSP

+			r_clipflags = clipflags;

+			R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);

+		}

+		else

+		{

+		// falls entirely in one leaf, so we just put all the

+		// edges in the edge list and let 1/z sorting handle

+		// drawing order

+			R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);

+		}

+

+	// put back world rotation and frustum clipping		

+	// FIXME: R_RotateBmodel should just work off base_vxx

+		VectorCopy (base_vpn, vpn);

+		VectorCopy (base_vup, vup);

+		VectorCopy (base_vright, vright);

+		VectorCopy (oldorigin, modelorg);

+		R_TransformFrustum ();

+	}

+

+	insubmodel = false;

+}

+

+

+/*

+================

+R_EdgeDrawing

+================

+*/

+void R_EdgeDrawing (void)

+{

+	edge_t	ledges[NUMSTACKEDGES +

+				((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];

+	surf_t	lsurfs[NUMSTACKSURFACES +

+				((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];

+

+	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )

+		return;

+

+	if (auxedges)

+	{

+		r_edges = auxedges;

+	}

+	else

+	{

+		r_edges =  (edge_t *)

+				(((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));

+	}

+

+	if (r_surfsonstack)

+	{

+		surfaces =  (surf_t *)

+				(((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));

+		surf_max = &surfaces[r_cnumsurfs];

+	// surface 0 doesn't really exist; it's just a dummy because index 0

+	// is used to indicate no edge attached to surface

+		surfaces--;

+		R_SurfacePatch ();

+	}

+

+	R_BeginEdgeFrame ();

+

+	if (r_dspeeds->value)

+	{

+		rw_time1 = Sys_Milliseconds ();

+	}

+

+	R_RenderWorld ();

+

+	if (r_dspeeds->value)

+	{

+		rw_time2 = Sys_Milliseconds ();

+		db_time1 = rw_time2;

+	}

+

+	R_DrawBEntitiesOnList ();

+

+	if (r_dspeeds->value)

+	{

+		db_time2 = Sys_Milliseconds ();

+		se_time1 = db_time2;

+	}

+

+	R_ScanEdges ();

+}

+

+//=======================================================================

+

+

+/*

+=============

+R_CalcPalette

+

+=============

+*/

+void R_CalcPalette (void)

+{

+	static qboolean modified;

+	byte	palette[256][4], *in, *out;

+	int		i, j;

+	float	alpha, one_minus_alpha;

+	vec3_t	premult;

+	int		v;

+

+	alpha = r_newrefdef.blend[3];

+	if (alpha <= 0)

+	{

+		if (modified)

+		{	// set back to default

+			modified = false;

+			R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );

+			return;

+		}

+		return;

+	}

+

+	modified = true;

+	if (alpha > 1)

+		alpha = 1;

+

+	premult[0] = r_newrefdef.blend[0]*alpha*255;

+	premult[1] = r_newrefdef.blend[1]*alpha*255;

+	premult[2] = r_newrefdef.blend[2]*alpha*255;

+

+	one_minus_alpha = (1.0 - alpha);

+

+	in = (byte *)d_8to24table;

+	out = palette[0];

+	for (i=0 ; i<256 ; i++, in+=4, out+=4)

+	{

+		for (j=0 ; j<3 ; j++)

+		{

+			v = premult[j] + one_minus_alpha * in[j];

+			if (v > 255)

+				v = 255;

+			out[j] = v;

+		}

+		out[3] = 255;

+	}

+

+	R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] );

+//	SWimp_SetPalette( palette[0] );

+}

+

+//=======================================================================

+

+void R_SetLightLevel (void)

+{

+	vec3_t		light;

+

+	if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))

+	{

+		r_lightlevel->value = 150.0;

+		return;

+	}

+

+	// save off light value for server to look at (BIG HACK!)

+	R_LightPoint (r_newrefdef.vieworg, light);

+	r_lightlevel->value = 150.0 * light[0];

+}

+

+

+/*

+@@@@@@@@@@@@@@@@

+R_RenderFrame

+

+@@@@@@@@@@@@@@@@

+*/

+void R_RenderFrame (refdef_t *fd)

+{

+	r_newrefdef = *fd;

+

+	if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )

+		ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");

+

+	VectorCopy (fd->vieworg, r_refdef.vieworg);

+	VectorCopy (fd->viewangles, r_refdef.viewangles);

+

+	if (r_speeds->value || r_dspeeds->value)

+		r_time1 = Sys_Milliseconds ();

+

+	R_SetupFrame ();

+

+	R_MarkLeaves ();	// done here so we know if we're in water

+

+	R_PushDlights (r_worldmodel);

+

+	R_EdgeDrawing ();

+

+	if (r_dspeeds->value)

+	{

+		se_time2 = Sys_Milliseconds ();

+		de_time1 = se_time2;

+	}

+

+	R_DrawEntitiesOnList ();

+

+	if (r_dspeeds->value)

+	{

+		de_time2 = Sys_Milliseconds ();

+		dp_time1 = Sys_Milliseconds ();

+	}

+

+	R_DrawParticles ();

+

+	if (r_dspeeds->value)

+		dp_time2 = Sys_Milliseconds ();

+

+	R_DrawAlphaSurfaces();

+

+	R_SetLightLevel ();

+

+	if (r_dowarp)

+		D_WarpScreen ();

+

+	if (r_dspeeds->value)

+		da_time1 = Sys_Milliseconds ();

+

+	if (r_dspeeds->value)

+		da_time2 = Sys_Milliseconds ();

+

+	R_CalcPalette ();

+

+	if (sw_aliasstats->value)

+		R_PrintAliasStats ();

+		

+	if (r_speeds->value)

+		R_PrintTimes ();

+

+	if (r_dspeeds->value)

+		R_PrintDSpeeds ();

+

+	if (sw_reportsurfout->value && r_outofsurfaces)

+		ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);

+

+	if (sw_reportedgeout->value && r_outofedges)

+		ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);

+}

+

+/*

+** R_InitGraphics

+*/

+void R_InitGraphics( int width, int height )

+{

+	vid.width  = width;

+	vid.height = height;

+

+	// free z buffer

+	if ( d_pzbuffer )

+	{

+		free( d_pzbuffer );

+		d_pzbuffer = NULL;

+	}

+

+	// free surface cache

+	if ( sc_base )

+	{

+		D_FlushCaches ();

+		free( sc_base );

+		sc_base = NULL;

+	}

+

+	d_pzbuffer = malloc(vid.width*vid.height*2);

+

+	R_InitCaches ();

+

+	R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table );

+}

+

+void SetStereoBuffer(int buf);

+

+/*

+** R_BeginFrame

+*/

+void R_BeginFrame( float camera_separation )

+{

+	extern void Draw_BuildGammaTable( void );

+

+	SetStereoBuffer((camera_separation <= 0.0) ? 0 : 1);

+

+	/*

+	** rebuild the gamma correction palette if necessary

+	*/

+	if ( vid_gamma->modified )

+	{

+		Draw_BuildGammaTable();

+		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );

+

+		vid_gamma->modified = false;

+	}

+

+	while ( sw_mode->modified || vid_fullscreen->modified )

+	{

+		rserr_t err;

+

+		/*

+		** if this returns rserr_invalid_fullscreen then it set the mode but not as a

+		** fullscreen mode, e.g. 320x200 on a system that doesn't support that res

+		*/

+		if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )

+		{

+			R_InitGraphics( vid.width, vid.height );

+

+			sw_state.prev_mode = sw_mode->value;

+			vid_fullscreen->modified = false;

+			sw_mode->modified = false;

+		}

+		else

+		{

+			if ( err == rserr_invalid_mode )

+			{

+				ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );

+				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );

+			}

+			else if ( err == rserr_invalid_fullscreen )

+			{

+				R_InitGraphics( vid.width, vid.height );

+

+				ri.Cvar_SetValue( "vid_fullscreen", 0);

+				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );

+				sw_state.prev_mode = sw_mode->value;

+//				vid_fullscreen->modified = false;

+//				sw_mode->modified = false;

+			}

+			else

+			{

+				ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );

+			}

+		}

+	}

+}

+

+/*

+** R_GammaCorrectAndSetPalette

+*/

+void R_GammaCorrectAndSetPalette( const unsigned char *palette )

+{

+	int i;

+

+	for ( i = 0; i < 256; i++ )

+	{

+		sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];

+		sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];

+		sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];

+	}

+

+	SWimp_SetPalette( sw_state.currentpalette );

+}

+

+/*

+** R_CinematicSetPalette

+*/

+void R_CinematicSetPalette( const unsigned char *palette )

+{

+	byte palette32[1024];

+	int		i, j, w;

+	int		*d;

+

+	// clear screen to black to avoid any palette flash

+	w = abs(vid.rowbytes)>>2;	// stupid negative pitch win32 stuff...

+	for (i=0 ; i<vid.height ; i++, d+=w)

+	{

+		d = (int *)(vid.buffer + i*vid.rowbytes);

+		for (j=0 ; j<w ; j++)

+			d[j] = 0;

+	}

+	// flush it to the screen

+	SWimp_EndFrame ();

+

+	if ( palette )

+	{

+		for ( i = 0; i < 256; i++ )

+		{

+			palette32[i*4+0] = palette[i*3+0];

+			palette32[i*4+1] = palette[i*3+1];

+			palette32[i*4+2] = palette[i*3+2];

+			palette32[i*4+3] = 0xFF;

+		}

+

+		R_GammaCorrectAndSetPalette( palette32 );

+	}

+	else

+	{

+		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );

+	}

+}

+

+/*

+================

+Draw_BuildGammaTable

+================

+*/

+void Draw_BuildGammaTable (void)

+{

+	int		i, inf;

+	float	g;

+

+	g = vid_gamma->value;

+

+	if (g == 1.0)

+	{

+		for (i=0 ; i<256 ; i++)

+			sw_state.gammatable[i] = i;

+		return;

+	}

+	

+	for (i=0 ; i<256 ; i++)

+	{

+		inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;

+		if (inf < 0)

+			inf = 0;

+		if (inf > 255)

+			inf = 255;

+		sw_state.gammatable[i] = inf;

+	}

+}

+

+/*

+** R_DrawBeam

+*/

+void R_DrawBeam( entity_t *e )

+{

+#define NUM_BEAM_SEGS 6

+

+	int	i;

+

+	vec3_t perpvec;

+	vec3_t direction, normalized_direction;

+	vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];

+	vec3_t oldorigin, origin;

+

+	oldorigin[0] = e->oldorigin[0];

+	oldorigin[1] = e->oldorigin[1];

+	oldorigin[2] = e->oldorigin[2];

+

+	origin[0] = e->origin[0];

+	origin[1] = e->origin[1];

+	origin[2] = e->origin[2];

+

+	normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];

+	normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];

+	normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];

+

+	if ( VectorNormalize( normalized_direction ) == 0 )

+		return;

+

+	PerpendicularVector( perpvec, normalized_direction );

+	VectorScale( perpvec, e->frame / 2, perpvec );

+

+	for ( i = 0; i < NUM_BEAM_SEGS; i++ )

+	{

+		RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );

+		VectorAdd( start_points[i], origin, start_points[i] );

+		VectorAdd( start_points[i], direction, end_points[i] );

+	}

+

+	for ( i = 0; i < NUM_BEAM_SEGS; i++ )

+	{

+		R_IMFlatShadedQuad( start_points[i],

+		                    end_points[i],

+							end_points[(i+1)%NUM_BEAM_SEGS],

+							start_points[(i+1)%NUM_BEAM_SEGS],

+							e->skinnum & 0xFF,

+							e->alpha );

+	}

+}

+

+

+//===================================================================

+

+/*

+============

+R_SetSky

+============

+*/

+// 3dstudio environment map names

+char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};

+int	r_skysideimage[6] = {5, 2, 4, 1, 0, 3};

+extern	mtexinfo_t		r_skytexinfo[6];

+void R_SetSky (char *name, float rotate, vec3_t axis)

+{

+	int		i;

+	char	pathname[MAX_QPATH];

+

+	strncpy (skyname, name, sizeof(skyname)-1);

+	skyrotate = rotate;

+	VectorCopy (axis, skyaxis);

+

+	for (i=0 ; i<6 ; i++)

+	{

+		Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);

+		r_skytexinfo[i].image = R_FindImage (pathname, it_sky);

+	}

+}

+

+

+/*

+===============

+Draw_GetPalette

+===============

+*/

+void Draw_GetPalette (void)

+{

+	byte	*pal, *out;

+	int		i;

+	int		r, g, b;

+

+	// get the palette and colormap

+	LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);

+	if (!vid.colormap)

+		ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");

+	vid.alphamap = vid.colormap + 64*256;

+

+	out = (byte *)d_8to24table;

+	for (i=0 ; i<256 ; i++, out+=4)

+	{

+		r = pal[i*3+0];

+		g = pal[i*3+1];

+		b = pal[i*3+2];

+

+        out[0] = r;

+        out[1] = g;

+        out[2] = b;

+	}

+

+	free (pal);

+}

+

+struct image_s *R_RegisterSkin (char *name);

+

+/*

+@@@@@@@@@@@@@@@@@@@@@

+GetRefAPI

+

+@@@@@@@@@@@@@@@@@@@@@

+*/

+refexport_t GetRefAPI (refimport_t rimp)

+{

+	refexport_t	re;

+

+	ri = rimp;

+

+	re.api_version = API_VERSION;

+

+	re.BeginRegistration = R_BeginRegistration;

+    re.RegisterModel = R_RegisterModel;

+    re.RegisterSkin = R_RegisterSkin;

+	re.RegisterPic = Draw_FindPic;

+	re.SetSky = R_SetSky;

+	re.EndRegistration = R_EndRegistration;

+

+	re.RenderFrame = R_RenderFrame;

+

+	re.DrawGetPicSize = Draw_GetPicSize;

+	re.DrawPic = Draw_Pic;

+	re.DrawStretchPic = Draw_StretchPic;

+	re.DrawChar = Draw_Char;

+	re.DrawTileClear = Draw_TileClear;

+	re.DrawFill = Draw_Fill;

+	re.DrawFadeScreen= Draw_FadeScreen;

+

+	re.DrawStretchRaw = Draw_StretchRaw;

+

+	re.Init = R_Init;

+	re.Shutdown = R_Shutdown;

+

+	re.CinematicSetPalette = R_CinematicSetPalette;

+	re.BeginFrame = R_BeginFrame;

+	re.EndFrame = SWimp_EndFrame;

+

+	re.AppActivate = SWimp_AppActivate;

+

+	Swap_Init ();

+

+	return re;

+}

+

+#ifndef REF_HARD_LINKED

+// this is only here so the functions in q_shared.c and q_shwin.c can link

+void Sys_Error (char *error, ...)

+{

+	va_list		argptr;

+	char		text[1024];

+

+	va_start (argptr, error);

+	vsprintf (text, error, argptr);

+	va_end (argptr);

+

+	ri.Sys_Error (ERR_FATAL, "%s", text);

+}

+

+void Com_Printf (char *fmt, ...)

+{

+	va_list		argptr;

+	char		text[1024];

+

+	va_start (argptr, fmt);

+	vsprintf (text, fmt, argptr);

+	va_end (argptr);

+

+	ri.Con_Printf (PRINT_ALL, "%s", text);

+}

+

+#endif



More information about the quake2 mailing list