
/*
Copyright (C) 1996-1997 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 "quakedef.h"

entity_t	r_worldentity;

qboolean	r_cache_thrash;		// compatability

vec3_t		modelorg, r_entorigin;

entity_t	*currententity;

int			r_visframecount;	// bumped when going to a new PVS

int			r_framecount;		// used for dlight push checking

mplane_t	frustum[4];

int			c_brush_polys, c_alias_polys;

qboolean	envmap;				// true during envmap command capture

int			currenttexture = -1;		// to avoid unnecessary texture sets

int			cnttextures[2] = {
	-1, -1};     // cached

int			particletexture;	// little dot for particles

int         smoketexture; //qbism//for Topaz particles

int			playertextures;		// up to 16 color translated skins

int			mirrortexturenum;	// quake texturenum, not gltexturenum

qboolean	mirror;
mplane_t	*mirror_plane;

//
// view origin
//
vec3_t	vup;
vec3_t	vpn;
vec3_t	vright;
vec3_t	r_origin;

float	r_world_matrix[16];
float	r_base_world_matrix[16];

//
// screen size info
//
refdef_t	r_refdef;

mleaf_t		*r_viewleaf, *r_oldviewleaf;

texture_t	*r_notexture_mip;

int		d_lightstylevalue[256];	// 8.8 fraction of base light value


void R_MarkLeaves (void);

cvar_t	r_norefresh = {
	"r_norefresh","0","Do not render view updates."};
cvar_t	r_drawentities = {
	"r_drawentities","1","Draw entities."};
cvar_t	r_drawviewmodel = {
	"r_drawviewmodel","1","Draw player's view model."};
cvar_t	r_speeds = {
	"r_speeds","0","Display polygon count statistics."};
cvar_t	r_fullbright = {
	"r_fullbright","0","Do not render lightmaps."};
cvar_t	r_lightmap = {
	"r_lightmap","0","Do not render textures."};
cvar_t	r_shadows = {
	"r_shadows","0","Render dynamic shadows of entities, projected on ground plane."}; //qbism//jf 2000-08-19 shadows off by default.

cvar_t	r_mirroralpha = {
	"r_mirroralpha","0.3","Reflectance of special mirror texture."}; //qbism//00-07-05 Paddy tutorial

cvar_t	r_wateralpha = {
	"r_wateralpha","0.5","Transparency of liquid textures."};
cvar_t	r_smoketrailwidth = {
	"r_smoketrailwidth","0.3","Width of smoke trail effect."}; //qbism//jf 00-07-05 adjustasble by request

cvar_t	r_skybox = { //qbism//00-07-05 Tane Piper tutorial

	"r_skybox","1","Render sky."};
cvar_t	r_dynamic = {
	"r_dynamic","1","Render dynamic lights."};
cvar_t	r_novis = {
	"r_novis","0","Do not use bsp tree polygon culling."};
cvar_t	r_waterwarp = {
	"r_waterwarp", "1","Animate liquid ripples."};	//qbism// 2000-01-02 Missing R_WATERWARP fix by Radix

//qbism//2000-02-27 r_waterripple from QuakeForge.
cvar_t  r_waterripple = {
	"r_waterripple", "3","Liquid ripple height."};

cvar_t	gl_finish = {
	"gl_finish","0","Call glFinish prior to rendering scene."};
cvar_t	gl_clear = {
	"gl_clear","0","Set GL_COLOR_BUFFER_BIT on glClear."};
cvar_t	gl_cull = {
	"gl_cull","1","Set glEnable(GL_CULL_FACE)."};
cvar_t	gl_texsort = {
	"gl_texsort","1","Sort rendering by texture."};
cvar_t	gl_smoothmodels = {
	"gl_smoothmodels","1","Smooth texturing and lighting of models."};
cvar_t	gl_affinemodels = {
	"gl_affinemodels","0","Affine method of texturing models (faster, less accurate)."};
cvar_t	gl_polyblend = {
	"gl_polyblend","1","Tint view with color for certain events (bio-suit, damage, bonus, etc.)"};
cvar_t	gl_flashblend = {
	"gl_flashblend","0","Render dynamic lights with glow ball instead of truly lighting world polys."};
//jft cvar_t	gl_playermip = {
//	"gl_playermip","0","need help string"};
//cvar_t	gl_nocolors = {  //qbism//jf 01-10-30//now automatically selected by model type. 0 for mdl, 1 for md2.
//	"gl_nocolors","1"}; //qbism//jf 00-10-15 changed for md2 player model. was 0

cvar_t	gl_keeptjunctions = {
	"gl_keeptjunctions","0","Keep co-linear polygon points instead of combining."};
//jft obsolete.  cvar_t	gl_doubleeyes = {
//	"gl_doubleeys", "1","need help string"};

	//qbism//jf 01-10-30 mrg
cvar_t	gl_showcuts = {"gl_showcuts", "0","Show world polygon edges."};

extern	cvar_t	gl_ztrick;

//qbism//00-07-02 NATAS - BramBo - Fog Code
	// Modified by Electro
	cvar_t fog_enable = {
	"fog_enable", "1","Enable fog."}; //qbism//jf 00-06-30

cvar_t fog_start = {
	"fog_start", "90.0","Fog start distance."};
cvar_t fog_end = {
	"fog_end", "1200.0","Fog end distance."};
cvar_t fog_density = {
	"fog_density", "0.5","Fog density at end distance."};
cvar_t fog_red = {
	"fog_red","0.5","Fog red color component."};
cvar_t fog_green = {
	"fog_green","0.45","Fog green color component."};
cvar_t fog_blue = {
	"fog_blue","0.4","Fog blue color component."};
cvar_t fog_alpha = {
	"fog_alpha", "0.2","Fog alpha color component."};
// END
	cvar_t gl_fisheye = {
	"gl_fisheye", "0","Simulated fisheye view rendering."};//qbism//jf GFE 00-07-12 off by default

cvar_t gl_fep1 = {
	"gl_fep1", "0.43","When gl_fisheye is enabled, pitch-angle offset 1 of view slivers."};
cvar_t gl_fep2 = {
	"gl_fep2", "0.31","When gl_fisheye is enabled, pitch-angle offset 2 of view slivers."};
cvar_t gl_fep3 = {
	"gl_fep3", "0.186","When gl_fisheye is enabled, pitch-angle offset 3 of view slivers."};


//qbism// 2000-02-03 fenix@io.com: model interpolation
cvar_t  r_lerpanimate = {
	"r_lerpanimate", "1", "Interpolate model animations.", true };
cvar_t  r_lerptransform = {
	"r_lerptransform", "1", "Interpolate model transformations.", true };

//qbism// 2000-04-10 Torch flares. KH
cvar_t	gl_torchflares = {
	"gl_torchflares", "1", "Torches cast dynamic light.", true};

sfx_t  *sfx_exhaust;

/*
=================
R_CullBox

Returns true if the box is completely outside the frustom
=================
*/
qboolean R_CullBox (vec3_t mins, vec3_t maxs)
{
	int		i;

	for (i=0 ; i<4 ; i++)
		if (BoxOnPlaneSide (mins, maxs, &frustum[i]) == 2)
			return true;
	return false;
}


void R_RotateForEntity (entity_t *e)
{
	glTranslatef (e->origin[0],  e->origin[1],  e->origin[2]);

	glRotatef (e->angles[1],  0, 0, 1);
	glRotatef (-e->angles[0],  0, 1, 0);
	glRotatef (e->angles[2],  1, 0, 0);
}






/*
=============
R_BlendedRotateForEntity

fenix@io.com: model transform interpolation
=============
*/
void R_BlendedRotateForEntity (entity_t *e)
{
	float timepassed;
	float blend;
	vec3_t d, dfudge;
	int i;
	trace_t        movetrace; //qbism//jf CSE 00-05-28 positional Client-Side Extrapolation


	// positional interpolation

	timepassed = realtime - e->translate_start_time;

	if (e->translate_start_time == 0 || timepassed > 1)
	{
		e->translate_start_time = realtime;
		VectorCopy (e->origin, e->origin1);
		VectorCopy (e->origin, e->origin2);
	}

	if (!VectorCompare (e->origin, e->origin2))
	{
		e->translate_start_time = realtime;
		VectorCopy (e->origin2, e->origin1);
		VectorCopy (e->origin,  e->origin2);
		blend = 0;
	}
	else
	    {
		//qbism//jf 01-10-30	if(cl.scores[cl.viewentity].ping) //qbism 00-11-19 CSE
	//	{
			blend = (realtime - e->translate_start_time)/(cl.mtime[0]-cl.mtime[1]);
		//			((float)cl.scores[cl.viewentity].ping*.001);
			//if(blend>0.1) blend = 0.1;
	//	}
	//	else blend =0.1;

		if (cl.paused || blend > 1) blend = 1;
	}

	VectorSubtract (e->origin2, e->origin1, d);

	memset (&movetrace, 0, sizeof(movetrace));//qbism//jf CSE 00-05-28

	//qbism//jf CSE 00-05-28 check if the movement vector collides with world.  if so, bail.
	if (blend>1)
	{
		SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, e->origin, d, &movetrace);
		if(movetrace.fraction <1) blend =1;
	}
	glTranslatef (
		e->origin1[0] + (d[0]*blend),
		e->origin1[1] + (d[1]*blend),
		e->origin1[2] + (d[2]*blend));

	// orientation interpolation (Euler angles, yuck!)

	//qbism//jf 00-10-15 not used timepassed = realtime - e->rotate_start_time;

	if (e->rotate_start_time == 0) //qbism//jf CSE 00-05-28 removed || timepassed > 1)
			{
		e->rotate_start_time = realtime;
		VectorCopy (e->angles, e->angles1);
		VectorCopy (e->angles, e->angles2);
	}

	if (!VectorCompare (e->angles, e->angles2))
	{
		e->rotate_start_time = realtime;
		VectorCopy (e->angles2, e->angles1);
		VectorCopy (e->angles,  e->angles2);
		blend = 0;
	}
	else
	    {
		//qbism//jf 01-10-30	if(cl.scores[cl.viewentity].ping) //qbism 00-11-19 CSE
	//	{
			blend = (realtime - e->translate_start_time)/(cl.mtime[0]-cl.mtime[1]);
		//			((float)cl.scores[cl.viewentity].ping*.001);
			//if(blend>0.1) blend = 0.1;
	//	}
	//	else blend =0.1;

		if (cl.paused || blend > 1) blend = 1;
	}


	// always interpolate along the shortest path
	for (i = 0;
	i < 3;
	i++)
	{
		if (d[i] > 180) d[i] -= 360;
		else if (d[i] < -180) d[i] += 360;
	}

	glRotatef ( e->angles1[1] + ( blend * d[1]),  0, 0, 1);
	glRotatef (-e->angles1[0] + (-blend * d[0]),  0, 1, 0);
	glRotatef ( e->angles1[2] + ( blend * d[2]),  1, 0, 0);
}




/*
=============================================================

SPRITE MODELS

=============================================================
*/

