]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_poly.c
78b6f5c85ed16139e5184cd29bd1e7d2b6254e83
[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         glShadeModel(GL_FLAT);
474         // make sure zbuffer is enabled
475         glEnable(GL_DEPTH_TEST);
476         glDisable(GL_ALPHA_TEST);
477         glDepthMask(1);
478         glColor3f(1,1,1);
479         if (r_fullbright.value) // LordHavoc: easy to do fullbright...
480         {
481                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
482                 texnum = -1;
483                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
484                 {
485                         if (p->texnum != texnum)
486                         {
487                                 texnum = p->texnum;
488                                 glBindTexture(GL_TEXTURE_2D, texnum);
489                         }
490                         vert = &wallvert[p->firstvert];
491                         glBegin(GL_POLYGON);
492                         for (j=0 ; j<p->verts ; j++, vert++)
493                         {
494                                 glTexCoord2f (vert->s, vert->t);
495                                 glVertex3fv (vert->vert);
496                         }
497                         glEnd ();
498                 }
499         }
500         else if (gl_multitexture.value)
501         {
502                 qglSelectTexture(gl_mtex_enum+0);
503                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
504                 glEnable(GL_TEXTURE_2D);
505                 qglSelectTexture(gl_mtex_enum+1);
506                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
507                 glEnable(GL_TEXTURE_2D);
508                 texnum = -1;
509                 lighttexnum = -1;
510                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
511                 {
512 //                      if (p->texnum != texnum || p->lighttexnum != lighttexnum)
513 //                      {
514                                 texnum = p->texnum;
515                                 lighttexnum = p->lighttexnum;
516                                 qglSelectTexture(gl_mtex_enum+0);
517                                 glBindTexture(GL_TEXTURE_2D, texnum);
518                                 qglSelectTexture(gl_mtex_enum+1);
519                                 glBindTexture(GL_TEXTURE_2D, lighttexnum);
520 //                      }
521                         vert = &wallvert[p->firstvert];
522                         glBegin(GL_POLYGON);
523                         for (j=0 ; j<p->verts ; j++, vert++)
524                         {
525                                 qglMTexCoord2f(gl_mtex_enum, vert->s, vert->t); // texture
526                                 qglMTexCoord2f((gl_mtex_enum+1), vert->u, vert->v); // lightmap
527                                 glVertex3fv (vert->vert);
528                         }
529                         glEnd ();
530                 }
531
532                 qglSelectTexture(gl_mtex_enum+1);
533                 glDisable(GL_TEXTURE_2D);
534                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
535                 qglSelectTexture(gl_mtex_enum+0);
536                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
537         }
538         else
539         {
540                 // first do the textures
541                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
542                 texnum = -1;
543                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
544                 {
545                         if (p->texnum != texnum)
546                         {
547                                 texnum = p->texnum;
548                                 glBindTexture(GL_TEXTURE_2D, texnum);
549                         }
550                         vert = &wallvert[p->firstvert];
551                         glBegin(GL_POLYGON);
552                         for (j=0 ; j<p->verts ; j++, vert++)
553                         {
554                                 glTexCoord2f (vert->s, vert->t);
555                                 glVertex3fv (vert->vert);
556                         }
557                         glEnd ();
558                 }
559                 // then modulate using the lightmaps
560                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
561                 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
562                 glEnable(GL_BLEND);
563                 texnum = -1;
564                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
565                 {
566                         if (p->lighttexnum != texnum)
567                         {
568                                 texnum = p->lighttexnum;
569                                 glBindTexture(GL_TEXTURE_2D, texnum);
570                         }
571                         vert = &wallvert[p->firstvert];
572                         glBegin(GL_POLYGON);
573                         for (j=0 ; j<p->verts ; j++, vert++)
574                         {
575                                 glTexCoord2f (vert->u, vert->v);
576                                 glVertex3fv (vert->vert);
577                         }
578                         glEnd ();
579                 }
580         }
581         // render glow textures
582         glDepthMask(0);
583         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
584         glBlendFunc(GL_ONE, GL_ONE);
585         glEnable(GL_BLEND);
586         if (lighthalf)
587                 glColor3f(0.5,0.5,0.5);
588         else
589                 glColor3f(1,1,1);
590         texnum = -1;
591         for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
592         {
593                 if (!p->glowtexnum)
594                         continue;
595                 if (p->glowtexnum != texnum)
596                 {
597                         texnum = p->glowtexnum;
598                         glBindTexture(GL_TEXTURE_2D, texnum);
599                 }
600                 vert = &wallvert[p->firstvert];
601                 glBegin(GL_POLYGON);
602                 for (j=0 ; j<p->verts ; j++, vert++)
603                 {
604                         glTexCoord2f (vert->s, vert->t);
605                         glVertex3fv (vert->vert);
606                 }
607                 glEnd ();
608         }
609         glColor3f(1,1,1);
610         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
611         glShadeModel(GL_SMOOTH);
612         if (fogenabled)
613         {
614                 vec3_t diff;
615                 glDisable(GL_TEXTURE_2D);
616                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
617                 {
618                         vert = &wallvert[p->firstvert];
619                         glBegin(GL_POLYGON);
620                         for (j=0 ; j<p->verts ; j++, vert++)
621                         {
622                                 VectorSubtract(vert->vert, r_refdef.vieworg,diff);
623                                 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
624                                 glVertex3fv (vert->vert);
625                         }
626                         glEnd ();
627                 }
628                 glEnable(GL_TEXTURE_2D);
629         }
630         glDisable(GL_BLEND);
631         glDepthMask(1);
632 }
633
634 void skypolyclear()
635 {
636         currentskypoly = currentskyvert = 0;
637 }
638
639 extern qboolean isATI;
640 void skypolyrender()
641 {
642         int i, j;
643         skypoly_t *p;
644         skyvert_t *vert;
645         if (currentskypoly < 1)
646                 return;
647         // testing
648 //      Con_DPrintf("skypolyrender: %i polys %i vertices\n", currentskypoly, currentskyvert);
649         glDisable(GL_TEXTURE_2D);
650         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
651         glDisable(GL_ALPHA_TEST);
652         glDisable(GL_BLEND);
653         // make sure zbuffer is enabled
654         glEnable(GL_DEPTH_TEST);
655         glDepthMask(1);
656         glColor3fv(fogcolor); // note: gets rendered over by sky if fog is not enabled
657         for (i = 0,p = &skypoly[0];i < currentskypoly;i++, p++)
658         {
659                 vert = &skyvert[p->firstvert];
660                 glBegin(GL_POLYGON);
661                 for (j=0 ; j<p->verts ; j++, vert++)
662                         glVertex3fv (vert->v);
663                 glEnd ();
664         }
665         glColor3f(1,1,1);
666         glEnable(GL_TEXTURE_2D);
667 }