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( int iswater );
55 
56 /*
57 ** R_DrawSpanletOpaque
58 */
R_DrawSpanletOpaque(void)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 */
R_DrawSpanletTurbulentStipple33(void)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 */
R_DrawSpanletTurbulentStipple66(void)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 */
R_DrawSpanletTurbulentBlended66(void)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 
R_DrawSpanletTurbulentBlended33(void)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 */
R_DrawSpanlet33(void)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 
R_DrawSpanletConstant33(void)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 */
R_DrawSpanlet66(void)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 */
R_DrawSpanlet33Stipple(void)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 */
R_DrawSpanlet66Stipple(void)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 */
R_ClipPolyFace(int nump,clipplane_t * pclipplane)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 // PGM - iswater was qboolean. changed to allow passing more flags
R_PolygonDrawSpans(espan_t * pspan,int iswater)587 void R_PolygonDrawSpans(espan_t *pspan, int iswater )
588 {
589 	int			count;
590 	fixed16_t	snext, tnext;
591 	float		sdivz, tdivz, zi, z, du, dv, spancountminus1;
592 	float		sdivzspanletstepu, tdivzspanletstepu, zispanletstepu;
593 
594 	s_spanletvars.pbase = cacheblock;
595 
596 //PGM
597 	if ( iswater & SURF_WARP)
598 		r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
599 	else if (iswater & SURF_FLOWING)
600 		r_turb_turb = blanktable;
601 //PGM
602 
603 	sdivzspanletstepu = d_sdivzstepu * AFFINE_SPANLET_SIZE;
604 	tdivzspanletstepu = d_tdivzstepu * AFFINE_SPANLET_SIZE;
605 	zispanletstepu = d_zistepu * AFFINE_SPANLET_SIZE;
606 
607 // we count on FP exceptions being turned off to avoid range problems
608 	s_spanletvars.izistep = (int)(d_zistepu * 0x8000 * 0x10000);
609 	s_spanletvars.izistep_times_2 = s_spanletvars.izistep * 2;
610 
611 	s_spanletvars.pz = 0;
612 
613 	do
614 	{
615 		s_spanletvars.pdest   = (byte *)d_viewbuffer + ( d_scantable[pspan->v] /*r_screenwidth * pspan->v*/) + pspan->u;
616 		s_spanletvars.pz      = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
617 		s_spanletvars.u       = pspan->u;
618 		s_spanletvars.v       = pspan->v;
619 
620 		count = pspan->count;
621 
622 		if (count <= 0)
623 			goto NextSpan;
624 
625 	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
626 		du = (float)pspan->u;
627 		dv = (float)pspan->v;
628 
629 		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
630 		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
631 
632 		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
633 		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
634 	// we count on FP exceptions being turned off to avoid range problems
635 		s_spanletvars.izi = (int)(zi * 0x8000 * 0x10000);
636 
637 		s_spanletvars.s = (int)(sdivz * z) + sadjust;
638 		s_spanletvars.t = (int)(tdivz * z) + tadjust;
639 
640 		if ( !iswater )
641 		{
642 			if (s_spanletvars.s > bbextents)
643 				s_spanletvars.s = bbextents;
644 			else if (s_spanletvars.s < 0)
645 				s_spanletvars.s = 0;
646 
647 			if (s_spanletvars.t > bbextentt)
648 				s_spanletvars.t = bbextentt;
649 			else if (s_spanletvars.t < 0)
650 				s_spanletvars.t = 0;
651 		}
652 
653 		do
654 		{
655 		// calculate s and t at the far end of the span
656 			if (count >= AFFINE_SPANLET_SIZE )
657 				s_spanletvars.spancount = AFFINE_SPANLET_SIZE;
658 			else
659 				s_spanletvars.spancount = count;
660 
661 			count -= s_spanletvars.spancount;
662 
663 			if (count)
664 			{
665 			// calculate s/z, t/z, zi->fixed s and t at far end of span,
666 			// calculate s and t steps across span by shifting
667 				sdivz += sdivzspanletstepu;
668 				tdivz += tdivzspanletstepu;
669 				zi += zispanletstepu;
670 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
671 
672 				snext = (int)(sdivz * z) + sadjust;
673 				tnext = (int)(tdivz * z) + tadjust;
674 
675 				if ( !iswater )
676 				{
677 					if (snext > bbextents)
678 						snext = bbextents;
679 					else if (snext < AFFINE_SPANLET_SIZE)
680 						snext = AFFINE_SPANLET_SIZE;	// prevent round-off error on <0 steps from
681 									//  from causing overstepping & running off the
682 									//  edge of the texture
683 
684 					if (tnext > bbextentt)
685 						tnext = bbextentt;
686 					else if (tnext < AFFINE_SPANLET_SIZE)
687 						tnext = AFFINE_SPANLET_SIZE;	// guard against round-off error on <0 steps
688 				}
689 
690 				s_spanletvars.sstep = (snext - s_spanletvars.s) >> AFFINE_SPANLET_SIZE_BITS;
691 				s_spanletvars.tstep = (tnext - s_spanletvars.t) >> AFFINE_SPANLET_SIZE_BITS;
692 			}
693 			else
694 			{
695 			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
696 			// can't step off polygon), clamp, calculate s and t steps across
697 			// span by division, biasing steps low so we don't run off the
698 			// texture
699 				spancountminus1 = (float)(s_spanletvars.spancount - 1);
700 				sdivz += d_sdivzstepu * spancountminus1;
701 				tdivz += d_tdivzstepu * spancountminus1;
702 				zi += d_zistepu * spancountminus1;
703 				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
704 				snext = (int)(sdivz * z) + sadjust;
705 				tnext = (int)(tdivz * z) + tadjust;
706 
707 				if ( !iswater )
708 				{
709 					if (snext > bbextents)
710 						snext = bbextents;
711 					else if (snext < AFFINE_SPANLET_SIZE)
712 						snext = AFFINE_SPANLET_SIZE;	// prevent round-off error on <0 steps from
713 									//  from causing overstepping & running off the
714 									//  edge of the texture
715 
716 					if (tnext > bbextentt)
717 						tnext = bbextentt;
718 					else if (tnext < AFFINE_SPANLET_SIZE)
719 						tnext = AFFINE_SPANLET_SIZE;	// guard against round-off error on <0 steps
720 				}
721 
722 				if (s_spanletvars.spancount > 1)
723 				{
724 					s_spanletvars.sstep = (snext - s_spanletvars.s) / (s_spanletvars.spancount - 1);
725 					s_spanletvars.tstep = (tnext - s_spanletvars.t) / (s_spanletvars.spancount - 1);
726 				}
727 			}
728 
729 			if ( iswater )
730 			{
731 				s_spanletvars.s = s_spanletvars.s & ((CYCLE<<16)-1);
732 				s_spanletvars.t = s_spanletvars.t & ((CYCLE<<16)-1);
733 			}
734 
735 			r_polydesc.drawspanlet();
736 
737 			s_spanletvars.s = snext;
738 			s_spanletvars.t = tnext;
739 
740 		} while (count > 0);
741 
742 NextSpan:
743 		pspan++;
744 
745 	} while (pspan->count != DS_SPAN_LIST_END);
746 }
747 
748 /*
749 **
750 ** R_PolygonScanLeftEdge
751 **
752 ** Goes through the polygon and scans the left edge, filling in
753 ** screen coordinate data for the spans
754 */
R_PolygonScanLeftEdge(void)755 void R_PolygonScanLeftEdge (void)
756 {
757 	int			i, v, itop, ibottom, lmaxindex;
758 	emitpoint_t	*pvert, *pnext;
759 	espan_t		*pspan;
760 	float		du, dv, vtop, vbottom, slope;
761 	fixed16_t	u, u_step;
762 
763 	pspan = s_polygon_spans;
764 	i = s_minindex;
765 	if (i == 0)
766 		i = r_polydesc.nump;
767 
768 	lmaxindex = s_maxindex;
769 	if (lmaxindex == 0)
770 		lmaxindex = r_polydesc.nump;
771 
772 	vtop = ceil (r_polydesc.pverts[i].v);
773 
774 	do
775 	{
776 		pvert = &r_polydesc.pverts[i];
777 		pnext = pvert - 1;
778 
779 		vbottom = ceil (pnext->v);
780 
781 		if (vtop < vbottom)
782 		{
783 			du = pnext->u - pvert->u;
784 			dv = pnext->v - pvert->v;
785 
786 			slope = du / dv;
787 			u_step = (int)(slope * 0x10000);
788 		// adjust u to ceil the integer portion
789 			u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
790 					(0x10000 - 1);
791 			itop = (int)vtop;
792 			ibottom = (int)vbottom;
793 
794 			for (v=itop ; v<ibottom ; v++)
795 			{
796 				pspan->u = u >> 16;
797 				pspan->v = v;
798 				u += u_step;
799 				pspan++;
800 			}
801 		}
802 
803 		vtop = vbottom;
804 
805 		i--;
806 		if (i == 0)
807 			i = r_polydesc.nump;
808 
809 	} while (i != lmaxindex);
810 }
811 
812 /*
813 ** R_PolygonScanRightEdge
814 **
815 ** Goes through the polygon and scans the right edge, filling in
816 ** count values.
817 */
R_PolygonScanRightEdge(void)818 void R_PolygonScanRightEdge (void)
819 {
820 	int			i, v, itop, ibottom;
821 	emitpoint_t	*pvert, *pnext;
822 	espan_t		*pspan;
823 	float		du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
824 	fixed16_t	u, u_step;
825 
826 	pspan = s_polygon_spans;
827 	i = s_minindex;
828 
829 	vvert = r_polydesc.pverts[i].v;
830 	if (vvert < r_refdef.fvrecty_adj)
831 		vvert = r_refdef.fvrecty_adj;
832 	if (vvert > r_refdef.fvrectbottom_adj)
833 		vvert = r_refdef.fvrectbottom_adj;
834 
835 	vtop = ceil (vvert);
836 
837 	do
838 	{
839 		pvert = &r_polydesc.pverts[i];
840 		pnext = pvert + 1;
841 
842 		vnext = pnext->v;
843 		if (vnext < r_refdef.fvrecty_adj)
844 			vnext = r_refdef.fvrecty_adj;
845 		if (vnext > r_refdef.fvrectbottom_adj)
846 			vnext = r_refdef.fvrectbottom_adj;
847 
848 		vbottom = ceil (vnext);
849 
850 		if (vtop < vbottom)
851 		{
852 			uvert = pvert->u;
853 			if (uvert < r_refdef.fvrectx_adj)
854 				uvert = r_refdef.fvrectx_adj;
855 			if (uvert > r_refdef.fvrectright_adj)
856 				uvert = r_refdef.fvrectright_adj;
857 
858 			unext = pnext->u;
859 			if (unext < r_refdef.fvrectx_adj)
860 				unext = r_refdef.fvrectx_adj;
861 			if (unext > r_refdef.fvrectright_adj)
862 				unext = r_refdef.fvrectright_adj;
863 
864 			du = unext - uvert;
865 			dv = vnext - vvert;
866 			slope = du / dv;
867 			u_step = (int)(slope * 0x10000);
868 		// adjust u to ceil the integer portion
869 			u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
870 					(0x10000 - 1);
871 			itop = (int)vtop;
872 			ibottom = (int)vbottom;
873 
874 			for (v=itop ; v<ibottom ; v++)
875 			{
876 				pspan->count = (u >> 16) - pspan->u;
877 				u += u_step;
878 				pspan++;
879 			}
880 		}
881 
882 		vtop = vbottom;
883 		vvert = vnext;
884 
885 		i++;
886 		if (i == r_polydesc.nump)
887 			i = 0;
888 
889 	} while (i != s_maxindex);
890 
891 	pspan->count = DS_SPAN_LIST_END;	// mark the end of the span list
892 }
893 
894 /*
895 ** R_ClipAndDrawPoly
896 */
897 // PGM - isturbulent was qboolean. changed to int to allow passing more flags
R_ClipAndDrawPoly(float alpha,int isturbulent,qboolean textured)898 void R_ClipAndDrawPoly ( float alpha, int isturbulent, qboolean textured )
899 {
900 	emitpoint_t	outverts[MAXWORKINGVERTS+3], *pout;
901 	float		*pv;
902 	int			i, nump;
903 	float		scale;
904 	vec3_t		transformed, local;
905 
906 	if ( !textured )
907 	{
908 		r_polydesc.drawspanlet = R_DrawSpanletConstant33;
909 	}
910 	else
911 	{
912 
913 		/*
914 		** choose the correct spanlet routine based on alpha
915 		*/
916 		if ( alpha == 1 )
917 		{
918 			// isturbulent is ignored because we know that turbulent surfaces
919 			// can't be opaque
920 			r_polydesc.drawspanlet = R_DrawSpanletOpaque;
921 		}
922 		else
923 		{
924 			if ( sw_stipplealpha->value )
925 			{
926 				if ( isturbulent )
927 				{
928 					if ( alpha > 0.33 )
929 						r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple66;
930 					else
931 						r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple33;
932 				}
933 				else
934 				{
935 					if ( alpha > 0.33 )
936 						r_polydesc.drawspanlet = R_DrawSpanlet66Stipple;
937 					else
938 						r_polydesc.drawspanlet = R_DrawSpanlet33Stipple;
939 				}
940 			}
941 			else
942 			{
943 				if ( isturbulent )
944 				{
945 					if ( alpha > 0.33 )
946 						r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended66;
947 					else
948 						r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended33;
949 				}
950 				else
951 				{
952 					if ( alpha > 0.33 )
953 						r_polydesc.drawspanlet = R_DrawSpanlet66;
954 					else
955 						r_polydesc.drawspanlet = R_DrawSpanlet33;
956 				}
957 			}
958 		}
959 	}
960 
961 	// clip to the frustum in worldspace
962 	nump = r_polydesc.nump;
963 	clip_current = 0;
964 
965 	for (i=0 ; i<4 ; i++)
966 	{
967 		nump = R_ClipPolyFace (nump, &view_clipplanes[i]);
968 		if (nump < 3)
969 			return;
970 		if (nump > MAXWORKINGVERTS)
971 			ri.Sys_Error(ERR_DROP, "R_ClipAndDrawPoly: too many points: %d", nump );
972 	}
973 
974 // transform vertices into viewspace and project
975 	pv = &r_clip_verts[clip_current][0][0];
976 
977 	for (i=0 ; i<nump ; i++)
978 	{
979 		VectorSubtract (pv, r_origin, local);
980 		TransformVector (local, transformed);
981 
982 		if (transformed[2] < NEAR_CLIP)
983 			transformed[2] = NEAR_CLIP;
984 
985 		pout = &outverts[i];
986 		pout->zi = 1.0 / transformed[2];
987 
988 		pout->s = pv[3];
989 		pout->t = pv[4];
990 
991 		scale = xscale * pout->zi;
992 		pout->u = (xcenter + scale * transformed[0]);
993 
994 		scale = yscale * pout->zi;
995 		pout->v = (ycenter - scale * transformed[1]);
996 
997 		pv += sizeof (vec5_t) / sizeof (pv);
998 	}
999 
1000 // draw it
1001 	r_polydesc.nump = nump;
1002 	r_polydesc.pverts = outverts;
1003 
1004 	R_DrawPoly( isturbulent );
1005 }
1006 
1007 /*
1008 ** R_BuildPolygonFromSurface
1009 */
R_BuildPolygonFromSurface(msurface_t * fa)1010 void R_BuildPolygonFromSurface(msurface_t *fa)
1011 {
1012 	int			i, lindex, lnumverts;
1013 	medge_t		*pedges, *r_pedge;
1014 	int			vertpage;
1015 	float		*vec;
1016 	vec5_t     *pverts;
1017 	float       tmins[2] = { 0, 0 };
1018 
1019 	r_polydesc.nump = 0;
1020 
1021 	// reconstruct the polygon
1022 	pedges = currentmodel->edges;
1023 	lnumverts = fa->numedges;
1024 	vertpage = 0;
1025 
1026 	pverts = r_clip_verts[0];
1027 
1028 	for (i=0 ; i<lnumverts ; i++)
1029 	{
1030 		lindex = currentmodel->surfedges[fa->firstedge + i];
1031 
1032 		if (lindex > 0)
1033 		{
1034 			r_pedge = &pedges[lindex];
1035 			vec = currentmodel->vertexes[r_pedge->v[0]].position;
1036 		}
1037 		else
1038 		{
1039 			r_pedge = &pedges[-lindex];
1040 			vec = currentmodel->vertexes[r_pedge->v[1]].position;
1041 		}
1042 
1043 		VectorCopy (vec, pverts[i] );
1044 	}
1045 
1046 	VectorCopy( fa->texinfo->vecs[0], r_polydesc.vright );
1047 	VectorCopy( fa->texinfo->vecs[1], r_polydesc.vup );
1048 	VectorCopy( fa->plane->normal, r_polydesc.vpn );
1049 	VectorCopy( r_origin, r_polydesc.viewer_position );
1050 
1051 	if ( fa->flags & SURF_PLANEBACK )
1052 	{
1053 		VectorSubtract( vec3_origin, r_polydesc.vpn, r_polydesc.vpn );
1054 	}
1055 
1056 // PGM 09/16/98
1057 	if ( fa->texinfo->flags & (SURF_WARP|SURF_FLOWING) )
1058 	{
1059 		r_polydesc.pixels       = fa->texinfo->image->pixels[0];
1060 		r_polydesc.pixel_width  = fa->texinfo->image->width;
1061 		r_polydesc.pixel_height = fa->texinfo->image->height;
1062 	}
1063 // PGM 09/16/98
1064 	else
1065 	{
1066 		surfcache_t *scache;
1067 
1068 		scache = D_CacheSurface( fa, 0 );
1069 
1070 		r_polydesc.pixels       = scache->data;
1071 		r_polydesc.pixel_width  = scache->width;
1072 		r_polydesc.pixel_height = scache->height;
1073 
1074 		tmins[0] = fa->texturemins[0];
1075 		tmins[1] = fa->texturemins[1];
1076 	}
1077 
1078 	r_polydesc.dist = DotProduct( r_polydesc.vpn, pverts[0] );
1079 
1080 	r_polydesc.s_offset = fa->texinfo->vecs[0][3] - tmins[0];
1081 	r_polydesc.t_offset = fa->texinfo->vecs[1][3] - tmins[1];
1082 
1083 	// scrolling texture addition
1084 	if (fa->texinfo->flags & SURF_FLOWING)
1085 	{
1086 		r_polydesc.s_offset += -128 * ( (r_newrefdef.time*0.25) - (int)(r_newrefdef.time*0.25) );
1087 	}
1088 
1089 	r_polydesc.nump = lnumverts;
1090 }
1091 
1092 /*
1093 ** R_PolygonCalculateGradients
1094 */
R_PolygonCalculateGradients(void)1095 void R_PolygonCalculateGradients (void)
1096 {
1097 	vec3_t		p_normal, p_saxis, p_taxis;
1098 	float		distinv;
1099 
1100 	TransformVector (r_polydesc.vpn, p_normal);
1101 	TransformVector (r_polydesc.vright, p_saxis);
1102 	TransformVector (r_polydesc.vup, p_taxis);
1103 
1104 	distinv = 1.0 / (-(DotProduct (r_polydesc.viewer_position, r_polydesc.vpn)) + r_polydesc.dist );
1105 
1106 	d_sdivzstepu  =  p_saxis[0] * xscaleinv;
1107 	d_sdivzstepv  = -p_saxis[1] * yscaleinv;
1108 	d_sdivzorigin =  p_saxis[2] - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv;
1109 
1110 	d_tdivzstepu  =  p_taxis[0] * xscaleinv;
1111 	d_tdivzstepv  = -p_taxis[1] * yscaleinv;
1112 	d_tdivzorigin =  p_taxis[2] - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv;
1113 
1114 	d_zistepu =   p_normal[0] * xscaleinv * distinv;
1115 	d_zistepv =  -p_normal[1] * yscaleinv * distinv;
1116 	d_ziorigin =  p_normal[2] * distinv - xcenter * d_zistepu - ycenter * d_zistepv;
1117 
1118 	sadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vright) + r_polydesc.s_offset ) * 0x10000 );
1119 	tadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vup   ) + r_polydesc.t_offset ) * 0x10000 );
1120 
1121 // -1 (-epsilon) so we never wander off the edge of the texture
1122 	bbextents = (r_polydesc.pixel_width << 16) - 1;
1123 	bbextentt = (r_polydesc.pixel_height << 16) - 1;
1124 }
1125 
1126 /*
1127 ** R_DrawPoly
1128 **
1129 ** Polygon drawing function.  Uses the polygon described in r_polydesc
1130 ** to calculate edges and gradients, then renders the resultant spans.
1131 **
1132 ** This should NOT be called externally since it doesn't do clipping!
1133 */
1134 // PGM - iswater was qboolean. changed to support passing more flags
R_DrawPoly(int iswater)1135 static void R_DrawPoly( int iswater )
1136 {
1137 	int			i, nump;
1138 	float		ymin, ymax;
1139 	emitpoint_t	*pverts;
1140 	espan_t	spans[MAXHEIGHT+1];
1141 
1142 	s_polygon_spans = spans;
1143 
1144 // find the top and bottom vertices, and make sure there's at least one scan to
1145 // draw
1146 	ymin = 999999.9;
1147 	ymax = -999999.9;
1148 	pverts = r_polydesc.pverts;
1149 
1150 	for (i=0 ; i<r_polydesc.nump ; i++)
1151 	{
1152 		if (pverts->v < ymin)
1153 		{
1154 			ymin = pverts->v;
1155 			s_minindex = i;
1156 		}
1157 
1158 		if (pverts->v > ymax)
1159 		{
1160 			ymax = pverts->v;
1161 			s_maxindex = i;
1162 		}
1163 
1164 		pverts++;
1165 	}
1166 
1167 	ymin = ceil (ymin);
1168 	ymax = ceil (ymax);
1169 
1170 	if (ymin >= ymax)
1171 		return;		// doesn't cross any scans at all
1172 
1173 	cachewidth = r_polydesc.pixel_width;
1174 	cacheblock = r_polydesc.pixels;
1175 
1176 // copy the first vertex to the last vertex, so we don't have to deal with
1177 // wrapping
1178 	nump = r_polydesc.nump;
1179 	pverts = r_polydesc.pverts;
1180 	pverts[nump] = pverts[0];
1181 
1182 	R_PolygonCalculateGradients ();
1183 	R_PolygonScanLeftEdge ();
1184 	R_PolygonScanRightEdge ();
1185 
1186 	R_PolygonDrawSpans( s_polygon_spans, iswater );
1187 }
1188 
1189 /*
1190 ** R_DrawAlphaSurfaces
1191 */
R_DrawAlphaSurfaces(void)1192 void R_DrawAlphaSurfaces( void )
1193 {
1194 	msurface_t *s = r_alpha_surfaces;
1195 
1196 	currentmodel = r_worldmodel;
1197 
1198 	modelorg[0] = -r_origin[0];
1199 	modelorg[1] = -r_origin[1];
1200 	modelorg[2] = -r_origin[2];
1201 
1202 	while ( s )
1203 	{
1204 		R_BuildPolygonFromSurface( s );
1205 
1206 //=======
1207 //PGM
1208 //		if (s->texinfo->flags & SURF_TRANS66)
1209 //			R_ClipAndDrawPoly( 0.60f, ( s->texinfo->flags & SURF_WARP) != 0, true );
1210 //		else
1211 //			R_ClipAndDrawPoly( 0.30f, ( s->texinfo->flags & SURF_WARP) != 0, true );
1212 
1213 		// PGM - pass down all the texinfo flags, not just SURF_WARP.
1214 		if (s->texinfo->flags & SURF_TRANS66)
1215 			R_ClipAndDrawPoly( 0.60f, (s->texinfo->flags & (SURF_WARP|SURF_FLOWING)), true );
1216 		else
1217 			R_ClipAndDrawPoly( 0.30f, (s->texinfo->flags & (SURF_WARP|SURF_FLOWING)), true );
1218 //PGM
1219 //=======
1220 
1221 		s = s->nextalphasurface;
1222 	}
1223 
1224 	r_alpha_surfaces = NULL;
1225 }
1226 
1227 /*
1228 ** R_IMFlatShadedQuad
1229 */
R_IMFlatShadedQuad(vec3_t a,vec3_t b,vec3_t c,vec3_t d,int color,float alpha)1230 void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha )
1231 {
1232 	vec3_t s0, s1;
1233 
1234 	r_polydesc.nump = 4;
1235 	VectorCopy( r_origin, r_polydesc.viewer_position );
1236 
1237 	VectorCopy( a, r_clip_verts[0][0] );
1238 	VectorCopy( b, r_clip_verts[0][1] );
1239 	VectorCopy( c, r_clip_verts[0][2] );
1240 	VectorCopy( d, r_clip_verts[0][3] );
1241 
1242 	r_clip_verts[0][0][3] = 0;
1243 	r_clip_verts[0][1][3] = 0;
1244 	r_clip_verts[0][2][3] = 0;
1245 	r_clip_verts[0][3][3] = 0;
1246 
1247 	r_clip_verts[0][0][4] = 0;
1248 	r_clip_verts[0][1][4] = 0;
1249 	r_clip_verts[0][2][4] = 0;
1250 	r_clip_verts[0][3][4] = 0;
1251 
1252 	VectorSubtract( d, c, s0 );
1253 	VectorSubtract( c, b, s1 );
1254 	CrossProduct( s0, s1, r_polydesc.vpn );
1255 	VectorNormalize( r_polydesc.vpn );
1256 
1257 	r_polydesc.dist = DotProduct( r_polydesc.vpn, r_clip_verts[0][0] );
1258 
1259 	r_polyblendcolor = color;
1260 
1261 	R_ClipAndDrawPoly( alpha, false, false );
1262 }
1263 
1264