/*
================
R_GetSpriteFrame
================
*/
mspriteframe_t *R_GetSpriteFrame (entity_t *currententity)
{
	msprite_t		*psprite;
	mspritegroup_t	*pspritegroup;
	mspriteframe_t	*pspriteframe;
	int				i, numframes, frame;
	float			*pintervals, fullinterval, targettime, time;

	psprite = currententity->model->cache.data;
	frame = currententity->frame;

	if ((frame >= psprite->numframes) || (frame < 0))
	{
		Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
		frame = 0;
	}

	if (psprite->frames[frame].type == SPR_SINGLE)
	{
		pspriteframe = psprite->frames[frame].frameptr;
	}
	else
	    {
		pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
		pintervals = pspritegroup->intervals;
		numframes = pspritegroup->numframes;
		fullinterval = pintervals[numframes-1];

		time = cl.time + currententity->syncbase;

		// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
	// are positive, so we don't have to worry about division by 0
		targettime = time - ((int)(time / fullinterval)) * fullinterval;

		for (i=0 ; i<(numframes-1) ; i++)
		{
			if (pintervals[i] > targettime)
				break;
		}

		pspriteframe = pspritegroup->frames[i];
	}

	return pspriteframe;
}


/*
=================
R_DrawSpriteModel

=================
*/
void R_DrawSpriteModel (entity_t *e)
{
	vec3_t	point;
	mspriteframe_t	*frame;
	float		*up, *right;
	vec3_t		v_forward, v_right, v_up;
	msprite_t		*psprite;

	// don't even bother culling, because it's just a single
	// polygon without a surface cache
	frame = R_GetSpriteFrame (e);
	psprite = currententity->model->cache.data;

	if (psprite->type == SPR_ORIENTED)
	{	// bullet marks on walls

		AngleVectors (currententity->angles, v_forward, v_right, v_up);
		up = v_up;
		right = v_right;
	}
	else
	    {	// normal sprite

		up = vup;
		right = vright;
	}

	glColor3f (1,1,1); //qbism//jf 01-10-30 soon alpha for sprites? e->alpha/255.0

	GL_DisableMultitexture();

	glBindTexture(GL_TEXTURE_2D,frame->gl_texturenum);

	glEnable (GL_ALPHA_TEST);
	glBegin (GL_QUADS);

	glTexCoord2f (0, 1);
	VectorMA (e->origin, frame->down, up, point);
	VectorMA (point, frame->left, right, point);
	glVertex3fv (point);

	glTexCoord2f (0, 0);
	VectorMA (e->origin, frame->up, up, point);
	VectorMA (point, frame->left, right, point);
	glVertex3fv (point);

	glTexCoord2f (1, 0);
	VectorMA (e->origin, frame->up, up, point);
	VectorMA (point, frame->right, right, point);
	glVertex3fv (point);

	glTexCoord2f (1, 1);
	VectorMA (e->origin, frame->down, up, point);
	VectorMA (point, frame->right, right, point);
	glVertex3fv (point);

	glEnd ();

	glDisable (GL_ALPHA_TEST);
}

/*
=============================================================

ALIAS MODELS

=============================================================
*/


#define NUMVERTEXNORMALS	162

float	r_avertexnormals[NUMVERTEXNORMALS][3] = {
#include "anorms.h"
};

vec3_t	shadevector;
//qbism//00-06-15 CSL - epca@powerup.com.au
float   shadelight[4];
// CSL
float   ambientlight;


// precalculated dot products for quantized angles
#define SHADEDOT_QUANT 16
float	r_avertexnormal_dots[SHADEDOT_QUANT][256] =
#include "anorm_dots.h"
;

float	*shadedots = r_avertexnormal_dots[0];

//qbism// 2000-02-03 fenix@io.com: model animation interpolation
int lastposenum0;


int	lastposenum;

/*
=============
GL_DrawAliasFrame
=============
*/
void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum, int modelalpha)
{
	float	s, t;
	float 	l;
	int		i, j;
	int		index;
	trivertx_t	*v, *verts;
	int		list;
	int		*order;
	vec3_t	point;
	float	*normal;
	int		count;

	lastposenum = posenum;

	verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
	verts += posenum * paliashdr->poseverts;
	order = (int *)((byte *)paliashdr + paliashdr->commands);

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glShadeModel(GL_FLAT); //JFT SMOOTH

	/*if (modelalpha != 255) //qbism//jf 01-10-30 transparent alias models
	{
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);
		 glDepthMask(0);
	}
	else
	{
		glDisable(GL_BLEND);
		glDepthMask(1);
	}
*/
	while (1)
	{
		// get the vertex count and primitive type
		count = *order++;
		if (!count)
			break;		// done

		if (count < 0)
		{
			count = -count;
			glBegin (GL_TRIANGLE_FAN);
		}
		else
		    glBegin (GL_TRIANGLE_STRIP);

		do
		    {
			// texture coordinates come from the draw list
			glTexCoord2f (((float *)order)[0], ((float *)order)[1]);
			order += 2;



			// normals and vertexes come from the frame list
//qbism//00-07-05 CSL - epca@powerup.com.au
			if (shadelight[0] || shadelight[1] || shadelight[2])
			{
				if(bspextensions == BSPVERSION)
					{
					l = shadelight[3] * shadedots[verts->lightnormalindex];


					glColor4f (l+shadelight[0], l+shadelight[1], l+shadelight[2], ((float)modelalpha)/255.0);

				}
				else
				    {
					//qbism//jf 00-06-15 in colored light mode, divide l to get rid of washout.
					l = (shadelight[3] * shadedots[verts->lightnormalindex] )/32.0;
					glColor4f (l*shadelight[0], l*shadelight[1], l*shadelight[2],((float)modelalpha)/255.0);
				}
			}
			else
			    {
				l = shadedots[verts->lightnormalindex] * shadelight[3];
				glColor4f (l, l, l, modelalpha/255.0);
			}
			//qbism//00-06-15 CSL
			glVertex3f (verts->v[0], verts->v[1], verts->v[2]);
			verts++;
		}
		while (--count);

		glEnd ();
	}

/*	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable (GL_BLEND);
	glDepthMask(1);

	glPopMatrix();
*/
}

/*
=============
GL_DrawAliasBlendedFrame
fenix@io.com: model animation interpolation
=============
*/
void GL_DrawAliasBlendedFrame (aliashdr_t *paliashdr, int pose1, int pose2, float blend, int modelalpha)
{
	float       l;
	trivertx_t* verts1;
	trivertx_t* verts2;
	int*        order;
	int         count;
	vec3_t      d;

	lastposenum0 = pose1;
	lastposenum  = pose2;

	verts1  = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
	verts2  = verts1;

	verts1 += pose1 * paliashdr->poseverts;
	verts2 += pose2 * paliashdr->poseverts;

	order = (int *)((byte *)paliashdr + paliashdr->commands);

	glEnable(GL_BLEND); //qbism//jf 01-10-30 for alpha
	// glDepthMask(FALSE); // disable zbuffer updates


	for (;;)
	{
		// get the vertex count and primitive type
	count = *order++;

		if (!count) break;

		if (count < 0)
		{
			count = -count;
			glBegin (GL_TRIANGLE_FAN);
		}
		else
		    {
			glBegin (GL_TRIANGLE_STRIP);
		}

		do
		    {
			// texture coordinates come from the draw list
		glTexCoord2f (((float *)order)[0], ((float *)order)[1]);
			order += 2;

			// normals and vertexes come from the frame list
		// blend the light intensity from the two frames together

			d[0] = shadedots[verts2->lightnormalindex] -
			    shadedots[verts1->lightnormalindex];

			//qbism//00-06-15 csl
				if (shadelight[0] || shadelight[1] || shadelight[2])
			{
				if(bspextensions == BSPVERSION)
					{
					l = shadelight[3] * (shadedots[verts1->lightnormalindex]
						    + (blend * d[0]));
					glColor4f (l+shadelight[0], l+shadelight[1], l+shadelight[2], ((float)modelalpha)/255.0);

				}
				else
				    {
					l = (shadelight[3] * (shadedots[verts1->lightnormalindex] + (blend * d[0])))/32;
					glColor4f (l*shadelight[0], l*shadelight[1], l*shadelight[2], ((float)modelalpha)/255.0);
				}
			}

			else
			    {
				l = shadelight[3] * (shadedots[verts1->lightnormalindex] + (blend * d[0]));
				glColor4f (l, l, l, modelalpha/255.0);
			}

			VectorSubtract(verts2->v, verts1->v, d);

			// blend the vertex positions from each frame together
		glVertex3f (
				verts1->v[0] + (blend * d[0]),
				verts1->v[1] + (blend * d[1]),
				verts1->v[2] + (blend * d[2]));

			verts1++;
			verts2++;
		}
		while (--count);
		glEnd ();
	}

glDisable(GL_BLEND); //qbism//jf 01-10-30 for alpha
// glDepthMask(TRUE); // zbuffer updates

}

/*
=============
GL_DrawAliasShadow
=============
*/
extern	vec3_t			lightspot;

void GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum)
{
	float    s, t, l;
	int        i, j;
	int        index;
	trivertx_t    *v, *verts;
	int        list;
	int        *order;
	vec3_t    point;
	float    *normal;

	int        count;

	//qbism//00-04-29 muff@yakko.globalnet.co.uk - 17 Mar 2000
	trace_t        steptrace, downtrace;
	vec3_t        dest,stop,downmove;
	float        s1,c1; //this will store the sin and cos values as they are used so heavily

	//end of muff




	verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
	verts += posenum * paliashdr->poseverts;
	order = (int *)((byte *)paliashdr + paliashdr->commands);

	//qbism//jf 00-10-15 not used height = -lheight + 1.0;

	//qbism//00-04-29 muff@yakko.globalnet.co.uk - 17 Mar 2000
	// better shadowing, now takes angle of ground into account
	// cast a traceline into the floor directly below the player
	// and gets normals from this
	VectorCopy (currententity->origin, downmove);
	downmove[2] = downmove[2] - 4096;
	memset (&downtrace, 0, sizeof(downtrace));
	SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, currententity->origin, downmove, &downtrace);//qbism//jf 01-10-30

	// calculate the all important angles to keep speed up
	s1 = sin( currententity->angles[1]/180*M_PI);
	c1 = cos( currententity->angles[1]/180*M_PI);

	// end of muff

	while (1)
	{
		// get the vertex count and primitive type
		count = *order++;
		if (!count)
			break;        // done

		if (count < 0)
		{
			count = -count;
			glBegin (GL_TRIANGLE_FAN);
		}
		else
		    glBegin (GL_TRIANGLE_STRIP);

		do
		    {
			// texture coordinates come from the draw list
			// (skipped for shadows) glTexCoord2fv ((float *)order);
			order += 2;

			// normals and vertexes come from the frame list
			point[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];
			point[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];
			point[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];

			//qbism//00-04-29 muff@yakko.globalnet.co.uk - 17 Mar 2000
			// first remove the existing height adjustment, as we are going to do this ourselves
			//original code
			// point[0] -= shadevector[0]*(point[0] +lheight);
			// point[1] -= shadevector[1]*(point[1] +lheight);
			//    point[2] = height;
			//    height -= 0.001;
			// end of original code

			point[0] -= shadevector[0]*(point[0]);
			point[1] -= shadevector[1]*(point[1]);
			point[2] -= shadevector[2]*(point[2]);

			//drop it down to floor
			point[2] = point[2] - (currententity->origin[2] - downtrace.endpos[2]) ;

			// now adjust the point with respect to all the normals of the tracepoint
			// I'm probably missing an easy piece of maths to do this
			// it reads messy, but works ;)
			point[2] +=     (        (point[1] * (s1 * downtrace.plane.normal[0])) -
				    (point[0] * (c1 * downtrace.plane.normal[0])) -
				    (point[0] * (s1 * downtrace.plane.normal[1])) -
				    (point[1] * (c1 * downtrace.plane.normal[1]))
				    ) +  ((1.0 - downtrace.plane.normal[2])*20)
				+ 0.2 ;

			//end of muff

			glVertex3fv (point);

			verts++;
		}
		while (--count);

		glEnd ();
	}
}


