3 transvert_t *transvert;
4 transpoly_t *transpoly;
5 unsigned short *transpolyindex;
7 wallvertcolor_t *wallvertcolor;
21 cvar_t r_multitexture = {0, "r_multitexture", "1"};
22 cvar_t r_skyquality = {CVAR_SAVE, "r_skyquality", "2"};
23 cvar_t r_mergesky = {CVAR_SAVE, "r_mergesky", "0"};
25 char skyworldname[1024];
26 rtexture_t *mergeskytexture;
27 rtexture_t *solidskytexture;
28 rtexture_t *alphaskytexture;
29 qboolean skyavailable_quake;
30 qboolean skyavailable_box;
32 void R_BuildSky (int scrollupper, int scrolllower);
34 typedef struct translistitem_s
37 struct translistitem_s *next;
41 translistitem translist[MAX_TRANSPOLYS];
42 translistitem *currenttranslist;
44 translistitem *translisthash[4096];
46 float transviewdist; // distance of view origin along the view normal
48 float transreciptable[256];
50 void gl_poly_start(void)
53 transvert = qmalloc(MAX_TRANSVERTS * sizeof(transvert_t));
54 transpoly = qmalloc(MAX_TRANSPOLYS * sizeof(transpoly_t));
55 transpolyindex = qmalloc(MAX_TRANSPOLYS * sizeof(unsigned short));
56 wallvert = qmalloc(MAX_WALLVERTS * sizeof(wallvert_t));
57 wallvertcolor = qmalloc(MAX_WALLVERTS * sizeof(wallvertcolor_t));
58 wallpoly = qmalloc(MAX_WALLPOLYS * sizeof(wallpoly_t));
59 skyvert = qmalloc(MAX_SKYVERTS * sizeof(skyvert_t));
60 skypoly = qmalloc(MAX_SKYPOLYS * sizeof(skypoly_t));
61 transreciptable[0] = 0.0f;
62 for (i = 1;i < 256;i++)
63 transreciptable[i] = 1.0f / i;
66 void gl_poly_shutdown(void)
70 qfree(transpolyindex);
78 void gl_poly_newmap(void)
80 skyavailable_box = false;
81 skyavailable_quake = false;
82 if (!strcmp(skyworldname, cl.worldmodel->name))
83 skyavailable_quake = true;
86 void GL_Poly_Init(void)
88 Cmd_AddCommand ("loadsky", &LoadSky_f);
89 Cvar_RegisterVariable (&r_multitexture);
90 Cvar_RegisterVariable (&r_skyquality);
91 Cvar_RegisterVariable (&r_mergesky);
92 R_RegisterModule("GL_Poly", gl_poly_start, gl_poly_shutdown, gl_poly_newmap);
95 void transpolyclear(void)
97 currenttranspoly = currenttransvert = 0;
98 currenttranslist = translist;
99 memset(translisthash, 0, sizeof(translisthash));
100 transviewdist = DotProduct(r_origin, vpn);
103 // turned into a #define
105 void transpolybegin(int texnum, int glowtexnum, int fogtexnum, int transpolytype)
107 if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
109 transpoly[currenttranspoly].texnum = (unsigned short) texnum;
110 transpoly[currenttranspoly].glowtexnum = (unsigned short) glowtexnum;
111 transpoly[currenttranspoly].fogtexnum = (unsigned short) fogtexnum;
112 transpoly[currenttranspoly].transpolytype = (unsigned short) transpolytype;
113 transpoly[currenttranspoly].firstvert = currenttransvert;
114 transpoly[currenttranspoly].verts = 0;
115 // transpoly[currenttranspoly].ndist = 0; // clear the normal
119 // turned into a #define
121 void transpolyvert(float x, float y, float z, float s, float t, int r, int g, int b, int a)
124 if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
126 transvert[currenttransvert].s = s;
127 transvert[currenttransvert].t = t;
128 transvert[currenttransvert].r = bound(0, r, 255);
129 transvert[currenttransvert].g = bound(0, g, 255);
130 transvert[currenttransvert].b = bound(0, b, 255);
131 transvert[currenttransvert].a = bound(0, a, 255);
132 transvert[currenttransvert].v[0] = x;
133 transvert[currenttransvert].v[1] = y;
134 transvert[currenttransvert].v[2] = z;
136 transpoly[currenttranspoly].verts++;
140 void transpolyend(void)
142 float center, d, maxdist;
145 if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
147 if (transpoly[currenttranspoly].verts < 3) // skip invalid polygons
149 currenttransvert = transpoly[currenttranspoly].firstvert; // reset vert pointer
153 maxdist = -1000000000000000.0f; // eh, it's definitely behind it, so...
154 for (i = 0,v = &transvert[transpoly[currenttranspoly].firstvert];i < transpoly[currenttranspoly].verts;i++, v++)
156 d = DotProduct(v->v, vpn);
161 maxdist -= transviewdist;
162 if (maxdist < 4.0f) // behind view
164 currenttransvert = transpoly[currenttranspoly].firstvert; // reset vert pointer
167 center *= transreciptable[transpoly[currenttranspoly].verts];
168 center -= transviewdist;
169 i = bound(0, (int) center, 4095);
170 currenttranslist->next = translisthash[i];
171 currenttranslist->poly = transpoly + currenttranspoly;
172 translisthash[i] = currenttranslist;
177 int transpolyindices;
179 void transpolyrender(void)
181 int i, j, tpolytype, texnum;
185 if (currenttranspoly < 1)
187 // transpolyrenderminmax();
188 // if (transpolyindices < 1)
191 // Con_DPrintf("transpolyrender: %i polys %i infront %i vertices\n", currenttranspoly, transpolyindices, currenttransvert);
192 // if (transpolyindices >= 2)
194 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
196 glShadeModel(GL_SMOOTH);
197 glDepthMask(0); // disable zbuffer updates
198 glDisable(GL_ALPHA_TEST);
199 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
200 tpolytype = TPOLYTYPE_ALPHA;
203 if (gl_vertexarrays.value)
205 // set up the vertex array
206 glInterleavedArrays(GL_T2F_C4UB_V3F, 0, transvert);
207 for (i = 0;i < transpolyindices;i++)
209 p = &transpoly[transpolyindex[i]];
210 if (p->texnum != texnum || p->transpolytype != tpolytype)
212 if (p->texnum != texnum)
215 glBindTexture(GL_TEXTURE_2D, texnum);
217 if (p->transpolytype != tpolytype)
219 tpolytype = p->transpolytype;
220 if (tpolytype == TPOLYTYPE_ADD) // additive
221 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
223 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
226 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
229 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
230 glBindTexture(GL_TEXTURE_2D, texnum);
231 tpolytype = TPOLYTYPE_ADD; // might match next poly
232 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
233 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
236 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
237 glDisableClientState(GL_COLOR_ARRAY);
238 glDisableClientState(GL_VERTEX_ARRAY);
246 for (i = 4095;i >= 0;i--)
248 item = translisthash[i];
253 if (p->texnum != texnum || p->verts != points || p->transpolytype != tpolytype)
258 // LordHavoc: Matrox G200 cards can't handle per pixel alpha
260 glEnable(GL_ALPHA_TEST);
262 glDisable(GL_ALPHA_TEST);
264 if (p->texnum != texnum)
267 glBindTexture(GL_TEXTURE_2D, texnum);
269 if (p->transpolytype != tpolytype)
271 tpolytype = p->transpolytype;
272 if (tpolytype == TPOLYTYPE_ADD) // additive
273 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
275 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
281 glBegin(GL_TRIANGLES);
288 points = -1; // to force a reinit on the next poly
292 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
294 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
295 glTexCoord2f(vert->s, vert->t);
296 // again, vector version isn't supported I think
297 glColor4ub(vert->r, vert->g, vert->b, vert->a);
298 glVertex3fv(vert->v);
303 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
304 glBindTexture(GL_TEXTURE_2D, texnum);
305 if (tpolytype != TPOLYTYPE_ADD)
307 tpolytype = TPOLYTYPE_ADD; // might match next poly
308 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
312 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
314 glColor4ub(255,255,255,vert->a);
315 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
316 glTexCoord2f(vert->s, vert->t);
317 glVertex3fv(vert->v);
321 if (fogenabled && p->transpolytype == TPOLYTYPE_ALPHA)
325 points = -1; // to force a reinit on the next poly
326 if (tpolytype != TPOLYTYPE_ALPHA)
328 tpolytype = TPOLYTYPE_ALPHA; // probably matchs next poly
329 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
333 if (texnum != p->fogtexnum) // highly unlikely to match next poly, but...
335 texnum = p->fogtexnum;
336 glBindTexture(GL_TEXTURE_2D, texnum);
339 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
341 VectorSubtract(vert->v, r_origin, diff);
342 glTexCoord2f(vert->s, vert->t);
343 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
344 glVertex3fv(vert->v);
350 glDisable(GL_TEXTURE_2D);
352 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
354 VectorSubtract(vert->v, r_origin, diff);
355 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
356 glVertex3fv(vert->v);
359 glEnable(GL_TEXTURE_2D);
367 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
368 glDepthMask(1); // enable zbuffer updates
369 glDisable(GL_ALPHA_TEST);
372 void wallpolyclear(void)
374 currentwallpoly = currentwallvert = 0;
377 void wallpolyrender(void)
379 int i, j, texnum, lighttexnum;
382 wallvertcolor_t *vertcolor;
385 if (currentwallpoly < 1)
387 c_brush_polys += currentwallpoly;
389 //Con_DPrintf("wallpolyrender: %i polys %i vertices\n", currentwallpoly, currentwallvert);
391 r_multitexture.value = 0;
393 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
394 glShadeModel(GL_FLAT);
395 // make sure zbuffer is enabled
396 glEnable(GL_DEPTH_TEST);
397 // glDisable(GL_ALPHA_TEST);
400 if (r_fullbright.value) // LordHavoc: easy to do fullbright...
402 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
404 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
406 if (p->texnum != texnum)
409 glBindTexture(GL_TEXTURE_2D, texnum);
411 vert = &wallvert[p->firstvert];
413 for (j=0 ; j<p->numverts ; j++, vert++)
415 glTexCoord2f (vert->vert[3], vert->vert[4]);
416 glVertex3fv (vert->vert);
421 else if (r_multitexture.value)
423 if (gl_combine.value)
425 qglSelectTexture(gl_mtex_enum+0);
426 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
427 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
428 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
429 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
430 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
431 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
432 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
433 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
434 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
435 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_TEXTURE);
436 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_TEXTURE);
437 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
438 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
439 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);
440 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0);
441 glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0);
442 glEnable(GL_TEXTURE_2D);
443 qglSelectTexture(gl_mtex_enum+1);
444 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
445 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
446 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
447 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
448 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
449 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
450 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
451 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
452 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
453 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
454 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_TEXTURE);
455 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
456 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
457 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);
458 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 4.0);
459 glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0);
460 glEnable(GL_TEXTURE_2D);
464 qglSelectTexture(gl_mtex_enum+0);
465 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
466 glEnable(GL_TEXTURE_2D);
467 qglSelectTexture(gl_mtex_enum+1);
468 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
469 glEnable(GL_TEXTURE_2D);
473 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
475 if (p->texnum != texnum || p->lighttexnum != lighttexnum)
478 lighttexnum = p->lighttexnum;
479 qglSelectTexture(gl_mtex_enum+0);
480 glBindTexture(GL_TEXTURE_2D, texnum);
481 qglSelectTexture(gl_mtex_enum+1);
482 glBindTexture(GL_TEXTURE_2D, lighttexnum);
484 vert = &wallvert[p->firstvert];
486 for (j=0 ; j<p->numverts ; j++, vert++)
488 qglMTexCoord2f(gl_mtex_enum, vert->vert[3], vert->vert[4]); // texture
489 qglMTexCoord2f((gl_mtex_enum+1), vert->vert[5], vert->vert[6]); // lightmap
490 glVertex3fv (vert->vert);
495 qglSelectTexture(gl_mtex_enum+1);
496 glDisable(GL_TEXTURE_2D);
497 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
498 qglSelectTexture(gl_mtex_enum+0);
499 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
503 // first do the textures
504 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
506 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
508 if (p->texnum != texnum)
511 glBindTexture(GL_TEXTURE_2D, texnum);
513 vert = &wallvert[p->firstvert];
515 for (j=0 ; j<p->numverts ; j++, vert++)
517 glTexCoord2f (vert->vert[3], vert->vert[4]);
518 glVertex3fv (vert->vert);
522 // then modulate using the lightmaps
523 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
524 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
527 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
529 if (p->lighttexnum != texnum)
531 texnum = p->lighttexnum;
532 glBindTexture(GL_TEXTURE_2D, texnum);
534 vert = &wallvert[p->firstvert];
536 for (j=0 ; j<p->numverts ; j++, vert++)
538 glTexCoord2f (vert->vert[5], vert->vert[6]);
539 glVertex3fv (vert->vert);
544 // switch to additive mode settings
546 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
547 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
549 // glDisable(GL_ALPHA_TEST);
550 glShadeModel(GL_SMOOTH);
551 // render vertex lit overlays ontop
553 for (i = 0, p = wallpoly;i < currentwallpoly;i++, p++)
557 for (j = 0,vertcolor = &wallvertcolor[p->firstvert];j < p->numverts;j++, vertcolor++)
558 if (vertcolor->r || vertcolor->g || vertcolor->b)
563 if (p->texnum != texnum)
566 glBindTexture(GL_TEXTURE_2D, texnum);
569 for (j = 0,vert = &wallvert[p->firstvert], vertcolor = &wallvertcolor[p->firstvert];j < p->numverts;j++, vert++, vertcolor++)
571 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
572 glTexCoord2f(vert->vert[3], vert->vert[4]);
573 // again, vector version isn't supported I think
574 glColor3ub(vertcolor->r, vertcolor->g, vertcolor->b);
575 glVertex3fv(vert->vert);
579 // render glow textures
580 glShadeModel(GL_FLAT);
581 glBlendFunc(GL_ONE, GL_ONE);
583 glColor3f(0.5,0.5,0.5);
587 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
591 if (p->glowtexnum != texnum)
593 texnum = p->glowtexnum;
594 glBindTexture(GL_TEXTURE_2D, texnum);
596 vert = &wallvert[p->firstvert];
598 for (j=0 ; j<p->numverts ; j++, vert++)
600 glTexCoord2f (vert->vert[3], vert->vert[4]);
601 glVertex3fv (vert->vert);
606 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
607 glShadeModel(GL_SMOOTH);
611 glDisable(GL_TEXTURE_2D);
612 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
614 vert = &wallvert[p->firstvert];
616 for (j=0 ; j<p->numverts ; j++, vert++)
618 VectorSubtract(vert->vert, r_origin, diff);
619 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
620 glVertex3fv (vert->vert);
624 glEnable(GL_TEXTURE_2D);
626 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
627 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
628 // glDisable(GL_ALPHA_TEST);
629 glShadeModel(GL_SMOOTH);
636 int skyrenderglquakepolys;
637 int skyrendertwolayers;
639 void skypolyclear(void)
641 currentskypoly = currentskyvert = 0;
642 skyrendersphere = false;
643 skyrenderbox = false;
644 skyrenderglquakepolys = false;
645 skyrendertwolayers = false;
646 if (r_skyquality.value >= 1 && !fogenabled)
648 if (skyavailable_box)
650 else if (skyavailable_quake)
652 switch((int) r_skyquality.value)
655 skyrenderglquakepolys = true;
658 skyrenderglquakepolys = true;
659 skyrendertwolayers = true;
662 skyrendersphere = true;
666 skyrendersphere = true;
667 skyrendertwolayers = true;
672 if (r_mergesky.value && (skyrenderglquakepolys || skyrendersphere))
674 skyrendertwolayers = false;
675 // R_BuildSky((int) (cl.time * 8.0), (int) (cl.time * 16.0));
676 // R_BuildSky((int) (cl.time * -8.0), 0);
677 R_BuildSky(0, (int) (cl.time * 8.0));
682 void skypolyrender(void)
687 float length, speedscale;
691 if (currentskypoly < 1)
693 // glDisable(GL_ALPHA_TEST);
695 // make sure zbuffer is enabled
696 glEnable(GL_DEPTH_TEST);
698 if (skyrenderglquakepolys)
700 if (r_mergesky.value)
701 glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture)); // both layers in one texture
703 glBindTexture(GL_TEXTURE_2D, R_GetTexture(solidskytexture)); // upper clouds
704 glTexCoordPointer(2, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].tex[0]);
705 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
706 glVertexPointer(3, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].v[0]);
707 glEnableClientState(GL_VERTEX_ARRAY);
709 glColor3f(0.5f, 0.5f, 0.5f);
711 glColor3f(1.0f,1.0f,1.0f);
712 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
713 glEnable(GL_TEXTURE_2D);
715 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
716 if (r_mergesky.value)
718 speedscale = cl.time * (8.0/128.0);
719 speedscale -= (int)speedscale;
723 speedscale = cl.time * (8.0/128.0);
724 speedscale -= (int)speedscale;
726 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
728 vert = skyvert + p->firstvert;
729 for (j = 0;j < p->verts;j++, vert++)
731 VectorSubtract (vert->v, r_origin, dir);
732 // flatten the sphere
735 length = 3.0f / sqrt(DotProduct(dir, dir));
737 vert->tex[0] = speedscale + dir[0] * length;
738 vert->tex[1] = speedscale + dir[1] * length;
741 GL_LockArray(0, currentskyvert);
742 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
743 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
745 if (skyrendertwolayers)
749 glBindTexture(GL_TEXTURE_2D, R_GetTexture(alphaskytexture)); // lower clouds
750 speedscale = cl.time * (16.0 / 128.0);
751 speedscale -= (int)speedscale;
752 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
754 vert = skyvert + p->firstvert;
755 for (j = 0;j < p->verts;j++, vert++)
757 VectorSubtract (vert->v, r_origin, dir);
758 // flatten the sphere
761 length = 3.0f / sqrt(DotProduct(dir, dir));
763 vert->tex[0] = speedscale + dir[0] * length;
764 vert->tex[1] = speedscale + dir[1] * length;
767 GL_LockArray(0, currentskyvert);
768 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
769 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
775 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
776 glDisableClientState(GL_VERTEX_ARRAY);
780 glVertexPointer(3, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].v[0]);
781 glEnableClientState(GL_VERTEX_ARRAY);
782 glDisable(GL_TEXTURE_2D);
783 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
784 // note: this color is not seen if skyrendersphere or skyrenderbox is on
785 glColor3fv(fogcolor);
786 GL_LockArray(0, currentskyvert);
787 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
788 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
791 glEnable(GL_TEXTURE_2D);
792 glDisableClientState(GL_VERTEX_ARRAY);
796 static char skyname[256];
803 char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
804 rtexture_t *skyboxside[6];
805 int R_SetSkyBox(char *sky)
811 if (strcmp(sky, skyname) == 0) // no change
814 if (strlen(sky) > 1000)
816 Con_Printf ("sky name too long (%i, max is 1000)\n", strlen(sky));
820 skyboxside[0] = skyboxside[1] = skyboxside[2] = skyboxside[3] = skyboxside[4] = skyboxside[5] = NULL;
821 skyavailable_box = false;
827 for (i = 0;i < 6;i++)
829 sprintf (name, "env/%s%s", sky, suf[i]);
830 if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
832 sprintf (name, "gfx/env/%s%s", sky, suf[i]);
833 if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
835 Con_Printf ("Couldn't load %s\n", name);
839 skyboxside[i] = R_LoadTexture(va("skyboxside%d", i), image_width, image_height, image_rgba, TEXF_RGBA | TEXF_PRECACHE);
843 if (skyboxside[0] || skyboxside[1] || skyboxside[2] || skyboxside[3] || skyboxside[4] || skyboxside[5])
845 skyavailable_box = true;
846 strcpy(skyname, sky);
852 // LordHavoc: added LoadSky console command
853 void LoadSky_f (void)
859 Con_Printf("current sky: %s\n", skyname);
861 Con_Printf("no skybox has been set\n");
864 if (R_SetSkyBox(Cmd_Argv(1)))
867 Con_Printf("skybox set to %s\n", skyname);
869 Con_Printf("skybox disabled\n");
872 Con_Printf("failed to load skybox %s\n", Cmd_Argv(1));
875 Con_Printf("usage: loadsky skyname\n");
880 #define R_SkyBoxPolyVec(s,t,x,y,z) \
881 glTexCoord2f((s) * (254.0f/256.0f) + (1.0f/256.0f), (t) * (254.0f/256.0f) + (1.0f/256.0f));\
882 glVertex3f((x) * 1024.0 + r_origin[0], (y) * 1024.0 + r_origin[1], (z) * 1024.0 + r_origin[2]);
886 glDisable(GL_DEPTH_TEST);
888 glDisable (GL_BLEND);
889 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
891 glColor3f(0.5,0.5,0.5);
894 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[3])); // front
896 R_SkyBoxPolyVec(1, 0, 1, -1, 1);
897 R_SkyBoxPolyVec(1, 1, 1, -1, -1);
898 R_SkyBoxPolyVec(0, 1, 1, 1, -1);
899 R_SkyBoxPolyVec(0, 0, 1, 1, 1);
901 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[1])); // back
903 R_SkyBoxPolyVec(1, 0, -1, 1, 1);
904 R_SkyBoxPolyVec(1, 1, -1, 1, -1);
905 R_SkyBoxPolyVec(0, 1, -1, -1, -1);
906 R_SkyBoxPolyVec(0, 0, -1, -1, 1);
908 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[0])); // right
910 R_SkyBoxPolyVec(1, 0, 1, 1, 1);
911 R_SkyBoxPolyVec(1, 1, 1, 1, -1);
912 R_SkyBoxPolyVec(0, 1, -1, 1, -1);
913 R_SkyBoxPolyVec(0, 0, -1, 1, 1);
915 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[2])); // left
917 R_SkyBoxPolyVec(1, 0, -1, -1, 1);
918 R_SkyBoxPolyVec(1, 1, -1, -1, -1);
919 R_SkyBoxPolyVec(0, 1, 1, -1, -1);
920 R_SkyBoxPolyVec(0, 0, 1, -1, 1);
922 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[4])); // up
924 R_SkyBoxPolyVec(1, 0, 1, -1, 1);
925 R_SkyBoxPolyVec(1, 1, 1, 1, 1);
926 R_SkyBoxPolyVec(0, 1, -1, 1, 1);
927 R_SkyBoxPolyVec(0, 0, -1, -1, 1);
929 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[5])); // down
931 R_SkyBoxPolyVec(1, 0, 1, 1, -1);
932 R_SkyBoxPolyVec(1, 1, 1, -1, -1);
933 R_SkyBoxPolyVec(0, 1, -1, -1, -1);
934 R_SkyBoxPolyVec(0, 0, -1, 1, -1);
937 glEnable (GL_DEPTH_TEST);
941 float skysphereouter[33*33*5];
942 float skysphereinner[33*33*5];
943 int skysphereindices[32*32*6];
944 void skyspherecalc(float *sphere, float dx, float dy, float dz)
946 float a, b, x, ax, ay, v[3], length;
948 for (a = 0;a <= 1;a += (1.0 / 32.0))
950 ax = cos(a * M_PI * 2);
951 ay = -sin(a * M_PI * 2);
952 for (b = 0;b <= 1;b += (1.0 / 32.0))
954 x = cos(b * M_PI * 2);
957 v[2] = -sin(b * M_PI * 2) * dz;
958 length = 3.0f / sqrt(v[0]*v[0]+v[1]*v[1]+(v[2]*v[2]*9));
959 *sphere++ = v[0] * length;
960 *sphere++ = v[1] * length;
966 index = skysphereindices;
967 for (j = 0;j < 32;j++)
969 for (i = 0;i < 32;i++)
971 *index++ = j * 33 + i;
972 *index++ = j * 33 + i + 1;
973 *index++ = (j + 1) * 33 + i;
975 *index++ = j * 33 + i + 1;
976 *index++ = (j + 1) * 33 + i + 1;
977 *index++ = (j + 1) * 33 + i;
983 void skysphere(float *source, float s)
985 float vert[33*33][4], tex[33*33][2], *v, *t;
989 for (i = 0;i < (33*33);i++)
991 *t++ = *source++ + s;
992 *t++ = *source++ + s;
993 *v++ = *source++ + r_origin[0];
994 *v++ = *source++ + r_origin[1];
995 *v++ = *source++ + r_origin[2];
998 glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 2, tex);
999 glVertexPointer(3, GL_FLOAT, sizeof(float) * 4, vert);
1000 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1001 glEnableClientState(GL_VERTEX_ARRAY);
1002 GL_LockArray(0, 32*32*6);
1003 glDrawElements(GL_TRIANGLES, 32*32*6, GL_UNSIGNED_INT, &skysphereindices[0]);
1005 glDisableClientState(GL_VERTEX_ARRAY);
1006 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1009 void R_SkySphere(void)
1012 static qboolean skysphereinitialized = false;
1013 if (!skysphereinitialized)
1015 skysphereinitialized = true;
1016 skyspherecalc(skysphereouter, 1024, 1024, 1024 / 3);
1017 skyspherecalc(skysphereinner, 1024, 1024, 1024 / 3);
1019 glDisable(GL_DEPTH_TEST);
1021 glDisable (GL_BLEND);
1022 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1023 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1025 glColor3f(0.5,0.5,0.5);
1028 if (r_mergesky.value)
1030 glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture)); // both layers in one texture
1031 speedscale = cl.time*8.0/128.0;
1032 speedscale -= (int)speedscale;
1033 skysphere(skysphereouter, speedscale);
1037 glBindTexture(GL_TEXTURE_2D, R_GetTexture(solidskytexture)); // upper clouds
1038 speedscale = cl.time*8.0/128.0;
1039 speedscale -= (int)speedscale;
1040 skysphere(skysphereouter, speedscale);
1041 if (skyrendertwolayers)
1043 glEnable (GL_BLEND);
1044 glBindTexture(GL_TEXTURE_2D, R_GetTexture(alphaskytexture)); // lower clouds
1045 speedscale = cl.time*16.0/128.0;
1046 speedscale -= (int)speedscale;
1047 skysphere(skysphereinner, speedscale);
1048 glDisable (GL_BLEND);
1052 glEnable (GL_DEPTH_TEST);
1058 if (!r_render.value)
1060 if (skyrendersphere)
1062 else if (skyrenderbox)
1066 //===============================================================
1068 byte skyupperlayerpixels[128*128*4];
1069 byte skylowerlayerpixels[128*128*4];
1070 byte skymergedpixels[128*128*4];
1072 void R_BuildSky (int scrollupper, int scrolllower)
1074 int x, y, ux, uy, lx, ly;
1076 m = skymergedpixels;
1077 for (y = 0;y < 128;y++)
1079 uy = (y + scrollupper) & 127;
1080 ly = (y + scrolllower) & 127;
1081 for (x = 0;x < 128;x++)
1083 ux = (x + scrollupper) & 127;
1084 lx = (x + scrolllower) & 127;
1085 u = &skyupperlayerpixels[(uy * 128 + ux) * 4];
1086 l = &skylowerlayerpixels[(ly * 128 + lx) * 4];
1090 *((int *)m) = *((int *)l);
1093 m[0] = ((((int) l[0] - (int) u[0]) * (int) l[3]) >> 8) + (int) u[0];
1094 m[1] = ((((int) l[1] - (int) u[1]) * (int) l[3]) >> 8) + (int) u[1];
1095 m[2] = ((((int) l[2] - (int) u[2]) * (int) l[3]) >> 8) + (int) u[2];
1100 *((int *)m) = *((int *)u);
1104 // FIXME: implement generated texture callbacks to speed this up? (skip identifier lookup, CRC, memcpy, etc)
1105 if (mergeskytexture)
1107 glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture));
1108 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, skymergedpixels);
1111 mergeskytexture = R_LoadTexture("mergedskytexture", 128, 128, skymergedpixels, TEXF_RGBA | TEXF_ALWAYSPRECACHE);
1118 A sky texture is 256*128, with the right side being a masked overlay
1121 void R_InitSky (byte *src, int bytesperpixel)
1124 unsigned trans[128*128];
1132 strcpy(skyworldname, loadmodel->name);
1133 if (bytesperpixel == 4)
1135 for (i = 0;i < 128;i++)
1136 for (j = 0;j < 128;j++)
1137 trans[(i*128) + j] = src[i*256+j+128];
1141 // make an average value for the back to avoid
1142 // a fringe on the top level
1144 for (i=0 ; i<128 ; i++)
1146 for (j=0 ; j<128 ; j++)
1148 p = src[i*256 + j + 128];
1149 rgba = &d_8to24table[p];
1150 trans[(i*128) + j] = *rgba;
1151 r += ((byte *)rgba)[0];
1152 g += ((byte *)rgba)[1];
1153 b += ((byte *)rgba)[2];
1157 ((byte *)&transpix)[0] = r/(128*128);
1158 ((byte *)&transpix)[1] = g/(128*128);
1159 ((byte *)&transpix)[2] = b/(128*128);
1160 ((byte *)&transpix)[3] = 0;
1163 memcpy(skyupperlayerpixels, trans, 128*128*4);
1165 solidskytexture = R_LoadTexture ("sky_solidtexture", 128, 128, (byte *) trans, TEXF_RGBA | TEXF_PRECACHE);
1167 if (bytesperpixel == 4)
1169 for (i = 0;i < 128;i++)
1170 for (j = 0;j < 128;j++)
1171 trans[(i*128) + j] = src[i*256+j];
1175 for (i=0 ; i<128 ; i++)
1177 for (j=0 ; j<128 ; j++)
1181 trans[(i*128) + j] = transpix;
1183 trans[(i*128) + j] = d_8to24table[p];
1188 memcpy(skylowerlayerpixels, trans, 128*128*4);
1190 alphaskytexture = R_LoadTexture ("sky_alphatexture", 128, 128, (byte *) trans, TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);