3 transvert_t *transvert;
4 transpoly_t *transpoly;
5 unsigned short *transpolyindex;
11 unsigned short currenttranspoly;
12 unsigned short currenttransvert;
13 unsigned short currentwallpoly;
14 unsigned short currentwallvert;
15 unsigned short currentskypoly;
16 unsigned short currentskyvert;
18 cvar_t gl_multitexture = {"gl_multitexture", "1"};
19 cvar_t gl_vertexarrays = {"gl_vertexarrays", "1"};
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));
36 currenttranspoly = currenttransvert = 0;
39 void transpolybegin(int texnum, int glowtexnum, int fogtexnum, int transpolytype)
41 if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
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
52 // turned into a #define
54 void transpolyvert(float x, float y, float z, float s, float t, int r, int g, int b, int a)
57 if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
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;
69 transpoly[currenttranspoly].verts++;
75 if (currenttranspoly >= MAX_TRANSPOLYS)
77 if (transpoly[currenttranspoly].verts < 3) // skip invalid polygons
79 currenttransvert = transpoly[currenttranspoly].firstvert; // reset vert pointer
82 if (currenttransvert >= MAX_TRANSVERTS)
88 void transpolyrenderminmax()
90 int i, j, k, lastvert;
91 vec_t d, min, max, viewdist, s, average;
95 viewdist = DotProduct(r_refdef.vieworg, vpn);
96 for (i = 0;i < currenttranspoly;i++)
98 if (transpoly[i].verts < 3) // only process valid polygons
100 min = 1000000;max = -1000000;
101 s = 1.0f / transpoly[i].verts;
102 lastvert = transpoly[i].firstvert + transpoly[i].verts;
104 for (j = transpoly[i].firstvert;j < lastvert;j++)
106 d = DotProduct(transvert[j].v, vpn)-viewdist;
107 if (d < min) min = d;
108 if (d > max) max = d;
111 if (max < 4) // free to check here, so skip polys behind the view
113 transpoly[i].distance = average;
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);
122 if (transpoly[i].verts > 3 && fabs(DotProduct(v1, v2)) >= (1.0f - (1.0f / 256.0f))) // colinear edges, find a better triple
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);
128 if (fabs(DotProduct(v1, v2)) < (1.0f - (1.0f / 256.0f))) // found a good triple
130 for (k = transpoly[i].firstvert + 2;k < (transpoly[i].firstvert + transpoly[i].verts - 1);k++)
132 VectorSubtract(transvert[k-1].v, transvert[k].v, v1);
133 VectorSubtract(transvert[k+1].v, transvert[k].v, v2);
136 if (fabs(DotProduct(v1, v2)) < (1.0f - (1.0f / 256.0f))) // found a good triple
139 VectorSubtract(transvert[k-1].v, transvert[k].v, v1);
140 VectorSubtract(transvert[transpoly[i].firstvert].v, transvert[k].v, v2);
143 if (fabs(DotProduct(v1, v2)) >= (1.0f - (1.0f / 256.0f))) // no good triples; the polygon is a line, skip it
147 CrossProduct(v1, v2, n);
149 ndist = DotProduct(transvert[transpoly[i].firstvert+1].v, n);
151 for (j = 0;j < transpolyindices;j++)
154 if (transpoly[transpolyindex[j]].mindistance > max)
156 if (transpoly[transpolyindex[j]].maxdistance < min)
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)
168 for (j = 0;j < transpolyindices;j++)
169 if (transpoly[transpolyindex[j]].distance < average)
171 for (k = transpolyindices;k > j;k--)
172 transpolyindex[k] = transpolyindex[k-1];
174 transpolyindex[j] = i;
178 // LordHavoc: qsort compare function
180 int transpolyqsort(const void *ia, const void *ib)
184 a = &transpoly[*((unsigned short *)ia)];
185 b = &transpoly[*((unsigned short *)ib)];
187 if (a->mindistance > b->mindistance && a->maxdistance > b->maxdistance)
189 if (a->mindistance < b->mindistance && a->maxdistance < b->maxdistance)
194 // calculate normal (eek)
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);
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
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);
212 extern qboolean isG200;
218 // qsort(&transpolyindex[0], transpolyindices, sizeof(unsigned short), transpolyqsort);
223 for (i = 1;i < transpolyindices;i++)
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)
233 if (!transpoly[transpolyindex[i - 1]].ndist)
235 // calculate normal (eek)
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);
243 if (DotProduct(transpoly[transpolyindex[i - 1]].n, vpn) >= 0.0f) // backface
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
252 // previous is infront (swap)
253 j = transpolyindex[i];
254 transpolyindex[i] = transpolyindex[i - 1];
255 transpolyindex[i - 1] = j;
264 void transpolyrender()
266 int i, j, tpolytype, texnum;
268 if (currenttranspoly < 1)
270 transpolyrenderminmax();
271 if (transpolyindices < 1)
274 // Con_DPrintf("transpolyrender: %i polys %i infront %i vertices\n", currenttranspoly, transpolyindices, currenttransvert);
275 // if (transpolyindices >= 2)
277 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
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);
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 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
290 tpolytype = TPOLYTYPE_ALPHA;
293 if (gl_vertexarrays.value)
295 // set up the vertex array
296 qglInterleavedArrays(GL_T2F_C4UB_V3F, 0, transvert);
297 for (i = 0;i < transpolyindices;i++)
299 p = &transpoly[transpolyindex[i]];
300 if (p->texnum != texnum || p->transpolytype != tpolytype)
302 if (p->texnum != texnum)
305 glBindTexture(GL_TEXTURE_2D, texnum);
307 if (p->transpolytype != tpolytype)
309 tpolytype = p->transpolytype;
310 if (tpolytype == TPOLYTYPE_ADD) // additive
311 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
313 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
316 qglDrawArrays(GL_TRIANGLE_FAN, p->firstvert, p->verts);
319 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
320 glBindTexture(GL_TEXTURE_2D, texnum);
321 tpolytype = TPOLYTYPE_ADD; // might match next poly
322 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
323 qglDrawArrays(GL_TRIANGLE_FAN, p->firstvert, p->verts);
326 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
327 glDisableClientState(GL_COLOR_ARRAY);
328 glDisableClientState(GL_VERTEX_ARRAY);
335 for (i = 0;i < transpolyindices;i++)
337 p = &transpoly[transpolyindex[i]];
338 if (p->texnum != texnum || p->verts != points || p->transpolytype != tpolytype)
343 if (p->fogtexnum) // alpha
344 glEnable(GL_ALPHA_TEST);
346 glDisable(GL_ALPHA_TEST);
348 if (p->texnum != texnum)
351 glBindTexture(GL_TEXTURE_2D, texnum);
353 if (p->transpolytype != tpolytype)
355 tpolytype = p->transpolytype;
356 if (tpolytype == TPOLYTYPE_ADD) // additive
357 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
359 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
365 glBegin(GL_TRIANGLES);
371 glBegin(GL_TRIANGLE_FAN);
372 points = -1; // to force a reinit on the next poly
376 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
378 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
379 glTexCoord2f(vert->s, vert->t);
380 // again, vector version isn't supported I think
381 glColor4ub(vert->r, vert->g, vert->b, vert->a);
382 glVertex3fv(vert->v);
387 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
388 glBindTexture(GL_TEXTURE_2D, texnum);
389 if (tpolytype != TPOLYTYPE_ADD)
391 tpolytype = TPOLYTYPE_ADD; // might match next poly
392 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
395 glBegin(GL_TRIANGLE_FAN);
396 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
398 glColor4ub(255,255,255,vert->a);
399 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
400 glTexCoord2f(vert->s, vert->t);
401 glVertex3fv(vert->v);
405 if (fogenabled && p->transpolytype == TPOLYTYPE_ALPHA)
409 points = -1; // to force a reinit on the next poly
410 if (tpolytype != TPOLYTYPE_ALPHA)
412 tpolytype = TPOLYTYPE_ALPHA; // probably matchs next poly
413 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
417 if (texnum != p->fogtexnum) // highly unlikely to match next poly, but...
419 texnum = p->fogtexnum;
420 glBindTexture(GL_TEXTURE_2D, texnum);
422 glBegin(GL_TRIANGLE_FAN);
423 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
425 VectorSubtract(vert->v, r_refdef.vieworg,diff);
426 glTexCoord2f(vert->s, vert->t);
427 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
428 glVertex3fv(vert->v);
434 glDisable(GL_TEXTURE_2D);
435 glBegin(GL_TRIANGLE_FAN);
436 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
438 VectorSubtract(vert->v, r_refdef.vieworg,diff);
439 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
440 glVertex3fv(vert->v);
443 glEnable(GL_TEXTURE_2D);
450 //glDisable(GL_POLYGON_OFFSET_FILL);
451 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
452 glDepthMask(1); // enable zbuffer updates
453 glDisable(GL_ALPHA_TEST);
458 currentwallpoly = currentwallvert = 0;
461 extern qboolean lighthalf;
462 void wallpolyrender()
464 int i, j, texnum, lighttexnum;
467 if (currentwallpoly < 1)
470 //Con_DPrintf("wallpolyrender: %i polys %i vertices\n", currentwallpoly, currentwallvert);
472 gl_multitexture.value = 0;
474 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
475 glShadeModel(GL_FLAT);
476 // make sure zbuffer is enabled
477 glEnable(GL_DEPTH_TEST);
478 glDisable(GL_ALPHA_TEST);
481 if (r_fullbright.value) // LordHavoc: easy to do fullbright...
483 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
485 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
487 if (p->texnum != texnum)
490 glBindTexture(GL_TEXTURE_2D, texnum);
492 vert = &wallvert[p->firstvert];
494 for (j=0 ; j<p->verts ; j++, vert++)
496 glTexCoord2f (vert->s, vert->t);
497 glVertex3fv (vert->vert);
502 else if (gl_multitexture.value)
504 qglSelectTexture(gl_mtex_enum+0);
505 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
506 glEnable(GL_TEXTURE_2D);
507 qglSelectTexture(gl_mtex_enum+1);
508 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
509 glEnable(GL_TEXTURE_2D);
512 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
514 // if (p->texnum != texnum || p->lighttexnum != lighttexnum)
517 lighttexnum = p->lighttexnum;
518 qglSelectTexture(gl_mtex_enum+0);
519 glBindTexture(GL_TEXTURE_2D, texnum);
520 qglSelectTexture(gl_mtex_enum+1);
521 glBindTexture(GL_TEXTURE_2D, lighttexnum);
523 vert = &wallvert[p->firstvert];
525 for (j=0 ; j<p->verts ; j++, vert++)
527 qglMTexCoord2f(gl_mtex_enum, vert->s, vert->t); // texture
528 qglMTexCoord2f((gl_mtex_enum+1), vert->u, vert->v); // lightmap
529 glVertex3fv (vert->vert);
534 qglSelectTexture(gl_mtex_enum+1);
535 glDisable(GL_TEXTURE_2D);
536 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
537 qglSelectTexture(gl_mtex_enum+0);
538 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
542 // first do the textures
543 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
545 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
547 if (p->texnum != texnum)
550 glBindTexture(GL_TEXTURE_2D, texnum);
552 vert = &wallvert[p->firstvert];
554 for (j=0 ; j<p->verts ; j++, vert++)
556 glTexCoord2f (vert->s, vert->t);
557 glVertex3fv (vert->vert);
561 // then modulate using the lightmaps
562 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
563 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
566 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
568 if (p->lighttexnum != texnum)
570 texnum = p->lighttexnum;
571 glBindTexture(GL_TEXTURE_2D, texnum);
573 vert = &wallvert[p->firstvert];
575 for (j=0 ; j<p->verts ; j++, vert++)
577 glTexCoord2f (vert->u, vert->v);
578 glVertex3fv (vert->vert);
583 // render glow textures
585 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
586 glBlendFunc(GL_ONE, GL_ONE);
589 glColor3f(0.5,0.5,0.5);
593 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
597 if (p->glowtexnum != texnum)
599 texnum = p->glowtexnum;
600 glBindTexture(GL_TEXTURE_2D, texnum);
602 vert = &wallvert[p->firstvert];
604 for (j=0 ; j<p->verts ; j++, vert++)
606 glTexCoord2f (vert->s, vert->t);
607 glVertex3fv (vert->vert);
612 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
613 glShadeModel(GL_SMOOTH);
617 glDisable(GL_TEXTURE_2D);
618 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
620 vert = &wallvert[p->firstvert];
622 for (j=0 ; j<p->verts ; j++, vert++)
624 VectorSubtract(vert->vert, r_refdef.vieworg,diff);
625 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
626 glVertex3fv (vert->vert);
630 glEnable(GL_TEXTURE_2D);
638 currentskypoly = currentskyvert = 0;
641 extern qboolean isATI;
647 if (currentskypoly < 1)
650 // Con_DPrintf("skypolyrender: %i polys %i vertices\n", currentskypoly, currentskyvert);
651 glDisable(GL_TEXTURE_2D);
652 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
653 glDisable(GL_ALPHA_TEST);
655 // make sure zbuffer is enabled
656 glEnable(GL_DEPTH_TEST);
658 glColor3fv(fogcolor); // note: gets rendered over by sky if fog is not enabled
659 for (i = 0,p = &skypoly[0];i < currentskypoly;i++, p++)
661 vert = &skyvert[p->firstvert];
663 for (j=0 ; j<p->verts ; j++, vert++)
664 glVertex3fv (vert->v);
668 glEnable(GL_TEXTURE_2D);