void GL_DrawAliasBlendedShadow (aliashdr_t *paliashdr, int pose1, int pose2, entity_t* e)
{
	trivertx_t* verts1;
	trivertx_t* verts2;
	int*        order;
	vec3_t      point1;
	vec3_t      point2;
	vec3_t      d;
	float       height;
	float       lheight;
	int         count;
	float       blend;

	//qbism//00-04-29 muff@yakko.globalnet.co.uk - 17 Mar 2000
	trace_t        steptrace, downtrace;
	vec3_t        dest,stop,downmove;
	float        s1,c1; //this will store the sin and cos values as they are used so heavily

	//end of muff

	//qbism//jf CSE 00-10-15 stretch out animation to match lag.  Smoothness.
	blend = (realtime - e->frame_start_time) / e->frame_interval;


	//qbism//jf CSE 00-06-07 shadow Client-Side Extrapolation- match animation extrapolation
	// wierd things start happening if blend passes 1

	if (cl.paused || blend >1) blend = 1; //qbism//jf 10-15-00 this is much less likely to happen now.

	lheight = e->origin[2] - lightspot[2];
	//qbism//jf 00-10-15 not used height  = -lheight + 1.0;

	//qbism//00-04-29 muff@yakko.globalnet.co.uk - 17 Mar 2000
	// better shadowing, now takes angle of ground into account
	// cast a traceline into the floor directly below the player
	// and gets normals from this
	// for proper surface shadowing, each point should be taken
	// seperately, we do it this way for speed
	// NOTE need fixing for when at liquid surface
	VectorCopy (currententity->origin, downmove);
	downmove[2] = downmove[2] - 4096;
	memset (&downtrace, 0, sizeof(downtrace));
	SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, currententity->origin, downmove, &downtrace);

	// calculate the all important angles
	s1 = sin( currententity->angles[1]/180*M_PI);
	c1 = cos( currententity->angles[1]/180*M_PI);

	// end of muff

	verts1 = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
	verts2 = verts1;

	verts1 += pose1 * paliashdr->poseverts;
	verts2 += pose2 * paliashdr->poseverts;

	order = (int *)((byte *)paliashdr + paliashdr->commands);

	for (;;)
	{
		// get the vertex count and primitive type
			count = *order++;

		if (!count) break;

		if (count < 0)
		{
			count = -count;
			glBegin (GL_TRIANGLE_FAN);
		}
		else
		    {
			glBegin (GL_TRIANGLE_STRIP);
		}

		do
		    {
			order += 2;

			point1[0] = verts1->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];
			point1[1] = verts1->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];
			point1[2] = verts1->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];

			point1[0] -= shadevector[0]*(point1[2]+lheight);
			point1[1] -= shadevector[1]*(point1[2]+lheight);

			point2[0] = verts2->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];
			point2[1] = verts2->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];
			point2[2] = verts2->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];

			point2[0] -= shadevector[0]*(point2[2]+lheight);
			point2[1] -= shadevector[1]*(point2[2]+lheight);

			VectorSubtract(point2, point1, d);


			//qbism//00-04-29 muff@yakko.globalnet.co.uk - 17 Mar 2000
			point1[0] = point1[0] + (blend * d[0]);  //+lheight); //muff

			point1[1] = point1[1] + (blend * d[1]);  //+lheight); //muff

			point1[2] = point1[2] + (blend * d[2]);  //+lheight); //muff

			//drop it down to floor
			point1[2] =  - (currententity->origin[2] - downtrace.endpos[2]) ;

			//now move the z-coordinate as appropriate
			point1[2] += (    (point1[1] * (s1 * downtrace.plane.normal[0])) -
				    (point1[0] * (c1 * downtrace.plane.normal[0])) -
				    (point1[0] * (s1 * downtrace.plane.normal[1])) -
				    (point1[1] * (c1 * downtrace.plane.normal[1]))
				    ) +  ((1.0 - downtrace.plane.normal[2])*20)
				+ 0.2 ;


			// now load the point we have just calculated
			glVertex3fv (point1);

			// remove this as we have new commands in above
			//  glVertex3f (point1[0] + (blend * d[0]),
						//  point1[1] + (blend * d[1]),
						//  height);


			//end of muff

			verts1++;
			verts2++;
		}
		while (--count);

		glEnd ();
	}
}



/*
=================
R_SetupAliasFrame

=================
*/
void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr, int modelalpha)
{
	int				pose, numposes;
	float			interval;

	if ((frame >= paliashdr->numframes) || (frame < 0))
	{
		Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
		frame = 0;
	}

	pose = paliashdr->frames[frame].firstpose;
	numposes = paliashdr->frames[frame].numposes;

	if (numposes > 1)
	{
		interval = paliashdr->frames[frame].interval;
		pose += (int)(cl.time / interval) % numposes;
	}

	GL_DrawAliasFrame (paliashdr, pose, modelalpha);
}


/*
=================
R_SetupAliasBlendedFrame
fenix@io.com: model animation interpolation
=================
*/
void R_SetupAliasBlendedFrame (int frame, aliashdr_t *paliashdr, entity_t* e)
{
	int   pose;
	int   numposes;
	float blend;

	if ((frame >= paliashdr->numframes) || (frame < 0))
	{
		Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
		frame = 0;
	}

	pose = paliashdr->frames[frame].firstpose;
	numposes = paliashdr->frames[frame].numposes;

	if (numposes > 1)
	{
		if(cl.scores[cl.viewentity].ping < paliashdr->frames[frame].interval)
			e->frame_interval = paliashdr->frames[frame].interval;
		else e->frame_interval = cl.scores[cl.viewentity].ping;
		pose += (int)(cl.time / e->frame_interval) % numposes;
	}
	else
	    {
		//qbism//jf 00-10-15 we can do better than this:
		/* One tenth of a second is a good for most Quake animations.
		If the nextthink is longer then the animation is usually meant to pause
		(e.g. check out the shambler magic animation in shambler.qc).  If its
		shorter then things will still be smoothed partly, and the jumps will be
		less noticable because of the shorter time.  So, this is probably a good
		assumption. */

		//qbism//jf 10-15-00 interval based on ping, if known.
		if(cl.scores[cl.viewentity].ping)
			e->frame_interval = ((float)cl.scores[cl.viewentity].ping*.001);
		else e->frame_interval = 0.1;
	}

	if (e->pose2 != pose)
	{
		e->frame_start_time = realtime;
		e->pose1 = e->pose2;
		e->pose2 = pose;
		blend = 0;
	}
	else
	    {
		blend = (realtime - e->frame_start_time) / e->frame_interval;
	}

	// wierd things start happening if blend passes 1
	if (cl.paused || blend>1) blend = 1; //qbism//jf CSE 00-10-15 this is much less likely to happen now.

	GL_DrawAliasBlendedFrame (paliashdr, e->pose1, e->pose2, blend, e->alpha);

}

//qbism//00-10-15 MD2

/*
=============
GL_DrawQ2AliasFrame
=============
*/
void GL_DrawQ2AliasFrame (entity_t *e, md2_t *pheader, int lastpose, int pose, float lerp)
{
	float   ilerp;
	int             *order, count;
	md2trivertx_t   *verts1, *verts2;
	vec3_t  scale1, translate1, scale2, translate2;
	md2frame_t *frame1, *frame2;

	//qbism//jf 00-10-15 MD2SHADING needed for shading
	vec3_t      d;
	float l;
	int i;
	int	lnum;
	vec3_t	dist;
	int *j;
	float		add;


	glShadeModel(GL_FLAT); //JFT SMOOTH

	//if (e->alpha != 255)
	//{
		//glDisable(GL_ALPHA_TEST);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		//glDepthMask (0);
	//}



/*
	if (e->alpha != 255) //qbism//jf 01-10-30 transparent alias models
	{
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);
		 glDepthMask(0);
	}
	else
	{
		glDisable(GL_BLEND);
		glDepthMask(1);
	}
*/

	ilerp = 1.0 - lerp;


	//new version by muff - fixes bug, easier to read, faster (well slightly)
	frame1 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * lastpose));
	frame2 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * pose));

	VectorCopy(frame1->scale, scale1);
	VectorCopy(frame1->translate, translate1);
	VectorCopy(frame2->scale, scale2);
	VectorCopy(frame2->translate, translate2);
	verts1 = &frame1->verts[0];
	verts2 = &frame2->verts[0];
	order = (int *)((int)pheader + pheader->ofs_glcmds);


	if(r_lerptransform.value)
	{
		while (1)
		{
			// get the vertex count and primitive type
			count = *order++;
			if (!count)
				break;          // done

			if (count < 0)
			{
				count = -count;
				glBegin (GL_TRIANGLE_FAN);
			}
			else
		    	glBegin (GL_TRIANGLE_STRIP);

			do
			{
				glTexCoord2f(((float *)order)[0], ((float *)order)[1]);

				//qbism//jf 00-10-15 MD2SHADING

				d[0] = shadedots[verts2->lightnormalindex] - shadedots[verts1->lightnormalindex];

				//qbism//00-06-15 csl
				if (shadelight[0] || shadelight[1] || shadelight[2])
				{
					if(bspextensions == BSPVERSION)
					{
						l = shadelight[3] * (shadedots[verts1->lightnormalindex]
						    + (lerp * d[0]));
						glColor4f (l+shadelight[0], l+shadelight[1], l+shadelight[2], ((float)e->alpha)/255.0);
					}
					else
					{
						l = (shadelight[3] * (shadedots[verts1->lightnormalindex] + (lerp * d[0])))/32;
						glColor4f (l*shadelight[0], l*shadelight[1], l*shadelight[2], ((float)e->alpha)/255.0);
					}
				}

				else
				{
					l = shadelight[3] * (shadedots[verts1->lightnormalindex] + (lerp * d[0]));
					glColor4f (l, l, l, e->alpha/255.0);
				}

				//qbism//jf 00-10-15 MD2SHADING

				glVertex3f(
				(verts1[order[2]].v[0]*scale1[0]+translate1[0])*ilerp+(verts2[order[2]].v[0]*scale2[0]+translate2[0])*lerp,
				(verts1[order[2]].v[1]*scale1[1]+translate1[1])*ilerp+(verts2[order[2]].v[1]*scale2[1]+translate2[1])*lerp,
				(verts1[order[2]].v[2]*scale1[2]+translate1[2])*ilerp+(verts2[order[2]].v[2]*scale2[2]+translate2[2])*lerp);

				order+=3;
			}
			while (--count);
			glEnd();
		}
	}

	else
	{
		while (1)
	{
		// get the vertex count and primitive type
									count = *order++;
		if (!count)
			break;          // done

		if (count < 0)
		{
			count = -count;
			glBegin (GL_TRIANGLE_FAN);
		}
		else
		    glBegin (GL_TRIANGLE_STRIP);

		do
		    {
			glTexCoord2f(((float *)order)[0], ((float *)order)[1]);


			//qbism//jf 00-10-15 MD2SHADING

			d[0] = shadedots[verts2->lightnormalindex] -
			    shadedots[verts1->lightnormalindex];

			//qbism//00-06-15 csl
				if (shadelight[0] || shadelight[1] || shadelight[2])
			{
				if(bspextensions == BSPVERSION)
					{
					l = shadelight[3] * (shadedots[verts1->lightnormalindex]
						    + (lerp * d[0]));
					glColor4f (l+shadelight[0], l+shadelight[1], l+shadelight[2], ((float)e->alpha)/255.0);

				}
				else
				    {
					l = (shadelight[3] * (shadedots[verts1->lightnormalindex] + (lerp * d[0])))/32;
					glColor4f (l*shadelight[0], l*shadelight[1], l*shadelight[2], ((float)e->alpha)/255.0);
				}
			}

			else
			    {
				l = shadelight[3] * (shadedots[verts1->lightnormalindex] + (lerp * d[0]));
				glColor4f (l, l, l, e->alpha/255.0);
			}

			//qbism//jf 00-10-15 MD2SHADING


				glVertex3f(
				(verts1[order[2]].v[0]*scale1[0])*ilerp+(verts2[order[2]].v[0]*scale2[0])*lerp+translate2[0],
				(verts1[order[2]].v[1]*scale1[1])*ilerp+(verts2[order[2]].v[1]*scale2[1])*lerp+translate2[1],
				(verts1[order[2]].v[2]*scale1[2])*ilerp+(verts2[order[2]].v[2]*scale2[2])*lerp+translate2[2]);

			order+=3;
		}
		while (--count);
		glEnd ();
}
}

