5 cvar_t r_skyquality = {CVAR_SAVE, "r_skyquality", "2"};
6 cvar_t r_skyflush = {0, "r_skyflush", "0"};
8 static char skyworldname[1024];
9 rtexture_t *solidskytexture;
10 rtexture_t *alphaskytexture;
11 static qboolean skyavailable_quake;
12 static qboolean skyavailable_box;
13 static rtexturepool_t *skytexturepool;
19 static void r_sky_start(void)
21 skytexturepool = R_AllocTexturePool();
22 solidskytexture = NULL;
23 alphaskytexture = NULL;
26 static void r_sky_shutdown(void)
28 R_FreeTexturePool(&skytexturepool);
29 solidskytexture = NULL;
30 alphaskytexture = NULL;
33 int R_SetSkyBox(char *sky);
35 static void r_sky_newmap(void)
37 skyavailable_quake = false;
38 if (!strcmp(skyworldname, cl.worldmodel->name))
39 skyavailable_quake = true;
44 Cmd_AddCommand ("loadsky", &LoadSky_f);
45 Cvar_RegisterVariable (&r_skyquality);
46 Cvar_RegisterVariable (&r_skyflush);
47 R_RegisterModule("R_Sky", r_sky_start, r_sky_shutdown, r_sky_newmap);
50 static int skyrendersphere;
51 static int skyrenderbox;
53 void R_SkyStartFrame(void)
56 skyrendersphere = false;
58 skyrenderglquake = false;
59 skyrendermasked = false;
60 if (r_skyquality.integer >= 1 && !fogenabled)
64 else if (skyavailable_quake)
66 switch(r_skyquality.integer)
69 skyrenderglquake = true;
73 skyrendersphere = true;
77 if (skyrenderbox || skyrendersphere)
79 // for depth-masked sky, render the sky on the first sky surface encountered
81 skyrendermasked = true;
86 static char skyname[256];
93 static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
94 static rtexture_t *skyboxside[6];
95 int R_SetSkyBox(char *sky)
101 if (strcmp(sky, skyname) == 0) // no change
104 skyboxside[0] = skyboxside[1] = skyboxside[2] = skyboxside[3] = skyboxside[4] = skyboxside[5] = NULL;
105 skyavailable_box = false;
111 if (strlen(sky) > 1000)
113 Con_Printf ("sky name too long (%i, max is 1000)\n", strlen(sky));
117 for (i = 0;i < 6;i++)
119 sprintf (name, "env/%s%s", sky, suf[i]);
120 if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
122 sprintf (name, "gfx/env/%s%s", sky, suf[i]);
123 if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
125 Con_Printf ("Couldn't load env/%s%s or gfx/env/%s%s\n", sky, suf[i], sky, suf[i]);
129 skyboxside[i] = R_LoadTexture(skytexturepool, va("skyboxside%d", i), image_width, image_height, image_rgba, TEXTYPE_RGBA, TEXF_PRECACHE);
130 Mem_Free(image_rgba);
133 if (skyboxside[0] || skyboxside[1] || skyboxside[2] || skyboxside[3] || skyboxside[4] || skyboxside[5])
135 skyavailable_box = true;
136 strcpy(skyname, sky);
142 // LordHavoc: added LoadSky console command
143 void LoadSky_f (void)
149 Con_Printf("current sky: %s\n", skyname);
151 Con_Printf("no skybox has been set\n");
154 if (R_SetSkyBox(Cmd_Argv(1)))
157 Con_Printf("skybox set to %s\n", skyname);
159 Con_Printf("skybox disabled\n");
162 Con_Printf("failed to load skybox %s\n", Cmd_Argv(1));
165 Con_Printf("usage: loadsky skyname\n");
170 #define R_SkyBoxPolyVec(i,s,t,x,y,z) \
171 vert[i][0] = (x) * 1024.0f + r_origin[0];\
172 vert[i][1] = (y) * 1024.0f + r_origin[1];\
173 vert[i][2] = (z) * 1024.0f + r_origin[2];\
174 st[i][0] = (s) * (254.0f/256.0f) + (1.0f/256.0f);\
175 st[i][1] = (t) * (254.0f/256.0f) + (1.0f/256.0f);
177 int skyboxindex[6] = {0, 1, 2, 0, 2, 3};
179 static void R_SkyBox(void)
181 float vert[4][4], st[4][2];
183 memset(&m, 0, sizeof(m));
184 m.transparent = false;
185 m.blendfunc1 = GL_ONE;
186 m.blendfunc2 = GL_ZERO;
189 m.index = skyboxindex;
190 m.vertex = &vert[0][0];
191 m.vertexstep = sizeof(float[4]);
196 m.texcoords[0] = &st[0][0];
197 m.texcoordstep[0] = sizeof(float[2]);
198 m.tex[0] = R_GetTexture(skyboxside[3]); // front
199 R_SkyBoxPolyVec(0, 1, 0, 1, -1, 1);
200 R_SkyBoxPolyVec(1, 1, 1, 1, -1, -1);
201 R_SkyBoxPolyVec(2, 0, 1, 1, 1, -1);
202 R_SkyBoxPolyVec(3, 0, 0, 1, 1, 1);
204 m.tex[0] = R_GetTexture(skyboxside[1]); // back
205 R_SkyBoxPolyVec(0, 1, 0, -1, 1, 1);
206 R_SkyBoxPolyVec(1, 1, 1, -1, 1, -1);
207 R_SkyBoxPolyVec(2, 0, 1, -1, -1, -1);
208 R_SkyBoxPolyVec(3, 0, 0, -1, -1, 1);
210 m.tex[0] = R_GetTexture(skyboxside[0]); // right
211 R_SkyBoxPolyVec(0, 1, 0, 1, 1, 1);
212 R_SkyBoxPolyVec(1, 1, 1, 1, 1, -1);
213 R_SkyBoxPolyVec(2, 0, 1, -1, 1, -1);
214 R_SkyBoxPolyVec(3, 0, 0, -1, 1, 1);
216 m.tex[0] = R_GetTexture(skyboxside[2]); // left
217 R_SkyBoxPolyVec(0, 1, 0, -1, -1, 1);
218 R_SkyBoxPolyVec(1, 1, 1, -1, -1, -1);
219 R_SkyBoxPolyVec(2, 0, 1, 1, -1, -1);
220 R_SkyBoxPolyVec(3, 0, 0, 1, -1, 1);
222 m.tex[0] = R_GetTexture(skyboxside[4]); // up
223 R_SkyBoxPolyVec(0, 1, 0, 1, -1, 1);
224 R_SkyBoxPolyVec(1, 1, 1, 1, 1, 1);
225 R_SkyBoxPolyVec(2, 0, 1, -1, 1, 1);
226 R_SkyBoxPolyVec(3, 0, 0, -1, -1, 1);
228 m.tex[0] = R_GetTexture(skyboxside[5]); // down
229 R_SkyBoxPolyVec(0, 1, 0, 1, 1, -1);
230 R_SkyBoxPolyVec(1, 1, 1, 1, -1, -1);
231 R_SkyBoxPolyVec(2, 0, 1, -1, -1, -1);
232 R_SkyBoxPolyVec(3, 0, 0, -1, 1, -1);
237 #define skygridx1 (skygridx + 1)
238 #define skygridxrecip (1.0f / (skygridx))
240 #define skygridy1 (skygridy + 1)
241 #define skygridyrecip (1.0f / (skygridy))
243 static float skysphere[skygridx1*skygridy1*5];
244 static int skysphereindices[skygridx*skygridy*6];
245 static void skyspherecalc(float *sphere, float dx, float dy, float dz)
247 float a, b, x, ax, ay, v[3], length;
249 for (j = 0;j <= skygridy;j++)
251 a = j * skygridyrecip;
252 ax = cos(a * M_PI * 2);
253 ay = -sin(a * M_PI * 2);
254 for (i = 0;i <= skygridx;i++)
256 b = i * skygridxrecip;
257 x = cos(b * M_PI * 2);
260 v[2] = -sin(b * M_PI * 2) * dz;
261 length = 3.0f / sqrt(v[0]*v[0]+v[1]*v[1]+(v[2]*v[2]*9));
262 *sphere++ = v[0] * length;
263 *sphere++ = v[1] * length;
269 index = skysphereindices;
270 for (j = 0;j < skygridy;j++)
272 for (i = 0;i < skygridx;i++)
274 *index++ = j * skygridx1 + i;
275 *index++ = j * skygridx1 + i + 1;
276 *index++ = (j + 1) * skygridx1 + i;
278 *index++ = j * skygridx1 + i + 1;
279 *index++ = (j + 1) * skygridx1 + i + 1;
280 *index++ = (j + 1) * skygridx1 + i;
286 static void skyspherearrays(float *vert, float *tex, float *tex2, float *source, float s, float s2)
288 float *v, *t, *t2, radius;
293 radius = r_farclip - 8;
294 for (i = 0;i < (skygridx1*skygridy1);i++)
296 *t++ = source[0] + s;
297 *t++ = source[1] + s;
298 *t2++ = source[0] + s2;
299 *t2++ = source[1] + s2;
300 *v++ = source[2] + r_origin[0];
301 *v++ = source[3] + r_origin[1];
302 *v++ = source[4] + r_origin[2];
308 static void R_SkySphere(void)
310 float speedscale, speedscale2;
311 float vert[skygridx1*skygridy1*4], tex[skygridx1*skygridy1*2], tex2[skygridx1*skygridy1*2];
312 static qboolean skysphereinitialized = false;
314 if (!skysphereinitialized)
316 skysphereinitialized = true;
317 skyspherecalc(skysphere, 1024, 1024, 1024 / 3);
319 memset(&m, 0, sizeof(m));
320 m.transparent = false;
321 m.blendfunc1 = GL_ONE;
322 m.blendfunc2 = GL_ZERO;
323 m.numtriangles = skygridx*skygridy*2;
324 m.numverts = skygridx1*skygridy1;
325 m.index = skysphereindices;
327 m.vertexstep = sizeof(float[4]);
332 m.texcoords[0] = tex;
333 m.texcoordstep[0] = sizeof(float[2]);
334 speedscale = cl.time*8.0/128.0;
335 speedscale -= (int)speedscale;
336 speedscale2 = cl.time*16.0/128.0;
337 speedscale2 -= (int)speedscale2;
338 skyspherearrays(vert, tex, tex2, skysphere, speedscale, speedscale2);
339 m.tex[0] = R_GetTexture(solidskytexture);
342 m.blendfunc1 = GL_SRC_ALPHA;
343 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
344 m.tex[0] = R_GetTexture(alphaskytexture);
345 m.texcoords[0] = tex2;
355 else if (skyrenderbox)
358 // clear the zbuffer that was used while rendering the sky
363 //===============================================================
369 A sky texture is 256*128, with the right side being a masked overlay
372 void R_InitSky (qbyte *src, int bytesperpixel)
374 int i, j, p, r, g, b;
375 qbyte skyupperlayerpixels[128*128*4], skylowerlayerpixels[128*128*4];
376 unsigned trans[128*128], transpix, *rgba;
378 strcpy(skyworldname, loadmodel->name);
380 // flush skytexturepool so we won't build up a leak from uploading textures multiple times
381 R_FreeTexturePool(&skytexturepool);
382 skytexturepool = R_AllocTexturePool();
383 solidskytexture = NULL;
384 alphaskytexture = NULL;
386 if (bytesperpixel == 4)
388 for (i = 0;i < 128;i++)
389 for (j = 0;j < 128;j++)
390 trans[(i*128) + j] = src[i*256+j+128];
394 // make an average value for the back to avoid
395 // a fringe on the top level
397 for (i=0 ; i<128 ; i++)
399 for (j=0 ; j<128 ; j++)
401 p = src[i*256 + j + 128];
402 rgba = &d_8to24table[p];
403 trans[(i*128) + j] = *rgba;
404 r += ((qbyte *)rgba)[0];
405 g += ((qbyte *)rgba)[1];
406 b += ((qbyte *)rgba)[2];
410 ((qbyte *)&transpix)[0] = r/(128*128);
411 ((qbyte *)&transpix)[1] = g/(128*128);
412 ((qbyte *)&transpix)[2] = b/(128*128);
413 ((qbyte *)&transpix)[3] = 0;
416 memcpy(skyupperlayerpixels, trans, 128*128*4);
418 solidskytexture = R_LoadTexture (skytexturepool, "sky_solidtexture", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_PRECACHE);
420 for (i = 0;i < 128*128;i++)
422 ((qbyte *)&trans[i])[0] >>= 1;
423 ((qbyte *)&trans[i])[1] >>= 1;
424 ((qbyte *)&trans[i])[2] >>= 1;
426 solidskytexture_half = R_LoadTexture (skytexturepool, "sky_solidtexture_half", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_PRECACHE);
429 if (bytesperpixel == 4)
431 for (i = 0;i < 128;i++)
432 for (j = 0;j < 128;j++)
433 trans[(i*128) + j] = src[i*256+j];
437 for (i=0 ; i<128 ; i++)
439 for (j=0 ; j<128 ; j++)
443 trans[(i*128) + j] = transpix;
445 trans[(i*128) + j] = d_8to24table[p];
450 memcpy(skylowerlayerpixels, trans, 128*128*4);
452 alphaskytexture = R_LoadTexture (skytexturepool, "sky_alphatexture", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
454 for (i = 0;i < 128*128;i++)
456 ((qbyte *)&trans[i])[0] >>= 1;
457 ((qbyte *)&trans[i])[1] >>= 1;
458 ((qbyte *)&trans[i])[2] >>= 1;
460 alphaskytexture_half = R_LoadTexture (skytexturepool, "sky_alphatexture_half", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);