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