glDisable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glDepthMask (1);

}

/*
=============
GL_DrawQ2AliasShadow
=============
*/
void GL_DrawQ2AliasShadow (entity_t *e, md2_t *pheader, int lastpose, int pose, float lerp)
{
	float   ilerp;
	int             *order, count;
	md2trivertx_t   *verts1, *verts2;
	vec3_t  scale1, translate1, scale2, translate2, point;
	md2frame_t *frame1, *frame2;

	//qbism//00-04-29 muff@yakko.globalnet.co.uk - 17 Mar 2000
	trace_t        steptrace, downtrace;
	vec3_t        dest,stop,downmove;
	float        s1,c1; //this will store the sin and cos values as they are used so heavily

	//end of muff





	ilerp = 1.0 - lerp;

	//new version by muff - fixes bug, easier to read, faster (well slightly)
	frame1 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * lastpose));
	frame2 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * pose));

	VectorCopy(frame1->scale, scale1);
	VectorCopy(frame1->translate, translate1);
	VectorCopy(frame2->scale, scale2);
	VectorCopy(frame2->translate, translate2);
	verts1 = &frame1->verts[0];
	verts2 = &frame2->verts[0];
	order = (int *)((int) pheader + pheader->ofs_glcmds);

	//qbism//jf 00-10-15 not used height = lheight + 1.0;

	//qbism//00-04-29 muff@yakko.globalnet.co.uk - 17 Mar 2000
	// better shadowing, now takes angle of ground into account
	// cast a traceline into the floor directly below the player
	// and gets normals from this
	VectorCopy (currententity->origin, downmove);
	downmove[2] = downmove[2] - 4096;
	memset (&downtrace, 0, sizeof(downtrace));
	SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, currententity->origin, downmove, &downtrace);

	// calculate the all important angles to keep speed up
	s1 = sin( currententity->angles[1]/180*M_PI);
	c1 = cos( currententity->angles[1]/180*M_PI);

	// end of muff

	while (1)
	{
		// get the vertex count and primitive type
									count = *order++;
		if (!count)
			break;          // done

		if (count < 0)
		{
			count = -count;
			glBegin (GL_TRIANGLE_FAN);
		}
		else
		    glBegin (GL_TRIANGLE_STRIP);

		do
		    {
			point[0] = (verts1[order[2]].v[0]*scale1[0]+translate1[0])*ilerp+(verts2[order[2]].v[0]*scale2[0]+translate2[0])*lerp;
			point[1] = (verts1[order[2]].v[1]*scale1[1]+translate1[1])*ilerp+(verts2[order[2]].v[1]*scale2[1]+translate2[1])*lerp;
			point[2] = (verts1[order[2]].v[2]*scale1[2]+translate1[2])*ilerp+(verts2[order[2]].v[2]*scale2[2]+translate2[2])*lerp;

			//qbism//00-04-29 muff@yakko.globalnet.co.uk - 17 Mar 2000
			// first remove the existing height adjustment, as we are going to do this ourselves
			//original code
			// point[0] -= shadevector[0]*(point[0] +lheight);
			// point[1] -= shadevector[1]*(point[1] +lheight);
			//    point[2] = height;
			//    height -= 0.001;
			// end of original code

			point[0] -= shadevector[0]*(point[0]);
			point[1] -= shadevector[1]*(point[1]);
			point[2] -= shadevector[2]*(point[2]);

			//drop it down to floor
			point[2] = point[2] - (currententity->origin[2] - downtrace.endpos[2]) ;

			// now adjust the point with respect to all the normals of the tracepoint
			// I'm probably missing an easy piece of maths to do this
			// it reads messy, but works ;)
			point[2] +=     (        (point[1] * (s1 * downtrace.plane.normal[0])) -
				    (point[0] * (c1 * downtrace.plane.normal[0])) -
				    (point[0] * (s1 * downtrace.plane.normal[1])) -
				    (point[1] * (c1 * downtrace.plane.normal[1]))
				    ) +  ((1.0 - downtrace.plane.normal[2])*20)
				+ 0.2 ;

			//end of muff

			glVertex3fv (point);
			order+=3;
		}
		while (--count);

		glEnd ();
	}

}



/*
=================
R_SetupQ2AliasFrame

=================
*/
void R_SetupQ2AliasFrame (entity_t *e, md2_t *pheader)
{
	int                             frame;
	float                   lerp, lerpscale;
	vec3_t		mins; //qbism//jf 00-10-15 for muff shadows (shadows follow slope)

	model_t		*clmodel; //qbism//jf 00-10-15 for muff shadows

	//qbism//00-04-29 muff@yakko.globalnet.co.uk - 05 Mar 00 - added
	trace_t        steptrace, downtrace;
	vec3_t        dest,stop,downmove;
	//end of muff

	frame = e->frame;

	glPushMatrix ();
	if (r_lerptransform.value)
		R_BlendedRotateForEntity (e); //qbism//jf 00-10-15 MD2 was r_rota...
	else
		R_RotateForEntity (e);

	if ((frame >= pheader->num_frames) || (frame < 0))
	{
		Con_DPrintf ("R_SetupQ2AliasFrame: no such frame %d\n", frame);
		frame = 0;
	}

	if (e->draw_lastmodel == e->model)
	{
		if (frame != e->draw_pose)
		{
			e->draw_lastpose = e->draw_pose;
			e->draw_pose = frame;
			e->draw_lerpstart = cl.time;
			lerp = 0;
		}
		else
			//qbism//jf 00-10-15 calc of "lerp"(md2) now like "blend" (mdl)
	//	lerp = (realtime - e->draw_lerpstart)/(cl.mtime[0]-cl.mtime[1]);
	//	lerp = (realtime - e->translate_start_time)/(cl.mtime[0]-cl.mtime[1]);
			lerp = (cl.time - e->draw_lerpstart) * 20.0;
	}
	else // uninitialized
							{
		e->draw_lastmodel = e->model;
		e->draw_lastpose = e->draw_pose = frame;
		e->draw_lerpstart = cl.time;
		lerp = 0;
	}


	if ((lerp > 1 ) || cl.paused) lerp = 1;

	GL_DrawQ2AliasFrame (e, pheader, e->draw_lastpose, frame, lerp);


	if (r_shadows.value)
	{

		shadevector[0] = 0;
		shadevector[1] = 0;
		shadevector[2] = 1;
		VectorNormalize (shadevector);

		clmodel = e->model;
		VectorAdd (e->origin, clmodel->mins, mins);


		//qbism//2000-04-29 muff@yakko.globalnet.co.uk - 14 Mar 2000
		// this is so we can calculate height of the ground accurately
		VectorCopy (e->origin, downmove);

		downmove[2] = downmove[2] - 4096;
		memset (&downtrace, 0, sizeof(downtrace));
		SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, e->origin, downmove, &downtrace);
		// end of muff


		glDisable (GL_TEXTURE_2D);
		glEnable (GL_BLEND);
		 glDepthMask(FALSE); // disable zbuffer updates

		//qbism//2000-04-29 muff@yakko.globalnet.co.uk - 14 Mar 2000
		// set the shade of the shadow based on height off ground
		glColor4f (0,0,0,1.0 - ((mins[2]-downtrace.endpos[2])/60)); //qbism//jf 00-10-15 was always black, added /60. mins-downtrace ~=0?

		//glColor4f (0,0,0,0.5);// * modelalpha);

		GL_DrawQ2AliasShadow (e, pheader, e->draw_lastpose, frame, lerp);
		 glDepthMask(TRUE); // enable zbuffer updates

		glEnable (GL_TEXTURE_2D);
		//glDisable (GL_BLEND); //qbism//jf 01-10-30 was commented out.  Why?
		glColor3f (1,1,1);
	}
	glPopMatrix ();
}


