Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

gl_mesh.c (19224B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 // gl_mesh.c: triangle model functions
     21 
     22 #include "gl_local.h"
     23 
     24 /*
     25 =============================================================
     26 
     27   ALIAS MODELS
     28 
     29 =============================================================
     30 */
     31 
     32 #define NUMVERTEXNORMALS	162
     33 
     34 float	r_avertexnormals[NUMVERTEXNORMALS][3] = {
     35 #include "anorms.h"
     36 };
     37 
     38 typedef float vec4_t[4];
     39 
     40 static	vec4_t	s_lerped[MAX_VERTS];
     41 //static	vec3_t	lerped[MAX_VERTS];
     42 
     43 vec3_t	shadevector;
     44 float	shadelight[3];
     45 
     46 // precalculated dot products for quantized angles
     47 #define SHADEDOT_QUANT 16
     48 float	r_avertexnormal_dots[SHADEDOT_QUANT][256] =
     49 #include "anormtab.h"
     50 ;
     51 
     52 float	*shadedots = r_avertexnormal_dots[0];
     53 
     54 void GL_LerpVerts( int nverts, dtrivertx_t *v, dtrivertx_t *ov, dtrivertx_t *verts, float *lerp, float move[3], float frontv[3], float backv[3] )
     55 {
     56 	int i;
     57 
     58 	//PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM
     59 	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
     60 	{
     61 		for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4 )
     62 		{
     63 			float *normal = r_avertexnormals[verts[i].lightnormalindex];
     64 
     65 			lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0] + normal[0] * POWERSUIT_SCALE;
     66 			lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1] + normal[1] * POWERSUIT_SCALE;
     67 			lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2] + normal[2] * POWERSUIT_SCALE; 
     68 		}
     69 	}
     70 	else
     71 	{
     72 		for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4)
     73 		{
     74 			lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0];
     75 			lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1];
     76 			lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2];
     77 		}
     78 	}
     79 
     80 }
     81 
     82 /*
     83 =============
     84 GL_DrawAliasFrameLerp
     85 
     86 interpolates between two frames and origins
     87 FIXME: batch lerp all vertexes
     88 =============
     89 */
     90 void GL_DrawAliasFrameLerp (dmdl_t *paliashdr, float backlerp)
     91 {
     92 	float 	l;
     93 	daliasframe_t	*frame, *oldframe;
     94 	dtrivertx_t	*v, *ov, *verts;
     95 	int		*order;
     96 	int		count;
     97 	float	frontlerp;
     98 	float	alpha;
     99 	vec3_t	move, delta, vectors[3];
    100 	vec3_t	frontv, backv;
    101 	int		i;
    102 	int		index_xyz;
    103 	float	*lerp;
    104 
    105 	frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames 
    106 		+ currententity->frame * paliashdr->framesize);
    107 	verts = v = frame->verts;
    108 
    109 	oldframe = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames 
    110 		+ currententity->oldframe * paliashdr->framesize);
    111 	ov = oldframe->verts;
    112 
    113 	order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds);
    114 
    115 //	glTranslatef (frame->translate[0], frame->translate[1], frame->translate[2]);
    116 //	glScalef (frame->scale[0], frame->scale[1], frame->scale[2]);
    117 
    118 	if (currententity->flags & RF_TRANSLUCENT)
    119 		alpha = currententity->alpha;
    120 	else
    121 		alpha = 1.0;
    122 
    123 	// PMM - added double shell
    124 	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
    125 		qglDisable( GL_TEXTURE_2D );
    126 
    127 	frontlerp = 1.0 - backlerp;
    128 
    129 	// move should be the delta back to the previous frame * backlerp
    130 	VectorSubtract (currententity->oldorigin, currententity->origin, delta);
    131 	AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]);
    132 
    133 	move[0] = DotProduct (delta, vectors[0]);	// forward
    134 	move[1] = -DotProduct (delta, vectors[1]);	// left
    135 	move[2] = DotProduct (delta, vectors[2]);	// up
    136 
    137 	VectorAdd (move, oldframe->translate, move);
    138 
    139 	for (i=0 ; i<3 ; i++)
    140 	{
    141 		move[i] = backlerp*move[i] + frontlerp*frame->translate[i];
    142 	}
    143 
    144 	for (i=0 ; i<3 ; i++)
    145 	{
    146 		frontv[i] = frontlerp*frame->scale[i];
    147 		backv[i] = backlerp*oldframe->scale[i];
    148 	}
    149 
    150 	lerp = s_lerped[0];
    151 
    152 	GL_LerpVerts( paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv );
    153 
    154 	if ( gl_vertex_arrays->value )
    155 	{
    156 		float colorArray[MAX_VERTS*4];
    157 
    158 		qglEnableClientState( GL_VERTEX_ARRAY );
    159 		qglVertexPointer( 3, GL_FLOAT, 16, s_lerped );	// padded for SIMD
    160 
    161 //		if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) )
    162 		// PMM - added double damage shell
    163 		if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
    164 		{
    165 			qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha );
    166 		}
    167 		else
    168 		{
    169 			qglEnableClientState( GL_COLOR_ARRAY );
    170 			qglColorPointer( 3, GL_FLOAT, 0, colorArray );
    171 
    172 			//
    173 			// pre light everything
    174 			//
    175 			for ( i = 0; i < paliashdr->num_xyz; i++ )
    176 			{
    177 				float l = shadedots[verts[i].lightnormalindex];
    178 
    179 				colorArray[i*3+0] = l * shadelight[0];
    180 				colorArray[i*3+1] = l * shadelight[1];
    181 				colorArray[i*3+2] = l * shadelight[2];
    182 			}
    183 		}
    184 
    185 		if ( qglLockArraysEXT != 0 )
    186 			qglLockArraysEXT( 0, paliashdr->num_xyz );
    187 
    188 		while (1)
    189 		{
    190 			// get the vertex count and primitive type
    191 			count = *order++;
    192 			if (!count)
    193 				break;		// done
    194 			if (count < 0)
    195 			{
    196 				count = -count;
    197 				qglBegin (GL_TRIANGLE_FAN);
    198 			}
    199 			else
    200 			{
    201 				qglBegin (GL_TRIANGLE_STRIP);
    202 			}
    203 
    204 			// PMM - added double damage shell
    205 			if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
    206 			{
    207 				do
    208 				{
    209 					index_xyz = order[2];
    210 					order += 3;
    211 
    212 					qglVertex3fv( s_lerped[index_xyz] );
    213 
    214 				} while (--count);
    215 			}
    216 			else
    217 			{
    218 				do
    219 				{
    220 					// texture coordinates come from the draw list
    221 					qglTexCoord2f (((float *)order)[0], ((float *)order)[1]);
    222 					index_xyz = order[2];
    223 
    224 					order += 3;
    225 
    226 					// normals and vertexes come from the frame list
    227 //					l = shadedots[verts[index_xyz].lightnormalindex];
    228 					
    229 //					qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha);
    230 					qglArrayElement( index_xyz );
    231 
    232 				} while (--count);
    233 			}
    234 			qglEnd ();
    235 		}
    236 
    237 		if ( qglUnlockArraysEXT != 0 )
    238 			qglUnlockArraysEXT();
    239 	}
    240 	else
    241 	{
    242 		while (1)
    243 		{
    244 			// get the vertex count and primitive type
    245 			count = *order++;
    246 			if (!count)
    247 				break;		// done
    248 			if (count < 0)
    249 			{
    250 				count = -count;
    251 				qglBegin (GL_TRIANGLE_FAN);
    252 			}
    253 			else
    254 			{
    255 				qglBegin (GL_TRIANGLE_STRIP);
    256 			}
    257 
    258 			if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) )
    259 			{
    260 				do
    261 				{
    262 					index_xyz = order[2];
    263 					order += 3;
    264 
    265 					qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha);
    266 					qglVertex3fv (s_lerped[index_xyz]);
    267 
    268 				} while (--count);
    269 			}
    270 			else
    271 			{
    272 				do
    273 				{
    274 					// texture coordinates come from the draw list
    275 					qglTexCoord2f (((float *)order)[0], ((float *)order)[1]);
    276 					index_xyz = order[2];
    277 					order += 3;
    278 
    279 					// normals and vertexes come from the frame list
    280 					l = shadedots[verts[index_xyz].lightnormalindex];
    281 					
    282 					qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha);
    283 					qglVertex3fv (s_lerped[index_xyz]);
    284 				} while (--count);
    285 			}
    286 
    287 			qglEnd ();
    288 		}
    289 	}
    290 
    291 //	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) )
    292 	// PMM - added double damage shell
    293 	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
    294 		qglEnable( GL_TEXTURE_2D );
    295 }
    296 
    297 
    298 #if 1
    299 /*
    300 =============
    301 GL_DrawAliasShadow
    302 =============
    303 */
    304 extern	vec3_t			lightspot;
    305 
    306 void GL_DrawAliasShadow (dmdl_t *paliashdr, int posenum)
    307 {
    308 	dtrivertx_t	*verts;
    309 	int		*order;
    310 	vec3_t	point;
    311 	float	height, lheight;
    312 	int		count;
    313 	daliasframe_t	*frame;
    314 
    315 	lheight = currententity->origin[2] - lightspot[2];
    316 
    317 	frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames 
    318 		+ currententity->frame * paliashdr->framesize);
    319 	verts = frame->verts;
    320 
    321 	height = 0;
    322 
    323 	order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds);
    324 
    325 	height = -lheight + 1.0;
    326 
    327 	while (1)
    328 	{
    329 		// get the vertex count and primitive type
    330 		count = *order++;
    331 		if (!count)
    332 			break;		// done
    333 		if (count < 0)
    334 		{
    335 			count = -count;
    336 			qglBegin (GL_TRIANGLE_FAN);
    337 		}
    338 		else
    339 			qglBegin (GL_TRIANGLE_STRIP);
    340 
    341 		do
    342 		{
    343 			// normals and vertexes come from the frame list
    344 /*
    345 			point[0] = verts[order[2]].v[0] * frame->scale[0] + frame->translate[0];
    346 			point[1] = verts[order[2]].v[1] * frame->scale[1] + frame->translate[1];
    347 			point[2] = verts[order[2]].v[2] * frame->scale[2] + frame->translate[2];
    348 */
    349 
    350 			memcpy( point, s_lerped[order[2]], sizeof( point )  );
    351 
    352 			point[0] -= shadevector[0]*(point[2]+lheight);
    353 			point[1] -= shadevector[1]*(point[2]+lheight);
    354 			point[2] = height;
    355 //			height -= 0.001;
    356 			qglVertex3fv (point);
    357 
    358 			order += 3;
    359 
    360 //			verts++;
    361 
    362 		} while (--count);
    363 
    364 		qglEnd ();
    365 	}	
    366 }
    367 
    368 #endif
    369 
    370 /*
    371 ** R_CullAliasModel
    372 */
    373 static qboolean R_CullAliasModel( vec3_t bbox[8], entity_t *e )
    374 {
    375 	int i;
    376 	vec3_t		mins, maxs;
    377 	dmdl_t		*paliashdr;
    378 	vec3_t		vectors[3];
    379 	vec3_t		thismins, oldmins, thismaxs, oldmaxs;
    380 	daliasframe_t *pframe, *poldframe;
    381 	vec3_t angles;
    382 
    383 	paliashdr = (dmdl_t *)currentmodel->extradata;
    384 
    385 	if ( ( e->frame >= paliashdr->num_frames ) || ( e->frame < 0 ) )
    386 	{
    387 		ri.Con_Printf (PRINT_ALL, "R_CullAliasModel %s: no such frame %d\n", 
    388 			currentmodel->name, e->frame);
    389 		e->frame = 0;
    390 	}
    391 	if ( ( e->oldframe >= paliashdr->num_frames ) || ( e->oldframe < 0 ) )
    392 	{
    393 		ri.Con_Printf (PRINT_ALL, "R_CullAliasModel %s: no such oldframe %d\n", 
    394 			currentmodel->name, e->oldframe);
    395 		e->oldframe = 0;
    396 	}
    397 
    398 	pframe = ( daliasframe_t * ) ( ( byte * ) paliashdr + 
    399 		                              paliashdr->ofs_frames +
    400 									  e->frame * paliashdr->framesize);
    401 
    402 	poldframe = ( daliasframe_t * ) ( ( byte * ) paliashdr + 
    403 		                              paliashdr->ofs_frames +
    404 									  e->oldframe * paliashdr->framesize);
    405 
    406 	/*
    407 	** compute axially aligned mins and maxs
    408 	*/
    409 	if ( pframe == poldframe )
    410 	{
    411 		for ( i = 0; i < 3; i++ )
    412 		{
    413 			mins[i] = pframe->translate[i];
    414 			maxs[i] = mins[i] + pframe->scale[i]*255;
    415 		}
    416 	}
    417 	else
    418 	{
    419 		for ( i = 0; i < 3; i++ )
    420 		{
    421 			thismins[i] = pframe->translate[i];
    422 			thismaxs[i] = thismins[i] + pframe->scale[i]*255;
    423 
    424 			oldmins[i]  = poldframe->translate[i];
    425 			oldmaxs[i]  = oldmins[i] + poldframe->scale[i]*255;
    426 
    427 			if ( thismins[i] < oldmins[i] )
    428 				mins[i] = thismins[i];
    429 			else
    430 				mins[i] = oldmins[i];
    431 
    432 			if ( thismaxs[i] > oldmaxs[i] )
    433 				maxs[i] = thismaxs[i];
    434 			else
    435 				maxs[i] = oldmaxs[i];
    436 		}
    437 	}
    438 
    439 	/*
    440 	** compute a full bounding box
    441 	*/
    442 	for ( i = 0; i < 8; i++ )
    443 	{
    444 		vec3_t   tmp;
    445 
    446 		if ( i & 1 )
    447 			tmp[0] = mins[0];
    448 		else
    449 			tmp[0] = maxs[0];
    450 
    451 		if ( i & 2 )
    452 			tmp[1] = mins[1];
    453 		else
    454 			tmp[1] = maxs[1];
    455 
    456 		if ( i & 4 )
    457 			tmp[2] = mins[2];
    458 		else
    459 			tmp[2] = maxs[2];
    460 
    461 		VectorCopy( tmp, bbox[i] );
    462 	}
    463 
    464 	/*
    465 	** rotate the bounding box
    466 	*/
    467 	VectorCopy( e->angles, angles );
    468 	angles[YAW] = -angles[YAW];
    469 	AngleVectors( angles, vectors[0], vectors[1], vectors[2] );
    470 
    471 	for ( i = 0; i < 8; i++ )
    472 	{
    473 		vec3_t tmp;
    474 
    475 		VectorCopy( bbox[i], tmp );
    476 
    477 		bbox[i][0] = DotProduct( vectors[0], tmp );
    478 		bbox[i][1] = -DotProduct( vectors[1], tmp );
    479 		bbox[i][2] = DotProduct( vectors[2], tmp );
    480 
    481 		VectorAdd( e->origin, bbox[i], bbox[i] );
    482 	}
    483 
    484 	{
    485 		int p, f, aggregatemask = ~0;
    486 
    487 		for ( p = 0; p < 8; p++ )
    488 		{
    489 			int mask = 0;
    490 
    491 			for ( f = 0; f < 4; f++ )
    492 			{
    493 				float dp = DotProduct( frustum[f].normal, bbox[p] );
    494 
    495 				if ( ( dp - frustum[f].dist ) < 0 )
    496 				{
    497 					mask |= ( 1 << f );
    498 				}
    499 			}
    500 
    501 			aggregatemask &= mask;
    502 		}
    503 
    504 		if ( aggregatemask )
    505 		{
    506 			return true;
    507 		}
    508 
    509 		return false;
    510 	}
    511 }
    512 
    513 /*
    514 =================
    515 R_DrawAliasModel
    516 
    517 =================
    518 */
    519 void R_DrawAliasModel (entity_t *e)
    520 {
    521 	int			i;
    522 	dmdl_t		*paliashdr;
    523 	float		an;
    524 	vec3_t		bbox[8];
    525 	image_t		*skin;
    526 
    527 	if ( !( e->flags & RF_WEAPONMODEL ) )
    528 	{
    529 		if ( R_CullAliasModel( bbox, e ) )
    530 			return;
    531 	}
    532 
    533 	if ( e->flags & RF_WEAPONMODEL )
    534 	{
    535 		if ( r_lefthand->value == 2 )
    536 			return;
    537 	}
    538 
    539 	paliashdr = (dmdl_t *)currentmodel->extradata;
    540 
    541 	//
    542 	// get lighting information
    543 	//
    544 	// PMM - rewrote, reordered to handle new shells & mixing
    545 	//
    546 	if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) )
    547 	{
    548 		// PMM -special case for godmode
    549 		if ( (currententity->flags & RF_SHELL_RED) &&
    550 			(currententity->flags & RF_SHELL_BLUE) &&
    551 			(currententity->flags & RF_SHELL_GREEN) )
    552 		{
    553 			for (i=0 ; i<3 ; i++)
    554 				shadelight[i] = 1.0;
    555 		}
    556 		else if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) )
    557 		{
    558 			VectorClear (shadelight);
    559 
    560 			if ( currententity->flags & RF_SHELL_RED )
    561 			{
    562 				shadelight[0] = 1.0;
    563 				if (currententity->flags & (RF_SHELL_BLUE|RF_SHELL_DOUBLE) )
    564 					shadelight[2] = 1.0;
    565 			}
    566 			else if ( currententity->flags & RF_SHELL_BLUE )
    567 			{
    568 				if ( currententity->flags & RF_SHELL_DOUBLE )
    569 				{
    570 					shadelight[1] = 1.0;
    571 					shadelight[2] = 1.0;
    572 				}
    573 				else
    574 				{
    575 					shadelight[2] = 1.0;
    576 				}
    577 			}
    578 			else if ( currententity->flags & RF_SHELL_DOUBLE )
    579 			{
    580 				shadelight[0] = 0.9;
    581 				shadelight[1] = 0.7;
    582 			}
    583 		}
    584 		else if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN ) )
    585 		{
    586 			VectorClear (shadelight);
    587 			// PMM - new colors
    588 			if ( currententity->flags & RF_SHELL_HALF_DAM )
    589 			{
    590 				shadelight[0] = 0.56;
    591 				shadelight[1] = 0.59;
    592 				shadelight[2] = 0.45;
    593 			}
    594 			if ( currententity->flags & RF_SHELL_GREEN )
    595 			{
    596 				shadelight[1] = 1.0;
    597 			}
    598 		}
    599 	}
    600 			//PMM - ok, now flatten these down to range from 0 to 1.0.
    601 	//		max_shell_val = max(shadelight[0], max(shadelight[1], shadelight[2]));
    602 	//		if (max_shell_val > 0)
    603 	//		{
    604 	//			for (i=0; i<3; i++)
    605 	//			{
    606 	//				shadelight[i] = shadelight[i] / max_shell_val;
    607 	//			}
    608 	//		}
    609 	// pmm
    610 	else if ( currententity->flags & RF_FULLBRIGHT )
    611 	{
    612 		for (i=0 ; i<3 ; i++)
    613 			shadelight[i] = 1.0;
    614 	}
    615 	else
    616 	{
    617 		R_LightPoint (currententity->origin, shadelight);
    618 
    619 		// player lighting hack for communication back to server
    620 		// big hack!
    621 		if ( currententity->flags & RF_WEAPONMODEL )
    622 		{
    623 			// pick the greatest component, which should be the same
    624 			// as the mono value returned by software
    625 			if (shadelight[0] > shadelight[1])
    626 			{
    627 				if (shadelight[0] > shadelight[2])
    628 					r_lightlevel->value = 150*shadelight[0];
    629 				else
    630 					r_lightlevel->value = 150*shadelight[2];
    631 			}
    632 			else
    633 			{
    634 				if (shadelight[1] > shadelight[2])
    635 					r_lightlevel->value = 150*shadelight[1];
    636 				else
    637 					r_lightlevel->value = 150*shadelight[2];
    638 			}
    639 
    640 		}
    641 		
    642 		if ( gl_monolightmap->string[0] != '0' )
    643 		{
    644 			float s = shadelight[0];
    645 
    646 			if ( s < shadelight[1] )
    647 				s = shadelight[1];
    648 			if ( s < shadelight[2] )
    649 				s = shadelight[2];
    650 
    651 			shadelight[0] = s;
    652 			shadelight[1] = s;
    653 			shadelight[2] = s;
    654 		}
    655 	}
    656 
    657 	if ( currententity->flags & RF_MINLIGHT )
    658 	{
    659 		for (i=0 ; i<3 ; i++)
    660 			if (shadelight[i] > 0.1)
    661 				break;
    662 		if (i == 3)
    663 		{
    664 			shadelight[0] = 0.1;
    665 			shadelight[1] = 0.1;
    666 			shadelight[2] = 0.1;
    667 		}
    668 	}
    669 
    670 	if ( currententity->flags & RF_GLOW )
    671 	{	// bonus items will pulse with time
    672 		float	scale;
    673 		float	min;
    674 
    675 		scale = 0.1 * sin(r_newrefdef.time*7);
    676 		for (i=0 ; i<3 ; i++)
    677 		{
    678 			min = shadelight[i] * 0.8;
    679 			shadelight[i] += scale;
    680 			if (shadelight[i] < min)
    681 				shadelight[i] = min;
    682 		}
    683 	}
    684 
    685 // =================
    686 // PGM	ir goggles color override
    687 	if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
    688 	{
    689 		shadelight[0] = 1.0;
    690 		shadelight[1] = 0.0;
    691 		shadelight[2] = 0.0;
    692 	}
    693 // PGM	
    694 // =================
    695 
    696 	shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];
    697 	
    698 	an = currententity->angles[1]/180*M_PI;
    699 	shadevector[0] = cos(-an);
    700 	shadevector[1] = sin(-an);
    701 	shadevector[2] = 1;
    702 	VectorNormalize (shadevector);
    703 
    704 	//
    705 	// locate the proper data
    706 	//
    707 
    708 	c_alias_polys += paliashdr->num_tris;
    709 
    710 	//
    711 	// draw all the triangles
    712 	//
    713 	if (currententity->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls
    714 		qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
    715 
    716 	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
    717 	{
    718 		extern void MYgluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar );
    719 
    720 		qglMatrixMode( GL_PROJECTION );
    721 		qglPushMatrix();
    722 		qglLoadIdentity();
    723 		qglScalef( -1, 1, 1 );
    724 	    MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height,  4,  4096);
    725 		qglMatrixMode( GL_MODELVIEW );
    726 
    727 		qglCullFace( GL_BACK );
    728 	}
    729 
    730     qglPushMatrix ();
    731 	e->angles[PITCH] = -e->angles[PITCH];	// sigh.
    732 	R_RotateForEntity (e);
    733 	e->angles[PITCH] = -e->angles[PITCH];	// sigh.
    734 
    735 	// select skin
    736 	if (currententity->skin)
    737 		skin = currententity->skin;	// custom player skin
    738 	else
    739 	{
    740 		if (currententity->skinnum >= MAX_MD2SKINS)
    741 			skin = currentmodel->skins[0];
    742 		else
    743 		{
    744 			skin = currentmodel->skins[currententity->skinnum];
    745 			if (!skin)
    746 				skin = currentmodel->skins[0];
    747 		}
    748 	}
    749 	if (!skin)
    750 		skin = r_notexture;	// fallback...
    751 	GL_Bind(skin->texnum);
    752 
    753 	// draw it
    754 
    755 	qglShadeModel (GL_SMOOTH);
    756 
    757 	GL_TexEnv( GL_MODULATE );
    758 	if ( currententity->flags & RF_TRANSLUCENT )
    759 	{
    760 		qglEnable (GL_BLEND);
    761 	}
    762 
    763 
    764 	if ( (currententity->frame >= paliashdr->num_frames) 
    765 		|| (currententity->frame < 0) )
    766 	{
    767 		ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n",
    768 			currentmodel->name, currententity->frame);
    769 		currententity->frame = 0;
    770 		currententity->oldframe = 0;
    771 	}
    772 
    773 	if ( (currententity->oldframe >= paliashdr->num_frames)
    774 		|| (currententity->oldframe < 0))
    775 	{
    776 		ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n",
    777 			currentmodel->name, currententity->oldframe);
    778 		currententity->frame = 0;
    779 		currententity->oldframe = 0;
    780 	}
    781 
    782 	if ( !r_lerpmodels->value )
    783 		currententity->backlerp = 0;
    784 	GL_DrawAliasFrameLerp (paliashdr, currententity->backlerp);
    785 
    786 	GL_TexEnv( GL_REPLACE );
    787 	qglShadeModel (GL_FLAT);
    788 
    789 	qglPopMatrix ();
    790 
    791 #if 0
    792 	qglDisable( GL_CULL_FACE );
    793 	qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
    794 	qglDisable( GL_TEXTURE_2D );
    795 	qglBegin( GL_TRIANGLE_STRIP );
    796 	for ( i = 0; i < 8; i++ )
    797 	{
    798 		qglVertex3fv( bbox[i] );
    799 	}
    800 	qglEnd();
    801 	qglEnable( GL_TEXTURE_2D );
    802 	qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
    803 	qglEnable( GL_CULL_FACE );
    804 #endif
    805 
    806 	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
    807 	{
    808 		qglMatrixMode( GL_PROJECTION );
    809 		qglPopMatrix();
    810 		qglMatrixMode( GL_MODELVIEW );
    811 		qglCullFace( GL_FRONT );
    812 	}
    813 
    814 	if ( currententity->flags & RF_TRANSLUCENT )
    815 	{
    816 		qglDisable (GL_BLEND);
    817 	}
    818 
    819 	if (currententity->flags & RF_DEPTHHACK)
    820 		qglDepthRange (gldepthmin, gldepthmax);
    821 
    822 #if 1
    823 	if (gl_shadows->value && !(currententity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL)))
    824 	{
    825 		qglPushMatrix ();
    826 		R_RotateForEntity (e);
    827 		qglDisable (GL_TEXTURE_2D);
    828 		qglEnable (GL_BLEND);
    829 		qglColor4f (0,0,0,0.5);
    830 		GL_DrawAliasShadow (paliashdr, currententity->frame );
    831 		qglEnable (GL_TEXTURE_2D);
    832 		qglDisable (GL_BLEND);
    833 		qglPopMatrix ();
    834 	}
    835 #endif
    836 	qglColor4f (1,1,1,1);
    837 }
    838 
    839