Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

r_poly.c (29528B)


      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 #include <assert.h>
     21 #include "r_local.h"
     22 
     23 #define AFFINE_SPANLET_SIZE      16
     24 #define AFFINE_SPANLET_SIZE_BITS 4
     25 
     26 typedef struct
     27 {
     28 	byte     *pbase, *pdest;
     29 	short	 *pz;
     30 	fixed16_t s, t;
     31 	fixed16_t sstep, tstep;
     32 	int       izi, izistep, izistep_times_2;
     33 	int       spancount;
     34 	unsigned  u, v;
     35 } spanletvars_t;
     36 
     37 spanletvars_t s_spanletvars;
     38 
     39 static int r_polyblendcolor;
     40 
     41 static espan_t	*s_polygon_spans;
     42 
     43 polydesc_t	r_polydesc;
     44 
     45 msurface_t *r_alpha_surfaces;
     46 
     47 extern int *r_turb_turb;
     48 
     49 static int		clip_current;
     50 vec5_t	r_clip_verts[2][MAXWORKINGVERTS+2];
     51 
     52 static int		s_minindex, s_maxindex;
     53 
     54 static void R_DrawPoly( qboolean iswater );
     55 
     56 /*
     57 ** R_DrawSpanletOpaque
     58 */
     59 void R_DrawSpanletOpaque( void )
     60 {
     61 	unsigned btemp;
     62 
     63 	do
     64 	{
     65 		unsigned ts, tt;
     66 
     67 		ts = s_spanletvars.s >> 16;
     68 		tt = s_spanletvars.t >> 16;
     69 
     70 		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
     71 		if (btemp != 255)
     72 		{
     73 			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
     74 			{
     75 				*s_spanletvars.pz    = s_spanletvars.izi >> 16;
     76 				*s_spanletvars.pdest = btemp;
     77 			}
     78 		}
     79 
     80 		s_spanletvars.izi += s_spanletvars.izistep;
     81 		s_spanletvars.pdest++;
     82 		s_spanletvars.pz++;
     83 		s_spanletvars.s += s_spanletvars.sstep;
     84 		s_spanletvars.t += s_spanletvars.tstep;
     85 	} while (--s_spanletvars.spancount > 0);
     86 }
     87 
     88 /*
     89 ** R_DrawSpanletTurbulentStipple33
     90 */
     91 void R_DrawSpanletTurbulentStipple33( void )
     92 {
     93 	unsigned btemp;
     94 	int	     sturb, tturb;
     95 	byte    *pdest = s_spanletvars.pdest;
     96 	short   *pz    = s_spanletvars.pz;
     97 	int      izi   = s_spanletvars.izi;
     98 	
     99 	if ( s_spanletvars.v & 1 )
    100 	{
    101 		s_spanletvars.pdest += s_spanletvars.spancount;
    102 		s_spanletvars.pz    += s_spanletvars.spancount;
    103 
    104 		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
    105 			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
    106 		else
    107 			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
    108 		
    109 		if ( s_spanletvars.u & 1 )
    110 		{
    111 			izi += s_spanletvars.izistep;
    112 			s_spanletvars.s   += s_spanletvars.sstep;
    113 			s_spanletvars.t   += s_spanletvars.tstep;
    114 
    115 			pdest++;
    116 			pz++;
    117 			s_spanletvars.spancount--;
    118 		}
    119 
    120 		s_spanletvars.sstep   *= 2;
    121 		s_spanletvars.tstep   *= 2;
    122 
    123 		while ( s_spanletvars.spancount > 0 )
    124 		{
    125 			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
    126 			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
    127 			
    128 			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
    129 			
    130 			if ( *pz <= ( izi >> 16 ) )
    131 				*pdest = btemp;
    132 			
    133 			izi               += s_spanletvars.izistep_times_2;
    134 			s_spanletvars.s   += s_spanletvars.sstep;
    135 			s_spanletvars.t   += s_spanletvars.tstep;
    136 			
    137 			pdest += 2;
    138 			pz    += 2;
    139 			
    140 			s_spanletvars.spancount -= 2;
    141 		}
    142 	}
    143 }
    144 
    145 /*
    146 ** R_DrawSpanletTurbulentStipple66
    147 */
    148 void R_DrawSpanletTurbulentStipple66( void )
    149 {
    150 	unsigned btemp;
    151 	int	     sturb, tturb;
    152 	byte    *pdest = s_spanletvars.pdest;
    153 	short   *pz    = s_spanletvars.pz;
    154 	int      izi   = s_spanletvars.izi;
    155 	
    156 	if ( !( s_spanletvars.v & 1 ) )
    157 	{
    158 		s_spanletvars.pdest += s_spanletvars.spancount;
    159 		s_spanletvars.pz    += s_spanletvars.spancount;
    160 
    161 		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
    162 			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
    163 		else
    164 			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
    165 		
    166 		if ( s_spanletvars.u & 1 )
    167 		{
    168 			izi += s_spanletvars.izistep;
    169 			s_spanletvars.s   += s_spanletvars.sstep;
    170 			s_spanletvars.t   += s_spanletvars.tstep;
    171 
    172 			pdest++;
    173 			pz++;
    174 			s_spanletvars.spancount--;
    175 		}
    176 
    177 		s_spanletvars.sstep   *= 2;
    178 		s_spanletvars.tstep   *= 2;
    179 
    180 		while ( s_spanletvars.spancount > 0 )
    181 		{
    182 			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
    183 			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
    184 			
    185 			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
    186 			
    187 			if ( *pz <= ( izi >> 16 ) )
    188 				*pdest = btemp;
    189 			
    190 			izi               += s_spanletvars.izistep_times_2;
    191 			s_spanletvars.s   += s_spanletvars.sstep;
    192 			s_spanletvars.t   += s_spanletvars.tstep;
    193 			
    194 			pdest += 2;
    195 			pz    += 2;
    196 			
    197 			s_spanletvars.spancount -= 2;
    198 		}
    199 	}
    200 	else
    201 	{
    202 		s_spanletvars.pdest += s_spanletvars.spancount;
    203 		s_spanletvars.pz    += s_spanletvars.spancount;
    204 
    205 		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
    206 			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
    207 		else
    208 			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
    209 		
    210 		while ( s_spanletvars.spancount > 0 )
    211 		{
    212 			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
    213 			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
    214 			
    215 			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
    216 			
    217 			if ( *pz <= ( izi >> 16 ) )
    218 				*pdest = btemp;
    219 			
    220 			izi               += s_spanletvars.izistep;
    221 			s_spanletvars.s   += s_spanletvars.sstep;
    222 			s_spanletvars.t   += s_spanletvars.tstep;
    223 			
    224 			pdest++;
    225 			pz++;
    226 			
    227 			s_spanletvars.spancount--;
    228 		}
    229 	}
    230 }
    231 
    232 /*
    233 ** R_DrawSpanletTurbulentBlended
    234 */
    235 void R_DrawSpanletTurbulentBlended66( void )
    236 {
    237 	unsigned btemp;
    238 	int	     sturb, tturb;
    239 
    240 	do
    241 	{
    242 		sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
    243 		tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
    244 
    245 		btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
    246 
    247 		if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
    248 			*s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
    249 
    250 		s_spanletvars.izi += s_spanletvars.izistep;
    251 		s_spanletvars.pdest++;
    252 		s_spanletvars.pz++;
    253 		s_spanletvars.s += s_spanletvars.sstep;
    254 		s_spanletvars.t += s_spanletvars.tstep;
    255 
    256 	} while ( --s_spanletvars.spancount > 0 );
    257 }
    258 
    259 void R_DrawSpanletTurbulentBlended33( void )
    260 {
    261 	unsigned btemp;
    262 	int	     sturb, tturb;
    263 
    264 	do
    265 	{
    266 		sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
    267 		tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
    268 
    269 		btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
    270 
    271 		if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
    272 			*s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
    273 
    274 		s_spanletvars.izi += s_spanletvars.izistep;
    275 		s_spanletvars.pdest++;
    276 		s_spanletvars.pz++;
    277 		s_spanletvars.s += s_spanletvars.sstep;
    278 		s_spanletvars.t += s_spanletvars.tstep;
    279 
    280 	} while ( --s_spanletvars.spancount > 0 );
    281 }
    282 
    283 /*
    284 ** R_DrawSpanlet33
    285 */
    286 void R_DrawSpanlet33( void )
    287 {
    288 	unsigned btemp;
    289 
    290 	do
    291 	{
    292 		unsigned ts, tt;
    293 
    294 		ts = s_spanletvars.s >> 16;
    295 		tt = s_spanletvars.t >> 16;
    296 
    297 		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
    298 
    299 		if ( btemp != 255 )
    300 		{
    301 			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
    302 			{
    303 				*s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
    304 			}
    305 		}
    306 
    307 		s_spanletvars.izi += s_spanletvars.izistep;
    308 		s_spanletvars.pdest++;
    309 		s_spanletvars.pz++;
    310 		s_spanletvars.s += s_spanletvars.sstep;
    311 		s_spanletvars.t += s_spanletvars.tstep;
    312 	} while (--s_spanletvars.spancount > 0);
    313 }
    314 
    315 void R_DrawSpanletConstant33( void )
    316 {
    317 	do
    318 	{
    319 		if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
    320 		{
    321 			*s_spanletvars.pdest = vid.alphamap[r_polyblendcolor+*s_spanletvars.pdest*256];
    322 		}
    323 
    324 		s_spanletvars.izi += s_spanletvars.izistep;
    325 		s_spanletvars.pdest++;
    326 		s_spanletvars.pz++;
    327 	} while (--s_spanletvars.spancount > 0);
    328 }
    329 
    330 /*
    331 ** R_DrawSpanlet66
    332 */
    333 void R_DrawSpanlet66( void )
    334 {
    335 	unsigned btemp;
    336 
    337 	do
    338 	{
    339 		unsigned ts, tt;
    340 
    341 		ts = s_spanletvars.s >> 16;
    342 		tt = s_spanletvars.t >> 16;
    343 
    344 		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
    345 
    346 		if ( btemp != 255 )
    347 		{
    348 			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
    349 			{
    350 				*s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
    351 			}
    352 		}
    353 
    354 		s_spanletvars.izi += s_spanletvars.izistep;
    355 		s_spanletvars.pdest++;
    356 		s_spanletvars.pz++;
    357 		s_spanletvars.s += s_spanletvars.sstep;
    358 		s_spanletvars.t += s_spanletvars.tstep;
    359 	} while (--s_spanletvars.spancount > 0);
    360 }
    361 
    362 /*
    363 ** R_DrawSpanlet33Stipple
    364 */
    365 void R_DrawSpanlet33Stipple( void )
    366 {
    367 	unsigned btemp;
    368 	byte    *pdest = s_spanletvars.pdest;
    369 	short   *pz    = s_spanletvars.pz;
    370 	int      izi   = s_spanletvars.izi;
    371 	
    372 	if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
    373 	{
    374 		s_spanletvars.pdest += s_spanletvars.spancount;
    375 		s_spanletvars.pz    += s_spanletvars.spancount;
    376 
    377 		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
    378 			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
    379 		else
    380 			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
    381 		
    382 		if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
    383 		{
    384 			izi += s_spanletvars.izistep;
    385 			s_spanletvars.s   += s_spanletvars.sstep;
    386 			s_spanletvars.t   += s_spanletvars.tstep;
    387 
    388 			pdest++;
    389 			pz++;
    390 			s_spanletvars.spancount--;
    391 		}
    392 
    393 		s_spanletvars.sstep *= 2;
    394 		s_spanletvars.tstep *= 2;
    395 
    396 		while ( s_spanletvars.spancount > 0 )
    397 		{
    398 			unsigned s = s_spanletvars.s >> 16;
    399 			unsigned t = s_spanletvars.t >> 16;
    400 
    401 			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
    402 			
    403 			if ( btemp != 255 )
    404 			{
    405 				if ( *pz <= ( izi >> 16 ) )
    406 					*pdest = btemp;
    407 			}
    408 			
    409 			izi               += s_spanletvars.izistep_times_2;
    410 			s_spanletvars.s   += s_spanletvars.sstep;
    411 			s_spanletvars.t   += s_spanletvars.tstep;
    412 			
    413 			pdest += 2;
    414 			pz    += 2;
    415 			
    416 			s_spanletvars.spancount -= 2;
    417 		}
    418 	}
    419 }
    420 
    421 /*
    422 ** R_DrawSpanlet66Stipple
    423 */
    424 void R_DrawSpanlet66Stipple( void )
    425 {
    426 	unsigned btemp;
    427 	byte    *pdest = s_spanletvars.pdest;
    428 	short   *pz    = s_spanletvars.pz;
    429 	int      izi   = s_spanletvars.izi;
    430 
    431 	s_spanletvars.pdest += s_spanletvars.spancount;
    432 	s_spanletvars.pz    += s_spanletvars.spancount;
    433 
    434 	if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
    435 		s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
    436 	else
    437 		s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
    438 
    439 	if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
    440 	{
    441 		if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
    442 		{
    443 			izi += s_spanletvars.izistep;
    444 			s_spanletvars.s += s_spanletvars.sstep;
    445 			s_spanletvars.t += s_spanletvars.tstep;
    446 
    447 			pdest++;
    448 			pz++;
    449 			s_spanletvars.spancount--;
    450 		}
    451 
    452 		s_spanletvars.sstep *= 2;
    453 		s_spanletvars.tstep *= 2;
    454 
    455 		while ( s_spanletvars.spancount > 0 )
    456 		{
    457 			unsigned s = s_spanletvars.s >> 16;
    458 			unsigned t = s_spanletvars.t >> 16;
    459 			
    460 			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
    461 
    462 			if ( btemp != 255 )
    463 			{
    464 				if ( *pz <= ( izi >> 16 ) )
    465 					*pdest = btemp;
    466 			}
    467 			
    468 			izi             += s_spanletvars.izistep_times_2;
    469 			s_spanletvars.s += s_spanletvars.sstep;
    470 			s_spanletvars.t += s_spanletvars.tstep;
    471 			
    472 			pdest += 2;
    473 			pz    += 2;
    474 			
    475 			s_spanletvars.spancount -= 2;
    476 		}
    477 	}
    478 	else
    479 	{
    480 		while ( s_spanletvars.spancount > 0 )
    481 		{
    482 			unsigned s = s_spanletvars.s >> 16;
    483 			unsigned t = s_spanletvars.t >> 16;
    484 			
    485 			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
    486 			
    487 			if ( btemp != 255 )
    488 			{
    489 				if ( *pz <= ( izi >> 16 ) )
    490 					*pdest = btemp;
    491 			}
    492 			
    493 			izi             += s_spanletvars.izistep;
    494 			s_spanletvars.s += s_spanletvars.sstep;
    495 			s_spanletvars.t += s_spanletvars.tstep;
    496 			
    497 			pdest++;
    498 			pz++;
    499 			
    500 			s_spanletvars.spancount--;
    501 		}
    502 	}
    503 }
    504 
    505 /*
    506 ** R_ClipPolyFace
    507 **
    508 ** Clips the winding at clip_verts[clip_current] and changes clip_current
    509 ** Throws out the back side
    510 */
    511 int R_ClipPolyFace (int nump, clipplane_t *pclipplane)
    512 {
    513 	int		i, outcount;
    514 	float	dists[MAXWORKINGVERTS+3];
    515 	float	frac, clipdist, *pclipnormal;
    516 	float	*in, *instep, *outstep, *vert2;
    517 
    518 	clipdist = pclipplane->dist;
    519 	pclipnormal = pclipplane->normal;
    520 	
    521 // calc dists
    522 	if (clip_current)
    523 	{
    524 		in = r_clip_verts[1][0];
    525 		outstep = r_clip_verts[0][0];
    526 		clip_current = 0;
    527 	}
    528 	else
    529 	{
    530 		in = r_clip_verts[0][0];
    531 		outstep = r_clip_verts[1][0];
    532 		clip_current = 1;
    533 	}
    534 	
    535 	instep = in;
    536 	for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
    537 	{
    538 		dists[i] = DotProduct (instep, pclipnormal) - clipdist;
    539 	}
    540 	
    541 // handle wraparound case
    542 	dists[nump] = dists[0];
    543 	memcpy (instep, in, sizeof (vec5_t));
    544 
    545 
    546 // clip the winding
    547 	instep = in;
    548 	outcount = 0;
    549 
    550 	for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
    551 	{
    552 		if (dists[i] >= 0)
    553 		{
    554 			memcpy (outstep, instep, sizeof (vec5_t));
    555 			outstep += sizeof (vec5_t) / sizeof (float);
    556 			outcount++;
    557 		}
    558 
    559 		if (dists[i] == 0 || dists[i+1] == 0)
    560 			continue;
    561 
    562 		if ( (dists[i] > 0) == (dists[i+1] > 0) )
    563 			continue;
    564 			
    565 	// split it into a new vertex
    566 		frac = dists[i] / (dists[i] - dists[i+1]);
    567 			
    568 		vert2 = instep + sizeof (vec5_t) / sizeof (float);
    569 		
    570 		outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
    571 		outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
    572 		outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
    573 		outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
    574 		outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
    575 
    576 		outstep += sizeof (vec5_t) / sizeof (float);
    577 		outcount++;
    578 	}	
    579 	
    580 	return outcount;
    581 }
    582 
    583 /*
    584 ** R_PolygonDrawSpans
    585 */
    586 void R_PolygonDrawSpans(espan_t *pspan, qboolean iswater )
    587 {
    588 	int			count;
    589 	fixed16_t	snext, tnext;
    590 	float		sdivz, tdivz, zi, z, du, dv, spancountminus1;
    591 	float		sdivzspanletstepu, tdivzspanletstepu, zispanletstepu;
    592 
    593 	s_spanletvars.pbase = cacheblock;
    594 
    595 	if ( iswater )
    596 		r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
    597 
    598 	sdivzspanletstepu = d_sdivzstepu * AFFINE_SPANLET_SIZE;
    599 	tdivzspanletstepu = d_tdivzstepu * AFFINE_SPANLET_SIZE;
    600 	zispanletstepu = d_zistepu * AFFINE_SPANLET_SIZE;
    601 
    602 // we count on FP exceptions being turned off to avoid range problems
    603 	s_spanletvars.izistep = (int)(d_zistepu * 0x8000 * 0x10000);
    604 	s_spanletvars.izistep_times_2 = s_spanletvars.izistep * 2;
    605 
    606 	s_spanletvars.pz = 0;
    607 
    608 	do
    609 	{
    610 		s_spanletvars.pdest   = (byte *)d_viewbuffer + ( d_scantable[pspan->v] /*r_screenwidth * pspan->v*/) + pspan->u;
    611 		s_spanletvars.pz      = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
    612 		s_spanletvars.u       = pspan->u;
    613 		s_spanletvars.v       = pspan->v;
    614 
    615 		count = pspan->count;
    616 
    617 		if (count <= 0)
    618 			goto NextSpan;
    619 
    620 	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
    621 		du = (float)pspan->u;
    622 		dv = (float)pspan->v;
    623 
    624 		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
    625 		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
    626 
    627 		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
    628 		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
    629 	// we count on FP exceptions being turned off to avoid range problems
    630 		s_spanletvars.izi = (int)(zi * 0x8000 * 0x10000);
    631 
    632 		s_spanletvars.s = (int)(sdivz * z) + sadjust;
    633 		s_spanletvars.t = (int)(tdivz * z) + tadjust;
    634 
    635 		if ( !iswater )
    636 		{
    637 			if (s_spanletvars.s > bbextents)
    638 				s_spanletvars.s = bbextents;
    639 			else if (s_spanletvars.s < 0)
    640 				s_spanletvars.s = 0;
    641 
    642 			if (s_spanletvars.t > bbextentt)
    643 				s_spanletvars.t = bbextentt;
    644 			else if (s_spanletvars.t < 0)
    645 				s_spanletvars.t = 0;
    646 		}
    647 
    648 		do
    649 		{
    650 		// calculate s and t at the far end of the span
    651 			if (count >= AFFINE_SPANLET_SIZE )
    652 				s_spanletvars.spancount = AFFINE_SPANLET_SIZE;
    653 			else
    654 				s_spanletvars.spancount = count;
    655 
    656 			count -= s_spanletvars.spancount;
    657 
    658 			if (count)
    659 			{
    660 			// calculate s/z, t/z, zi->fixed s and t at far end of span,
    661 			// calculate s and t steps across span by shifting
    662 				sdivz += sdivzspanletstepu;
    663 				tdivz += tdivzspanletstepu;
    664 				zi += zispanletstepu;
    665 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
    666 
    667 				snext = (int)(sdivz * z) + sadjust;
    668 				tnext = (int)(tdivz * z) + tadjust;
    669 
    670 				if ( !iswater )
    671 				{
    672 					if (snext > bbextents)
    673 						snext = bbextents;
    674 					else if (snext < AFFINE_SPANLET_SIZE)
    675 						snext = AFFINE_SPANLET_SIZE;	// prevent round-off error on <0 steps from
    676 									//  from causing overstepping & running off the
    677 									//  edge of the texture
    678 
    679 					if (tnext > bbextentt)
    680 						tnext = bbextentt;
    681 					else if (tnext < AFFINE_SPANLET_SIZE)
    682 						tnext = AFFINE_SPANLET_SIZE;	// guard against round-off error on <0 steps
    683 				}
    684 
    685 				s_spanletvars.sstep = (snext - s_spanletvars.s) >> AFFINE_SPANLET_SIZE_BITS;
    686 				s_spanletvars.tstep = (tnext - s_spanletvars.t) >> AFFINE_SPANLET_SIZE_BITS;
    687 			}
    688 			else
    689 			{
    690 			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
    691 			// can't step off polygon), clamp, calculate s and t steps across
    692 			// span by division, biasing steps low so we don't run off the
    693 			// texture
    694 				spancountminus1 = (float)(s_spanletvars.spancount - 1);
    695 				sdivz += d_sdivzstepu * spancountminus1;
    696 				tdivz += d_tdivzstepu * spancountminus1;
    697 				zi += d_zistepu * spancountminus1;
    698 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
    699 				snext = (int)(sdivz * z) + sadjust;
    700 				tnext = (int)(tdivz * z) + tadjust;
    701 
    702 				if ( !iswater )
    703 				{
    704 					if (snext > bbextents)
    705 						snext = bbextents;
    706 					else if (snext < AFFINE_SPANLET_SIZE)
    707 						snext = AFFINE_SPANLET_SIZE;	// prevent round-off error on <0 steps from
    708 									//  from causing overstepping & running off the
    709 									//  edge of the texture
    710 
    711 					if (tnext > bbextentt)
    712 						tnext = bbextentt;
    713 					else if (tnext < AFFINE_SPANLET_SIZE)
    714 						tnext = AFFINE_SPANLET_SIZE;	// guard against round-off error on <0 steps
    715 				}
    716 
    717 				if (s_spanletvars.spancount > 1)
    718 				{
    719 					s_spanletvars.sstep = (snext - s_spanletvars.s) / (s_spanletvars.spancount - 1);
    720 					s_spanletvars.tstep = (tnext - s_spanletvars.t) / (s_spanletvars.spancount - 1);
    721 				}
    722 			}
    723 
    724 			if ( iswater )
    725 			{
    726 				s_spanletvars.s = s_spanletvars.s & ((CYCLE<<16)-1);
    727 				s_spanletvars.t = s_spanletvars.t & ((CYCLE<<16)-1);
    728 			}
    729 
    730 			r_polydesc.drawspanlet();
    731 
    732 			s_spanletvars.s = snext;
    733 			s_spanletvars.t = tnext;
    734 
    735 		} while (count > 0);
    736 
    737 NextSpan:
    738 		pspan++;
    739 
    740 	} while (pspan->count != DS_SPAN_LIST_END);
    741 }
    742 
    743 /*
    744 **
    745 ** R_PolygonScanLeftEdge
    746 **
    747 ** Goes through the polygon and scans the left edge, filling in 
    748 ** screen coordinate data for the spans
    749 */
    750 void R_PolygonScanLeftEdge (void)
    751 {
    752 	int			i, v, itop, ibottom, lmaxindex;
    753 	emitpoint_t	*pvert, *pnext;
    754 	espan_t		*pspan;
    755 	float		du, dv, vtop, vbottom, slope;
    756 	fixed16_t	u, u_step;
    757 
    758 	pspan = s_polygon_spans;
    759 	i = s_minindex;
    760 	if (i == 0)
    761 		i = r_polydesc.nump;
    762 
    763 	lmaxindex = s_maxindex;
    764 	if (lmaxindex == 0)
    765 		lmaxindex = r_polydesc.nump;
    766 
    767 	vtop = ceil (r_polydesc.pverts[i].v);
    768 
    769 	do
    770 	{
    771 		pvert = &r_polydesc.pverts[i];
    772 		pnext = pvert - 1;
    773 
    774 		vbottom = ceil (pnext->v);
    775 
    776 		if (vtop < vbottom)
    777 		{
    778 			du = pnext->u - pvert->u;
    779 			dv = pnext->v - pvert->v;
    780 
    781 			slope = du / dv;
    782 			u_step = (int)(slope * 0x10000);
    783 		// adjust u to ceil the integer portion
    784 			u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
    785 					(0x10000 - 1);
    786 			itop = (int)vtop;
    787 			ibottom = (int)vbottom;
    788 
    789 			for (v=itop ; v<ibottom ; v++)
    790 			{
    791 				pspan->u = u >> 16;
    792 				pspan->v = v;
    793 				u += u_step;
    794 				pspan++;
    795 			}
    796 		}
    797 
    798 		vtop = vbottom;
    799 
    800 		i--;
    801 		if (i == 0)
    802 			i = r_polydesc.nump;
    803 
    804 	} while (i != lmaxindex);
    805 }
    806 
    807 /*
    808 ** R_PolygonScanRightEdge
    809 **
    810 ** Goes through the polygon and scans the right edge, filling in
    811 ** count values.
    812 */
    813 void R_PolygonScanRightEdge (void)
    814 {
    815 	int			i, v, itop, ibottom;
    816 	emitpoint_t	*pvert, *pnext;
    817 	espan_t		*pspan;
    818 	float		du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
    819 	fixed16_t	u, u_step;
    820 
    821 	pspan = s_polygon_spans;
    822 	i = s_minindex;
    823 
    824 	vvert = r_polydesc.pverts[i].v;
    825 	if (vvert < r_refdef.fvrecty_adj)
    826 		vvert = r_refdef.fvrecty_adj;
    827 	if (vvert > r_refdef.fvrectbottom_adj)
    828 		vvert = r_refdef.fvrectbottom_adj;
    829 
    830 	vtop = ceil (vvert);
    831 
    832 	do
    833 	{
    834 		pvert = &r_polydesc.pverts[i];
    835 		pnext = pvert + 1;
    836 
    837 		vnext = pnext->v;
    838 		if (vnext < r_refdef.fvrecty_adj)
    839 			vnext = r_refdef.fvrecty_adj;
    840 		if (vnext > r_refdef.fvrectbottom_adj)
    841 			vnext = r_refdef.fvrectbottom_adj;
    842 
    843 		vbottom = ceil (vnext);
    844 
    845 		if (vtop < vbottom)
    846 		{
    847 			uvert = pvert->u;
    848 			if (uvert < r_refdef.fvrectx_adj)
    849 				uvert = r_refdef.fvrectx_adj;
    850 			if (uvert > r_refdef.fvrectright_adj)
    851 				uvert = r_refdef.fvrectright_adj;
    852 
    853 			unext = pnext->u;
    854 			if (unext < r_refdef.fvrectx_adj)
    855 				unext = r_refdef.fvrectx_adj;
    856 			if (unext > r_refdef.fvrectright_adj)
    857 				unext = r_refdef.fvrectright_adj;
    858 
    859 			du = unext - uvert;
    860 			dv = vnext - vvert;
    861 			slope = du / dv;
    862 			u_step = (int)(slope * 0x10000);
    863 		// adjust u to ceil the integer portion
    864 			u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
    865 					(0x10000 - 1);
    866 			itop = (int)vtop;
    867 			ibottom = (int)vbottom;
    868 
    869 			for (v=itop ; v<ibottom ; v++)
    870 			{
    871 				pspan->count = (u >> 16) - pspan->u;
    872 				u += u_step;
    873 				pspan++;
    874 			}
    875 		}
    876 
    877 		vtop = vbottom;
    878 		vvert = vnext;
    879 
    880 		i++;
    881 		if (i == r_polydesc.nump)
    882 			i = 0;
    883 
    884 	} while (i != s_maxindex);
    885 
    886 	pspan->count = DS_SPAN_LIST_END;	// mark the end of the span list 
    887 }
    888 
    889 /*
    890 ** R_ClipAndDrawPoly
    891 */
    892 void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured )
    893 {
    894 	emitpoint_t	outverts[MAXWORKINGVERTS+3], *pout;
    895 	float		*pv;
    896 	int			i, nump;
    897 	float		scale;
    898 	vec3_t		transformed, local;
    899 
    900 	if ( !textured )
    901 	{
    902 		r_polydesc.drawspanlet = R_DrawSpanletConstant33;
    903 	}
    904 	else
    905 	{
    906 
    907 		/*
    908 		** choose the correct spanlet routine based on alpha
    909 		*/
    910 		if ( alpha == 1 )
    911 		{
    912 			// isturbulent is ignored because we know that turbulent surfaces
    913 			// can't be opaque
    914 			r_polydesc.drawspanlet = R_DrawSpanletOpaque;
    915 		}
    916 		else
    917 		{
    918 			if ( sw_stipplealpha->value )
    919 			{
    920 				if ( isturbulent )
    921 				{
    922 					if ( alpha > 0.33 )
    923 						r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple66;
    924 					else 
    925 						r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple33;
    926 				}
    927 				else
    928 				{
    929 					if ( alpha > 0.33 )
    930 						r_polydesc.drawspanlet = R_DrawSpanlet66Stipple;
    931 					else 
    932 						r_polydesc.drawspanlet = R_DrawSpanlet33Stipple;
    933 				}
    934 			}
    935 			else
    936 			{
    937 				if ( isturbulent )
    938 				{
    939 					if ( alpha > 0.33 )
    940 						r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended66;
    941 					else
    942 						r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended33;
    943 				}
    944 				else
    945 				{
    946 					if ( alpha > 0.33 )
    947 						r_polydesc.drawspanlet = R_DrawSpanlet66;
    948 					else 
    949 						r_polydesc.drawspanlet = R_DrawSpanlet33;
    950 				}
    951 			}
    952 		}
    953 	}
    954 
    955 	// clip to the frustum in worldspace
    956 	nump = r_polydesc.nump;
    957 	clip_current = 0;
    958 
    959 	for (i=0 ; i<4 ; i++)
    960 	{
    961 		nump = R_ClipPolyFace (nump, &view_clipplanes[i]);
    962 		if (nump < 3)
    963 			return;
    964 		if (nump > MAXWORKINGVERTS)
    965 			ri.Sys_Error(ERR_DROP, "R_ClipAndDrawPoly: too many points: %d", nump );
    966 	}
    967 
    968 // transform vertices into viewspace and project
    969 	pv = &r_clip_verts[clip_current][0][0];
    970 
    971 	for (i=0 ; i<nump ; i++)
    972 	{
    973 		VectorSubtract (pv, r_origin, local);
    974 		TransformVector (local, transformed);
    975 
    976 		if (transformed[2] < NEAR_CLIP)
    977 			transformed[2] = NEAR_CLIP;
    978 
    979 		pout = &outverts[i];
    980 		pout->zi = 1.0 / transformed[2];
    981 
    982 		pout->s = pv[3];
    983 		pout->t = pv[4];
    984 		
    985 		scale = xscale * pout->zi;
    986 		pout->u = (xcenter + scale * transformed[0]);
    987 
    988 		scale = yscale * pout->zi;
    989 		pout->v = (ycenter - scale * transformed[1]);
    990 
    991 		pv += sizeof (vec5_t) / sizeof (pv);
    992 	}
    993 
    994 // draw it
    995 	r_polydesc.nump = nump;
    996 	r_polydesc.pverts = outverts;
    997 
    998 	R_DrawPoly( isturbulent );
    999 }
   1000 
   1001 /*
   1002 ** R_BuildPolygonFromSurface
   1003 */
   1004 void R_BuildPolygonFromSurface(msurface_t *fa)
   1005 {
   1006 	int			i, lindex, lnumverts;
   1007 	medge_t		*pedges, *r_pedge;
   1008 	int			vertpage;
   1009 	float		*vec;
   1010 	vec5_t     *pverts;
   1011 	float       tmins[2] = { 0, 0 };
   1012 
   1013 	r_polydesc.nump = 0;
   1014 
   1015 	// reconstruct the polygon
   1016 	pedges = currentmodel->edges;
   1017 	lnumverts = fa->numedges;
   1018 	vertpage = 0;
   1019 
   1020 	pverts = r_clip_verts[0];
   1021 
   1022 	for (i=0 ; i<lnumverts ; i++)
   1023 	{
   1024 		lindex = currentmodel->surfedges[fa->firstedge + i];
   1025 
   1026 		if (lindex > 0)
   1027 		{
   1028 			r_pedge = &pedges[lindex];
   1029 			vec = currentmodel->vertexes[r_pedge->v[0]].position;
   1030 		}
   1031 		else
   1032 		{
   1033 			r_pedge = &pedges[-lindex];
   1034 			vec = currentmodel->vertexes[r_pedge->v[1]].position;
   1035 		}
   1036 
   1037 		VectorCopy (vec, pverts[i] );
   1038 	}
   1039 
   1040 	VectorCopy( fa->texinfo->vecs[0], r_polydesc.vright );
   1041 	VectorCopy( fa->texinfo->vecs[1], r_polydesc.vup );
   1042 	VectorCopy( fa->plane->normal, r_polydesc.vpn );
   1043 	VectorCopy( r_origin, r_polydesc.viewer_position );
   1044 
   1045 	if ( fa->flags & SURF_PLANEBACK )
   1046 	{
   1047 		VectorSubtract( vec3_origin, r_polydesc.vpn, r_polydesc.vpn );
   1048 	}
   1049 
   1050 	if ( fa->texinfo->flags & SURF_WARP )
   1051 	{
   1052 		r_polydesc.pixels       = fa->texinfo->image->pixels[0];
   1053 		r_polydesc.pixel_width  = fa->texinfo->image->width;
   1054 		r_polydesc.pixel_height = fa->texinfo->image->height;
   1055 	}
   1056 	else
   1057 	{
   1058 		surfcache_t *scache;
   1059 
   1060 		scache = D_CacheSurface( fa, 0 );
   1061 
   1062 		r_polydesc.pixels       = scache->data;
   1063 		r_polydesc.pixel_width  = scache->width;
   1064 		r_polydesc.pixel_height = scache->height;
   1065 
   1066 		tmins[0] = fa->texturemins[0];
   1067 		tmins[1] = fa->texturemins[1];
   1068 	}
   1069 
   1070 	r_polydesc.dist = DotProduct( r_polydesc.vpn, pverts[0] );
   1071 
   1072 	r_polydesc.s_offset = fa->texinfo->vecs[0][3] - tmins[0];
   1073 	r_polydesc.t_offset = fa->texinfo->vecs[1][3] - tmins[1];
   1074 
   1075 	// scrolling texture addition
   1076 	if (fa->texinfo->flags & SURF_FLOWING)
   1077 	{
   1078 		r_polydesc.s_offset += -128 * ( (r_newrefdef.time*0.25) - (int)(r_newrefdef.time*0.25) );
   1079 	}
   1080 
   1081 	r_polydesc.nump = lnumverts;
   1082 }
   1083 
   1084 /*
   1085 ** R_PolygonCalculateGradients
   1086 */
   1087 void R_PolygonCalculateGradients (void)
   1088 {
   1089 	vec3_t		p_normal, p_saxis, p_taxis;
   1090 	float		distinv;
   1091 
   1092 	TransformVector (r_polydesc.vpn, p_normal);
   1093 	TransformVector (r_polydesc.vright, p_saxis);
   1094 	TransformVector (r_polydesc.vup, p_taxis);
   1095 
   1096 	distinv = 1.0 / (-(DotProduct (r_polydesc.viewer_position, r_polydesc.vpn)) + r_polydesc.dist );
   1097 
   1098 	d_sdivzstepu  =  p_saxis[0] * xscaleinv;
   1099 	d_sdivzstepv  = -p_saxis[1] * yscaleinv;
   1100 	d_sdivzorigin =  p_saxis[2] - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv;
   1101 
   1102 	d_tdivzstepu  =  p_taxis[0] * xscaleinv;
   1103 	d_tdivzstepv  = -p_taxis[1] * yscaleinv;
   1104 	d_tdivzorigin =  p_taxis[2] - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv;
   1105 
   1106 	d_zistepu =   p_normal[0] * xscaleinv * distinv;
   1107 	d_zistepv =  -p_normal[1] * yscaleinv * distinv;
   1108 	d_ziorigin =  p_normal[2] * distinv - xcenter * d_zistepu - ycenter * d_zistepv;
   1109 
   1110 	sadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vright) + r_polydesc.s_offset ) * 0x10000 );
   1111 	tadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vup   ) + r_polydesc.t_offset ) * 0x10000 );
   1112 
   1113 // -1 (-epsilon) so we never wander off the edge of the texture
   1114 	bbextents = (r_polydesc.pixel_width << 16) - 1;
   1115 	bbextentt = (r_polydesc.pixel_height << 16) - 1;
   1116 }
   1117 
   1118 /*
   1119 ** R_DrawPoly
   1120 **
   1121 ** Polygon drawing function.  Uses the polygon described in r_polydesc
   1122 ** to calculate edges and gradients, then renders the resultant spans.
   1123 **
   1124 ** This should NOT be called externally since it doesn't do clipping!
   1125 */
   1126 static void R_DrawPoly( qboolean iswater )
   1127 {
   1128 	int			i, nump;
   1129 	float		ymin, ymax;
   1130 	emitpoint_t	*pverts;
   1131 	espan_t	spans[MAXHEIGHT+1];
   1132 
   1133 	s_polygon_spans = spans;
   1134 
   1135 // find the top and bottom vertices, and make sure there's at least one scan to
   1136 // draw
   1137 	ymin = 999999.9;
   1138 	ymax = -999999.9;
   1139 	pverts = r_polydesc.pverts;
   1140 
   1141 	for (i=0 ; i<r_polydesc.nump ; i++)
   1142 	{
   1143 		if (pverts->v < ymin)
   1144 		{
   1145 			ymin = pverts->v;
   1146 			s_minindex = i;
   1147 		}
   1148 
   1149 		if (pverts->v > ymax)
   1150 		{
   1151 			ymax = pverts->v;
   1152 			s_maxindex = i;
   1153 		}
   1154 
   1155 		pverts++;
   1156 	}
   1157 
   1158 	ymin = ceil (ymin);
   1159 	ymax = ceil (ymax);
   1160 
   1161 	if (ymin >= ymax)
   1162 		return;		// doesn't cross any scans at all
   1163 
   1164 	cachewidth = r_polydesc.pixel_width;
   1165 	cacheblock = r_polydesc.pixels;
   1166 
   1167 // copy the first vertex to the last vertex, so we don't have to deal with
   1168 // wrapping
   1169 	nump = r_polydesc.nump;
   1170 	pverts = r_polydesc.pverts;
   1171 	pverts[nump] = pverts[0];
   1172 
   1173 	R_PolygonCalculateGradients ();
   1174 	R_PolygonScanLeftEdge ();
   1175 	R_PolygonScanRightEdge ();
   1176 
   1177 	R_PolygonDrawSpans( s_polygon_spans, iswater );
   1178 }
   1179 
   1180 /*
   1181 ** R_DrawAlphaSurfaces
   1182 */
   1183 void R_DrawAlphaSurfaces( void )
   1184 {
   1185 	msurface_t *s = r_alpha_surfaces;
   1186 
   1187 	currentmodel = r_worldmodel;
   1188 
   1189 	modelorg[0] = -r_origin[0];
   1190 	modelorg[1] = -r_origin[1];
   1191 	modelorg[2] = -r_origin[2];
   1192 
   1193 	while ( s )
   1194 	{
   1195 		R_BuildPolygonFromSurface( s );
   1196 
   1197 		if (s->texinfo->flags & SURF_TRANS66)
   1198 			R_ClipAndDrawPoly( 0.60f, ( s->texinfo->flags & SURF_WARP) != 0, true );
   1199 		else
   1200 			R_ClipAndDrawPoly( 0.30f, ( s->texinfo->flags & SURF_WARP) != 0, true );
   1201 
   1202 		s = s->nextalphasurface;
   1203 	}
   1204 	
   1205 	r_alpha_surfaces = NULL;
   1206 }
   1207 
   1208 /*
   1209 ** R_IMFlatShadedQuad
   1210 */
   1211 void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha )
   1212 {
   1213 	vec3_t s0, s1;
   1214 
   1215 	r_polydesc.nump = 4;
   1216 	VectorCopy( r_origin, r_polydesc.viewer_position );
   1217 
   1218 	VectorCopy( a, r_clip_verts[0][0] );
   1219 	VectorCopy( b, r_clip_verts[0][1] );
   1220 	VectorCopy( c, r_clip_verts[0][2] );
   1221 	VectorCopy( d, r_clip_verts[0][3] );
   1222 
   1223 	r_clip_verts[0][0][3] = 0;
   1224 	r_clip_verts[0][1][3] = 0;
   1225 	r_clip_verts[0][2][3] = 0;
   1226 	r_clip_verts[0][3][3] = 0;
   1227 
   1228 	r_clip_verts[0][0][4] = 0;
   1229 	r_clip_verts[0][1][4] = 0;
   1230 	r_clip_verts[0][2][4] = 0;
   1231 	r_clip_verts[0][3][4] = 0;
   1232 
   1233 	VectorSubtract( d, c, s0 );
   1234 	VectorSubtract( c, b, s1 );
   1235 	CrossProduct( s0, s1, r_polydesc.vpn );
   1236 	VectorNormalize( r_polydesc.vpn );
   1237 
   1238 	r_polydesc.dist = DotProduct( r_polydesc.vpn, r_clip_verts[0][0] );
   1239 
   1240 	r_polyblendcolor = color;
   1241 
   1242 	R_ClipAndDrawPoly( alpha, false, false );
   1243 }
   1244