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);
292 if (gl_vertexarrays.value)
294 // set up the vertex array
295 qglInterleavedArrays(GL_T2F_C4UB_V3F, 0, transvert);
296 for (i = 0;i < transpolyindices;i++)
298 p = &transpoly[transpolyindex[i]];
299 if (p->texnum != texnum || p->transpolytype != tpolytype)
301 if (p->texnum != texnum)
304 glBindTexture(GL_TEXTURE_2D, texnum);
306 if (p->transpolytype != tpolytype)
308 tpolytype = p->transpolytype;
309 if (tpolytype == TPOLYTYPE_ADD) // additive
310 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
312 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
315 qglDrawArrays(GL_TRIANGLE_FAN, p->firstvert, p->verts);
318 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
319 glBindTexture(GL_TEXTURE_2D, texnum);
320 tpolytype = TPOLYTYPE_ADD; // might match next poly
321 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
322 qglDrawArrays(GL_TRIANGLE_FAN, p->firstvert, p->verts);
325 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
326 glDisableClientState(GL_COLOR_ARRAY);
327 glDisableClientState(GL_VERTEX_ARRAY);
334 for (i = 0;i < transpolyindices;i++)
336 p = &transpoly[transpolyindex[i]];
337 if (p->texnum != texnum || p->verts != points || p->transpolytype != tpolytype)
342 if (p->fogtexnum) // alpha
343 glEnable(GL_ALPHA_TEST);
345 glDisable(GL_ALPHA_TEST);
347 if (p->texnum != texnum)
350 glBindTexture(GL_TEXTURE_2D, texnum);
352 if (p->transpolytype != tpolytype)
354 tpolytype = p->transpolytype;
355 if (tpolytype == TPOLYTYPE_ADD) // additive
356 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
358 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
364 glBegin(GL_TRIANGLES);
370 glBegin(GL_TRIANGLE_FAN);
371 points = -1; // to force a reinit on the next poly
375 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
377 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
378 glTexCoord2f(vert->s, vert->t);
379 // again, vector version isn't supported I think
380 glColor4ub(vert->r, vert->g, vert->b, vert->a);
381 glVertex3fv(vert->v);
386 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
387 glBindTexture(GL_TEXTURE_2D, texnum);
388 if (tpolytype != TPOLYTYPE_ADD)
390 tpolytype = TPOLYTYPE_ADD; // might match next poly
391 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
394 glBegin(GL_TRIANGLE_FAN);
395 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
397 glColor4ub(255,255,255,vert->a);
398 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
399 glTexCoord2f(vert->s, vert->t);
400 glVertex3fv(vert->v);
404 if (fogenabled && p->transpolytype == TPOLYTYPE_ALPHA)
408 points = -1; // to force a reinit on the next poly
409 if (tpolytype != TPOLYTYPE_ALPHA)
411 tpolytype = TPOLYTYPE_ALPHA; // probably matchs next poly
412 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
416 if (texnum != p->fogtexnum) // highly unlikely to match next poly, but...
418 texnum = p->fogtexnum;
419 glBindTexture(GL_TEXTURE_2D, texnum);
421 glBegin(GL_TRIANGLE_FAN);
422 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
424 VectorSubtract(vert->v, r_refdef.vieworg,diff);
425 glTexCoord2f(vert->s, vert->t);
426 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
427 glVertex3fv(vert->v);
433 glDisable(GL_TEXTURE_2D);
434 glBegin(GL_TRIANGLE_FAN);
435 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
437 VectorSubtract(vert->v, r_refdef.vieworg,diff);
438 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
439 glVertex3fv(vert->v);
442 glEnable(GL_TEXTURE_2D);
449 //glDisable(GL_POLYGON_OFFSET_FILL);
450 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
451 glDepthMask(1); // enable zbuffer updates
452 glDisable(GL_ALPHA_TEST);
457 currentwallpoly = currentwallvert = 0;
460 extern qboolean lighthalf;
461 void wallpolyrender()
463 int i, j, texnum, lighttexnum;
466 if (currentwallpoly < 1)
469 //Con_DPrintf("wallpolyrender: %i polys %i vertices\n", currentwallpoly, currentwallvert);
471 gl_multitexture.value = 0;
473 glShadeModel(GL_FLAT);
474 // make sure zbuffer is enabled
475 glEnable(GL_DEPTH_TEST);
476 glDisable(GL_ALPHA_TEST);
479 if (r_fullbright.value) // LordHavoc: easy to do fullbright...
481 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
483 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
485 if (p->texnum != texnum)
488 glBindTexture(GL_TEXTURE_2D, texnum);
490 vert = &wallvert[p->firstvert];
492 for (j=0 ; j<p->verts ; j++, vert++)
494 glTexCoord2f (vert->s, vert->t);
495 glVertex3fv (vert->vert);
500 else if (gl_multitexture.value)
502 qglSelectTexture(gl_mtex_enum+0);
503 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
504 glEnable(GL_TEXTURE_2D);
505 qglSelectTexture(gl_mtex_enum+1);
506 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
507 glEnable(GL_TEXTURE_2D);
510 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
512 // if (p->texnum != texnum || p->lighttexnum != lighttexnum)
515 lighttexnum = p->lighttexnum;
516 qglSelectTexture(gl_mtex_enum+0);
517 glBindTexture(GL_TEXTURE_2D, texnum);
518 qglSelectTexture(gl_mtex_enum+1);
519 glBindTexture(GL_TEXTURE_2D, lighttexnum);
521 vert = &wallvert[p->firstvert];
523 for (j=0 ; j<p->verts ; j++, vert++)
525 qglMTexCoord2f(gl_mtex_enum, vert->s, vert->t); // texture
526 qglMTexCoord2f((gl_mtex_enum+1), vert->u, vert->v); // lightmap
527 glVertex3fv (vert->vert);
532 qglSelectTexture(gl_mtex_enum+1);
533 glDisable(GL_TEXTURE_2D);
534 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
535 qglSelectTexture(gl_mtex_enum+0);
536 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
540 // first do the textures
541 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
543 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
545 if (p->texnum != texnum)
548 glBindTexture(GL_TEXTURE_2D, texnum);
550 vert = &wallvert[p->firstvert];
552 for (j=0 ; j<p->verts ; j++, vert++)
554 glTexCoord2f (vert->s, vert->t);
555 glVertex3fv (vert->vert);
559 // then modulate using the lightmaps
560 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
561 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
564 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
566 if (p->lighttexnum != texnum)
568 texnum = p->lighttexnum;
569 glBindTexture(GL_TEXTURE_2D, texnum);
571 vert = &wallvert[p->firstvert];
573 for (j=0 ; j<p->verts ; j++, vert++)
575 glTexCoord2f (vert->u, vert->v);
576 glVertex3fv (vert->vert);
581 // render glow textures
583 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
584 glBlendFunc(GL_ONE, GL_ONE);
587 glColor3f(0.5,0.5,0.5);
591 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
595 if (p->glowtexnum != texnum)
597 texnum = p->glowtexnum;
598 glBindTexture(GL_TEXTURE_2D, texnum);
600 vert = &wallvert[p->firstvert];
602 for (j=0 ; j<p->verts ; j++, vert++)
604 glTexCoord2f (vert->s, vert->t);
605 glVertex3fv (vert->vert);
610 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
611 glShadeModel(GL_SMOOTH);
615 glDisable(GL_TEXTURE_2D);
616 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
618 vert = &wallvert[p->firstvert];
620 for (j=0 ; j<p->verts ; j++, vert++)
622 VectorSubtract(vert->vert, r_refdef.vieworg,diff);
623 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
624 glVertex3fv (vert->vert);
628 glEnable(GL_TEXTURE_2D);
636 currentskypoly = currentskyvert = 0;
639 extern qboolean isATI;
645 if (currentskypoly < 1)
648 // Con_DPrintf("skypolyrender: %i polys %i vertices\n", currentskypoly, currentskyvert);
649 glDisable(GL_TEXTURE_2D);
650 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
651 glDisable(GL_ALPHA_TEST);
653 // make sure zbuffer is enabled
654 glEnable(GL_DEPTH_TEST);
656 glColor3fv(fogcolor); // note: gets rendered over by sky if fog is not enabled
657 for (i = 0,p = &skypoly[0];i < currentskypoly;i++, p++)
659 vert = &skyvert[p->firstvert];
661 for (j=0 ; j<p->verts ; j++, vert++)
662 glVertex3fv (vert->v);
666 glEnable(GL_TEXTURE_2D);