]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_poly.c
08af798dc1bee321910c9be667e8b65b70c9d673
[xonotic/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 void glpoly_init()
22 {
23         Cvar_RegisterVariable (&gl_multitexture);
24         Cvar_RegisterVariable (&gl_vertexarrays);
25         transvert = malloc(MAX_TRANSVERTS * sizeof(transvert_t));
26         transpoly = malloc(MAX_TRANSPOLYS * sizeof(transpoly_t));
27         transpolyindex = malloc(MAX_TRANSPOLYS * sizeof(unsigned short));
28         wallvert = malloc(MAX_WALLVERTS * sizeof(wallvert_t));
29         wallpoly = malloc(MAX_WALLPOLYS * sizeof(wallpoly_t));
30         skyvert = malloc(MAX_SKYVERTS * sizeof(skyvert_t));
31         skypoly = malloc(MAX_SKYPOLYS * sizeof(skypoly_t));
32 }
33
34 void transpolyclear()
35 {
36         currenttranspoly = currenttransvert = 0;
37 }
38
39 void transpolybegin(int texnum, int glowtexnum, int fogtexnum, int transpolytype)
40 {
41         if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
42                 return;
43         transpoly[currenttranspoly].texnum = (unsigned short) texnum;
44         transpoly[currenttranspoly].glowtexnum = (unsigned short) glowtexnum;
45         transpoly[currenttranspoly].fogtexnum = (unsigned short) fogtexnum;
46         transpoly[currenttranspoly].transpolytype = (unsigned short) transpolytype;
47         transpoly[currenttranspoly].firstvert = currenttransvert;
48         transpoly[currenttranspoly].verts = 0;
49 //      transpoly[currenttranspoly].ndist = 0; // clear the normal
50 }
51
52 // turned into a #define
53 /*
54 void transpolyvert(float x, float y, float z, float s, float t, int r, int g, int b, int a)
55 {
56         int i;
57         if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
58                 return;
59         transvert[currenttransvert].s = s;
60         transvert[currenttransvert].t = t;
61         transvert[currenttransvert].r = bound(0, r, 255);
62         transvert[currenttransvert].g = bound(0, g, 255);
63         transvert[currenttransvert].b = bound(0, b, 255);
64         transvert[currenttransvert].a = bound(0, a, 255);
65         transvert[currenttransvert].v[0] = x;
66         transvert[currenttransvert].v[1] = y;
67         transvert[currenttransvert].v[2] = z;
68         currenttransvert++;
69         transpoly[currenttranspoly].verts++;
70 }
71 */
72
73 void transpolyend()
74 {
75         if (currenttranspoly >= MAX_TRANSPOLYS)
76                 return;
77         if (transpoly[currenttranspoly].verts < 3) // skip invalid polygons
78         {
79                 currenttransvert = transpoly[currenttranspoly].firstvert; // reset vert pointer
80                 return;
81         }
82         if (currenttransvert >= MAX_TRANSVERTS)
83                 return;
84         currenttranspoly++;
85 }
86
87 int transpolyindices;
88 void transpolyrenderminmax()
89 {
90         int i, j, k, lastvert;
91         vec_t d, min, max, viewdist, s, average;
92         //vec_t ndist;
93         //vec3_t v1, v2, n;
94         transpolyindices = 0;
95         viewdist = DotProduct(r_refdef.vieworg, vpn);
96         for (i = 0;i < currenttranspoly;i++)
97         {
98                 if (transpoly[i].verts < 3) // only process valid polygons
99                         continue;
100                 min = 1000000;max = -1000000;
101                 s = 1.0f / transpoly[i].verts;
102                 lastvert = transpoly[i].firstvert + transpoly[i].verts;
103                 average = 0;
104                 for (j = transpoly[i].firstvert;j < lastvert;j++)
105                 {
106                         d = DotProduct(transvert[j].v, vpn)-viewdist;
107                         if (d < min) min = d;
108                         if (d > max) max = d;
109                         average += d * s;
110                 }
111                 if (max < 4) // free to check here, so skip polys behind the view
112                         continue;
113                 transpoly[i].distance = average;
114                 /*
115                 transpoly[i].mindistance = min;
116                 transpoly[i].maxdistance = max;
117                 // calculate normal (eek)
118                 VectorSubtract(transvert[transpoly[i].firstvert  ].v, transvert[transpoly[i].firstvert+1].v, v1);
119                 VectorSubtract(transvert[transpoly[i].firstvert+2].v, transvert[transpoly[i].firstvert+1].v, v2);
120                 VectorNormalize(v1);
121                 VectorNormalize(v2);
122                 if (transpoly[i].verts > 3 && fabs(DotProduct(v1, v2)) >= (1.0f - (1.0f / 256.0f))) // colinear edges, find a better triple
123                 {
124                         VectorSubtract(transvert[transpoly[i].firstvert + transpoly[i].verts - 1].v, transvert[transpoly[i].firstvert].v, v1);
125                         VectorSubtract(transvert[transpoly[i].firstvert + 1].v, transvert[transpoly[i].firstvert].v, v2);
126                         VectorNormalize(v1);
127                         VectorNormalize(v2);
128                         if (fabs(DotProduct(v1, v2)) < (1.0f - (1.0f / 256.0f))) // found a good triple
129                                 goto foundtriple;
130                         for (k = transpoly[i].firstvert + 2;k < (transpoly[i].firstvert + transpoly[i].verts - 1);k++)
131                         {
132                                 VectorSubtract(transvert[k-1].v, transvert[k].v, v1);
133                                 VectorSubtract(transvert[k+1].v, transvert[k].v, v2);
134                                 VectorNormalize(v1);
135                                 VectorNormalize(v2);
136                                 if (fabs(DotProduct(v1, v2)) < (1.0f - (1.0f / 256.0f))) // found a good triple
137                                         goto foundtriple;
138                         }
139                         VectorSubtract(transvert[k-1].v, transvert[k].v, v1);
140                         VectorSubtract(transvert[transpoly[i].firstvert].v, transvert[k].v, v2);
141                         VectorNormalize(v1);
142                         VectorNormalize(v2);
143                         if (fabs(DotProduct(v1, v2)) >= (1.0f - (1.0f / 256.0f))) // no good triples; the polygon is a line, skip it
144                                 continue;
145                 }
146 foundtriple:
147                 CrossProduct(v1, v2, n);
148                 VectorNormalize(n);
149                 ndist = DotProduct(transvert[transpoly[i].firstvert+1].v, n);
150                 // sorted insert
151                 for (j = 0;j < transpolyindices;j++)
152                 {
153                         // easy cases
154                         if (transpoly[transpolyindex[j]].mindistance > max)
155                                 continue;
156                         if (transpoly[transpolyindex[j]].maxdistance < min)
157                                 break;
158                         // hard case, check side
159                         for (k = transpoly[transpolyindex[j]].firstvert;k < (transpoly[transpolyindex[j]].firstvert + transpoly[transpolyindex[j]].verts);k++)
160                                 if (DotProduct(transvert[k].v, n) < ndist)
161                                         goto skip;
162                         break;
163 skip:
164                         ;
165                 }
166                 */
167                 // sorted insert
168                 for (j = 0;j < transpolyindices;j++)
169                         if (transpoly[transpolyindex[j]].distance < average)
170                                 break;
171                 for (k = transpolyindices;k > j;k--)
172                         transpolyindex[k] = transpolyindex[k-1];
173                 transpolyindices++;
174                 transpolyindex[j] = i;
175         }
176 }
177
178 // LordHavoc: qsort compare function
179 /*
180 int transpolyqsort(const void *ia, const void *ib)
181 {
182         transpoly_t *a, *b;
183         int i, j;
184         a = &transpoly[*((unsigned short *)ia)];
185         b = &transpoly[*((unsigned short *)ib)];
186         // easy cases
187         if (a->mindistance > b->mindistance && a->maxdistance > b->maxdistance)
188                 return -1; // behind
189         if (a->mindistance < b->mindistance && a->maxdistance < b->maxdistance)
190                 return 1; // infront
191         // hard case
192         if (!a->ndist)
193         {
194                 // calculate normal (eek)
195                 vec3_t v1, v2;
196                 VectorSubtract(transvert[a->firstvert  ].v, transvert[a->firstvert+1].v, v1);
197                 VectorSubtract(transvert[a->firstvert+2].v, transvert[a->firstvert+1].v, v2);
198                 CrossProduct(v1, v2, a->n);
199                 VectorNormalize(a->n);
200                 a->ndist = DotProduct(transvert[a->firstvert  ].v, a->n);
201         }
202         // check side
203         for (i = b->firstvert, j = 0;i < (b->firstvert + b->verts);i++)
204                 j += DotProduct(transvert[i].v, a->n) < a->ndist; // (1) b is infront of a
205         if (j == 0)
206                 return -1; // (-1) a is behind b
207         return j == b->verts; // (1) a is infront of b    (0) a and b intersect
208 //      return (transpoly[*((unsigned short *)ib)].mindistance + transpoly[*((unsigned short *)ib)].maxdistance) - (transpoly[*((unsigned short *)ia)].mindistance + transpoly[*((unsigned short *)ia)].maxdistance);
209 }
210 */
211
212 extern qboolean isG200;
213
214 /*
215 void transpolysort()
216 {
217         int i, j, a;
218 //      qsort(&transpolyindex[0], transpolyindices, sizeof(unsigned short), transpolyqsort);
219         a = true;
220         while(a)
221         {
222                 a = false;
223                 for (i = 1;i < transpolyindices;i++)
224                 {
225                         // easy cases
226                         if (transpoly[transpolyindex[i - 1]].mindistance > transpoly[transpolyindex[i]].mindistance && transpoly[transpolyindex[i - 1]].maxdistance > transpoly[transpolyindex[i]].maxdistance)
227                                 continue; // previous is behind (no swap)
228                         if (transpoly[transpolyindex[i - 1]].mindistance < transpoly[transpolyindex[i]].mindistance && transpoly[transpolyindex[i - 1]].maxdistance < transpoly[transpolyindex[i]].maxdistance)
229                                 goto swap; // previous is infront (swap)
230                         // hard case
231 */
232                         /*
233                         if (!transpoly[transpolyindex[i - 1]].ndist)
234                         {
235                                 // calculate normal (eek)
236                                 vec3_t v1, v2;
237                                 VectorSubtract(transvert[transpoly[transpolyindex[i - 1]].firstvert  ].v, transvert[transpoly[transpolyindex[i - 1]].firstvert+1].v, v1);
238                                 VectorSubtract(transvert[transpoly[transpolyindex[i - 1]].firstvert+2].v, transvert[transpoly[transpolyindex[i - 1]].firstvert+1].v, v2);
239                                 CrossProduct(v1, v2, transpoly[transpolyindex[i - 1]].n);
240                                 VectorNormalize(transpoly[transpolyindex[i - 1]].n);
241                                 transpoly[transpolyindex[i - 1]].ndist = DotProduct(transvert[transpoly[transpolyindex[i - 1]].firstvert  ].v, transpoly[transpolyindex[i - 1]].n);
242                         }
243                         if (DotProduct(transpoly[transpolyindex[i - 1]].n, vpn) >= 0.0f) // backface
244                                 continue;
245                         */
246 /*
247                         // check side
248                         for (i = transpoly[transpolyindex[i]].firstvert;i < (transpoly[transpolyindex[i]].firstvert + transpoly[transpolyindex[i]].verts);i++)
249                                 if (DotProduct(transvert[i].v, transpoly[transpolyindex[i - 1]].n) >= transpoly[transpolyindex[i - 1]].ndist)
250                                         goto noswap; // previous is behind or they intersect
251 swap:
252                         // previous is infront (swap)
253                         j = transpolyindex[i];
254                         transpolyindex[i] = transpolyindex[i - 1];
255                         transpolyindex[i - 1] = j;
256                         a = true;
257 noswap:
258                         ;
259                 }
260         }
261 }
262 */
263
264 void transpolyrender()
265 {
266         int i, j, tpolytype, texnum;
267         transpoly_t *p;
268         if (currenttranspoly < 1)
269                 return;
270         transpolyrenderminmax();
271         if (transpolyindices < 1)
272                 return;
273         // testing
274 //      Con_DPrintf("transpolyrender: %i polys %i infront %i vertices\n", currenttranspoly, transpolyindices, currenttransvert);
275 //      if (transpolyindices >= 2)
276 //              transpolysort();
277         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
278         glEnable(GL_BLEND);
279         glShadeModel(GL_SMOOTH);
280         glDepthMask(0); // disable zbuffer updates
281         if (isG200) // Matrox G200 cards can't handle per pixel alpha
282                 glEnable(GL_ALPHA_TEST);
283         else
284                 glDisable(GL_ALPHA_TEST);
285         // later note: wasn't working on my TNT drivers...  strangely...  used a cheaper hack in transpolyvert
286         //// offset by 16 depth units so decal sprites appear infront of walls
287         //glPolygonOffset(1, -16);
288         //glEnable(GL_POLYGON_OFFSET_FILL);
289         tpolytype = -1;
290         texnum = -1;
291         /*
292         if (gl_vertexarrays.value)
293         {
294                 // set up the vertex array
295                 qglInterleavedArrays(GL_T2F_C4UB_V3F, 0, transvert);
296                 for (i = 0;i < transpolyindices;i++)
297                 {
298                         p = &transpoly[transpolyindex[i]];
299                         if (p->texnum != texnum || p->transpolytype != tpolytype)
300                         {
301                                 if (p->texnum != texnum)
302                                 {
303                                         texnum = p->texnum;
304                                         glBindTexture(GL_TEXTURE_2D, texnum);
305                                 }
306                                 if (p->transpolytype != tpolytype)
307                                 {
308                                         tpolytype = p->transpolytype;
309                                         if (tpolytype == TPOLYTYPE_ADD) // additive
310                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
311                                         else // alpha
312                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
313                                 }
314                         }
315                         qglDrawArrays(GL_TRIANGLE_FAN, p->firstvert, p->verts);
316                         if (p->glowtexnum)
317                         {
318                                 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
319                                 glBindTexture(GL_TEXTURE_2D, texnum);
320                                 tpolytype = TPOLYTYPE_ADD; // might match next poly
321                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
322                                 qglDrawArrays(GL_TRIANGLE_FAN, p->firstvert, p->verts);
323                         }
324                 }
325                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
326                 glDisableClientState(GL_COLOR_ARRAY);
327                 glDisableClientState(GL_VERTEX_ARRAY);
328         }
329         else
330         */
331         {
332                 int points = -1;
333                 transvert_t *vert;
334                 for (i = 0;i < transpolyindices;i++)
335                 {
336                         p = &transpoly[transpolyindex[i]];
337                         if (p->texnum != texnum || p->verts != points || p->transpolytype != tpolytype)
338                         {
339                                 glEnd();
340                                 if (isG200)
341                                 {
342                                         if (p->fogtexnum) // alpha
343                                                 glEnable(GL_ALPHA_TEST);
344                                         else
345                                                 glDisable(GL_ALPHA_TEST);
346                                 }
347                                 if (p->texnum != texnum)
348                                 {
349                                         texnum = p->texnum;
350                                         glBindTexture(GL_TEXTURE_2D, texnum);
351                                 }
352                                 if (p->transpolytype != tpolytype)
353                                 {
354                                         tpolytype = p->transpolytype;
355                                         if (tpolytype == TPOLYTYPE_ADD) // additive
356                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
357                                         else // alpha
358                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
359                                 }
360                                 points = p->verts;
361                                 switch (points)
362                                 {
363                                 case 3:
364                                         glBegin(GL_TRIANGLES);
365                                         break;
366                                 case 4:
367                                         glBegin(GL_QUADS);
368                                         break;
369                                 default:
370                                         glBegin(GL_TRIANGLE_FAN);
371                                         points = -1; // to force a reinit on the next poly
372                                         break;
373                                 }
374                         }
375                         for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
376                         {
377                                 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
378                                 glTexCoord2f(vert->s, vert->t);
379                                 // again, vector version isn't supported I think
380                                 glColor4ub(vert->r, vert->g, vert->b, vert->a);
381                                 glVertex3fv(vert->v);
382                         }
383                         if (p->glowtexnum)
384                         {
385                                 glEnd();
386                                 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
387                                 glBindTexture(GL_TEXTURE_2D, texnum);
388                                 if (tpolytype != TPOLYTYPE_ADD)
389                                 {
390                                         tpolytype = TPOLYTYPE_ADD; // might match next poly
391                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
392                                 }
393                                 points = -1;
394                                 glBegin(GL_TRIANGLE_FAN);
395                                 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
396                                 {
397                                         glColor4ub(255,255,255,vert->a);
398                                         // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
399                                         glTexCoord2f(vert->s, vert->t);
400                                         glVertex3fv(vert->v);
401                                 }
402                                 glEnd();
403                         }
404                         if (fogenabled && p->transpolytype == TPOLYTYPE_ALPHA)
405                         {
406                                 vec3_t diff;
407                                 glEnd();
408                                 points = -1; // to force a reinit on the next poly
409                                 if (tpolytype != TPOLYTYPE_ALPHA)
410                                 {
411                                         tpolytype = TPOLYTYPE_ALPHA; // probably matchs next poly
412                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
413                                 }
414                                 if (p->fogtexnum)
415                                 {
416                                         if (texnum != p->fogtexnum) // highly unlikely to match next poly, but...
417                                         {
418                                                 texnum = p->fogtexnum;
419                                                 glBindTexture(GL_TEXTURE_2D, texnum);
420                                         }
421                                         glBegin(GL_TRIANGLE_FAN);
422                                         for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
423                                         {
424                                                 VectorSubtract(vert->v, r_refdef.vieworg,diff);
425                                                 glTexCoord2f(vert->s, vert->t);
426                                                 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
427                                                 glVertex3fv(vert->v);
428                                         }
429                                         glEnd ();
430                                 }
431                                 else
432                                 {
433                                         glDisable(GL_TEXTURE_2D);
434                                         glBegin(GL_TRIANGLE_FAN);
435                                         for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
436                                         {
437                                                 VectorSubtract(vert->v, r_refdef.vieworg,diff);
438                                                 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
439                                                 glVertex3fv(vert->v);
440                                         }
441                                         glEnd ();
442                                         glEnable(GL_TEXTURE_2D);
443                                 }
444                         }
445                 }
446                 glEnd();
447         }
448
449         //glDisable(GL_POLYGON_OFFSET_FILL);
450         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
451         glDepthMask(1); // enable zbuffer updates
452         glDisable(GL_ALPHA_TEST);
453 }
454
455 void wallpolyclear()
456 {
457         currentwallpoly = currentwallvert = 0;
458 }
459
460 extern qboolean lighthalf;
461 void wallpolyrender()
462 {
463         int i, j, texnum, lighttexnum;
464         wallpoly_t *p;
465         wallvert_t *vert;
466         if (currentwallpoly < 1)
467                 return;
468         // testing
469         //Con_DPrintf("wallpolyrender: %i polys %i vertices\n", currentwallpoly, currentwallvert);
470         if (!gl_mtexable)
471                 gl_multitexture.value = 0;
472         glDisable(GL_BLEND);
473         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
474         glShadeModel(GL_FLAT);
475         // make sure zbuffer is enabled
476         glEnable(GL_DEPTH_TEST);
477         glDisable(GL_ALPHA_TEST);
478         glDepthMask(1);
479         glColor3f(1,1,1);
480         if (r_fullbright.value) // LordHavoc: easy to do fullbright...
481         {
482                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
483                 texnum = -1;
484                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
485                 {
486                         if (p->texnum != texnum)
487                         {
488                                 texnum = p->texnum;
489                                 glBindTexture(GL_TEXTURE_2D, texnum);
490                         }
491                         vert = &wallvert[p->firstvert];
492                         glBegin(GL_POLYGON);
493                         for (j=0 ; j<p->verts ; j++, vert++)
494                         {
495                                 glTexCoord2f (vert->s, vert->t);
496                                 glVertex3fv (vert->vert);
497                         }
498                         glEnd ();
499                 }
500         }
501         else if (gl_multitexture.value)
502         {
503                 qglSelectTexture(gl_mtex_enum+0);
504                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
505                 glEnable(GL_TEXTURE_2D);
506                 qglSelectTexture(gl_mtex_enum+1);
507                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
508                 glEnable(GL_TEXTURE_2D);
509                 texnum = -1;
510                 lighttexnum = -1;
511                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
512                 {
513 //                      if (p->texnum != texnum || p->lighttexnum != lighttexnum)
514 //                      {
515                                 texnum = p->texnum;
516                                 lighttexnum = p->lighttexnum;
517                                 qglSelectTexture(gl_mtex_enum+0);
518                                 glBindTexture(GL_TEXTURE_2D, texnum);
519                                 qglSelectTexture(gl_mtex_enum+1);
520                                 glBindTexture(GL_TEXTURE_2D, lighttexnum);
521 //                      }
522                         vert = &wallvert[p->firstvert];
523                         glBegin(GL_POLYGON);
524                         for (j=0 ; j<p->verts ; j++, vert++)
525                         {
526                                 qglMTexCoord2f(gl_mtex_enum, vert->s, vert->t); // texture
527                                 qglMTexCoord2f((gl_mtex_enum+1), vert->u, vert->v); // lightmap
528                                 glVertex3fv (vert->vert);
529                         }
530                         glEnd ();
531                 }
532
533                 qglSelectTexture(gl_mtex_enum+1);
534                 glDisable(GL_TEXTURE_2D);
535                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
536                 qglSelectTexture(gl_mtex_enum+0);
537                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
538         }
539         else
540         {
541                 // first do the textures
542                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
543                 texnum = -1;
544                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
545                 {
546                         if (p->texnum != texnum)
547                         {
548                                 texnum = p->texnum;
549                                 glBindTexture(GL_TEXTURE_2D, texnum);
550                         }
551                         vert = &wallvert[p->firstvert];
552                         glBegin(GL_POLYGON);
553                         for (j=0 ; j<p->verts ; j++, vert++)
554                         {
555                                 glTexCoord2f (vert->s, vert->t);
556                                 glVertex3fv (vert->vert);
557                         }
558                         glEnd ();
559                 }
560                 // then modulate using the lightmaps
561                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
562                 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
563                 glEnable(GL_BLEND);
564                 texnum = -1;
565                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
566                 {
567                         if (p->lighttexnum != texnum)
568                         {
569                                 texnum = p->lighttexnum;
570                                 glBindTexture(GL_TEXTURE_2D, texnum);
571                         }
572                         vert = &wallvert[p->firstvert];
573                         glBegin(GL_POLYGON);
574                         for (j=0 ; j<p->verts ; j++, vert++)
575                         {
576                                 glTexCoord2f (vert->u, vert->v);
577                                 glVertex3fv (vert->vert);
578                         }
579                         glEnd ();
580                 }
581         }
582         // render glow textures
583         glDepthMask(0);
584         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
585         glBlendFunc(GL_ONE, GL_ONE);
586         glEnable(GL_BLEND);
587         if (lighthalf)
588                 glColor3f(0.5,0.5,0.5);
589         else
590                 glColor3f(1,1,1);
591         texnum = -1;
592         for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
593         {
594                 if (!p->glowtexnum)
595                         continue;
596                 if (p->glowtexnum != texnum)
597                 {
598                         texnum = p->glowtexnum;
599                         glBindTexture(GL_TEXTURE_2D, texnum);
600                 }
601                 vert = &wallvert[p->firstvert];
602                 glBegin(GL_POLYGON);
603                 for (j=0 ; j<p->verts ; j++, vert++)
604                 {
605                         glTexCoord2f (vert->s, vert->t);
606                         glVertex3fv (vert->vert);
607                 }
608                 glEnd ();
609         }
610         glColor3f(1,1,1);
611         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
612         glShadeModel(GL_SMOOTH);
613         if (fogenabled)
614         {
615                 vec3_t diff;
616                 glDisable(GL_TEXTURE_2D);
617                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
618                 {
619                         vert = &wallvert[p->firstvert];
620                         glBegin(GL_POLYGON);
621                         for (j=0 ; j<p->verts ; j++, vert++)
622                         {
623                                 VectorSubtract(vert->vert, r_refdef.vieworg,diff);
624                                 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
625                                 glVertex3fv (vert->vert);
626                         }
627                         glEnd ();
628                 }
629                 glEnable(GL_TEXTURE_2D);
630         }
631         glDisable(GL_BLEND);
632         glDepthMask(1);
633 }
634
635 void skypolyclear()
636 {
637         currentskypoly = currentskyvert = 0;
638 }
639
640 extern qboolean isATI;
641 void skypolyrender()
642 {
643         int i, j;
644         skypoly_t *p;
645         skyvert_t *vert;
646         if (currentskypoly < 1)
647                 return;
648         // testing
649 //      Con_DPrintf("skypolyrender: %i polys %i vertices\n", currentskypoly, currentskyvert);
650         glDisable(GL_TEXTURE_2D);
651         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
652         glDisable(GL_ALPHA_TEST);
653         glDisable(GL_BLEND);
654         // make sure zbuffer is enabled
655         glEnable(GL_DEPTH_TEST);
656         glDepthMask(1);
657         glColor3fv(fogcolor); // note: gets rendered over by sky if fog is not enabled
658         for (i = 0,p = &skypoly[0];i < currentskypoly;i++, p++)
659         {
660                 vert = &skyvert[p->firstvert];
661                 glBegin(GL_POLYGON);
662                 for (j=0 ; j<p->verts ; j++, vert++)
663                         glVertex3fv (vert->v);
664                 glEnd ();
665         }
666         glColor3f(1,1,1);
667         glEnable(GL_TEXTURE_2D);
668 }