/*
=================
R_DrawAliasModel

=================
*/
void R_DrawAliasModel (entity_t *e)
{
	int         i,k;
	//qbism// 00-06-15  CSL - epca@powerup.com.au
	int         *j;
	// CSL
	int			lnum;
	vec3_t		dist;
	float		add;
	model_t		*clmodel;
	vec3_t		mins, maxs;
	aliashdr_t	*paliashdr;
	trivertx_t	*verts, *v;
	int			index;
	float		s, t, an;
	int			anim;
	//qbism//00-10-15 MD2
		md2_t           *pheader; // LH / muff

	qboolean	torch = false; //qbism//2000-04-10 KH Flags is this model is a torch

	//qbism//00-04-29 muff@yakko.globalnet.co.uk - 05 Mar 00 - added
	trace_t        steptrace, downtrace;
	vec3_t        dest,stop,downmove;
	//end of muff

	clmodel = currententity->model;

	VectorAdd (currententity->origin, clmodel->mins, mins);
	VectorAdd (currententity->origin, clmodel->maxs, maxs);

	//qbism 00-10-10//jf FIXME- a visible model is sometimes culled, esp. w/low fov.
	if (R_CullBox (mins, maxs))
		return;


	VectorCopy (currententity->origin, r_entorigin);
	VectorSubtract (r_origin, r_entorigin, modelorg);

	//
	// get lighting information
	//

	//qbism//00-06-15 CSL - epca@powerup.com.au
	j = R_LightPoint (currententity->origin);
	// Can't assign int* to float[4]...damn
	shadelight[0] = (float) j[0];
	shadelight[1] = (float) j[1];
	shadelight[2] = (float) j[2];
	shadelight[3] = (float) j[3];
	ambientlight = shadelight[3];
	// CSL

	// allways give the gun some light
	if (e == &cl.viewent && ambientlight < 24)
	{
		//qbism//00-06-15 CSL - epca@powerup.com.au
		ambientlight = shadelight[3] = 24;
		// CSL
	}

	for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
	{
		if (cl_dlights[lnum].die >= cl.time)
		{
			VectorSubtract (currententity->origin,
				cl_dlights[lnum].origin,
				dist);
			add = cl_dlights[lnum].radius - Length(dist);

			if (add > 0) {
				ambientlight += add;
				//ZOID models should be affected by dlights as well
				//qbism//00-06-15 CSL - epca@powerup.com.au
				shadelight[0] += cl_dlights[lnum].color[0];
				shadelight[1] += cl_dlights[lnum].color[1];
				shadelight[2] += cl_dlights[lnum].color[2];
				shadelight[3] += add;
				// CSL
			}
		}
	}

	if (ambientlight > 128)
		ambientlight = 128;
	//qbism//00-06-15 CSL - epca@powerup.com.au
	if (ambientlight + shadelight[3] > 255) //qbism//jf 00-10-15 was 192
		shadelight[3] = 192 - ambientlight;
	// CSL

	// ZOID: never allow players to go totally black
	i = currententity - cl_entities;
	if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
		if (ambientlight < 8)
			//qbism//00-06-15 CSL - epca@powerup.com.au
			ambientlight = shadelight[3] = 8;
	// CSL


	// HACK HACK HACK -- no fullbright colors, so make torches full light
	if (!strcmp (clmodel->name, "progs/flame2.mdl")||
		    !strcmp (clmodel->name, "progs/flame.mdl"))
	{
		//qbism//00-06-15 CSL - epca@powerup.com.au
		ambientlight = shadelight[3] = 255; //qbism//00-10-15 LordHavoc: was 256, changed to 255

		// CSL
		torch = true; //qbism//2000-04-10 This model is a torch. KH

	}
	if (   !strcmp (clmodel->name, "progs/laser.mdl")	//qbism//jf 2000-02-21 more bright things
		|| !strcmp (clmodel->name, "progs/bolt.mdl") )	//qbism//jf 2000-02-21
		//qbism//00-06-15 CSL - epca@powerup.com.au
		ambientlight = shadelight[3] = 256;
	// CSL
	shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];
	//qbism//00-06-15 CSL - epca@powerup.com.au
	shadelight[3] = shadelight[3] / 200.0;
	// CSL
	an = e->angles[1]/180*M_PI;
	shadevector[0] = cos(-an);
	shadevector[1] = sin(-an);
	shadevector[2] = 1;
	VectorNormalize (shadevector);

	//qbism//00-10-15 MD2
  //
							// locate the proper data
							//
	if (clmodel->aliastype == ALIASTYPE_MD2)
	{
		pheader = (md2_t *)Mod_Extradata (currententity->model);
		c_alias_polys += pheader->num_tris;
	}
	else
	    {
		paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);
		c_alias_polys += paliashdr->numtris;
	}
	//qbism//00-10-15 end MD2

	//
	// draw all the triangles
	//

	GL_DisableMultitexture();

//qbism//jf 01-10-30
	//glEnable(GL_BLEND);
	//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	//qbism//00-10-15 MD2
	if (clmodel->aliastype != ALIASTYPE_MD2)
	{
		//qbism//00-10-15 end MD2
	glPushMatrix ();

		//qbism// 2000-02-03 fenix@io.com: model transform interpolation
	if (r_lerptransform.value)
		{
			R_BlendedRotateForEntity (e);
		}
		else
		{
			R_RotateForEntity (e);
		}

		//jft obsolete.if (!strcmp (clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) {
		//	glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8));
			// double size of eyes, since they are really hard to see in gl
		//glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2);
		//}
		//else {
			glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
			glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
		//}
	}


	if (clmodel->aliastype == ALIASTYPE_MD2)
		glBindTexture(GL_TEXTURE_2D,pheader->gl_texturenum[currententity->skinnum]);
	else
	    {
		anim = (int)(cl.time*10) & 3;
		glBindTexture(GL_TEXTURE_2D,paliashdr->gl_texturenum[currententity->skinnum][anim]);
		//qbism//00-10-15 MD2

	}
	//qbism//00-10-15 end MD2

	// we can't dynamically colormap textures, so they are cached
	// seperately for the players.  Heads are just uncolored.
	if (currententity->colormap != vid.colormap && clmodel->aliastype != ALIASTYPE_MD2) //qbism//jf 01-10-30 only map mdl, not md2
	{
		i = currententity - cl_entities;
		if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
			glBindTexture(GL_TEXTURE_2D,playertextures - 1 + i);
	}

	//jft obsolete if (gl_smoothmodels.value)
	//	glShadeModel (GL_SMOOTH);

	//jft obsolete if (gl_affinemodels.value)
	//		glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);

	// fenix@io.com: model animation interpolation
	if (r_lerpanimate.value && !torch)
	{
		if (clmodel->aliastype == ALIASTYPE_MD2)
			R_SetupQ2AliasFrame (e, pheader);//qbism//jf 01-10-30

		else
		    R_SetupAliasBlendedFrame (e->frame, paliashdr, e);
	}
	else
    {
		if (clmodel->aliastype == ALIASTYPE_MD2)
			R_SetupQ2AliasFrame (e, pheader);
		else
		    R_SetupAliasFrame (e->frame, paliashdr, e->alpha);
		//qbism//00-10-15 MD2
	}
	//qbism//00-10-15 end MD2

	//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

	glShadeModel (GL_FLAT);
	//jft if (gl_affinemodels.value)
	//	glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	//qbism//00-10-15 MD2
		if (clmodel->aliastype != ALIASTYPE_MD2)
	{
		//qbism//00-10-15 MD2 end
							glPopMatrix ();

		//qbism//2000-04-10 glow effects from muff's tutorial
		// Based on code originally from UNOFFICAL GLQUAKE code
		//qbism//2000-04-29 muff@yakko.globalnet.co.uk
		// added lightning glow code  -  20 Mar 2000
		// added rocket tailglow code -  20 Mar 2000
		// other can be added as later (such as 'laser.mdl')
		if ((!strncmp (clmodel->name, "progs/flame",11))      ||
			    (!strncmp (clmodel->name, "progs/bolt",10))       ||
			    (!strcmp  (clmodel->name, "progs/missile.mdl"))   ||
			    (!strcmp  (clmodel->name, "progs/quaddama.mdl"))  ||
			    (!strcmp  (clmodel->name, "progs/invulner.mdl"))
			    )
		{

			const int TORCH_STYLE = 1;      // Flicker.

			vec3_t  lightorigin;    // Origin of glow.

			vec3_t  v;                      // Vector to torch.

			float           radius;         // Radius of torch flare.

			float           distance;               // Vector distance to torch.

			float           intensity;              // Intensity of torch flare.

			VectorCopy(currententity->origin, lightorigin);

			//set radius based on what model we are doing here
		//qbism//jf 00-05-28 set the radius large when missile first appears
		if(torch && gl_torchflares.value)
				radius = 30.0;
			else if(!strcmp (clmodel->name, "progs/missile.mdl"))
			{
				if(currententity->forcelink == true) radius = 80.0f;
				else {
					radius = 20.0f;
					//qbism//00-11-08 moving rocket sound
					//move up before culling- S_StartSound (-1, 0, sfx_exhaust, currententity->origin, 1, 1);
																																				}
			}
			else if (!strncmp (clmodel->name, "progs/bolt",10))
				radius = 15.0f;
			else if( (!strcmp (clmodel->name, "progs/quaddama.mdl")) ||
				    (!strcmp (clmodel->name, "progs/invulner.mdl"))
				    )
				radius = 50.0f;

			VectorSubtract(lightorigin, r_origin, v);

			// See if view is outside the light.
				distance = Length(v);
			if (distance > radius) {

				 glDepthMask (0);
				glDisable (GL_TEXTURE_2D);
				glShadeModel (GL_FLAT); //JFT SMOOTH
				glEnable (GL_BLEND);
				glBlendFunc (GL_ONE, GL_ONE);

				//qbism//2000-04-29 Translate the glow to coincide with the flame. KH
						// or be at the tail of the missile - muff
						// or the Quad or Pent - muff
			glPushMatrix();
				if (torch && gl_torchflares.value)
					glTranslatef(0.0f, 0.0f, 10.0f); //qbism//jf 2000-04-10 was 0,0,8... up a tad.

				else if (!strcmp (clmodel->name, "progs/missile.mdl"))
				{
					//move the glow behind the rocket
					glTranslatef( cos( e->angles[1]/180*M_PI)*(-20.0f),
						sin( e->angles[1]/180*M_PI)*(-20.0f),
						sin( e->angles[0]/180*M_PI)*(-20.0f)   );
				}
				else if( (!strcmp (clmodel->name, "progs/quaddama.mdl")) ||
					    (!strcmp (clmodel->name, "progs/invulner.mdl"))
					    )
					glTranslatef(0.0f, 0.0f, 20.0f);


				glBegin(GL_TRIANGLE_FAN);


				// Invert (fades as you approach) - if we are a torch
						if (torch && gl_torchflares.value)
				{
					// Diminish torch flare inversely with distance.
							intensity = (1024.0f - distance) / 1024.0f;
					intensity = (1.0f - intensity);
				}
				// or fix settings if lightning or missile
						else if (!strncmp (clmodel->name, "progs/bolt",10))
					intensity = 0.15f;
				else if (!strcmp (clmodel->name, "progs/missile.mdl"))
					intensity = 0.3f;
				else if( (!strcmp (clmodel->name, "progs/quaddama.mdl")) ||
					    (!strcmp (clmodel->name, "progs/invulner.mdl")) )
					intensity = 0.3f;

				// Clamp, but don't let the flare disappear.
						if (intensity > 1.0f) intensity = 1.0f;
				if (intensity < 0.0f) intensity = 0.0f;

				// Now modulate with flicker.
						i = (int)(cl.time*10);
				if (!cl_lightstyle[TORCH_STYLE].length) {
					j[3] = 256;
				}
				else {
					j[3] = i % cl_lightstyle[TORCH_STYLE].length;
					j[3] = cl_lightstyle[TORCH_STYLE].map[j[3]] - 'a';
					j[3] = j[3]*22;
				}
				intensity *= ((float)j[3] / 255.0f);

				// Set yellow intensity
		#if 0
				// Testing
						glColor3f(0.8f, 0.4f, 0.1f);
#else
				//qbism//2000-04-10 set the color of the glow - muff
						if ((torch && gl_torchflares.value))
					glColor3f(0.4f*intensity, 0.2f*intensity, 0.05f);
				else if (!strcmp (clmodel->name, "progs/missile.mdl"))
					glColor3f(0.9f*intensity, 0.2f*intensity, 0.1f*intensity);
				else if (!strncmp (clmodel->name, "progs/bolt",10))
					glColor3f(0.2f*intensity, 0.2f*intensity, 0.8f*intensity);
				else if (!strcmp (clmodel->name, "progs/quaddama.mdl"))
					glColor3f(0.1f*intensity, 0.1f*intensity, 0.8f*intensity);
				else if (!strcmp (clmodel->name, "progs/invulner.mdl"))
					glColor3f(0.8f*intensity, 0.1f*intensity, 0.1f*intensity);

#endif
				for (i=0 ; i<3 ; i++)
					v[i] = lightorigin[i] - vpn[i]*radius;
				glVertex3fv(v);
				glColor3f(0.0f, 0.0f, 0.0f);
				for (i=16; i>=0; i--) {
					float a = i/16.0f * M_PI*2;
					for (k=0; k<3; k++)
						v[k] = lightorigin[k] +
						    vright[k]*cos(a)*radius +
						    vup[k]*sin(a)*radius;
					glVertex3fv(v);
				}
				glEnd();

				// Restore previous matrix! KH
						glPopMatrix();

				glColor4f (1,1,1,1);
				glDisable (GL_BLEND);
				glEnable (GL_TEXTURE_2D);
				glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				 glDepthMask (1);
			}
		}


		if (r_shadows.value)
		{


			//qbism//2000-04-29  muff@yakko.globalnet.co.uk - 05 Mar 00
		// lightning bolts really shouldn't cast a shadow
		// Neither should rockets
		// lots of other to go in here no doubt, but we'll add them as and when
		if ( (!strncmp (clmodel->name, "progs/bolt",10)) ||
				    // (!strcmp  (clmodel->name, "progs/missile.mdl")) ||//qbism//jf 00-05-24 missile shadow
			(!strcmp  (clmodel->name, "progs/laser.mdl")) ||
				    (!strcmp  (clmodel->name, "progs/flame.mdl")) ||//qbism//jf 00-04-27 no torch shadow
			(!strcmp  (clmodel->name, "progs/flame2.mdl")) ||//qbism//jf 00-04-27 no torch shadow
			(!strcmp  (clmodel->name, "progs/lavaball.mdl")) ||
				    (!strcmp  (clmodel->name, "progs/quaddama.mdl")) ||
				    (!strcmp  (clmodel->name, "progs/invulner.mdl"))
				    )
				return;

			// in first person the engine currently draws the player's weapon,
		// but no player. This means a weapon shadow is drawn
		// we'll remove weapon shadow until this is fixed
		if (!strncmp (clmodel->name, "progs/v_",8))
				return;
			// end of muff

			glPushMatrix ();

			//qbism//2000-04-29 muff@yakko.globalnet.co.uk - 05 Mar 00
		// this determines the shadow vector relative to origin of entity
		// changed always be directly below entity for the moment.
		// will alter later (hopefully) when I got proper light source shadows working
		shadevector[0] = 0;
			shadevector[1] = 0;
			shadevector[2] = 1;
			VectorNormalize (shadevector);

			//original code
		//        R_RotateForEntity (e);


			//qbism//2000-04-29 muff@yakko.globalnet.co.uk - 050300 - added
		// this translates the location of the shadow, and rotates in horizontal plane only
		// this means that shadows now work properly for chase_cam, grenade etc
		// hence removal of code above
		if (r_lerpanimate.value)
				R_BlendedRotateForEntity (e); // we've re-written this to work properly

			else
			    {
				glTranslatef (e->origin[0],  e->origin[1],  e->origin[2]);
				glRotatef (e->angles[1],  0, 0, 1);
			}
			//end of muff


			//qbism//2000-04-29 muff@yakko.globalnet.co.uk - 14 Mar 2000
		// this is so we can calculate height of the ground accurately
		VectorCopy (e->origin, downmove);

			downmove[2] = downmove[2] - 4096;
			memset (&downtrace, 0, sizeof(downtrace));
			SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, e->origin, downmove, &downtrace);
			// end of muff

			glDisable (GL_TEXTURE_2D);
			glEnable (GL_BLEND);

			// original code
		//    glColor4f (0,0,0,0.5);


			//qbism//2000-04-29 muff@yakko.globalnet.co.uk - 14 Mar 2000
		// set the shade of the shadow based on height off ground
		glColor4f (0,0,0,1.0 - ((mins[2]-downtrace.endpos[2])/60));
			//end of muff

			//original code
		//    GL_DrawAliasShadow (paliashdr, lastposenum);

			// fenix@io.com: model animation interpolation
		if (r_lerpanimate.value)
				GL_DrawAliasBlendedShadow (paliashdr, lastposenum0, lastposenum, currententity);
			else
			    GL_DrawAliasShadow (paliashdr, lastposenum);


			glEnable (GL_TEXTURE_2D);
			glDisable (GL_BLEND);
			glColor4f (1,1,1,1);
			glPopMatrix ();
		}
		//qbism//00-10-15 MD2
	}
	//qbism//00-10-15 MD2 end
}

