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