Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

r_alias.c (34793B)


      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 // r_alias.c: routines for setting up to draw alias models
     21 
     22 /*
     23 ** use a real variable to control lerping
     24 */
     25 #include "r_local.h"
     26 
     27 #define LIGHT_MIN	5		// lowest light value we'll allow, to avoid the
     28 							//  need for inner-loop light clamping
     29 
     30 //PGM
     31 extern byte iractive;
     32 //PGM
     33 
     34 int				r_amodels_drawn;
     35 
     36 affinetridesc_t	r_affinetridesc;
     37 
     38 vec3_t			r_plightvec;
     39 vec3_t          r_lerped[1024];
     40 vec3_t          r_lerp_frontv, r_lerp_backv, r_lerp_move;
     41 
     42 int				r_ambientlight;
     43 int				r_aliasblendcolor;
     44 float			r_shadelight;
     45 
     46 
     47 daliasframe_t	*r_thisframe, *r_lastframe;
     48 dmdl_t			*s_pmdl;
     49 
     50 float	aliastransform[3][4];
     51 float   aliasworldtransform[3][4];
     52 float   aliasoldworldtransform[3][4];
     53 
     54 static float	s_ziscale;
     55 static vec3_t	s_alias_forward, s_alias_right, s_alias_up;
     56 
     57 
     58 #define NUMVERTEXNORMALS	162
     59 
     60 float	r_avertexnormals[NUMVERTEXNORMALS][3] = {
     61 #include "anorms.h"
     62 };
     63 
     64 
     65 void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp );
     66 void R_AliasSetUpTransform (void);
     67 void R_AliasTransformVector (vec3_t in, vec3_t out, float m[3][4] );
     68 void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
     69 
     70 void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv );
     71 
     72 void R_AliasLerpFrames( dmdl_t *paliashdr, float backlerp );
     73 
     74 /*
     75 ================
     76 R_AliasCheckBBox
     77 ================
     78 */
     79 typedef struct {
     80 	int	index0;
     81 	int	index1;
     82 } aedge_t;
     83 
     84 static aedge_t	aedges[12] = {
     85 {0, 1}, {1, 2}, {2, 3}, {3, 0},
     86 {4, 5}, {5, 6}, {6, 7}, {7, 4},
     87 {0, 5}, {1, 4}, {2, 7}, {3, 6}
     88 };
     89 
     90 #define BBOX_TRIVIAL_ACCEPT 0
     91 #define BBOX_MUST_CLIP_XY   1
     92 #define BBOX_MUST_CLIP_Z    2
     93 #define BBOX_TRIVIAL_REJECT 8
     94 
     95 /*
     96 ** R_AliasCheckFrameBBox
     97 **
     98 ** Checks a specific alias frame bounding box
     99 */
    100 unsigned long R_AliasCheckFrameBBox( daliasframe_t *frame, float worldxf[3][4] )
    101 {
    102 	unsigned long aggregate_and_clipcode = ~0U, 
    103 		          aggregate_or_clipcode = 0;
    104 	int           i;
    105 	vec3_t        mins, maxs;
    106 	vec3_t        transformed_min, transformed_max;
    107 	qboolean      zclipped = false, zfullyclipped = true;
    108 	float         minz = 9999.0F;
    109 
    110 	/*
    111 	** get the exact frame bounding box
    112 	*/
    113 	for (i=0 ; i<3 ; i++)
    114 	{
    115 		mins[i] = frame->translate[i];
    116 		maxs[i] = mins[i] + frame->scale[i]*255;
    117 	}
    118 
    119 	/*
    120 	** transform the min and max values into view space
    121 	*/
    122 	R_AliasTransformVector( mins, transformed_min, aliastransform );
    123 	R_AliasTransformVector( maxs, transformed_max, aliastransform );
    124 
    125 	if ( transformed_min[2] >= ALIAS_Z_CLIP_PLANE )
    126 		zfullyclipped = false;
    127 	if ( transformed_max[2] >= ALIAS_Z_CLIP_PLANE )
    128 		zfullyclipped = false;
    129 
    130 	if ( zfullyclipped )
    131 	{
    132 		return BBOX_TRIVIAL_REJECT;
    133 	}
    134 	if ( zclipped )
    135 	{
    136 		return ( BBOX_MUST_CLIP_XY | BBOX_MUST_CLIP_Z );
    137 	}
    138 
    139 	/*
    140 	** build a transformed bounding box from the given min and max
    141 	*/
    142 	for ( i = 0; i < 8; i++ )
    143 	{
    144 		int      j;
    145 		vec3_t   tmp, transformed;
    146 		unsigned long clipcode = 0;
    147 
    148 		if ( i & 1 )
    149 			tmp[0] = mins[0];
    150 		else
    151 			tmp[0] = maxs[0];
    152 
    153 		if ( i & 2 )
    154 			tmp[1] = mins[1];
    155 		else
    156 			tmp[1] = maxs[1];
    157 
    158 		if ( i & 4 )
    159 			tmp[2] = mins[2];
    160 		else
    161 			tmp[2] = maxs[2];
    162 
    163 		R_AliasTransformVector( tmp, transformed, worldxf );
    164 
    165 		for ( j = 0; j < 4; j++ )
    166 		{
    167 			float dp = DotProduct( transformed, view_clipplanes[j].normal );
    168 
    169 			if ( ( dp - view_clipplanes[j].dist ) < 0.0F )
    170 				clipcode |= 1 << j;
    171 		}
    172 
    173 		aggregate_and_clipcode &= clipcode;
    174 		aggregate_or_clipcode  |= clipcode;
    175 	}
    176 
    177 	if ( aggregate_and_clipcode )
    178 	{
    179 		return BBOX_TRIVIAL_REJECT;
    180 	}
    181 	if ( !aggregate_or_clipcode )
    182 	{
    183 		return BBOX_TRIVIAL_ACCEPT;
    184 	}
    185 
    186 	return BBOX_MUST_CLIP_XY;
    187 }
    188 
    189 qboolean R_AliasCheckBBox (void)
    190 {
    191 	unsigned long ccodes[2] = { 0, 0 };
    192 
    193 	ccodes[0] = R_AliasCheckFrameBBox( r_thisframe, aliasworldtransform );
    194 
    195 	/*
    196 	** non-lerping model
    197 	*/
    198 	if ( currententity->backlerp == 0 )
    199 	{
    200 		if ( ccodes[0] == BBOX_TRIVIAL_ACCEPT )
    201 			return BBOX_TRIVIAL_ACCEPT;
    202 		else if ( ccodes[0] & BBOX_TRIVIAL_REJECT )
    203 			return BBOX_TRIVIAL_REJECT;
    204 		else
    205 			return ( ccodes[0] & ~BBOX_TRIVIAL_REJECT );
    206 	}
    207 
    208 	ccodes[1] = R_AliasCheckFrameBBox( r_lastframe, aliasoldworldtransform );
    209 
    210 	if ( ( ccodes[0] | ccodes[1] ) == BBOX_TRIVIAL_ACCEPT )
    211 		return BBOX_TRIVIAL_ACCEPT;
    212 	else if ( ( ccodes[0] & ccodes[1] ) & BBOX_TRIVIAL_REJECT )
    213 		return BBOX_TRIVIAL_REJECT;
    214 	else
    215 		return ( ccodes[0] | ccodes[1] ) & ~BBOX_TRIVIAL_REJECT;
    216 }
    217 
    218 
    219 /*
    220 ================
    221 R_AliasTransformVector
    222 ================
    223 */
    224 void R_AliasTransformVector(vec3_t in, vec3_t out, float xf[3][4] )
    225 {
    226 	out[0] = DotProduct(in, xf[0]) + xf[0][3];
    227 	out[1] = DotProduct(in, xf[1]) + xf[1][3];
    228 	out[2] = DotProduct(in, xf[2]) + xf[2][3];
    229 }
    230 
    231 
    232 /*
    233 ================
    234 R_AliasPreparePoints
    235 
    236 General clipped case
    237 ================
    238 */
    239 typedef struct
    240 {
    241 	int          num_points;
    242 	dtrivertx_t *last_verts;   // verts from the last frame
    243 	dtrivertx_t *this_verts;   // verts from this frame
    244 	finalvert_t *dest_verts;   // destination for transformed verts
    245 } aliasbatchedtransformdata_t;
    246 
    247 aliasbatchedtransformdata_t aliasbatchedtransformdata;
    248 
    249 void R_AliasPreparePoints (void)
    250 {
    251 	int			i;
    252 	dstvert_t	*pstverts;
    253 	dtriangle_t	*ptri;
    254 	finalvert_t	*pfv[3];
    255 	finalvert_t	finalverts[MAXALIASVERTS +
    256 						((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 3];
    257 	finalvert_t	*pfinalverts;
    258 
    259 //PGM
    260 	iractive = (r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE);
    261 //	iractive = 0;
    262 //	if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
    263 //		iractive = 1;
    264 //PGM
    265 
    266 	// put work vertexes on stack, cache aligned
    267 	pfinalverts = (finalvert_t *)
    268 			(((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
    269 
    270 	aliasbatchedtransformdata.num_points = s_pmdl->num_xyz;
    271 	aliasbatchedtransformdata.last_verts = r_lastframe->verts;
    272 	aliasbatchedtransformdata.this_verts = r_thisframe->verts;
    273 	aliasbatchedtransformdata.dest_verts = pfinalverts;
    274 
    275 	R_AliasTransformFinalVerts( aliasbatchedtransformdata.num_points,
    276 		                        aliasbatchedtransformdata.dest_verts,
    277 								aliasbatchedtransformdata.last_verts,
    278 								aliasbatchedtransformdata.this_verts );
    279 
    280 // clip and draw all triangles
    281 //
    282 	pstverts = (dstvert_t *)((byte *)s_pmdl + s_pmdl->ofs_st);
    283 	ptri = (dtriangle_t *)((byte *)s_pmdl + s_pmdl->ofs_tris);
    284 
    285 	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
    286 	{
    287 		for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
    288 		{
    289 			pfv[0] = &pfinalverts[ptri->index_xyz[0]];
    290 			pfv[1] = &pfinalverts[ptri->index_xyz[1]];
    291 			pfv[2] = &pfinalverts[ptri->index_xyz[2]];
    292 
    293 			if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
    294 				continue;		// completely clipped
    295 
    296 			// insert s/t coordinates
    297 			pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
    298 			pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
    299 
    300 			pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
    301 			pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
    302 
    303 			pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
    304 			pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
    305 
    306 			if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
    307 			{	// totally unclipped
    308 				aliastriangleparms.a = pfv[2];
    309 				aliastriangleparms.b = pfv[1];
    310 				aliastriangleparms.c = pfv[0];
    311 
    312 				R_DrawTriangle();
    313 			}
    314 			else
    315 			{
    316 				R_AliasClipTriangle (pfv[2], pfv[1], pfv[0]);
    317 			}
    318 		}
    319 	}
    320 	else
    321 	{
    322 		for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
    323 		{
    324 			pfv[0] = &pfinalverts[ptri->index_xyz[0]];
    325 			pfv[1] = &pfinalverts[ptri->index_xyz[1]];
    326 			pfv[2] = &pfinalverts[ptri->index_xyz[2]];
    327 
    328 			if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
    329 				continue;		// completely clipped
    330 
    331 			// insert s/t coordinates
    332 			pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
    333 			pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
    334 
    335 			pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
    336 			pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
    337 
    338 			pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
    339 			pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
    340 
    341 			if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
    342 			{	// totally unclipped
    343 				aliastriangleparms.a = pfv[0];
    344 				aliastriangleparms.b = pfv[1];
    345 				aliastriangleparms.c = pfv[2];
    346 
    347 				R_DrawTriangle();
    348 			}
    349 			else		
    350 			{	// partially clipped
    351 				R_AliasClipTriangle (pfv[0], pfv[1], pfv[2]);
    352 			}
    353 		}
    354 	}
    355 }
    356 
    357 
    358 /*
    359 ================
    360 R_AliasSetUpTransform
    361 ================
    362 */
    363 void R_AliasSetUpTransform (void)
    364 {
    365 	int				i;
    366 	static float	viewmatrix[3][4];
    367 	vec3_t			angles;
    368 
    369 // TODO: should really be stored with the entity instead of being reconstructed
    370 // TODO: should use a look-up table
    371 // TODO: could cache lazily, stored in the entity
    372 // 
    373 	angles[ROLL] = currententity->angles[ROLL];
    374 	angles[PITCH] = currententity->angles[PITCH];
    375 	angles[YAW] = currententity->angles[YAW];
    376 	AngleVectors( angles, s_alias_forward, s_alias_right, s_alias_up );
    377 
    378 // TODO: can do this with simple matrix rearrangement
    379 
    380 	memset( aliasworldtransform, 0, sizeof( aliasworldtransform ) );
    381 	memset( aliasoldworldtransform, 0, sizeof( aliasworldtransform ) );
    382 
    383 	for (i=0 ; i<3 ; i++)
    384 	{
    385 		aliasoldworldtransform[i][0] = aliasworldtransform[i][0] =  s_alias_forward[i];
    386 		aliasoldworldtransform[i][0] = aliasworldtransform[i][1] = -s_alias_right[i];
    387 		aliasoldworldtransform[i][0] = aliasworldtransform[i][2] =  s_alias_up[i];
    388 	}
    389 
    390 	aliasworldtransform[0][3] = currententity->origin[0]-r_origin[0];
    391 	aliasworldtransform[1][3] = currententity->origin[1]-r_origin[1];
    392 	aliasworldtransform[2][3] = currententity->origin[2]-r_origin[2];
    393 
    394 	aliasoldworldtransform[0][3] = currententity->oldorigin[0]-r_origin[0];
    395 	aliasoldworldtransform[1][3] = currententity->oldorigin[1]-r_origin[1];
    396 	aliasoldworldtransform[2][3] = currententity->oldorigin[2]-r_origin[2];
    397 
    398 // FIXME: can do more efficiently than full concatenation
    399 //	memcpy( rotationmatrix, t2matrix, sizeof( rotationmatrix ) );
    400 
    401 //	R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
    402 
    403 // TODO: should be global, set when vright, etc., set
    404 	VectorCopy (vright, viewmatrix[0]);
    405 	VectorCopy (vup, viewmatrix[1]);
    406 	VectorInverse (viewmatrix[1]);
    407 	VectorCopy (vpn, viewmatrix[2]);
    408 
    409 	viewmatrix[0][3] = 0;
    410 	viewmatrix[1][3] = 0;
    411 	viewmatrix[2][3] = 0;
    412 
    413 //	memcpy( aliasworldtransform, rotationmatrix, sizeof( aliastransform ) );
    414 
    415 	R_ConcatTransforms (viewmatrix, aliasworldtransform, aliastransform);
    416 
    417 	aliasworldtransform[0][3] = currententity->origin[0];
    418 	aliasworldtransform[1][3] = currententity->origin[1];
    419 	aliasworldtransform[2][3] = currententity->origin[2];
    420 
    421 	aliasoldworldtransform[0][3] = currententity->oldorigin[0];
    422 	aliasoldworldtransform[1][3] = currententity->oldorigin[1];
    423 	aliasoldworldtransform[2][3] = currententity->oldorigin[2];
    424 }
    425 
    426 
    427 /*
    428 ================
    429 R_AliasTransformFinalVerts
    430 ================
    431 */
    432 #if id386 && !defined __linux__
    433 void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv )
    434 {
    435 	float  lightcos;
    436 	float	lerped_vert[3];
    437 	int    byte_to_dword_ptr_var;
    438 	int    tmpint;
    439 
    440 	float  one = 1.0F;
    441 	float  zi;
    442 
    443 	static float  FALIAS_Z_CLIP_PLANE = ALIAS_Z_CLIP_PLANE;
    444 	static float  PS_SCALE = POWERSUIT_SCALE;
    445 
    446 	__asm mov ecx, numpoints
    447 
    448 	/*
    449 	lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0];
    450 	lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1];
    451 	lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2];
    452 	*/
    453 top_of_loop:
    454 
    455 	__asm mov esi, oldv
    456 	__asm mov edi, newv
    457 
    458 	__asm xor ebx, ebx
    459 
    460 	__asm mov bl, byte ptr [esi+DTRIVERTX_V0]
    461 	__asm mov byte_to_dword_ptr_var, ebx
    462 	__asm fild dword ptr byte_to_dword_ptr_var      
    463 	__asm fmul dword ptr [r_lerp_backv+0]                  ; oldv[0]*rlb[0]
    464 
    465 	__asm mov bl, byte ptr [esi+DTRIVERTX_V1]
    466 	__asm mov byte_to_dword_ptr_var, ebx
    467 	__asm fild dword ptr byte_to_dword_ptr_var
    468 	__asm fmul dword ptr [r_lerp_backv+4]                  ; oldv[1]*rlb[1] | oldv[0]*rlb[0]
    469 
    470 	__asm mov bl, byte ptr [esi+DTRIVERTX_V2]
    471 	__asm mov byte_to_dword_ptr_var, ebx
    472 	__asm fild dword ptr byte_to_dword_ptr_var
    473 	__asm fmul dword ptr [r_lerp_backv+8]                  ; oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0]
    474 
    475 	__asm mov bl, byte ptr [edi+DTRIVERTX_V0]
    476 	__asm mov byte_to_dword_ptr_var, ebx
    477 	__asm fild dword ptr byte_to_dword_ptr_var      
    478 	__asm fmul dword ptr [r_lerp_frontv+0]                 ; newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0]
    479 
    480 	__asm mov bl, byte ptr [edi+DTRIVERTX_V1]
    481 	__asm mov byte_to_dword_ptr_var, ebx
    482 	__asm fild dword ptr byte_to_dword_ptr_var
    483 	__asm fmul dword ptr [r_lerp_frontv+4]                 ; newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0]
    484 
    485 	__asm mov bl, byte ptr [edi+DTRIVERTX_V2]
    486 	__asm mov byte_to_dword_ptr_var, ebx
    487 	__asm fild dword ptr byte_to_dword_ptr_var
    488 	__asm fmul dword ptr [r_lerp_frontv+8]                 ; newv[2]*rlf[2] | newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0]
    489 
    490 	__asm fxch st(5)                     ; oldv[0]*rlb[0] | newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | newv[2]*rlf[2]
    491 	__asm faddp st(2), st                ; newv[1]*rlf[1] | oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | newv[2]*rlf[2]
    492 	__asm faddp st(3), st                ; oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] + newv[1]*rlf[1] | newv[2]*rlf[2]
    493 	__asm fxch st(1)                     ; oldv[2]*rlb[2] | oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[1]*rlb[1] + newv[1]*rlf[1] | newv[2]*rlf[2]
    494 	__asm faddp st(3), st                ; oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[1]*rlb[1] + newv[1]*rlf[1] | oldv[2]*rlb[2] + newv[2]*rlf[2]
    495 	__asm fadd dword ptr [r_lerp_move+0] ; lv0 | oldv[1]*rlb[1] + newv[1]*rlf[1] | oldv[2]*rlb[2] + newv[2]*rlf[2]
    496 	__asm fxch st(1)                     ; oldv[1]*rlb[1] + newv[1]*rlf[1] | lv0 | oldv[2]*rlb[2] + newv[2]*rlf[2]
    497 	__asm fadd dword ptr [r_lerp_move+4] ; lv1 | lv0 | oldv[2]*rlb[2] + newv[2]*rlf[2]
    498 	__asm fxch st(2)                     ; oldv[2]*rlb[2] + newv[2]*rlf[2] | lv0 | lv1
    499 	__asm fadd dword ptr [r_lerp_move+8] ; lv2 | lv0 | lv1
    500 	__asm fxch st(1)                     ; lv0 | lv2 | lv1
    501 	__asm fstp dword ptr [lerped_vert+0] ; lv2 | lv1
    502 	__asm fstp dword ptr [lerped_vert+8] ; lv2
    503 	__asm fstp dword ptr [lerped_vert+4] ; (empty)
    504 
    505 	__asm mov  eax, currententity
    506 	__asm mov  eax, dword ptr [eax+ENTITY_FLAGS]
    507 	__asm mov  ebx, RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM
    508 	__asm and  eax, ebx
    509 	__asm jz   not_powersuit
    510 
    511 	/*
    512 	**    lerped_vert[0] += lightnormal[0] * POWERSUIT_SCALE
    513 	**    lerped_vert[1] += lightnormal[1] * POWERSUIT_SCALE
    514 	**    lerped_vert[2] += lightnormal[2] * POWERSUIT_SCALE
    515 	*/
    516 
    517 	__asm xor ebx, ebx
    518 	__asm mov bl,  byte ptr [edi+DTRIVERTX_LNI]
    519 	__asm mov eax, 12
    520 	__asm mul ebx
    521 	__asm lea eax, [r_avertexnormals+eax]
    522 
    523 	__asm fld  dword ptr [eax+0]				; n[0]
    524 	__asm fmul PS_SCALE							; n[0] * PS
    525 	__asm fld  dword ptr [eax+4]				; n[1] | n[0] * PS
    526 	__asm fmul PS_SCALE							; n[1] * PS | n[0] * PS
    527 	__asm fld  dword ptr [eax+8]				; n[2] | n[1] * PS | n[0] * PS
    528 	__asm fmul PS_SCALE							; n[2] * PS | n[1] * PS | n[0] * PS
    529 	__asm fld  dword ptr [lerped_vert+0]		; lv0 | n[2] * PS | n[1] * PS | n[0] * PS
    530 	__asm faddp st(3), st						; n[2] * PS | n[1] * PS | n[0] * PS + lv0
    531 	__asm fld  dword ptr [lerped_vert+4]		; lv1 | n[2] * PS | n[1] * PS | n[0] * PS + lv0
    532 	__asm faddp st(2), st						; n[2] * PS | n[1] * PS + lv1 | n[0] * PS + lv0
    533 	__asm fadd dword ptr [lerped_vert+8]		; n[2] * PS + lv2 | n[1] * PS + lv1 | n[0] * PS + lv0
    534 	__asm fxch st(2)							; LV0 | LV1 | LV2
    535 	__asm fstp dword ptr [lerped_vert+0]		; LV1 | LV2
    536 	__asm fstp dword ptr [lerped_vert+4]		; LV2
    537 	__asm fstp dword ptr [lerped_vert+8]		; (empty)
    538 
    539 not_powersuit:
    540 
    541 	/*
    542 	fv->flags = 0;
    543 
    544 	fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3];
    545 	fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3];
    546 	fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3];
    547 	*/
    548 	__asm mov  eax, fv
    549 	__asm mov  dword ptr [eax+FINALVERT_FLAGS], 0
    550 
    551 	__asm fld  dword ptr [lerped_vert+0]           ; lv0
    552 	__asm fmul dword ptr [aliastransform+0]        ; lv0*at[0][0]
    553 	__asm fld  dword ptr [lerped_vert+4]           ; lv1 | lv0*at[0][0]
    554 	__asm fmul dword ptr [aliastransform+4]        ; lv1*at[0][1] | lv0*at[0][0]
    555 	__asm fld  dword ptr [lerped_vert+8]           ; lv2 | lv1*at[0][1] | lv0*at[0][0]
    556 	__asm fmul dword ptr [aliastransform+8]        ; lv2*at[0][2] | lv1*at[0][1] | lv0*at[0][0]
    557 	__asm fxch st(2)                               ; lv0*at[0][0] | lv1*at[0][1] | lv2*at[0][2]
    558 	__asm faddp st(1), st                          ; lv0*at[0][0] + lv1*at[0][1] | lv2*at[0][2]
    559 	__asm faddp st(1), st                          ; lv0*at[0][0] + lv1*at[0][1] + lv2*at[0][2]
    560 	__asm fadd  dword ptr [aliastransform+12]      ; FV.X
    561 
    562 	__asm fld  dword ptr [lerped_vert+0]           ; lv0
    563 	__asm fmul dword ptr [aliastransform+16]       ; lv0*at[1][0]
    564 	__asm fld  dword ptr [lerped_vert+4]           ; lv1 | lv0*at[1][0]
    565 	__asm fmul dword ptr [aliastransform+20]       ; lv1*at[1][1] | lv0*at[1][0]
    566 	__asm fld  dword ptr [lerped_vert+8]           ; lv2 | lv1*at[1][1] | lv0*at[1][0]
    567 	__asm fmul dword ptr [aliastransform+24]       ; lv2*at[1][2] | lv1*at[1][1] | lv0*at[1][0]
    568 	__asm fxch st(2)                               ; lv0*at[1][0] | lv1*at[1][1] | lv2*at[1][2]
    569 	__asm faddp st(1), st                          ; lv0*at[1][0] + lv1*at[1][1] | lv2*at[1][2]
    570 	__asm faddp st(1), st                          ; lv0*at[1][0] + lv1*at[1][1] + lv2*at[1][2]
    571 	__asm fadd dword ptr [aliastransform+28]       ; FV.Y | FV.X
    572 	__asm fxch st(1)                               ; FV.X | FV.Y
    573 	__asm fstp  dword ptr [eax+FINALVERT_X]        ; FV.Y
    574 	
    575 	__asm fld  dword ptr [lerped_vert+0]           ; lv0
    576 	__asm fmul dword ptr [aliastransform+32]       ; lv0*at[2][0]
    577 	__asm fld  dword ptr [lerped_vert+4]           ; lv1 | lv0*at[2][0]
    578 	__asm fmul dword ptr [aliastransform+36]       ; lv1*at[2][1] | lv0*at[2][0]
    579 	__asm fld  dword ptr [lerped_vert+8]           ; lv2 | lv1*at[2][1] | lv0*at[2][0]
    580 	__asm fmul dword ptr [aliastransform+40]       ; lv2*at[2][2] | lv1*at[2][1] | lv0*at[2][0]
    581 	__asm fxch st(2)                               ; lv0*at[2][0] | lv1*at[2][1] | lv2*at[2][2]
    582 	__asm faddp st(1), st                          ; lv0*at[2][0] + lv1*at[2][1] | lv2*at[2][2]
    583 	__asm faddp st(1), st                          ; lv0*at[2][0] + lv1*at[2][1] + lv2*at[2][2]
    584 	__asm fadd dword ptr [aliastransform+44]       ; FV.Z | FV.Y
    585 	__asm fxch st(1)                               ; FV.Y | FV.Z
    586 	__asm fstp dword ptr [eax+FINALVERT_Y]         ; FV.Z
    587 	__asm fstp dword ptr [eax+FINALVERT_Z]         ; (empty)
    588 
    589 	/*
    590 	**  lighting
    591 	**
    592 	**  plightnormal = r_avertexnormals[newv->lightnormalindex];
    593 	**	lightcos = DotProduct (plightnormal, r_plightvec);
    594 	**	temp = r_ambientlight;
    595 	*/
    596 	__asm xor ebx, ebx
    597 	__asm mov bl,  byte ptr [edi+DTRIVERTX_LNI]
    598 	__asm mov eax, 12
    599 	__asm mul ebx
    600 	__asm lea eax, [r_avertexnormals+eax]
    601 	__asm lea ebx, r_plightvec
    602 
    603 	__asm fld  dword ptr [eax+0]
    604 	__asm fmul dword ptr [ebx+0]
    605 	__asm fld  dword ptr [eax+4]
    606 	__asm fmul dword ptr [ebx+4]
    607 	__asm fld  dword ptr [eax+8]
    608 	__asm fmul dword ptr [ebx+8]
    609 	__asm fxch st(2)
    610 	__asm faddp st(1), st
    611 	__asm faddp st(1), st
    612 	__asm fstp dword ptr lightcos
    613 	__asm mov eax, lightcos
    614 	__asm mov ebx, r_ambientlight
    615 
    616 	/*
    617 	if (lightcos < 0)
    618 	{
    619 		temp += (int)(r_shadelight * lightcos);
    620 
    621 		// clamp; because we limited the minimum ambient and shading light, we
    622 		// don't have to clamp low light, just bright
    623 		if (temp < 0)
    624 			temp = 0;
    625 	}
    626 
    627 	fv->v[4] = temp;
    628 	*/
    629 	__asm or  eax, eax
    630 	__asm jns store_fv4
    631 
    632 	__asm fld   dword ptr r_shadelight
    633 	__asm fmul  dword ptr lightcos
    634 	__asm fistp dword ptr tmpint
    635 	__asm add   ebx, tmpint
    636 
    637 	__asm or    ebx, ebx
    638 	__asm jns   store_fv4
    639 	__asm mov   ebx, 0
    640 
    641 store_fv4:
    642 	__asm mov edi, fv
    643 	__asm mov dword ptr [edi+FINALVERT_V4], ebx
    644 
    645 	__asm mov edx, dword ptr [edi+FINALVERT_FLAGS]
    646 
    647 	/*
    648 	** do clip testing and projection here
    649 	*/
    650 	/*
    651 	if ( dest_vert->xyz[2] < ALIAS_Z_CLIP_PLANE )
    652 	{
    653 		dest_vert->flags |= ALIAS_Z_CLIP;
    654 	}
    655 	else
    656 	{
    657 		R_AliasProjectAndClipTestFinalVert( dest_vert );
    658 	}
    659 	*/
    660 	__asm mov eax, dword ptr [edi+FINALVERT_Z]
    661 	__asm and eax, eax
    662 	__asm js  alias_z_clip
    663 	__asm cmp eax, FALIAS_Z_CLIP_PLANE
    664 	__asm jl  alias_z_clip
    665 
    666 	/*
    667 	This is the code to R_AliasProjectAndClipTestFinalVert
    668 
    669 	float	zi;
    670 	float	x, y, z;
    671 
    672 	x = fv->xyz[0];
    673 	y = fv->xyz[1];
    674 	z = fv->xyz[2];
    675 	zi = 1.0 / z;
    676 
    677 	fv->v[5] = zi * s_ziscale;
    678 
    679 	fv->v[0] = (x * aliasxscale * zi) + aliasxcenter;
    680 	fv->v[1] = (y * aliasyscale * zi) + aliasycenter;
    681 	*/
    682 	__asm fld   one                             ; 1
    683 	__asm fdiv  dword ptr [edi+FINALVERT_Z]     ; zi
    684 
    685 	__asm mov   eax, dword ptr [edi+32]
    686 	__asm mov   eax, dword ptr [edi+64]
    687 
    688 	__asm fst   zi                              ; zi
    689 	__asm fmul  s_ziscale                       ; fv5
    690 	__asm fld   dword ptr [edi+FINALVERT_X]     ; x | fv5
    691 	__asm fmul  aliasxscale                     ; x * aliasxscale | fv5
    692 	__asm fld   dword ptr [edi+FINALVERT_Y]     ; y | x * aliasxscale | fv5
    693 	__asm fmul  aliasyscale                     ; y * aliasyscale | x * aliasxscale | fv5
    694 	__asm fxch  st(1)                           ; x * aliasxscale | y * aliasyscale | fv5
    695 	__asm fmul  zi                              ; x * asx * zi | y * asy | fv5
    696 	__asm fadd  aliasxcenter                    ; fv0 | y * asy | fv5
    697 	__asm fxch  st(1)                           ; y * asy | fv0 | fv5
    698 	__asm fmul  zi                              ; y * asy * zi | fv0 | fv5
    699 	__asm fadd  aliasycenter                    ; fv1 | fv0 | fv5
    700 	__asm fxch  st(2)                           ; fv5 | fv0 | fv1
    701 	__asm fistp dword ptr [edi+FINALVERT_V5]    ; fv0 | fv1
    702 	__asm fistp dword ptr [edi+FINALVERT_V0]    ; fv1
    703 	__asm fistp dword ptr [edi+FINALVERT_V1]    ; (empty)
    704 
    705 	/*
    706 	if (fv->v[0] < r_refdef.aliasvrect.x)
    707 		fv->flags |= ALIAS_LEFT_CLIP;
    708 	if (fv->v[1] < r_refdef.aliasvrect.y)
    709 		fv->flags |= ALIAS_TOP_CLIP;
    710 	if (fv->v[0] > r_refdef.aliasvrectright)
    711 		fv->flags |= ALIAS_RIGHT_CLIP;
    712 	if (fv->v[1] > r_refdef.aliasvrectbottom)
    713 		fv->flags |= ALIAS_BOTTOM_CLIP;
    714 	*/
    715 	__asm mov eax, dword ptr [edi+FINALVERT_V0]
    716 	__asm mov ebx, dword ptr [edi+FINALVERT_V1]
    717 
    718 	__asm cmp eax, r_refdef.aliasvrect.x
    719 	__asm jge ct_alias_top
    720 	__asm or  edx, ALIAS_LEFT_CLIP
    721 ct_alias_top:
    722 	__asm cmp ebx, r_refdef.aliasvrect.y
    723 	__asm jge ct_alias_right
    724 	__asm or edx, ALIAS_TOP_CLIP
    725 ct_alias_right:
    726 	__asm cmp eax, r_refdef.aliasvrectright
    727 	__asm jle ct_alias_bottom
    728 	__asm or edx, ALIAS_RIGHT_CLIP
    729 ct_alias_bottom:
    730 	__asm cmp ebx, r_refdef.aliasvrectbottom
    731 	__asm jle end_of_loop
    732 	__asm or  edx, ALIAS_BOTTOM_CLIP
    733 
    734 	__asm jmp end_of_loop
    735 
    736 alias_z_clip:
    737 	__asm or  edx, ALIAS_Z_CLIP
    738 
    739 end_of_loop:
    740 
    741 	__asm mov dword ptr [edi+FINALVERT_FLAGS], edx
    742 	__asm add oldv, DTRIVERTX_SIZE
    743 	__asm add newv, DTRIVERTX_SIZE
    744 	__asm add fv, FINALVERT_SIZE
    745 
    746 	__asm dec ecx
    747 	__asm jnz top_of_loop
    748 }
    749 #else
    750 void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv )
    751 {
    752 	int i;
    753 
    754 	for ( i = 0; i < numpoints; i++, fv++, oldv++, newv++ )
    755 	{
    756 		int		temp;
    757 		float	lightcos, *plightnormal;
    758 		vec3_t  lerped_vert;
    759 
    760 		lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0];
    761 		lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1];
    762 		lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2];
    763 
    764 		plightnormal = r_avertexnormals[newv->lightnormalindex];
    765 
    766 		// PMM - added double damage shell
    767 		if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
    768 		{
    769 			lerped_vert[0] += plightnormal[0] * POWERSUIT_SCALE;
    770 			lerped_vert[1] += plightnormal[1] * POWERSUIT_SCALE;
    771 			lerped_vert[2] += plightnormal[2] * POWERSUIT_SCALE;
    772 		}
    773 
    774 		fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3];
    775 		fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3];
    776 		fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3];
    777 
    778 		fv->flags = 0;
    779 
    780 		// lighting
    781 		lightcos = DotProduct (plightnormal, r_plightvec);
    782 		temp = r_ambientlight;
    783 
    784 		if (lightcos < 0)
    785 		{
    786 			temp += (int)(r_shadelight * lightcos);
    787 
    788 			// clamp; because we limited the minimum ambient and shading light, we
    789 			// don't have to clamp low light, just bright
    790 			if (temp < 0)
    791 				temp = 0;
    792 		}
    793 
    794 		fv->l = temp;
    795 
    796 		if ( fv->xyz[2] < ALIAS_Z_CLIP_PLANE )
    797 		{
    798 			fv->flags |= ALIAS_Z_CLIP;
    799 		}
    800 		else
    801 		{
    802 			R_AliasProjectAndClipTestFinalVert( fv );
    803 		}
    804 	}
    805 }
    806 
    807 #endif
    808 
    809 /*
    810 ================
    811 R_AliasProjectAndClipTestFinalVert
    812 ================
    813 */
    814 void R_AliasProjectAndClipTestFinalVert( finalvert_t *fv )
    815 {
    816 	float	zi;
    817 	float	x, y, z;
    818 
    819 	// project points
    820 	x = fv->xyz[0];
    821 	y = fv->xyz[1];
    822 	z = fv->xyz[2];
    823 	zi = 1.0 / z;
    824 
    825 	fv->zi = zi * s_ziscale;
    826 
    827 	fv->u = (x * aliasxscale * zi) + aliasxcenter;
    828 	fv->v = (y * aliasyscale * zi) + aliasycenter;
    829 
    830 	if (fv->u < r_refdef.aliasvrect.x)
    831 		fv->flags |= ALIAS_LEFT_CLIP;
    832 	if (fv->v < r_refdef.aliasvrect.y)
    833 		fv->flags |= ALIAS_TOP_CLIP;
    834 	if (fv->u > r_refdef.aliasvrectright)
    835 		fv->flags |= ALIAS_RIGHT_CLIP;
    836 	if (fv->v > r_refdef.aliasvrectbottom)
    837 		fv->flags |= ALIAS_BOTTOM_CLIP;	
    838 }
    839 
    840 /*
    841 ===============
    842 R_AliasSetupSkin
    843 ===============
    844 */
    845 static qboolean R_AliasSetupSkin (void)
    846 {
    847 	int				skinnum;
    848 	image_t			*pskindesc;
    849 
    850 	if (currententity->skin)
    851 		pskindesc = currententity->skin;
    852 	else
    853 	{
    854 		skinnum = currententity->skinnum;
    855 		if ((skinnum >= s_pmdl->num_skins) || (skinnum < 0))
    856 		{
    857 			ri.Con_Printf (PRINT_ALL, "R_AliasSetupSkin %s: no such skin # %d\n", 
    858 				currentmodel->name, skinnum);
    859 			skinnum = 0;
    860 		}
    861 
    862 		pskindesc = currentmodel->skins[skinnum];
    863 	}
    864 
    865 	if ( !pskindesc )
    866 		return false;
    867 
    868 	r_affinetridesc.pskin = pskindesc->pixels[0];
    869 	r_affinetridesc.skinwidth = pskindesc->width;
    870 	r_affinetridesc.skinheight = pskindesc->height;
    871 
    872 	R_PolysetUpdateTables ();		// FIXME: precalc edge lookups
    873 
    874 	return true;
    875 }
    876 
    877 
    878 /*
    879 ================
    880 R_AliasSetupLighting
    881 
    882   FIXME: put lighting into tables
    883 ================
    884 */
    885 void R_AliasSetupLighting (void)
    886 {
    887 	alight_t		lighting;
    888 	float			lightvec[3] = {-1, 0, 0};
    889 	vec3_t			light;
    890 	int				i, j;
    891 
    892 	// all components of light should be identical in software
    893 	if ( currententity->flags & RF_FULLBRIGHT )
    894 	{
    895 		for (i=0 ; i<3 ; i++)
    896 			light[i] = 1.0;
    897 	}
    898 	else
    899 	{
    900 		R_LightPoint (currententity->origin, light);
    901 	}
    902 
    903 	// save off light value for server to look at (BIG HACK!)
    904 	if ( currententity->flags & RF_WEAPONMODEL )
    905 		r_lightlevel->value = 150.0 * light[0];
    906 
    907 
    908 	if ( currententity->flags & RF_MINLIGHT )
    909 	{
    910 		for (i=0 ; i<3 ; i++)
    911 			if (light[i] < 0.1)
    912 				light[i] = 0.1;
    913 	}
    914 
    915 	if ( currententity->flags & RF_GLOW )
    916 	{	// bonus items will pulse with time
    917 		float	scale;
    918 		float	min;
    919 
    920 		scale = 0.1 * sin(r_newrefdef.time*7);
    921 		for (i=0 ; i<3 ; i++)
    922 		{
    923 			min = light[i] * 0.8;
    924 			light[i] += scale;
    925 			if (light[i] < min)
    926 				light[i] = min;
    927 		}
    928 	}
    929 
    930 	j = (light[0] + light[1] + light[2])*0.3333*255;
    931 
    932 	lighting.ambientlight = j;
    933 	lighting.shadelight = j;
    934 
    935 	lighting.plightvec = lightvec;
    936 
    937 // clamp lighting so it doesn't overbright as much
    938 	if (lighting.ambientlight > 128)
    939 		lighting.ambientlight = 128;
    940 	if (lighting.ambientlight + lighting.shadelight > 192)
    941 		lighting.shadelight = 192 - lighting.ambientlight;
    942 
    943 // guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have
    944 // to clamp off the bottom
    945 	r_ambientlight = lighting.ambientlight;
    946 
    947 	if (r_ambientlight < LIGHT_MIN)
    948 		r_ambientlight = LIGHT_MIN;
    949 
    950 	r_ambientlight = (255 - r_ambientlight) << VID_CBITS;
    951 
    952 	if (r_ambientlight < LIGHT_MIN)
    953 		r_ambientlight = LIGHT_MIN;
    954 
    955 	r_shadelight = lighting.shadelight;
    956 
    957 	if (r_shadelight < 0)
    958 		r_shadelight = 0;
    959 
    960 	r_shadelight *= VID_GRADES;
    961 
    962 // rotate the lighting vector into the model's frame of reference
    963 	r_plightvec[0] =  DotProduct( lighting.plightvec, s_alias_forward );
    964 	r_plightvec[1] = -DotProduct( lighting.plightvec, s_alias_right );
    965 	r_plightvec[2] =  DotProduct( lighting.plightvec, s_alias_up );
    966 }
    967 
    968 
    969 /*
    970 =================
    971 R_AliasSetupFrames
    972 
    973 =================
    974 */
    975 void R_AliasSetupFrames( dmdl_t *pmdl )
    976 {
    977 	int thisframe = currententity->frame;
    978 	int lastframe = currententity->oldframe;
    979 
    980 	if ( ( thisframe >= pmdl->num_frames ) || ( thisframe < 0 ) )
    981 	{
    982 		ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such thisframe %d\n", 
    983 			currentmodel->name, thisframe);
    984 		thisframe = 0;
    985 	}
    986 	if ( ( lastframe >= pmdl->num_frames ) || ( lastframe < 0 ) )
    987 	{
    988 		ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such lastframe %d\n", 
    989 			currentmodel->name, lastframe);
    990 		lastframe = 0;
    991 	}
    992 
    993 	r_thisframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames 
    994 		+ thisframe * pmdl->framesize);
    995 
    996 	r_lastframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames 
    997 		+ lastframe * pmdl->framesize);
    998 }
    999 
   1000 /*
   1001 ** R_AliasSetUpLerpData
   1002 **
   1003 ** Precomputes lerp coefficients used for the whole frame.
   1004 */
   1005 void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp )
   1006 {
   1007 	float	frontlerp;
   1008 	vec3_t	translation, vectors[3];
   1009 	int		i;
   1010 
   1011 	frontlerp = 1.0F - backlerp;
   1012 
   1013 	/*
   1014 	** convert entity's angles into discrete vectors for R, U, and F
   1015 	*/
   1016 	AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]);
   1017 
   1018 	/*
   1019 	** translation is the vector from last position to this position
   1020 	*/
   1021 	VectorSubtract (currententity->oldorigin, currententity->origin, translation);
   1022 
   1023 	/*
   1024 	** move should be the delta back to the previous frame * backlerp
   1025 	*/
   1026 	r_lerp_move[0] =  DotProduct(translation, vectors[0]);	// forward
   1027 	r_lerp_move[1] = -DotProduct(translation, vectors[1]);	// left
   1028 	r_lerp_move[2] =  DotProduct(translation, vectors[2]);	// up
   1029 
   1030 	VectorAdd( r_lerp_move, r_lastframe->translate, r_lerp_move );
   1031 
   1032 	for (i=0 ; i<3 ; i++)
   1033 	{
   1034 		r_lerp_move[i] = backlerp*r_lerp_move[i] + frontlerp * r_thisframe->translate[i];
   1035 	}
   1036 
   1037 	for (i=0 ; i<3 ; i++)
   1038 	{
   1039 		r_lerp_frontv[i] = frontlerp * r_thisframe->scale[i];
   1040 		r_lerp_backv[i]  = backlerp  * r_lastframe->scale[i];
   1041 	}
   1042 }
   1043 
   1044 /*
   1045 ================
   1046 R_AliasDrawModel
   1047 ================
   1048 */
   1049 void R_AliasDrawModel (void)
   1050 {
   1051 	extern void	(*d_pdrawspans)(void *);
   1052 	extern void R_PolysetDrawSpans8_Opaque( void * );
   1053 	extern void R_PolysetDrawSpans8_33( void * );
   1054 	extern void R_PolysetDrawSpans8_66( void * );
   1055 	extern void R_PolysetDrawSpansConstant8_33( void * );
   1056 	extern void R_PolysetDrawSpansConstant8_66( void * );
   1057 
   1058 	s_pmdl = (dmdl_t *)currentmodel->extradata;
   1059 
   1060 	if ( r_lerpmodels->value == 0 )
   1061 		currententity->backlerp = 0;
   1062 
   1063 	if ( currententity->flags & RF_WEAPONMODEL )
   1064 	{
   1065 		if ( r_lefthand->value == 1.0F )
   1066 			aliasxscale = -aliasxscale;
   1067 		else if ( r_lefthand->value == 2.0F )
   1068 			return;
   1069 	}
   1070 
   1071 	/*
   1072 	** we have to set our frame pointers and transformations before
   1073 	** doing any real work
   1074 	*/
   1075 	R_AliasSetupFrames( s_pmdl );
   1076 	R_AliasSetUpTransform();
   1077 
   1078 	// see if the bounding box lets us trivially reject, also sets
   1079 	// trivial accept status
   1080 	if ( R_AliasCheckBBox() == BBOX_TRIVIAL_REJECT )
   1081 	{
   1082 		if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
   1083 		{
   1084 			aliasxscale = -aliasxscale;
   1085 		}
   1086 		return;
   1087 	}
   1088 
   1089 	// set up the skin and verify it exists
   1090 	if ( !R_AliasSetupSkin () )
   1091 	{
   1092 		ri.Con_Printf( PRINT_ALL, "R_AliasDrawModel %s: NULL skin found\n",
   1093 			currentmodel->name);
   1094 		return;
   1095 	}
   1096 
   1097 	r_amodels_drawn++;
   1098 	R_AliasSetupLighting ();
   1099 
   1100 	/*
   1101 	** select the proper span routine based on translucency
   1102 	*/
   1103 	// PMM - added double damage shell
   1104 	// PMM - reordered to handle blending
   1105 	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
   1106 	{
   1107 		int		color;
   1108 
   1109 		// PMM - added double
   1110 		color = currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM);
   1111 		// PMM - reordered, old code first
   1112 /*
   1113 		if ( color == RF_SHELL_RED )
   1114 			r_aliasblendcolor = SHELL_RED_COLOR;
   1115 		else if ( color == RF_SHELL_GREEN )
   1116 			r_aliasblendcolor = SHELL_GREEN_COLOR;
   1117 		else if ( color == RF_SHELL_BLUE )
   1118 			r_aliasblendcolor = SHELL_BLUE_COLOR;
   1119 		else if ( color == (RF_SHELL_RED | RF_SHELL_GREEN) )
   1120 			r_aliasblendcolor = SHELL_RG_COLOR;
   1121 		else if ( color == (RF_SHELL_RED | RF_SHELL_BLUE) )
   1122 			r_aliasblendcolor = SHELL_RB_COLOR;
   1123 		else if ( color == (RF_SHELL_BLUE | RF_SHELL_GREEN) )
   1124 			r_aliasblendcolor = SHELL_BG_COLOR;
   1125 		// PMM - added this .. it's yellowish
   1126 		else if ( color == (RF_SHELL_DOUBLE) )
   1127 			r_aliasblendcolor = SHELL_DOUBLE_COLOR;
   1128 		else if ( color == (RF_SHELL_HALF_DAM) )
   1129 			r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
   1130 		// pmm
   1131 		else
   1132 			r_aliasblendcolor = SHELL_WHITE_COLOR;
   1133 */
   1134 		if ( color & RF_SHELL_RED )
   1135 		{
   1136 			if ( ( color & RF_SHELL_BLUE) && ( color & RF_SHELL_GREEN) )
   1137 				r_aliasblendcolor = SHELL_WHITE_COLOR;
   1138 			else if ( color & (RF_SHELL_BLUE | RF_SHELL_DOUBLE))
   1139 				r_aliasblendcolor = SHELL_RB_COLOR;
   1140 			else
   1141 				r_aliasblendcolor = SHELL_RED_COLOR;
   1142 		}
   1143 		else if ( color & RF_SHELL_BLUE)
   1144 		{
   1145 			if ( color & RF_SHELL_DOUBLE )
   1146 				r_aliasblendcolor = SHELL_CYAN_COLOR;
   1147 			else
   1148 				r_aliasblendcolor = SHELL_BLUE_COLOR;
   1149 		}
   1150 		else if ( color & (RF_SHELL_DOUBLE) )
   1151 			r_aliasblendcolor = SHELL_DOUBLE_COLOR;
   1152 		else if ( color & (RF_SHELL_HALF_DAM) )
   1153 			r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
   1154 		else if ( color & RF_SHELL_GREEN )
   1155 			r_aliasblendcolor = SHELL_GREEN_COLOR;
   1156 		else
   1157 			r_aliasblendcolor = SHELL_WHITE_COLOR;
   1158 
   1159 
   1160 		if ( currententity->alpha > 0.33 )
   1161 			d_pdrawspans = R_PolysetDrawSpansConstant8_66;
   1162 		else
   1163 			d_pdrawspans = R_PolysetDrawSpansConstant8_33;
   1164 	}
   1165 	else if ( currententity->flags & RF_TRANSLUCENT )
   1166 	{
   1167 		if ( currententity->alpha > 0.66 )
   1168 			d_pdrawspans = R_PolysetDrawSpans8_Opaque;
   1169 		else if ( currententity->alpha > 0.33 )
   1170 			d_pdrawspans = R_PolysetDrawSpans8_66;
   1171 		else
   1172 			d_pdrawspans = R_PolysetDrawSpans8_33;
   1173 	}
   1174 	else
   1175 	{
   1176 		d_pdrawspans = R_PolysetDrawSpans8_Opaque;
   1177 	}
   1178 
   1179 	/*
   1180 	** compute this_frame and old_frame addresses
   1181 	*/
   1182 	R_AliasSetUpLerpData( s_pmdl, currententity->backlerp );
   1183 
   1184 	if (currententity->flags & RF_DEPTHHACK)
   1185 		s_ziscale = (float)0x8000 * (float)0x10000 * 3.0;
   1186 	else
   1187 		s_ziscale = (float)0x8000 * (float)0x10000;
   1188 
   1189 	R_AliasPreparePoints ();
   1190 
   1191 	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
   1192 	{
   1193 		aliasxscale = -aliasxscale;
   1194 	}
   1195 }
   1196 
   1197 
   1198