//==================================================================================



/*=================
//qbism//jf 01-10-30 MPMODEL  R_DrawAliasVwep, Head, and Legs
//jft Yes I'm sure there's a better way than this brutality

=================
*/


void R_DrawAliasLegs (entity_t *e)
{
	vec3_t  temporigin, temporigin1, temporigin2; //qbism//jf 01-10-30
vec3_t  tempangles, tempangles1, tempangles2; //qbism//jf 01-10-30
float temp_rotate_start_time;
int  tempdraw_lastpose, tempdraw_pose;       // for interpolation
int  tempframe, tempskinnum, tempalpha;
float                   tempdraw_lerpstart;                 // for interpolation
struct model_s          *tempmodel, *tempdraw_lastmodel;                // for interpolation


	tempmodel = e->model;
	tempframe = e->frame;
	tempskinnum = e->skinnum;
	tempalpha = e->alpha;

	e->model= e->legsmodel;
	e->frame= e->legsframe;
	e->skinnum= e->legsskinnum;
	e->alpha= e->legsalpha;

	tempdraw_pose =e->draw_pose;
	tempdraw_lastpose =e->draw_lastpose;
	tempdraw_lerpstart = e->draw_lerpstart;
	tempdraw_lastmodel = e->draw_lastmodel;

	e->draw_pose =e->legsdraw_pose;
	e->draw_lastpose =e->legsdraw_lastpose;
	e->draw_lerpstart = e->legsdraw_lerpstart;
	e->draw_lastmodel = e->legsdraw_lastmodel;


	temp_rotate_start_time= e->rotate_start_time;
	VectorCopy (e->origin, temporigin);
	VectorCopy (e->origin1, temporigin1);
	VectorCopy (e->origin2, temporigin2);
	VectorCopy (e->angles, tempangles);
	VectorCopy (e->angles1, tempangles1);
	VectorCopy (e->angles2, tempangles2);
	VectorAdd (e->angles, e->legsangles, e->angles);
	VectorAdd (e->angles1, e->legsangles1, e->angles1);
	VectorAdd (e->angles2, e->legsangles2, e->angles2);

	R_DrawAliasModel (e);

	VectorSubtract (e->angles, tempangles, e->legsangles);
	VectorSubtract (e->angles1, tempangles1, e->legsangles1);
	VectorSubtract (e->angles2, tempangles2, e->legsangles2);
	VectorCopy (temporigin, e->origin);
	VectorCopy (temporigin1, e->origin1);
	VectorCopy (temporigin2, e->origin2);
	VectorCopy (tempangles, e->angles);
	VectorCopy (tempangles1, e->angles1);
	VectorCopy (tempangles2, e->angles2);

	e->rotate_start_time= temp_rotate_start_time;
	e->legsdraw_pose =e->draw_pose;
	e->legsdraw_lastpose =e->draw_lastpose;
	e->legsdraw_lerpstart = e->draw_lerpstart;
	e->legsdraw_lastmodel = e->draw_lastmodel;

	e->draw_pose =tempdraw_pose;
	e->draw_lastpose =tempdraw_lastpose;
	e->draw_lerpstart = tempdraw_lerpstart;
	e->draw_lastmodel = tempdraw_lastmodel;

	e->model= tempmodel;
	e->frame= tempframe;
	e->skinnum= tempskinnum;
	e->alpha= tempalpha;
}


void R_DrawAliasTorso (entity_t *e)
{
	vec3_t  temporigin, temporigin1, temporigin2; //qbism//jf 01-10-30
vec3_t  tempangles, tempangles1, tempangles2; //qbism//jf 01-10-30
float temp_rotate_start_time;
int                     tempdraw_lastpose, tempdraw_pose;       // for interpolation
int  tempframe, tempskinnum, tempalpha;
float                   tempdraw_lerpstart;                 // for interpolation
struct model_s          *tempmodel, *tempdraw_lastmodel;                // for interpolation

	tempmodel = e->model;
	tempframe = e->frame;
	tempskinnum = e->skinnum;
	tempalpha = e->alpha;

	e->model= e->legsmodel;
	e->model= e->torsomodel;
	e->frame= e->torsoframe;
	e->skinnum= e->torsoskinnum;
	e->alpha= e->torsoalpha;

	tempdraw_pose =e->draw_pose;
	tempdraw_lastpose =e->draw_lastpose;
	tempdraw_lerpstart = e->draw_lerpstart;
	tempdraw_lastmodel = e->draw_lastmodel;

	e->draw_pose =e->torsodraw_pose;
	e->draw_lastpose =e->torsodraw_lastpose;
	e->draw_lerpstart = e->torsodraw_lerpstart;
	e->draw_lastmodel = e->torsodraw_lastmodel;


	temp_rotate_start_time= e->rotate_start_time;
	VectorCopy (e->origin, temporigin);
	VectorCopy (e->origin1, temporigin1);
	VectorCopy (e->origin2, temporigin2);
	VectorCopy (e->angles, tempangles);
	VectorCopy (e->angles1, tempangles1);
	VectorCopy (e->angles2, tempangles2);
	VectorAdd (e->angles, e->torsoangles, e->angles);
	VectorAdd (e->angles1, e->torsoangles1, e->angles1);
	VectorAdd (e->angles2, e->torsoangles2, e->angles2);

	R_DrawAliasModel (e);

	VectorSubtract (e->angles, tempangles, e->torsoangles);
	VectorSubtract (e->angles1, tempangles1, e->torsoangles1);
	VectorSubtract (e->angles2, tempangles2, e->torsoangles2);
	VectorCopy (temporigin, e->origin);
	VectorCopy (temporigin1, e->origin1);
	VectorCopy (temporigin2, e->origin2);
	VectorCopy (tempangles, e->angles);
	VectorCopy (tempangles1, e->angles1);
	VectorCopy (tempangles2, e->angles2);

	e->rotate_start_time= temp_rotate_start_time;
	e->torsodraw_pose =e->draw_pose;
	e->torsodraw_lastpose =e->draw_lastpose;
	e->torsodraw_lerpstart = e->draw_lerpstart;
	e->torsodraw_lastmodel = e->draw_lastmodel;

	e->draw_pose =tempdraw_pose;
	e->draw_lastpose =tempdraw_lastpose;
	e->draw_lerpstart = tempdraw_lerpstart;
	e->draw_lastmodel = tempdraw_lastmodel;

	e->model= tempmodel;
	e->frame= tempframe;
	e->skinnum= tempskinnum;
	e->alpha= tempalpha;
}


