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