3 transvert_t *transvert;
4 transpoly_t *transpoly;
5 unsigned short *transpolyindex;
7 wallvertcolor_t *wallvertcolor;
19 cvar_t gl_multitexture = {"gl_multitexture", "1"};
21 typedef struct translistitem_s
24 struct translistitem_s *next;
28 translistitem translist[MAX_TRANSPOLYS];
29 translistitem *currenttranslist;
31 translistitem *translisthash[4096];
33 float transviewdist; // distance of view origin along the view normal
35 float transreciptable[256];
37 void gl_poly_start(void)
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;
53 void gl_poly_shutdown(void)
57 qfree(transpolyindex);
65 void gl_poly_newmap(void)
69 void GL_Poly_Init(void)
71 Cvar_RegisterVariable (&gl_multitexture);
72 R_RegisterModule("GL_Poly", gl_poly_start, gl_poly_shutdown, gl_poly_newmap);
75 void transpolyclear(void)
77 currenttranspoly = currenttransvert = 0;
78 currenttranslist = translist;
79 memset(translisthash, 0, sizeof(translisthash));
80 transviewdist = DotProduct(r_origin, vpn);
83 // turned into a #define
85 void transpolybegin(int texnum, int glowtexnum, int fogtexnum, int transpolytype)
87 if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
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
99 // turned into a #define
101 void transpolyvert(float x, float y, float z, float s, float t, int r, int g, int b, int a)
104 if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
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;
116 transpoly[currenttranspoly].verts++;
120 void transpolyend(void)
122 float center, d, maxdist;
125 if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
127 if (transpoly[currenttranspoly].verts < 3) // skip invalid polygons
129 currenttransvert = transpoly[currenttranspoly].firstvert; // reset vert pointer
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++)
136 d = DotProduct(v->v, vpn);
141 maxdist -= transviewdist;
142 if (maxdist < 4.0f) // behind view
144 currenttransvert = transpoly[currenttranspoly].firstvert; // reset vert pointer
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;
157 int transpolyindices;
159 void transpolyrender(void)
161 int i, j, tpolytype, texnum;
165 if (currenttranspoly < 1)
167 // transpolyrenderminmax();
168 // if (transpolyindices < 1)
171 // Con_DPrintf("transpolyrender: %i polys %i infront %i vertices\n", currenttranspoly, transpolyindices, currenttransvert);
172 // if (transpolyindices >= 2)
174 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
176 glShadeModel(GL_SMOOTH);
177 glDepthMask(0); // disable zbuffer updates
178 glDisable(GL_ALPHA_TEST);
179 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
180 tpolytype = TPOLYTYPE_ALPHA;
183 if (gl_vertexarrays.value)
185 // set up the vertex array
186 glInterleavedArrays(GL_T2F_C4UB_V3F, 0, transvert);
187 for (i = 0;i < transpolyindices;i++)
189 p = &transpoly[transpolyindex[i]];
190 if (p->texnum != texnum || p->transpolytype != tpolytype)
192 if (p->texnum != texnum)
195 glBindTexture(GL_TEXTURE_2D, texnum);
197 if (p->transpolytype != tpolytype)
199 tpolytype = p->transpolytype;
200 if (tpolytype == TPOLYTYPE_ADD) // additive
201 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
203 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
206 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
209 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
210 glBindTexture(GL_TEXTURE_2D, texnum);
211 tpolytype = TPOLYTYPE_ADD; // might match next poly
212 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
213 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
216 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
217 glDisableClientState(GL_COLOR_ARRAY);
218 glDisableClientState(GL_VERTEX_ARRAY);
226 for (i = 4095;i >= 0;i--)
228 item = translisthash[i];
233 if (p->texnum != texnum || p->verts != points || p->transpolytype != tpolytype)
238 // LordHavoc: Matrox G200 cards can't handle per pixel alpha
240 glEnable(GL_ALPHA_TEST);
242 glDisable(GL_ALPHA_TEST);
244 if (p->texnum != texnum)
247 glBindTexture(GL_TEXTURE_2D, texnum);
249 if (p->transpolytype != tpolytype)
251 tpolytype = p->transpolytype;
252 if (tpolytype == TPOLYTYPE_ADD) // additive
253 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
255 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
261 glBegin(GL_TRIANGLES);
268 points = -1; // to force a reinit on the next poly
272 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
274 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
275 glTexCoord2f(vert->s, vert->t);
276 // again, vector version isn't supported I think
277 glColor4ub(vert->r, vert->g, vert->b, vert->a);
278 glVertex3fv(vert->v);
283 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
284 glBindTexture(GL_TEXTURE_2D, texnum);
285 if (tpolytype != TPOLYTYPE_ADD)
287 tpolytype = TPOLYTYPE_ADD; // might match next poly
288 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
292 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
294 glColor4ub(255,255,255,vert->a);
295 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
296 glTexCoord2f(vert->s, vert->t);
297 glVertex3fv(vert->v);
301 if (fogenabled && p->transpolytype == TPOLYTYPE_ALPHA)
305 points = -1; // to force a reinit on the next poly
306 if (tpolytype != TPOLYTYPE_ALPHA)
308 tpolytype = TPOLYTYPE_ALPHA; // probably matchs next poly
309 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
313 if (texnum != p->fogtexnum) // highly unlikely to match next poly, but...
315 texnum = p->fogtexnum;
316 glBindTexture(GL_TEXTURE_2D, texnum);
319 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
321 VectorSubtract(vert->v, r_origin, diff);
322 glTexCoord2f(vert->s, vert->t);
323 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
324 glVertex3fv(vert->v);
330 glDisable(GL_TEXTURE_2D);
332 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
334 VectorSubtract(vert->v, r_origin, diff);
335 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
336 glVertex3fv(vert->v);
339 glEnable(GL_TEXTURE_2D);
347 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
348 glDepthMask(1); // enable zbuffer updates
349 glDisable(GL_ALPHA_TEST);
352 void wallpolyclear(void)
354 currentwallpoly = currentwallvert = 0;
357 void wallpolyrender(void)
359 int i, j, texnum, lighttexnum;
362 wallvertcolor_t *vertcolor;
365 if (currentwallpoly < 1)
367 c_brush_polys += currentwallpoly;
369 //Con_DPrintf("wallpolyrender: %i polys %i vertices\n", currentwallpoly, currentwallvert);
371 gl_multitexture.value = 0;
373 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
374 glShadeModel(GL_FLAT);
375 // make sure zbuffer is enabled
376 glEnable(GL_DEPTH_TEST);
377 // glDisable(GL_ALPHA_TEST);
380 if (r_fullbright.value) // LordHavoc: easy to do fullbright...
382 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
384 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
386 if (p->texnum != texnum)
389 glBindTexture(GL_TEXTURE_2D, texnum);
391 vert = &wallvert[p->firstvert];
393 for (j=0 ; j<p->numverts ; j++, vert++)
395 glTexCoord2f (vert->vert[3], vert->vert[4]);
396 glVertex3fv (vert->vert);
401 else if (gl_multitexture.value)
403 qglSelectTexture(gl_mtex_enum+0);
404 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
405 glEnable(GL_TEXTURE_2D);
406 qglSelectTexture(gl_mtex_enum+1);
407 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
408 glEnable(GL_TEXTURE_2D);
411 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
413 if (p->texnum != texnum || p->lighttexnum != lighttexnum)
416 lighttexnum = p->lighttexnum;
417 qglSelectTexture(gl_mtex_enum+0);
418 glBindTexture(GL_TEXTURE_2D, texnum);
419 qglSelectTexture(gl_mtex_enum+1);
420 glBindTexture(GL_TEXTURE_2D, lighttexnum);
422 vert = &wallvert[p->firstvert];
424 for (j=0 ; j<p->numverts ; j++, vert++)
426 qglMTexCoord2f(gl_mtex_enum, vert->vert[3], vert->vert[4]); // texture
427 qglMTexCoord2f((gl_mtex_enum+1), vert->vert[5], vert->vert[6]); // lightmap
428 glVertex3fv (vert->vert);
433 qglSelectTexture(gl_mtex_enum+1);
434 glDisable(GL_TEXTURE_2D);
435 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
436 qglSelectTexture(gl_mtex_enum+0);
437 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
441 // first do the textures
442 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
444 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
446 if (p->texnum != texnum)
449 glBindTexture(GL_TEXTURE_2D, texnum);
451 vert = &wallvert[p->firstvert];
453 for (j=0 ; j<p->numverts ; j++, vert++)
455 glTexCoord2f (vert->vert[3], vert->vert[4]);
456 glVertex3fv (vert->vert);
460 // then modulate using the lightmaps
461 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
462 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
465 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
467 if (p->lighttexnum != texnum)
469 texnum = p->lighttexnum;
470 glBindTexture(GL_TEXTURE_2D, texnum);
472 vert = &wallvert[p->firstvert];
474 for (j=0 ; j<p->numverts ; j++, vert++)
476 glTexCoord2f (vert->vert[5], vert->vert[6]);
477 glVertex3fv (vert->vert);
482 // switch to additive mode settings
484 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
485 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
487 // glDisable(GL_ALPHA_TEST);
488 glShadeModel(GL_SMOOTH);
489 // render vertex lit overlays ontop
491 for (i = 0, p = wallpoly;i < currentwallpoly;i++, p++)
495 for (j = 0,vertcolor = &wallvertcolor[p->firstvert];j < p->numverts;j++, vertcolor++)
496 if (vertcolor->r || vertcolor->g || vertcolor->b)
501 if (p->texnum != texnum)
504 glBindTexture(GL_TEXTURE_2D, texnum);
507 for (j = 0,vert = &wallvert[p->firstvert], vertcolor = &wallvertcolor[p->firstvert];j < p->numverts;j++, vert++, vertcolor++)
509 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
510 glTexCoord2f(vert->vert[3], vert->vert[4]);
511 // again, vector version isn't supported I think
512 glColor3ub(vertcolor->r, vertcolor->g, vertcolor->b);
513 glVertex3fv(vert->vert);
517 // render glow textures
518 glShadeModel(GL_FLAT);
519 glBlendFunc(GL_ONE, GL_ONE);
521 glColor3f(0.5,0.5,0.5);
525 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
529 if (p->glowtexnum != texnum)
531 texnum = p->glowtexnum;
532 glBindTexture(GL_TEXTURE_2D, texnum);
534 vert = &wallvert[p->firstvert];
536 for (j=0 ; j<p->numverts ; j++, vert++)
538 glTexCoord2f (vert->vert[3], vert->vert[4]);
539 glVertex3fv (vert->vert);
544 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
545 glShadeModel(GL_SMOOTH);
549 glDisable(GL_TEXTURE_2D);
550 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
552 vert = &wallvert[p->firstvert];
554 for (j=0 ; j<p->numverts ; j++, vert++)
556 VectorSubtract(vert->vert, r_origin, diff);
557 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
558 glVertex3fv (vert->vert);
562 glEnable(GL_TEXTURE_2D);
564 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
565 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
566 // glDisable(GL_ALPHA_TEST);
567 glShadeModel(GL_SMOOTH);
572 void skypolyclear(void)
574 currentskypoly = currentskyvert = 0;
577 void skypolyrender(void)
582 float length, speedscale;
586 if (currentskypoly < 1)
589 // Con_DPrintf("skypolyrender: %i polys %i vertices\n", currentskypoly, currentskyvert);
590 // glDisable(GL_ALPHA_TEST);
592 // make sure zbuffer is enabled
593 glEnable(GL_DEPTH_TEST);
595 if (!fogenabled && !skyname[0]) // normal quake sky
597 glInterleavedArrays(GL_T2F_V3F, 0, skyvert);
598 // glTexCoordPointer(2, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].tex[0]);
599 // glEnableClientState(GL_TEXTURE_COORD_ARRAY);
600 // glVertexPointer(3, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].v[0]);
601 // glEnableClientState(GL_VERTEX_ARRAY);
603 glColor3f(0.5f, 0.5f, 0.5f);
605 glColor3f(1.0f,1.0f,1.0f);
606 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
607 glEnable(GL_TEXTURE_2D);
609 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
610 glBindTexture(GL_TEXTURE_2D, R_GetTexture(solidskytexture)); // upper clouds
611 speedscale = cl.time*8;
612 speedscale -= (int)speedscale & ~127 ;
613 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
615 vert = skyvert + p->firstvert;
616 for (j = 0;j < p->verts;j++, vert++)
618 VectorSubtract (vert->v, r_origin, dir);
619 dir[2] *= 3; // flatten the sphere
621 length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];
622 length = sqrt (length);
623 length = 6*63/length;
625 vert->tex[0] = (speedscale + dir[0] * length) * (1.0/128);
626 vert->tex[1] = (speedscale + dir[1] * length) * (1.0/128);
629 GL_LockArray(0, currentskyvert);
630 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
631 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
635 glBindTexture(GL_TEXTURE_2D, R_GetTexture(alphaskytexture)); // lower clouds
636 speedscale = cl.time*16;
637 speedscale -= (int)speedscale & ~127 ;
638 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
640 vert = skyvert + p->firstvert;
641 for (j = 0;j < p->verts;j++, vert++)
643 VectorSubtract (vert->v, r_origin, dir);
644 dir[2] *= 3; // flatten the sphere
646 length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];
647 length = sqrt (length);
648 length = 6*63/length;
650 vert->tex[0] = (speedscale + dir[0] * length) * (1.0/128);
651 vert->tex[1] = (speedscale + dir[1] * length) * (1.0/128);
654 GL_LockArray(0, currentskyvert);
655 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
656 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
661 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
662 glDisableClientState(GL_VERTEX_ARRAY);
666 glVertexPointer(3, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].v[0]);
667 glEnableClientState(GL_VERTEX_ARRAY);
668 glDisable(GL_TEXTURE_2D);
669 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
670 glColor3fv(fogcolor); // note: gets rendered over by skybox if fog is not enabled
671 GL_LockArray(0, currentskyvert);
672 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
673 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
676 glEnable(GL_TEXTURE_2D);
677 glDisableClientState(GL_VERTEX_ARRAY);