3 transvert_t *transvert;
4 transpoly_t *transpoly;
5 unsigned short *transpolyindex;
7 wallvertcolor_t *wallvertcolor;
21 cvar_t r_multitexture = {"r_multitexture", "1"};
22 cvar_t r_skyquality = {"r_skyquality", "2"};
23 cvar_t r_mergesky = {"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 qglSelectTexture(gl_mtex_enum+0);
424 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
425 glEnable(GL_TEXTURE_2D);
426 qglSelectTexture(gl_mtex_enum+1);
427 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
428 glEnable(GL_TEXTURE_2D);
431 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
433 if (p->texnum != texnum || p->lighttexnum != lighttexnum)
436 lighttexnum = p->lighttexnum;
437 qglSelectTexture(gl_mtex_enum+0);
438 glBindTexture(GL_TEXTURE_2D, texnum);
439 qglSelectTexture(gl_mtex_enum+1);
440 glBindTexture(GL_TEXTURE_2D, lighttexnum);
442 vert = &wallvert[p->firstvert];
444 for (j=0 ; j<p->numverts ; j++, vert++)
446 qglMTexCoord2f(gl_mtex_enum, vert->vert[3], vert->vert[4]); // texture
447 qglMTexCoord2f((gl_mtex_enum+1), vert->vert[5], vert->vert[6]); // lightmap
448 glVertex3fv (vert->vert);
453 qglSelectTexture(gl_mtex_enum+1);
454 glDisable(GL_TEXTURE_2D);
455 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
456 qglSelectTexture(gl_mtex_enum+0);
457 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
461 // first do the textures
462 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
464 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
466 if (p->texnum != texnum)
469 glBindTexture(GL_TEXTURE_2D, texnum);
471 vert = &wallvert[p->firstvert];
473 for (j=0 ; j<p->numverts ; j++, vert++)
475 glTexCoord2f (vert->vert[3], vert->vert[4]);
476 glVertex3fv (vert->vert);
480 // then modulate using the lightmaps
481 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
482 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
485 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
487 if (p->lighttexnum != texnum)
489 texnum = p->lighttexnum;
490 glBindTexture(GL_TEXTURE_2D, texnum);
492 vert = &wallvert[p->firstvert];
494 for (j=0 ; j<p->numverts ; j++, vert++)
496 glTexCoord2f (vert->vert[5], vert->vert[6]);
497 glVertex3fv (vert->vert);
502 // switch to additive mode settings
504 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
505 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
507 // glDisable(GL_ALPHA_TEST);
508 glShadeModel(GL_SMOOTH);
509 // render vertex lit overlays ontop
511 for (i = 0, p = wallpoly;i < currentwallpoly;i++, p++)
515 for (j = 0,vertcolor = &wallvertcolor[p->firstvert];j < p->numverts;j++, vertcolor++)
516 if (vertcolor->r || vertcolor->g || vertcolor->b)
521 if (p->texnum != texnum)
524 glBindTexture(GL_TEXTURE_2D, texnum);
527 for (j = 0,vert = &wallvert[p->firstvert], vertcolor = &wallvertcolor[p->firstvert];j < p->numverts;j++, vert++, vertcolor++)
529 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
530 glTexCoord2f(vert->vert[3], vert->vert[4]);
531 // again, vector version isn't supported I think
532 glColor3ub(vertcolor->r, vertcolor->g, vertcolor->b);
533 glVertex3fv(vert->vert);
537 // render glow textures
538 glShadeModel(GL_FLAT);
539 glBlendFunc(GL_ONE, GL_ONE);
541 glColor3f(0.5,0.5,0.5);
545 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
549 if (p->glowtexnum != texnum)
551 texnum = p->glowtexnum;
552 glBindTexture(GL_TEXTURE_2D, texnum);
554 vert = &wallvert[p->firstvert];
556 for (j=0 ; j<p->numverts ; j++, vert++)
558 glTexCoord2f (vert->vert[3], vert->vert[4]);
559 glVertex3fv (vert->vert);
564 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
565 glShadeModel(GL_SMOOTH);
569 glDisable(GL_TEXTURE_2D);
570 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
572 vert = &wallvert[p->firstvert];
574 for (j=0 ; j<p->numverts ; j++, vert++)
576 VectorSubtract(vert->vert, r_origin, diff);
577 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
578 glVertex3fv (vert->vert);
582 glEnable(GL_TEXTURE_2D);
584 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
585 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
586 // glDisable(GL_ALPHA_TEST);
587 glShadeModel(GL_SMOOTH);
594 int skyrenderglquakepolys;
595 int skyrendertwolayers;
597 void skypolyclear(void)
599 currentskypoly = currentskyvert = 0;
600 skyrendersphere = false;
601 skyrenderbox = false;
602 skyrenderglquakepolys = false;
603 skyrendertwolayers = false;
604 if (r_skyquality.value >= 1 && !fogenabled)
606 if (skyavailable_box)
608 else if (skyavailable_quake)
610 switch((int) r_skyquality.value)
613 skyrenderglquakepolys = true;
616 skyrenderglquakepolys = true;
617 skyrendertwolayers = true;
620 skyrendersphere = true;
624 skyrendersphere = true;
625 skyrendertwolayers = true;
630 if (r_mergesky.value && (skyrenderglquakepolys || skyrendersphere))
632 skyrendertwolayers = false;
633 // R_BuildSky((int) (cl.time * 8.0), (int) (cl.time * 16.0));
634 // R_BuildSky((int) (cl.time * -8.0), 0);
635 R_BuildSky(0, (int) (cl.time * 8.0));
640 void skypolyrender(void)
645 float length, speedscale;
649 if (currentskypoly < 1)
651 // glDisable(GL_ALPHA_TEST);
653 // make sure zbuffer is enabled
654 glEnable(GL_DEPTH_TEST);
656 if (skyrenderglquakepolys)
658 if (r_mergesky.value)
659 glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture)); // both layers in one texture
661 glBindTexture(GL_TEXTURE_2D, R_GetTexture(solidskytexture)); // upper clouds
662 glTexCoordPointer(2, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].tex[0]);
663 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
664 glVertexPointer(3, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].v[0]);
665 glEnableClientState(GL_VERTEX_ARRAY);
667 glColor3f(0.5f, 0.5f, 0.5f);
669 glColor3f(1.0f,1.0f,1.0f);
670 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
671 glEnable(GL_TEXTURE_2D);
673 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
674 if (r_mergesky.value)
676 speedscale = cl.time * (8.0/128.0);
677 speedscale -= (int)speedscale;
681 speedscale = cl.time * (8.0/128.0);
682 speedscale -= (int)speedscale;
684 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
686 vert = skyvert + p->firstvert;
687 for (j = 0;j < p->verts;j++, vert++)
689 VectorSubtract (vert->v, r_origin, dir);
690 // flatten the sphere
693 length = 3.0f / sqrt(DotProduct(dir, dir));
695 vert->tex[0] = speedscale + dir[0] * length;
696 vert->tex[1] = speedscale + dir[1] * length;
699 GL_LockArray(0, currentskyvert);
700 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
701 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
703 if (skyrendertwolayers)
707 glBindTexture(GL_TEXTURE_2D, R_GetTexture(alphaskytexture)); // lower clouds
708 speedscale = cl.time * (16.0 / 128.0);
709 speedscale -= (int)speedscale;
710 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
712 vert = skyvert + p->firstvert;
713 for (j = 0;j < p->verts;j++, vert++)
715 VectorSubtract (vert->v, r_origin, dir);
716 // flatten the sphere
719 length = 3.0f / sqrt(DotProduct(dir, dir));
721 vert->tex[0] = speedscale + dir[0] * length;
722 vert->tex[1] = speedscale + dir[1] * length;
725 GL_LockArray(0, currentskyvert);
726 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
727 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
733 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
734 glDisableClientState(GL_VERTEX_ARRAY);
738 glVertexPointer(3, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].v[0]);
739 glEnableClientState(GL_VERTEX_ARRAY);
740 glDisable(GL_TEXTURE_2D);
741 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
742 // note: this color is not seen if skyrendersphere or skyrenderbox is on
743 glColor3fv(fogcolor);
744 GL_LockArray(0, currentskyvert);
745 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
746 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
749 glEnable(GL_TEXTURE_2D);
750 glDisableClientState(GL_VERTEX_ARRAY);
761 char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
762 rtexture_t *skyboxside[6];
763 void R_SetSkyBox(char *sky)
769 if (strcmp(sky, skyname) == 0) // no change
772 if (strlen(sky) > 1000)
774 Con_Printf ("sky name too long (%i, max is 1000)\n", strlen(sky));
778 skyboxside[0] = skyboxside[1] = skyboxside[2] = skyboxside[3] = skyboxside[4] = skyboxside[5] = NULL;
779 skyavailable_box = false;
785 for (i = 0;i < 6;i++)
787 sprintf (name, "env/%s%s", skyname, suf[i]);
788 if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
790 sprintf (name, "gfx/env/%s%s", skyname, suf[i]);
791 if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
793 Con_Printf ("Couldn't load %s\n", name);
797 skyboxside[i] = R_LoadTexture(va("skyboxside%d", i), image_width, image_height, image_rgba, TEXF_RGBA | TEXF_PRECACHE);
801 if (skyboxside[0] || skyboxside[1] || skyboxside[2] || skyboxside[3] || skyboxside[4] || skyboxside[5])
803 skyavailable_box = true;
804 strcpy(skyname, sky);
808 // LordHavoc: added LoadSky console command
809 void LoadSky_f (void)
815 Con_Printf("current sky: %s\n", skyname);
817 Con_Printf("no skybox has been set\n", skyname);
820 R_SetSkyBox(Cmd_Argv(1));
821 Con_Printf("skybox set to %s\n", skyname);
824 Con_Printf("usage: loadsky skyname\n");
829 #define R_SkyBoxPolyVec(s,t,x,y,z) \
830 glTexCoord2f((s) * (254.0f/256.0f) + (1.0f/256.0f), (t) * (254.0f/256.0f) + (1.0f/256.0f));\
831 glVertex3f((x) * 1024.0 + r_origin[0], (y) * 1024.0 + r_origin[1], (z) * 1024.0 + r_origin[2]);
835 glDisable(GL_DEPTH_TEST);
837 glDisable (GL_BLEND);
838 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
840 glColor3f(0.5,0.5,0.5);
843 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[3])); // front
845 R_SkyBoxPolyVec(1, 0, 1, -1, 1);
846 R_SkyBoxPolyVec(1, 1, 1, -1, -1);
847 R_SkyBoxPolyVec(0, 1, 1, 1, -1);
848 R_SkyBoxPolyVec(0, 0, 1, 1, 1);
850 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[1])); // back
852 R_SkyBoxPolyVec(1, 0, -1, 1, 1);
853 R_SkyBoxPolyVec(1, 1, -1, 1, -1);
854 R_SkyBoxPolyVec(0, 1, -1, -1, -1);
855 R_SkyBoxPolyVec(0, 0, -1, -1, 1);
857 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[0])); // right
859 R_SkyBoxPolyVec(1, 0, 1, 1, 1);
860 R_SkyBoxPolyVec(1, 1, 1, 1, -1);
861 R_SkyBoxPolyVec(0, 1, -1, 1, -1);
862 R_SkyBoxPolyVec(0, 0, -1, 1, 1);
864 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[2])); // left
866 R_SkyBoxPolyVec(1, 0, -1, -1, 1);
867 R_SkyBoxPolyVec(1, 1, -1, -1, -1);
868 R_SkyBoxPolyVec(0, 1, 1, -1, -1);
869 R_SkyBoxPolyVec(0, 0, 1, -1, 1);
871 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[4])); // up
873 R_SkyBoxPolyVec(1, 0, 1, -1, 1);
874 R_SkyBoxPolyVec(1, 1, 1, 1, 1);
875 R_SkyBoxPolyVec(0, 1, -1, 1, 1);
876 R_SkyBoxPolyVec(0, 0, -1, -1, 1);
878 glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[5])); // down
880 R_SkyBoxPolyVec(1, 0, 1, 1, -1);
881 R_SkyBoxPolyVec(1, 1, 1, -1, -1);
882 R_SkyBoxPolyVec(0, 1, -1, -1, -1);
883 R_SkyBoxPolyVec(0, 0, -1, 1, -1);
886 glEnable (GL_DEPTH_TEST);
890 float skysphereouter[33*33*5];
891 float skysphereinner[33*33*5];
892 int skysphereindices[32*32*6];
893 void skyspherecalc(float *sphere, float dx, float dy, float dz)
895 float a, b, x, ax, ay, v[3], length;
897 for (a = 0;a <= 1;a += (1.0 / 32.0))
899 ax = cos(a * M_PI * 2);
900 ay = -sin(a * M_PI * 2);
901 for (b = 0;b <= 1;b += (1.0 / 32.0))
903 x = cos(b * M_PI * 2);
906 v[2] = -sin(b * M_PI * 2) * dz;
907 length = 3.0f / sqrt(v[0]*v[0]+v[1]*v[1]+(v[2]*v[2]*9));
908 *sphere++ = v[0] * length;
909 *sphere++ = v[1] * length;
915 index = skysphereindices;
916 for (j = 0;j < 32;j++)
918 for (i = 0;i < 32;i++)
920 *index++ = j * 33 + i;
921 *index++ = j * 33 + i + 1;
922 *index++ = (j + 1) * 33 + i;
924 *index++ = j * 33 + i + 1;
925 *index++ = (j + 1) * 33 + i + 1;
926 *index++ = (j + 1) * 33 + i;
932 void skysphere(float *source, float s)
934 float vert[33*33][4], tex[33*33][2], *v, *t;
938 for (i = 0;i < (33*33);i++)
940 *t++ = *source++ + s;
941 *t++ = *source++ + s;
942 *v++ = *source++ + r_origin[0];
943 *v++ = *source++ + r_origin[1];
944 *v++ = *source++ + r_origin[2];
947 glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 2, tex);
948 glVertexPointer(3, GL_FLOAT, sizeof(float) * 4, vert);
949 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
950 glEnableClientState(GL_VERTEX_ARRAY);
951 GL_LockArray(0, 32*32*6);
952 glDrawElements(GL_TRIANGLES, 32*32*6, GL_UNSIGNED_INT, &skysphereindices[0]);
954 glDisableClientState(GL_VERTEX_ARRAY);
955 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
958 void R_SkySphere(void)
961 static qboolean skysphereinitialized = false;
962 if (!skysphereinitialized)
964 skysphereinitialized = true;
965 skyspherecalc(skysphereouter, 1024, 1024, 1024 / 3);
966 skyspherecalc(skysphereinner, 1024, 1024, 1024 / 3);
968 glDisable(GL_DEPTH_TEST);
970 glDisable (GL_BLEND);
971 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
972 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
974 glColor3f(0.5,0.5,0.5);
977 if (r_mergesky.value)
979 glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture)); // both layers in one texture
980 speedscale = cl.time*8.0/128.0;
981 speedscale -= (int)speedscale;
982 skysphere(skysphereouter, speedscale);
986 glBindTexture(GL_TEXTURE_2D, R_GetTexture(solidskytexture)); // upper clouds
987 speedscale = cl.time*8.0/128.0;
988 speedscale -= (int)speedscale;
989 skysphere(skysphereouter, speedscale);
990 if (skyrendertwolayers)
993 glBindTexture(GL_TEXTURE_2D, R_GetTexture(alphaskytexture)); // lower clouds
994 speedscale = cl.time*16.0/128.0;
995 speedscale -= (int)speedscale;
996 skysphere(skysphereinner, speedscale);
997 glDisable (GL_BLEND);
1001 glEnable (GL_DEPTH_TEST);
1007 if (!r_render.value)
1009 if (skyrendersphere)
1011 else if (skyrenderbox)
1015 //===============================================================
1017 byte skyupperlayerpixels[128*128*4];
1018 byte skylowerlayerpixels[128*128*4];
1019 byte skymergedpixels[128*128*4];
1021 void R_BuildSky (int scrollupper, int scrolllower)
1023 int x, y, ux, uy, lx, ly;
1025 m = skymergedpixels;
1026 for (y = 0;y < 128;y++)
1028 uy = (y + scrollupper) & 127;
1029 ly = (y + scrolllower) & 127;
1030 for (x = 0;x < 128;x++)
1032 ux = (x + scrollupper) & 127;
1033 lx = (x + scrolllower) & 127;
1034 u = &skyupperlayerpixels[(uy * 128 + ux) * 4];
1035 l = &skylowerlayerpixels[(ly * 128 + lx) * 4];
1039 *((int *)m) = *((int *)l);
1042 m[0] = ((((int) l[0] - (int) u[0]) * (int) l[3]) >> 8) + (int) u[0];
1043 m[1] = ((((int) l[1] - (int) u[1]) * (int) l[3]) >> 8) + (int) u[1];
1044 m[2] = ((((int) l[2] - (int) u[2]) * (int) l[3]) >> 8) + (int) u[2];
1049 *((int *)m) = *((int *)u);
1053 // FIXME: implement generated texture callbacks to speed this up? (skip identifier lookup, CRC, memcpy, etc)
1054 if (mergeskytexture)
1056 glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture));
1057 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, skymergedpixels);
1060 mergeskytexture = R_LoadTexture("mergedskytexture", 128, 128, skymergedpixels, TEXF_RGBA | TEXF_ALWAYSPRECACHE);
1067 A sky texture is 256*128, with the right side being a masked overlay
1070 void R_InitSky (byte *src, int bytesperpixel)
1073 unsigned trans[128*128];
1081 strcpy(skyworldname, loadmodel->name);
1082 if (bytesperpixel == 4)
1084 for (i = 0;i < 128;i++)
1085 for (j = 0;j < 128;j++)
1086 trans[(i*128) + j] = src[i*256+j+128];
1090 // make an average value for the back to avoid
1091 // a fringe on the top level
1093 for (i=0 ; i<128 ; i++)
1095 for (j=0 ; j<128 ; j++)
1097 p = src[i*256 + j + 128];
1098 rgba = &d_8to24table[p];
1099 trans[(i*128) + j] = *rgba;
1100 r += ((byte *)rgba)[0];
1101 g += ((byte *)rgba)[1];
1102 b += ((byte *)rgba)[2];
1106 ((byte *)&transpix)[0] = r/(128*128);
1107 ((byte *)&transpix)[1] = g/(128*128);
1108 ((byte *)&transpix)[2] = b/(128*128);
1109 ((byte *)&transpix)[3] = 0;
1112 memcpy(skyupperlayerpixels, trans, 128*128*4);
1114 solidskytexture = R_LoadTexture ("sky_solidtexture", 128, 128, (byte *) trans, TEXF_RGBA | TEXF_PRECACHE);
1116 if (bytesperpixel == 4)
1118 for (i = 0;i < 128;i++)
1119 for (j = 0;j < 128;j++)
1120 trans[(i*128) + j] = src[i*256+j];
1124 for (i=0 ; i<128 ; i++)
1126 for (j=0 ; j<128 ; j++)
1130 trans[(i*128) + j] = transpix;
1132 trans[(i*128) + j] = d_8to24table[p];
1137 memcpy(skylowerlayerpixels, trans, 128*128*4);
1139 alphaskytexture = R_LoadTexture ("sky_alphatexture", 128, 128, (byte *) trans, TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);