void R_DrawAliasVwep (entity_t *e)
{
	vec3_t  temporigin, temporigin1, temporigin2; //qbism//jf 01-10-30
	vec3_t  tempangles, tempangles1, tempangles2; //qbism//jf 01-10-30
float temp_rotate_start_time;
int                    tempdraw_lastpose, tempdraw_pose;       // for interpolation
int  tempframe, tempskinnum, tempalpha;
float                   tempdraw_lerpstart;                 // for interpolation
struct model_s          *tempmodel, *tempdraw_lastmodel;                // for interpolation

	tempmodel = e->model;
	tempframe = e->frame;
	tempskinnum = e->skinnum;
	tempalpha = e->alpha;

	e->model= e->legsmodel;
	e->model= e->vwepmodel;
	e->frame= e->vwepframe;
	e->skinnum= e->vwepskinnum;
	e->alpha= e->vwepalpha;

	tempdraw_pose =e->draw_pose;
	tempdraw_lastpose =e->draw_lastpose;
	tempdraw_lerpstart = e->draw_lerpstart;
	tempdraw_lastmodel = e->draw_lastmodel;

	e->draw_pose =e->vwepdraw_pose;
	e->draw_lastpose =e->vwepdraw_lastpose;
	e->draw_lerpstart = e->vwepdraw_lerpstart;
	e->draw_lastmodel = e->vwepdraw_lastmodel;

	temp_rotate_start_time= e->rotate_start_time;
	VectorCopy (e->origin, temporigin);
	VectorCopy (e->origin1, temporigin1);
	VectorCopy (e->origin2, temporigin2);
	VectorCopy (e->angles, tempangles);
	VectorCopy (e->angles1, tempangles1);
	VectorCopy (e->angles2, tempangles2);
	VectorAdd (e->angles, e->vwepangles, e->angles);
	VectorAdd (e->angles1, e->vwepangles1, e->angles1);
	VectorAdd (e->angles2, e->vwepangles2, e->angles2);

	R_DrawAliasModel (e);

	VectorSubtract (e->angles, tempangles, e->vwepangles);
	VectorSubtract (e->angles1, tempangles1, e->vwepangles1);
	VectorSubtract (e->angles2, tempangles2, e->vwepangles2);
	VectorCopy (temporigin, e->origin);
	VectorCopy (temporigin1, e->origin1);
	VectorCopy (temporigin2, e->origin2);
	VectorCopy (tempangles, e->angles);
	VectorCopy (tempangles1, e->angles1);
	VectorCopy (tempangles2, e->angles2);

	e->rotate_start_time= temp_rotate_start_time;
	e->vwepdraw_pose =e->draw_pose;
	e->vwepdraw_lastpose =e->draw_lastpose;
	e->vwepdraw_lerpstart = e->draw_lerpstart;
	e->vwepdraw_lastmodel = e->draw_lastmodel;

	e->draw_pose =tempdraw_pose;
	e->draw_lastpose =tempdraw_lastpose;
	e->draw_lerpstart = tempdraw_lerpstart;
	e->draw_lastmodel = tempdraw_lastmodel;

	e->model= tempmodel;
	e->frame= tempframe;
	e->skinnum= tempskinnum;
	e->alpha= tempalpha;
}


/*
=============
R_DrawEntitiesOnList
=============
*/



void R_DrawSolidBrushEntities (void)
{
	int		i;

	if (!r_drawentities.value)
		return;

	for (i=0 ; i<cl_numvisedicts ; i++)
	{
		if (cl_visedicts[i]->model->type != mod_brush || cl_visedicts[i]->alpha != 255)
			continue;

		currententity = cl_visedicts[i];
		R_DrawBrushModel (currententity);
	}
}

void R_DrawTransparentBrushEntities (void)
{
	int		i;

	if (!r_drawentities.value)
		return;

	for (i=0 ; i<cl_numvisedicts ; i++)
	{
		if (cl_visedicts[i]->model->type != mod_brush || cl_visedicts[i]->alpha == 255)
			continue;

		currententity = cl_visedicts[i];
		R_DrawBrushModel (currententity);
	}
}


void R_DrawSolidAliasEntities (void)
{
	int		i;

	if (!r_drawentities.value)
		return;

	for (i=0 ; i<cl_numvisedicts ; i++)
	{
		currententity = cl_visedicts[i];


		//qbism// 2000-01-09 ChaseCam fix by FrikaC  start
		if (currententity == &cl_entities[cl.viewentity])
		{
			// chase_active.value not checked as player model is necessary for shadows
			currententity->angles[0] *= 0.3;
		}
		//qbism// 2000-01-09 ChaseCam fix by FrikaC  end

		switch (currententity->model->type)
		{
		case mod_alias:

		if(currententity->alpha ==255)
		{
			//qbism//jf 01-10-30 MPMODEL draw vwep, torso, and legs
			R_DrawAliasModel(currententity);
				if(currententity->legsmodel)
				{
					R_DrawAliasLegs(currententity);
				}

				if(currententity->vwepmodel)
				{
					R_DrawAliasVwep(currententity);
				}

				if(currententity->torsomodel)
				{
					R_DrawAliasTorso(currententity);
				}
		}

			break;

		case mod_sprite:
			if(currententity->alpha ==255)
			{
				R_DrawSpriteModel (currententity);
			}
			break;

		default:
			break;
		}
	}
}



void R_DrawTransparentAliasEntities (void)
{
	int		i;

	if (!r_drawentities.value)
		return;

	for (i=0 ; i<cl_numvisedicts ; i++)
	{
		currententity = cl_visedicts[i];


		//qbism// 2000-01-09 ChaseCam fix by FrikaC  start
		if (currententity == &cl_entities[cl.viewentity])
		{
			// chase_active.value not checked as player model is necessary for shadows
			currententity->angles[0] *= 0.3;
		}
		//qbism// 2000-01-09 ChaseCam fix by FrikaC  end

		switch (currententity->model->type)
		{
		case mod_alias:

		if(currententity->alpha !=255)
		{
			//qbism//jf 01-10-30 MPMODEL draw vwep, torso, and legs
			R_DrawAliasModel(currententity);
				if(currententity->legsmodel)
				{
					R_DrawAliasLegs(currententity);
				}

				if(currententity->vwepmodel)
				{
					R_DrawAliasVwep(currententity);
				}

				if(currententity->torsomodel)
				{
					R_DrawAliasTorso(currententity);
				}
		}

			break;

		case mod_sprite:
			if(currententity->alpha !=255)
			{
				R_DrawSpriteModel (currententity);
			}
			break;

		default:
			break;
		}
	}
}

/*
//qbism//jf 01-10-30 replaced by above 2 functs


void R_DrawEntitiesOnList (void)
{
	int		i;

	if (!r_drawentities.value)
		return;

	// draw sprites seperately, because of alpha blending
	for (i=0 ;
	i<cl_numvisedicts ;
	i++)
	{
		currententity = cl_visedicts[i];

		//qbism// 2000-01-09 ChaseCam fix by FrikaC  start
		if (currententity == &cl_entities[cl.viewentity])
		{
			// chase_active.value not checked as player model is necessary for shadows
			currententity->angles[0] *= 0.3;
		}
		//qbism// 2000-01-09 ChaseCam fix by FrikaC  end

		switch (currententity->model->type)
		{
		case mod_alias:
			//qbism//jf 01-10-30 MPMODEL draw vwep, torso, and legs
		R_DrawAliasModel(currententity);
			if(currententity->legsmodel)
			{
				//	currententity = cl_visedicts[i];  //qbism//jf 01-10-30 MPMODEL do we have to reset? cuz code is sloppy!
				R_DrawAliasLegs(currententity);
			}

			if(currententity->vwepmodel)
			{
					//currententity = cl_visedicts[i];  //qbism//jf 01-10-30 MPMODEL do we have to reset? cuz code is sloppy!
				R_DrawAliasVwep(currententity);
			}

			if(currententity->torsomodel)
			{
				//	currententity = cl_visedicts[i];  //qbism//jf 01-10-30 MPMODEL do we have to reset? cuz code is sloppy!
				R_DrawAliasTorso(currententity);
			}

		//	currententity = cl_visedicts[i];  //qbism//jf 01-10-30 MPMODEL do we have to reset? cuz code is sloppy!


			break;

		case mod_brush:
			R_DrawBrushModel (currententity);
			break;

		default:
			break;
		}
	}

	for (i=0 ; i<cl_numvisedicts ; i++)
	{
		currententity = cl_visedicts[i];

		switch (currententity->model->type)
		{
		case mod_sprite:
			R_DrawSpriteModel (currententity);
			break;
		}
	}
}
*/

/*
=============
R_DrawViewModel
=============
*/
void R_DrawViewModel (void)
{
	float		ambient[4], diffuse[4];
	//qbism//00-06-15 CSL - epca@powerup.com.au
	int         *j;
	int         shadelight[4];
	// CSL
	int			lnum;
	vec3_t		dist;
	float		add;
	dlight_t	*dl;
	int			ambientlight;

	//qbism// 2000-02-03 fenix@io.com: model transform interpolation
	float old_interpolate_model_transform;



	if (!r_drawviewmodel.value)
		return;

	if (chase_active.value)
		return;

	if (envmap)
		return;

	if (!r_drawentities.value)
		return;

	if (cl.items & IT_INVISIBILITY)
		return;

	if (cl.stats[STAT_HEALTH] <= 0)
		return;

	currententity = &cl.viewent;
	if (!currententity->model)
		return;
	currententity->alpha = 255; //jft this is a hack.  some way we could set variable alpha.

	j = R_LightPoint (currententity->origin);

	//qbism//00-06-15 CSL - epca@powerup.com.au
	if (j[3] < 24)
		j[3] = 24;      // allways give some light on gun

	ambientlight = j[3];
	// Can't assign int* to int[4]...damn
	shadelight[0] = j[0];
	shadelight[1] = j[1];
	shadelight[2] = j[2];
	shadelight[3] = j[3];
	// CSL

	// add dynamic lights
	for (lnum=0 ;
	lnum<MAX_DLIGHTS ;
	lnum++)
	{
		dl = &cl_dlights[lnum];
		if (!dl->radius)
			continue;
		if (!dl->radius)
			continue;
		if (dl->die < cl.time)
			continue;

		VectorSubtract (currententity->origin, dl->origin, dist);
		add = dl->radius - Length(dist);
		if (add > 0)
		{
			//qbism//00-06-15 CSL - epca@powerup.com.au
			shadelight[0] += dl->color[0];
			shadelight[1] += dl->color[1];
			shadelight[2] += dl->color[2];
			shadelight[3] += add;
			// CSL
			ambientlight += add;
		}
	}

	//qbism//jf 00-10-15 not used    ambient[0] = ambient[1] = ambient[2] = ambient[3] = (float)ambientlight / 128;
	//qbism//00-06-15 CSL - epca@powerup.com.au
	//qbism//jf 00-10-15 not used    diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight[3] / 128;
	// CSL

	// hack the depth range to prevent view model from poking into walls
	glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));

	//qbism// 2000-02-03 fenix@io.com: model transform interpolation
	old_interpolate_model_transform = r_lerptransform.value;
	r_lerptransform.value = false;

	R_DrawAliasModel (currententity); //qbism//jf 01-10-30 if...?
	if(currententity->legsmodel)
	{
	R_DrawAliasLegs(currententity);
	}

	if(currententity->vwepmodel)
	{
		R_DrawAliasVwep(currententity); //qbism//jf 01-10-30

	}

	if(currententity->torsomodel)
	{
	R_DrawAliasTorso(currententity);

	}

	r_lerptransform.value = old_interpolate_model_transform;




	glDepthRange (gldepthmin, gldepthmax);
}


