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