]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_poly.c
Gigantic commit - dlight system rewritten
[divverent/darkplaces.git] / gl_poly.c
1 #include "quakedef.h"
2
3 transvert_t *transvert;
4 transpoly_t *transpoly;
5 unsigned short *transpolyindex;
6 wallvert_t *wallvert;
7 wallpoly_t *wallpoly;
8 skyvert_t *skyvert;
9 skypoly_t *skypoly;
10
11 unsigned short currenttranspoly;
12 unsigned short currenttransvert;
13 unsigned short currentwallpoly;
14 unsigned short currentwallvert;
15 unsigned short currentskypoly;
16 unsigned short currentskyvert;
17
18 cvar_t gl_multitexture = {"gl_multitexture", "1"};
19 cvar_t gl_vertexarrays = {"gl_vertexarrays", "1"};
20
21 typedef struct translistitem_s
22 {
23         transpoly_t *poly;
24         struct translistitem_s *next;
25 }
26 translistitem;
27
28 translistitem translist[MAX_TRANSPOLYS];
29 translistitem *currenttranslist;
30
31 translistitem *translisthash[4096];
32
33 float transviewdist; // distance of view origin along the view normal
34
35 float transreciptable[256];
36
37 void glpoly_init()
38 {
39         int i;
40         Cvar_RegisterVariable (&gl_multitexture);
41         Cvar_RegisterVariable (&gl_vertexarrays);
42         transvert = malloc(MAX_TRANSVERTS * sizeof(transvert_t));
43         transpoly = malloc(MAX_TRANSPOLYS * sizeof(transpoly_t));
44         transpolyindex = malloc(MAX_TRANSPOLYS * sizeof(unsigned short));
45         wallvert = malloc(MAX_WALLVERTS * sizeof(wallvert_t));
46         wallpoly = malloc(MAX_WALLPOLYS * sizeof(wallpoly_t));
47         skyvert = malloc(MAX_SKYVERTS * sizeof(skyvert_t));
48         skypoly = malloc(MAX_SKYPOLYS * sizeof(skypoly_t));
49         transreciptable[0] = 0.0f;
50         for (i = 1;i < 256;i++)
51                 transreciptable[i] = 1.0f / i;
52 }
53
54 void transpolyclear()
55 {
56         currenttranspoly = currenttransvert = 0;
57         currenttranslist = translist;
58         memset(translisthash, 0, sizeof(translisthash));
59         transviewdist = DotProduct(r_refdef.vieworg, vpn);
60 }
61
62 void transpolybegin(int texnum, int glowtexnum, int fogtexnum, int transpolytype)
63 {
64         if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
65                 return;
66         transpoly[currenttranspoly].texnum = (unsigned short) texnum;
67         transpoly[currenttranspoly].glowtexnum = (unsigned short) glowtexnum;
68         transpoly[currenttranspoly].fogtexnum = (unsigned short) fogtexnum;
69         transpoly[currenttranspoly].transpolytype = (unsigned short) transpolytype;
70         transpoly[currenttranspoly].firstvert = currenttransvert;
71         transpoly[currenttranspoly].verts = 0;
72 //      transpoly[currenttranspoly].ndist = 0; // clear the normal
73 }
74
75 // turned into a #define
76 /*
77 void transpolyvert(float x, float y, float z, float s, float t, int r, int g, int b, int a)
78 {
79         int i;
80         if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
81                 return;
82         transvert[currenttransvert].s = s;
83         transvert[currenttransvert].t = t;
84         transvert[currenttransvert].r = bound(0, r, 255);
85         transvert[currenttransvert].g = bound(0, g, 255);
86         transvert[currenttransvert].b = bound(0, b, 255);
87         transvert[currenttransvert].a = bound(0, a, 255);
88         transvert[currenttransvert].v[0] = x;
89         transvert[currenttransvert].v[1] = y;
90         transvert[currenttransvert].v[2] = z;
91         currenttransvert++;
92         transpoly[currenttranspoly].verts++;
93 }
94 */
95
96 void transpolyend()
97 {
98         float center, d, maxdist;
99         int i;
100         transvert_t *v;
101         if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
102                 return;
103         if (transpoly[currenttranspoly].verts < 3) // skip invalid polygons
104         {
105                 currenttransvert = transpoly[currenttranspoly].firstvert; // reset vert pointer
106                 return;
107         }
108         center = 0;
109         maxdist = -1000000000000000.0f; // eh, it's definitely behind it, so...
110         for (i = 0,v = &transvert[transpoly[currenttranspoly].firstvert];i < transpoly[currenttranspoly].verts;i++, v++)
111         {
112                 d = DotProduct(v->v, vpn);
113                 center += d;
114                 if (d > maxdist)
115                         maxdist = d;
116         }
117         maxdist -= transviewdist;
118         if (maxdist < 4.0f) // behind view
119         {
120                 currenttransvert = transpoly[currenttranspoly].firstvert; // reset vert pointer
121                 return;
122         }
123         center *= transreciptable[transpoly[currenttranspoly].verts];
124         center -= transviewdist;
125         i = bound(0, (int) center, 4095);
126         currenttranslist->next = translisthash[i];
127         currenttranslist->poly = transpoly + currenttranspoly;
128         translisthash[i] = currenttranslist;
129         currenttranslist++;
130         currenttranspoly++;
131 }
132
133 int transpolyindices;
134 extern qboolean isG200;
135
136 /*
137 void transpolyrenderminmax()
138 {
139         int i, j, k, lastvert;
140         vec_t d, min, max, viewdist, s, average;
141         //vec_t ndist;
142         //vec3_t v1, v2, n;
143         transpolyindices = 0;
144         viewdist = DotProduct(r_refdef.vieworg, vpn);
145         for (i = 0;i < currenttranspoly;i++)
146         {
147                 if (transpoly[i].verts < 3) // only process valid polygons
148                         continue;
149                 min = 1000000;max = -1000000;
150                 s = 1.0f / transpoly[i].verts;
151                 lastvert = transpoly[i].firstvert + transpoly[i].verts;
152                 average = 0;
153                 for (j = transpoly[i].firstvert;j < lastvert;j++)
154                 {
155                         d = DotProduct(transvert[j].v, vpn)-viewdist;
156                         if (d < min) min = d;
157                         if (d > max) max = d;
158                         average += d * s;
159                 }
160                 if (max < 4) // free to check here, so skip polys behind the view
161                         continue;
162                 transpoly[i].distance = average;
163 */
164                 /*
165                 transpoly[i].mindistance = min;
166                 transpoly[i].maxdistance = max;
167                 // calculate normal (eek)
168                 VectorSubtract(transvert[transpoly[i].firstvert  ].v, transvert[transpoly[i].firstvert+1].v, v1);
169                 VectorSubtract(transvert[transpoly[i].firstvert+2].v, transvert[transpoly[i].firstvert+1].v, v2);
170                 VectorNormalize(v1);
171                 VectorNormalize(v2);
172                 if (transpoly[i].verts > 3 && fabs(DotProduct(v1, v2)) >= (1.0f - (1.0f / 256.0f))) // colinear edges, find a better triple
173                 {
174                         VectorSubtract(transvert[transpoly[i].firstvert + transpoly[i].verts - 1].v, transvert[transpoly[i].firstvert].v, v1);
175                         VectorSubtract(transvert[transpoly[i].firstvert + 1].v, transvert[transpoly[i].firstvert].v, v2);
176                         VectorNormalize(v1);
177                         VectorNormalize(v2);
178                         if (fabs(DotProduct(v1, v2)) < (1.0f - (1.0f / 256.0f))) // found a good triple
179                                 goto foundtriple;
180                         for (k = transpoly[i].firstvert + 2;k < (transpoly[i].firstvert + transpoly[i].verts - 1);k++)
181                         {
182                                 VectorSubtract(transvert[k-1].v, transvert[k].v, v1);
183                                 VectorSubtract(transvert[k+1].v, transvert[k].v, v2);
184                                 VectorNormalize(v1);
185                                 VectorNormalize(v2);
186                                 if (fabs(DotProduct(v1, v2)) < (1.0f - (1.0f / 256.0f))) // found a good triple
187                                         goto foundtriple;
188                         }
189                         VectorSubtract(transvert[k-1].v, transvert[k].v, v1);
190                         VectorSubtract(transvert[transpoly[i].firstvert].v, transvert[k].v, v2);
191                         VectorNormalize(v1);
192                         VectorNormalize(v2);
193                         if (fabs(DotProduct(v1, v2)) >= (1.0f - (1.0f / 256.0f))) // no good triples; the polygon is a line, skip it
194                                 continue;
195                 }
196 foundtriple:
197                 CrossProduct(v1, v2, n);
198                 VectorNormalize(n);
199                 ndist = DotProduct(transvert[transpoly[i].firstvert+1].v, n);
200                 // sorted insert
201                 for (j = 0;j < transpolyindices;j++)
202                 {
203                         // easy cases
204                         if (transpoly[transpolyindex[j]].mindistance > max)
205                                 continue;
206                         if (transpoly[transpolyindex[j]].maxdistance < min)
207                                 break;
208                         // hard case, check side
209                         for (k = transpoly[transpolyindex[j]].firstvert;k < (transpoly[transpolyindex[j]].firstvert + transpoly[transpolyindex[j]].verts);k++)
210                                 if (DotProduct(transvert[k].v, n) < ndist)
211                                         goto skip;
212                         break;
213 skip:
214                         ;
215                 }
216                 */
217 /*
218                 // sorted insert
219                 for (j = 0;j < transpolyindices;j++)
220                         if (transpoly[transpolyindex[j]].distance < average)
221                                 break;
222                 for (k = transpolyindices;k > j;k--)
223                         transpolyindex[k] = transpolyindex[k-1];
224                 transpolyindices++;
225                 transpolyindex[j] = i;
226         }
227 }
228 */
229 /*
230 // LordHavoc: qsort compare function
231 int transpolyqsort(const void *ia, const void *ib)
232 {
233         transpoly_t *a, *b;
234         int i, j;
235         a = &transpoly[*((unsigned short *)ia)];
236         b = &transpoly[*((unsigned short *)ib)];
237         // easy cases
238         if (a->mindistance > b->mindistance && a->maxdistance > b->maxdistance)
239                 return -1; // behind
240         if (a->mindistance < b->mindistance && a->maxdistance < b->maxdistance)
241                 return 1; // infront
242         // hard case
243         if (!a->ndist)
244         {
245                 // calculate normal (eek)
246                 vec3_t v1, v2;
247                 VectorSubtract(transvert[a->firstvert  ].v, transvert[a->firstvert+1].v, v1);
248                 VectorSubtract(transvert[a->firstvert+2].v, transvert[a->firstvert+1].v, v2);
249                 CrossProduct(v1, v2, a->n);
250                 VectorNormalize(a->n);
251                 a->ndist = DotProduct(transvert[a->firstvert  ].v, a->n);
252         }
253         // check side
254         for (i = b->firstvert, j = 0;i < (b->firstvert + b->verts);i++)
255                 j += DotProduct(transvert[i].v, a->n) < a->ndist; // (1) b is infront of a
256         if (j == 0)
257                 return -1; // (-1) a is behind b
258         return j == b->verts; // (1) a is infront of b    (0) a and b intersect
259 //      return (transpoly[*((unsigned short *)ib)].mindistance + transpoly[*((unsigned short *)ib)].maxdistance) - (transpoly[*((unsigned short *)ia)].mindistance + transpoly[*((unsigned short *)ia)].maxdistance);
260         */
261 /*
262         return ((transpoly_t*)ia)->distance - ((transpoly_t*)ib)->distance;
263 }
264 */
265
266 /*
267 int transpolyqsort(const void *ia, const void *ib)
268 {
269         return (transpoly[*((unsigned short *)ib)].distance - transpoly[*((unsigned short *)ia)].distance);
270 }
271 */
272
273 /*
274 void transpolyrenderminmax()
275 {
276         int i, j, lastvert;
277         vec_t d, max, viewdist, average;
278         transpolyindices = 0;
279         viewdist = DotProduct(r_refdef.vieworg, vpn);
280         for (i = 0;i < currenttranspoly;i++)
281         {
282                 if (transpoly[i].verts < 3) // only process valid polygons
283                         continue;
284                 max = -1000000;
285                 lastvert = transpoly[i].firstvert + transpoly[i].verts;
286                 average = 0;
287                 for (j = transpoly[i].firstvert;j < lastvert;j++)
288                 {
289                         d = DotProduct(transvert[j].v, vpn)-viewdist;
290                         average += d;
291                         if (d > max)
292                                 max = d;
293                 }
294                 if (max < 4) // free to check here, so skip polys behind the view
295                         continue;
296                 transpoly[i].distance = average / transpoly[i].verts;
297                 transpolyindex[transpolyindices++] = i;
298         }
299         qsort(&transpolyindex[0], transpolyindices, sizeof(unsigned short), transpolyqsort);
300 }
301 */
302 /*
303         int i, j, a;
304         a = true;
305         while(a)
306         {
307                 a = false;
308                 for (i = 1;i < transpolyindices;i++)
309                 {
310                         // easy cases
311                         if (transpoly[transpolyindex[i - 1]].mindistance > transpoly[transpolyindex[i]].mindistance && transpoly[transpolyindex[i - 1]].maxdistance > transpoly[transpolyindex[i]].maxdistance)
312                                 continue; // previous is behind (no swap)
313                         if (transpoly[transpolyindex[i - 1]].mindistance < transpoly[transpolyindex[i]].mindistance && transpoly[transpolyindex[i - 1]].maxdistance < transpoly[transpolyindex[i]].maxdistance)
314                                 goto swap; // previous is infront (swap)
315                         // hard case
316 */
317                         /*
318                         if (!transpoly[transpolyindex[i - 1]].ndist)
319                         {
320                                 // calculate normal (eek)
321                                 vec3_t v1, v2;
322                                 VectorSubtract(transvert[transpoly[transpolyindex[i - 1]].firstvert  ].v, transvert[transpoly[transpolyindex[i - 1]].firstvert+1].v, v1);
323                                 VectorSubtract(transvert[transpoly[transpolyindex[i - 1]].firstvert+2].v, transvert[transpoly[transpolyindex[i - 1]].firstvert+1].v, v2);
324                                 CrossProduct(v1, v2, transpoly[transpolyindex[i - 1]].n);
325                                 VectorNormalize(transpoly[transpolyindex[i - 1]].n);
326                                 transpoly[transpolyindex[i - 1]].ndist = DotProduct(transvert[transpoly[transpolyindex[i - 1]].firstvert  ].v, transpoly[transpolyindex[i - 1]].n);
327                         }
328                         if (DotProduct(transpoly[transpolyindex[i - 1]].n, vpn) >= 0.0f) // backface
329                                 continue;
330                         */
331 /*
332                         // check side
333                         for (i = transpoly[transpolyindex[i]].firstvert;i < (transpoly[transpolyindex[i]].firstvert + transpoly[transpolyindex[i]].verts);i++)
334                                 if (DotProduct(transvert[i].v, transpoly[transpolyindex[i - 1]].n) >= transpoly[transpolyindex[i - 1]].ndist)
335                                         goto noswap; // previous is behind or they intersect
336 swap:
337                         // previous is infront (swap)
338                         j = transpolyindex[i];
339                         transpolyindex[i] = transpolyindex[i - 1];
340                         transpolyindex[i - 1] = j;
341                         a = true;
342 noswap:
343                         ;
344                 }
345         }
346 }
347 */
348
349 void transpolyrender()
350 {
351         int i, j, tpolytype, texnum;
352         transpoly_t *p;
353         if (currenttranspoly < 1)
354                 return;
355 //      transpolyrenderminmax();
356 //      if (transpolyindices < 1)
357 //              return;
358         // testing
359 //      Con_DPrintf("transpolyrender: %i polys %i infront %i vertices\n", currenttranspoly, transpolyindices, currenttransvert);
360 //      if (transpolyindices >= 2)
361 //              transpolysort();
362         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
363         glEnable(GL_BLEND);
364         glShadeModel(GL_SMOOTH);
365         glDepthMask(0); // disable zbuffer updates
366         if (isG200) // Matrox G200 cards can't handle per pixel alpha
367                 glEnable(GL_ALPHA_TEST);
368         else
369                 glDisable(GL_ALPHA_TEST);
370         // later note: wasn't working on my TNT drivers...  strangely...  used a cheaper hack in transpolyvert
371         //// offset by 16 depth units so decal sprites appear infront of walls
372         //glPolygonOffset(1, -16);
373         //glEnable(GL_POLYGON_OFFSET_FILL);
374         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
375         tpolytype = TPOLYTYPE_ALPHA;
376         texnum = -1;
377         /*
378         if (gl_vertexarrays.value)
379         {
380                 // set up the vertex array
381                 qglInterleavedArrays(GL_T2F_C4UB_V3F, 0, transvert);
382                 for (i = 0;i < transpolyindices;i++)
383                 {
384                         p = &transpoly[transpolyindex[i]];
385                         if (p->texnum != texnum || p->transpolytype != tpolytype)
386                         {
387                                 if (p->texnum != texnum)
388                                 {
389                                         texnum = p->texnum;
390                                         glBindTexture(GL_TEXTURE_2D, texnum);
391                                 }
392                                 if (p->transpolytype != tpolytype)
393                                 {
394                                         tpolytype = p->transpolytype;
395                                         if (tpolytype == TPOLYTYPE_ADD) // additive
396                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
397                                         else // alpha
398                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
399                                 }
400                         }
401                         qglDrawArrays(GL_TRIANGLE_FAN, p->firstvert, p->verts);
402                         if (p->glowtexnum)
403                         {
404                                 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
405                                 glBindTexture(GL_TEXTURE_2D, texnum);
406                                 tpolytype = TPOLYTYPE_ADD; // might match next poly
407                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
408                                 qglDrawArrays(GL_TRIANGLE_FAN, p->firstvert, p->verts);
409                         }
410                 }
411                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
412                 glDisableClientState(GL_COLOR_ARRAY);
413                 glDisableClientState(GL_VERTEX_ARRAY);
414         }
415         else
416         */
417         {
418                 int points = -1;
419                 translistitem *item;
420                 transvert_t *vert;
421                 for (i = 4095;i >= 0;i--)
422                 {
423                         item = translisthash[i];
424                         while (item)
425                         {
426                                 p = item->poly;
427                                 item = item->next;
428                                 if (p->texnum != texnum || p->verts != points || p->transpolytype != tpolytype)
429                                 {
430                                         glEnd();
431                                         if (isG200)
432                                         {
433                                                 if (p->fogtexnum) // alpha
434                                                         glEnable(GL_ALPHA_TEST);
435                                                 else
436                                                         glDisable(GL_ALPHA_TEST);
437                                         }
438                                         if (p->texnum != texnum)
439                                         {
440                                                 texnum = p->texnum;
441                                                 glBindTexture(GL_TEXTURE_2D, texnum);
442                                         }
443                                         if (p->transpolytype != tpolytype)
444                                         {
445                                                 tpolytype = p->transpolytype;
446                                                 if (tpolytype == TPOLYTYPE_ADD) // additive
447                                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
448                                                 else // alpha
449                                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
450                                         }
451                                         points = p->verts;
452                                         switch (points)
453                                         {
454                                         case 3:
455                                                 glBegin(GL_TRIANGLES);
456                                                 break;
457                                         case 4:
458                                                 glBegin(GL_QUADS);
459                                                 break;
460                                         default:
461                                                 glBegin(GL_TRIANGLE_FAN);
462                                                 points = -1; // to force a reinit on the next poly
463                                                 break;
464                                         }
465                                 }
466                                 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
467                                 {
468                                         // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
469                                         glTexCoord2f(vert->s, vert->t);
470                                         // again, vector version isn't supported I think
471                                         glColor4ub(vert->r, vert->g, vert->b, vert->a);
472                                         glVertex3fv(vert->v);
473                                 }
474                                 if (p->glowtexnum)
475                                 {
476                                         glEnd();
477                                         texnum = p->glowtexnum; // highly unlikely to match next poly, but...
478                                         glBindTexture(GL_TEXTURE_2D, texnum);
479                                         if (tpolytype != TPOLYTYPE_ADD)
480                                         {
481                                                 tpolytype = TPOLYTYPE_ADD; // might match next poly
482                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
483                                         }
484                                         points = -1;
485                                         glBegin(GL_TRIANGLE_FAN);
486                                         for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
487                                         {
488                                                 glColor4ub(255,255,255,vert->a);
489                                                 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
490                                                 glTexCoord2f(vert->s, vert->t);
491                                                 glVertex3fv(vert->v);
492                                         }
493                                         glEnd();
494                                 }
495                                 if (fogenabled && p->transpolytype == TPOLYTYPE_ALPHA)
496                                 {
497                                         vec3_t diff;
498                                         glEnd();
499                                         points = -1; // to force a reinit on the next poly
500                                         if (tpolytype != TPOLYTYPE_ALPHA)
501                                         {
502                                                 tpolytype = TPOLYTYPE_ALPHA; // probably matchs next poly
503                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
504                                         }
505                                         if (p->fogtexnum)
506                                         {
507                                                 if (texnum != p->fogtexnum) // highly unlikely to match next poly, but...
508                                                 {
509                                                         texnum = p->fogtexnum;
510                                                         glBindTexture(GL_TEXTURE_2D, texnum);
511                                                 }
512                                                 glBegin(GL_TRIANGLE_FAN);
513                                                 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
514                                                 {
515                                                         VectorSubtract(vert->v, r_refdef.vieworg,diff);
516                                                         glTexCoord2f(vert->s, vert->t);
517                                                         glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
518                                                         glVertex3fv(vert->v);
519                                                 }
520                                                 glEnd ();
521                                         }
522                                         else
523                                         {
524                                                 glDisable(GL_TEXTURE_2D);
525                                                 glBegin(GL_TRIANGLE_FAN);
526                                                 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
527                                                 {
528                                                         VectorSubtract(vert->v, r_refdef.vieworg,diff);
529                                                         glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
530                                                         glVertex3fv(vert->v);
531                                                 }
532                                                 glEnd ();
533                                                 glEnable(GL_TEXTURE_2D);
534                                         }
535                                 }
536                         }
537                 }
538                 glEnd();
539         }
540
541         //glDisable(GL_POLYGON_OFFSET_FILL);
542         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
543         glDepthMask(1); // enable zbuffer updates
544         glDisable(GL_ALPHA_TEST);
545 }
546
547 /*
548 void lightpolybegin(int texnum)
549 {
550         if (currentlightpoly >= MAX_LIGHTPOLYS || currentlightvert >= MAX_LIGHTVERTS)
551                 return;
552         lightpoly[currentlightpoly].texnum = (unsigned short) texnum;
553         lightpoly[currentlightpoly].firstvert = currentlightvert;
554         lightpoly[currentlightpoly].verts = 0;
555 }
556
557 // lightpolyvert is a #define
558
559 void lightpolyend()
560 {
561         if (currentlightpoly >= MAX_LIGHTPOLYS)
562                 return;
563         if (lightpoly[currentlightpoly].verts < 3) // skip invalid polygons
564         {
565                 currentlightvert = lightpoly[currentlightpoly].firstvert; // reset vert pointer
566                 return;
567         }
568         if (currentlightvert >= MAX_LIGHTVERTS)
569                 return;
570         currentlightpoly++;
571 }
572 */
573
574 extern qboolean isG200;
575
576 void wallpolyclear()
577 {
578         currentwallpoly = currentwallvert = 0;
579 }
580
581 extern qboolean lighthalf;
582 void wallpolyrender()
583 {
584         int i, j, texnum, lighttexnum;
585         wallpoly_t *p;
586         wallvert_t *vert;
587         if (currentwallpoly < 1)
588                 return;
589         c_brush_polys += currentwallpoly;
590         // testing
591         //Con_DPrintf("wallpolyrender: %i polys %i vertices\n", currentwallpoly, currentwallvert);
592         if (!gl_mtexable)
593                 gl_multitexture.value = 0;
594         glDisable(GL_BLEND);
595         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
596         glShadeModel(GL_FLAT);
597         // make sure zbuffer is enabled
598         glEnable(GL_DEPTH_TEST);
599         glDisable(GL_ALPHA_TEST);
600         glDepthMask(1);
601         glColor3f(1,1,1);
602         if (r_fullbright.value) // LordHavoc: easy to do fullbright...
603         {
604                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
605                 texnum = -1;
606                 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
607                 {
608                         if (p->texnum != texnum)
609                         {
610                                 texnum = p->texnum;
611                                 glBindTexture(GL_TEXTURE_2D, texnum);
612                         }
613                         vert = &wallvert[p->firstvert];
614                         glBegin(GL_POLYGON);
615                         for (j=0 ; j<p->numverts ; j++, vert++)
616                         {
617                                 glTexCoord2f (vert->s, vert->t);
618                                 glVertex3fv (vert->vert);
619                         }
620                         glEnd ();
621                 }
622         }
623         else if (gl_multitexture.value)
624         {
625                 qglSelectTexture(gl_mtex_enum+0);
626                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
627                 glEnable(GL_TEXTURE_2D);
628                 qglSelectTexture(gl_mtex_enum+1);
629                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
630                 glEnable(GL_TEXTURE_2D);
631                 texnum = -1;
632                 lighttexnum = -1;
633                 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
634                 {
635                         if (p->texnum != texnum || p->lighttexnum != lighttexnum)
636                         {
637                                 texnum = p->texnum;
638                                 lighttexnum = p->lighttexnum;
639                                 qglSelectTexture(gl_mtex_enum+0);
640                                 glBindTexture(GL_TEXTURE_2D, texnum);
641                                 qglSelectTexture(gl_mtex_enum+1);
642                                 glBindTexture(GL_TEXTURE_2D, lighttexnum);
643                         }
644                         vert = &wallvert[p->firstvert];
645                         glBegin(GL_POLYGON);
646                         for (j=0 ; j<p->numverts ; j++, vert++)
647                         {
648                                 qglMTexCoord2f(gl_mtex_enum, vert->s, vert->t); // texture
649                                 qglMTexCoord2f((gl_mtex_enum+1), vert->u, vert->v); // lightmap
650                                 glVertex3fv (vert->vert);
651                         }
652                         glEnd ();
653                 }
654
655                 qglSelectTexture(gl_mtex_enum+1);
656                 glDisable(GL_TEXTURE_2D);
657                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
658                 qglSelectTexture(gl_mtex_enum+0);
659                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
660         }
661         else
662         {
663                 // first do the textures
664                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
665                 texnum = -1;
666                 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
667                 {
668                         if (p->texnum != texnum)
669                         {
670                                 texnum = p->texnum;
671                                 glBindTexture(GL_TEXTURE_2D, texnum);
672                         }
673                         vert = &wallvert[p->firstvert];
674                         glBegin(GL_POLYGON);
675                         for (j=0 ; j<p->numverts ; j++, vert++)
676                         {
677                                 glTexCoord2f (vert->s, vert->t);
678                                 glVertex3fv (vert->vert);
679                         }
680                         glEnd ();
681                 }
682                 // then modulate using the lightmaps
683                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
684                 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
685                 glEnable(GL_BLEND);
686                 texnum = -1;
687                 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
688                 {
689                         if (p->lighttexnum != texnum)
690                         {
691                                 texnum = p->lighttexnum;
692                                 glBindTexture(GL_TEXTURE_2D, texnum);
693                         }
694                         vert = &wallvert[p->firstvert];
695                         glBegin(GL_POLYGON);
696                         for (j=0 ; j<p->numverts ; j++, vert++)
697                         {
698                                 glTexCoord2f (vert->u, vert->v);
699                                 glVertex3fv (vert->vert);
700                         }
701                         glEnd ();
702                 }
703         }
704         // switch to additive mode settings
705         glDepthMask(0);
706         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
707         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
708         glEnable(GL_BLEND);
709         glDisable(GL_ALPHA_TEST);
710         glShadeModel(GL_SMOOTH);
711         // render vertex lit overlays ontop
712         texnum = -1;
713         for (i = 0, p = wallpoly;i < currentwallpoly;i++, p++)
714         {
715                 if (!p->lit)
716                         continue;
717                 for (j = 0,vert = &wallvert[p->firstvert];j < p->numverts;j++, vert++)
718                         if (vert->r || vert->g || vert->b)
719                                 goto lit;
720                 continue;
721 lit:
722                 c_light_polys++;
723                 if (p->texnum != texnum)
724                 {
725                         texnum = p->texnum;
726                         glBindTexture(GL_TEXTURE_2D, texnum);
727                 }
728                 glBegin(GL_POLYGON);
729                 for (j = 0,vert = &wallvert[p->firstvert];j < p->numverts;j++, vert++)
730                 {
731                         // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
732                         glTexCoord2f(vert->s, vert->t);
733                         // again, vector version isn't supported I think
734                         glColor3ub(vert->r, vert->g, vert->b);
735                         glVertex3fv(vert->vert);
736                 }
737                 glEnd();
738         }
739         // render glow textures
740         glShadeModel(GL_FLAT);
741         glBlendFunc(GL_ONE, GL_ONE);
742         if (lighthalf)
743                 glColor3f(0.5,0.5,0.5);
744         else
745                 glColor3f(1,1,1);
746         texnum = -1;
747         for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
748         {
749                 if (!p->glowtexnum)
750                         continue;
751                 if (p->glowtexnum != texnum)
752                 {
753                         texnum = p->glowtexnum;
754                         glBindTexture(GL_TEXTURE_2D, texnum);
755                 }
756                 vert = &wallvert[p->firstvert];
757                 glBegin(GL_POLYGON);
758                 for (j=0 ; j<p->numverts ; j++, vert++)
759                 {
760                         glTexCoord2f (vert->s, vert->t);
761                         glVertex3fv (vert->vert);
762                 }
763                 glEnd();
764         }
765         glColor3f(1,1,1);
766         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
767         glShadeModel(GL_SMOOTH);
768         if (fogenabled)
769         {
770                 vec3_t diff;
771                 glDisable(GL_TEXTURE_2D);
772                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
773                 {
774                         vert = &wallvert[p->firstvert];
775                         glBegin(GL_POLYGON);
776                         for (j=0 ; j<p->numverts ; j++, vert++)
777                         {
778                                 VectorSubtract(vert->vert, r_refdef.vieworg,diff);
779                                 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
780                                 glVertex3fv (vert->vert);
781                         }
782                         glEnd ();
783                 }
784                 glEnable(GL_TEXTURE_2D);
785         }
786         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
787         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
788         glDisable(GL_ALPHA_TEST);
789         glShadeModel(GL_SMOOTH);
790         glDisable(GL_BLEND);
791         glDepthMask(1);
792 }
793
794 void skypolyclear()
795 {
796         currentskypoly = currentskyvert = 0;
797 }
798
799 extern qboolean isATI;
800
801 extern char skyname[];
802 extern int solidskytexture, alphaskytexture;
803 void skypolyrender()
804 {
805         int i, j;
806         skypoly_t *p;
807         skyvert_t *vert;
808         float length, speedscale;
809         vec3_t dir;
810         if (currentskypoly < 1)
811                 return;
812         // testing
813 //      Con_DPrintf("skypolyrender: %i polys %i vertices\n", currentskypoly, currentskyvert);
814         glDisable(GL_ALPHA_TEST);
815         glDisable(GL_BLEND);
816         // make sure zbuffer is enabled
817         glEnable(GL_DEPTH_TEST);
818         glDepthMask(1);
819         if (!fogenabled && !skyname[0]) // normal quake sky
820         {
821                 glColor3f(0.5f, 0.5f, 0.5f);
822                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
823                 glEnable(GL_TEXTURE_2D);
824                 glDisable(GL_BLEND);
825                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
826                 glBindTexture(GL_TEXTURE_2D, solidskytexture); // upper clouds
827                 speedscale = realtime*8;
828                 speedscale -= (int)speedscale & ~127 ;
829                 for (i = 0,p = &skypoly[0];i < currentskypoly;i++, p++)
830                 {
831                         vert = &skyvert[p->firstvert];
832                         glBegin(GL_POLYGON);
833                         for (j=0 ; j<p->verts ; j++, vert++)
834                         {
835                                 VectorSubtract (vert->v, r_origin, dir);
836                                 dir[2] *= 3;    // flatten the sphere
837
838                                 length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];
839                                 length = sqrt (length);
840                                 length = 6*63/length;
841
842                                 glTexCoord2f ((speedscale + dir[0] * length) * (1.0/128), (speedscale + dir[1] * length) * (1.0/128));
843                                 glVertex3fv (vert->v);
844                         }
845                         glEnd ();
846                 }
847                 glEnable(GL_BLEND);
848                 glDepthMask(0);
849                 glBindTexture(GL_TEXTURE_2D, alphaskytexture); // lower clouds
850                 speedscale = realtime*16;
851                 speedscale -= (int)speedscale & ~127 ;
852                 for (i = 0,p = &skypoly[0];i < currentskypoly;i++, p++)
853                 {
854                         vert = &skyvert[p->firstvert];
855                         glBegin(GL_POLYGON);
856                         for (j=0 ; j<p->verts ; j++, vert++)
857                         {
858                                 VectorSubtract (vert->v, r_origin, dir);
859                                 dir[2] *= 3;    // flatten the sphere
860
861                                 length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];
862                                 length = sqrt (length);
863                                 length = 6*63/length;
864
865                                 glTexCoord2f ((speedscale + dir[0] * length) * (1.0/128), (speedscale + dir[1] * length) * (1.0/128));
866                                 glVertex3fv (vert->v);
867                         }
868                         glEnd ();
869                 }
870                 glDisable(GL_BLEND);
871                 glColor3f(1,1,1);
872                 glDepthMask(1);
873         }
874         else
875         {
876                 glDisable(GL_TEXTURE_2D);
877                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
878                 glColor3fv(fogcolor); // note: gets rendered over by skybox if fog is not enabled
879                 for (i = 0,p = &skypoly[0];i < currentskypoly;i++, p++)
880                 {
881                         vert = &skyvert[p->firstvert];
882                         glBegin(GL_POLYGON);
883                         for (j=0 ; j<p->verts ; j++, vert++)
884                                 glVertex3fv (vert->v);
885                         glEnd ();
886                 }
887                 glColor3f(1,1,1);
888                 glEnable(GL_TEXTURE_2D);
889         }
890 }