/*
============
R_PolyBlend
============
*/
void R_PolyBlend (void)
{
	if (!gl_polyblend.value)
		return;
	if (!v_blend[3])
		return;

	GL_DisableMultitexture();

	glDisable (GL_ALPHA_TEST);
	glEnable (GL_BLEND);
	glDisable (GL_DEPTH_TEST);
	glDisable (GL_TEXTURE_2D);

	glLoadIdentity ();

	glRotatef (-90,  1, 0, 0);	    // put Z going up

	glRotatef (90,  0, 0, 1);	    // put Z going up

	glColor4fv (v_blend);

	glBegin (GL_QUADS);

	glVertex3f (10, 100, 100);
	glVertex3f (10, -100, 100);
	glVertex3f (10, -100, -100);
	glVertex3f (10, 100, -100);
	glEnd ();

	glDisable (GL_BLEND);
	glEnable (GL_TEXTURE_2D);
	glEnable (GL_ALPHA_TEST);
}


int SignbitsForPlane (mplane_t *out)
{
	int	bits, j;

	// for fast box on planeside test

	bits = 0;
	for (j=0 ; j<3 ; j++)
	{
		if (out->normal[j] < 0)
			bits |= 1<<j;
	}
	return bits;
}


void R_SetFrustum (void)
{
	int		i;

	if (r_refdef.fov_x == 90)
	{
		// front side is visible

		VectorAdd (vpn, vright, frustum[0].normal);
		VectorSubtract (vpn, vright, frustum[1].normal);

		VectorAdd (vpn, vup, frustum[2].normal);
		VectorSubtract (vpn, vup, frustum[3].normal);
	}
	else
	    {
		// rotate VPN right by FOV_X/2 degrees
		RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
		// rotate VPN left by FOV_X/2 degrees
		RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
		// rotate VPN up by FOV_X/2 degrees
		RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
		// rotate VPN down by FOV_X/2 degrees
		RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
	}

	for (i=0 ; i<4 ; i++)
	{
		frustum[i].type = PLANE_ANYZ;
		frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
		frustum[i].signbits = SignbitsForPlane (&frustum[i]);
	}
}



/*
===============
R_SetupFrame
===============
*/
void R_SetupFrame (void)
{
	int				edgecount;
	vrect_t			vrect;
	float			w, h;

	// don't allow cheats in multiplayer
	if (cl.maxclients > 1)
		Cvar_Set ("r_fullbright", "0");

	R_AnimateLight ();

	r_framecount++;

	// build the transformation matrix for the given view angles
	VectorCopy (r_refdef.vieworg, r_origin);

	AngleVectors (r_refdef.viewangles, vpn, vright, vup);

	// current viewleaf
	r_oldviewleaf = r_viewleaf;
	r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);

	V_SetContentsColor (r_viewleaf->contents);
	V_CalcBlend ();

	r_cache_thrash = false;

	c_brush_polys = 0;
	c_alias_polys = 0;

}


void MYgluPerspective( GLdouble fovy, GLdouble aspect,
	GLdouble zNear, GLdouble zFar )
{
	GLdouble xmin, xmax, ymin, ymax;

	ymax = zNear * tan( fovy * M_PI / 360.0 );
	ymin = -ymax;

	xmin = ymin * aspect;
	xmax = ymax * aspect;

	glFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
}


/*
=============
R_SetupGL
=============
*/
void R_SetupGL (void)
{
	float	screenaspect;
	float	yfov;
	int		i;
	extern	int glwidth, glheight;
	int		x, x2, y2, y, w, h;

	//
	// set up viewpoint
	//
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity ();
	x = r_refdef.vrect.x * glwidth/vid.width;
	x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width;
	y = (vid.height-r_refdef.vrect.y) * glheight/vid.height;
	y2 = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height;

	// fudge around because of frac screen scale
	if (x > 0)
		x--;
	if (x2 < glwidth)
		x2++;
	if (y2 < 0)
		y2--;
	if (y < glheight)
		y++;

	w = x2 - x;
	h = y - y2;

	if (envmap)
	{
		x = y2 = 0;
		w = h = 256;
	}

	glViewport (glx + x, gly + y2, w, h);
	screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height;
	//	yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI;
	MYgluPerspective (r_refdef.fov_y,  screenaspect,  4,  4096);

	if (mirror)
	{
		if (mirror_plane->normal[2])
			glScalef (1, -1, 1);
		else
		    glScalef (-1, 1, 1);
		glCullFace(GL_BACK);
	}
	else
	    glCullFace(GL_FRONT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity ();

	glRotatef (-90,  1, 0, 0);	    // put Z going up

	glRotatef (90,  0, 0, 1);	    // put Z going up

	glRotatef (-r_refdef.viewangles[2],  1, 0, 0);
	glRotatef (-r_refdef.viewangles[0],  0, 1, 0);
	glRotatef (-r_refdef.viewangles[1],  0, 0, 1);
	glTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);

	glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);

	//
	// set drawing parms
	//
	if (gl_cull.value)
		glEnable(GL_CULL_FACE);
	else
	    glDisable(GL_CULL_FACE);

	glDisable(GL_BLEND);
	glDisable(GL_ALPHA_TEST);
	glEnable(GL_DEPTH_TEST);
}

/*
================
R_RenderScene

r_refdef must be set before the first call
================
*/
void R_RenderScene (void)
{
	R_SetupFrame ();

	R_SetFrustum ();

	R_SetupGL ();

	R_MarkLeaves ();	// done here so we know if we're in water

	R_DrawWorld ();		// adds static entities to the list

	//R_DrawParticles (); // draw particles

	R_DrawSolidAliasEntities(); //qbism//jf 01-10-30 draw all potentially visible alias models now

	R_DrawSolidBrushEntities(); //qbism//jf 01-10-30 draw all potentially visible brush models now

	R_DrawTransparentAliasEntities(); //qbism//jf 01-10-30 draw all potentially visible alias models now

	R_DrawTransparentBrushEntities(); //qbism//jf 01-10-30 draw all potentially visible brush models now


	//	R_DrawEntitiesOnList ();

	GL_DisableMultitexture();

	R_RenderDlights ();

	S_ExtraUpdate ();	// don't let sound get messed up if going slow

	R_DrawParticles ();

#ifdef GLTEST
	Test_Draw ();
#endif

}


/*
=============
R_Clear
=============
*/
void R_Clear (void)
{
	if (r_mirroralpha.value != 1.0)
	{
		if (gl_clear.value)
			glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		else
		    glClear (GL_DEPTH_BUFFER_BIT);
		gldepthmin = 0;
		gldepthmax = 0.5;
		glDepthFunc (GL_LEQUAL);
	}
	else if (gl_ztrick.value)
	{
		static int trickframe;

		if (gl_clear.value)
			glClear (GL_COLOR_BUFFER_BIT);

		trickframe++;
		if (trickframe & 1)
		{
			gldepthmin = 0;
			gldepthmax = 0.49999;
			glDepthFunc (GL_LEQUAL);
		}
		else
		    {
			gldepthmin = 1;
			gldepthmax = 0.5;
			glDepthFunc (GL_GEQUAL);
		}
	}
	else
	    {
		if (gl_clear.value)
			glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		else
		    glClear (GL_DEPTH_BUFFER_BIT);
		gldepthmin = 0;
		gldepthmax = 1;
		glDepthFunc (GL_LEQUAL);
	}

	glDepthRange (gldepthmin, gldepthmax);
}

/*
=============
R_Mirror
=============
*/
void R_Mirror (void)
{
	float		d;
	msurface_t	*s;
	entity_t	*ent;

	if (!mirror)
		return;

	memcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix));

	d = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist;
	VectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg);

	d = DotProduct (vpn, mirror_plane->normal);
	VectorMA (vpn, -2*d, mirror_plane->normal, vpn);

	r_refdef.viewangles[0] = -asin (vpn[2])/M_PI*180;
	r_refdef.viewangles[1] = atan2 (vpn[1], vpn[0])/M_PI*180;
	r_refdef.viewangles[2] = -r_refdef.viewangles[2];

	ent = &cl_entities[cl.viewentity];
	if (cl_numvisedicts < MAX_VISEDICTS)
	{
		cl_visedicts[cl_numvisedicts] = ent;
		cl_numvisedicts++;
	}

	gldepthmin = 0.5;
	gldepthmax = 1;
	glDepthRange (gldepthmin, gldepthmax);
	glDepthFunc (GL_LEQUAL);

	R_RenderScene ();
	R_DrawWaterSurfaces ();

	gldepthmin = 0;
	gldepthmax = 0.5;
	glDepthRange (gldepthmin, gldepthmax);
	glDepthFunc (GL_LEQUAL);

	// blend on top
	glEnable (GL_BLEND);
	glMatrixMode(GL_PROJECTION);
	if (mirror_plane->normal[2])
		glScalef (1,-1,1);
	else
	    glScalef (-1,1,1);
	glCullFace(GL_FRONT);
	glMatrixMode(GL_MODELVIEW);

	glLoadMatrixf (r_base_world_matrix);

	glColor4f (1,1,1,r_mirroralpha.value);
	s = cl.worldmodel->textures[mirrortexturenum]->texturechain;
	for ( ; s ; s=s->texturechain)
		R_RenderBrushPoly (s);
	cl.worldmodel->textures[mirrortexturenum]->texturechain = NULL;
	glDisable (GL_BLEND);
	glColor4f (1,1,1,1);
}

/*
================
R_RenderView

r_refdef must be set before the first call
================
*/
void R_RenderView (void)
{
	double	time1, time2;
	GLfloat colors[4];

	if (r_norefresh.value)
		return;

	if (!r_worldentity.model || !cl.worldmodel)
		Sys_Error ("R_RenderView: NULL worldmodel");

	if (r_speeds.value)
	{
		glFinish ();
		time1 = Sys_FloatTime ();
		c_brush_polys = 0;
		c_alias_polys = 0;
	}

	mirror = false;

	if (gl_finish.value)
		glFinish ();

	R_Clear ();

	// render normal view

	//qbism//00-06-15 NATAS - BramBo - fog code
	if( fog_enable.value )
	{
		glFogi(GL_FOG_MODE, GL_LINEAR);
		colors[0] = fog_red.value;
		colors[1] = fog_green.value;
		colors[2] = fog_blue.value;
		colors[3] = fog_alpha.value;
		glFogfv(GL_FOG_COLOR, colors);
		glFogf(GL_FOG_START, fog_start.value);
		glFogf(GL_FOG_END, fog_end.value);
		glFogf(GL_FOG_DENSITY, fog_density.value);
		glEnable(GL_FOG);
	}
	else
	    {
		glDisable(GL_FOG);
	}
	// END

	R_RenderScene ();
	R_DrawViewModel ();
	R_DrawWaterSurfaces ();

	//qbism//00-06-15  NATAS - BramBo - Fog code
		glDisable(GL_FOG);
	// END

	// render mirror view
	R_Mirror ();

	R_PolyBlend ();

	if (r_speeds.value)
	{
		//		glFinish ();
		time2 = Sys_FloatTime ();
		Con_Printf ("%3i ms  %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys);
	}
}
