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);
235 if (r_skyflush.integer)
237 // clear the zbuffer that was used while rendering the sky
238 glClear(GL_DEPTH_BUFFER_BIT);
239 if (r_skyflush.integer)
243 static float skysphere[33*33*5];
244 static int skysphereindices[32*32*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 (a = 0;a <= 1;a += (1.0 / 32.0))
251 ax = cos(a * M_PI * 2);
252 ay = -sin(a * M_PI * 2);
253 for (b = 0;b <= 1;b += (1.0 / 32.0))
255 x = cos(b * M_PI * 2);
258 v[2] = -sin(b * M_PI * 2) * dz;
259 length = 3.0f / sqrt(v[0]*v[0]+v[1]*v[1]+(v[2]*v[2]*9));
260 *sphere++ = v[0] * length;
261 *sphere++ = v[1] * length;
267 index = skysphereindices;
268 for (j = 0;j < 32;j++)
270 for (i = 0;i < 32;i++)
272 *index++ = j * 33 + i;
273 *index++ = j * 33 + i + 1;
274 *index++ = (j + 1) * 33 + i;
276 *index++ = j * 33 + i + 1;
277 *index++ = (j + 1) * 33 + i + 1;
278 *index++ = (j + 1) * 33 + i;
284 static void skyspherearrays(float *vert, float *tex, float *tex2, float *source, float s, float s2)
286 float *v, *t, *t2, radius;
291 radius = r_farclip - 8;
292 for (i = 0;i < (33*33);i++)
294 *t++ = source[0] + s;
295 *t++ = source[1] + s;
296 *t2++ = source[0] + s2;
297 *t2++ = source[1] + s2;
298 *v++ = source[2] + r_origin[0];
299 *v++ = source[3] + r_origin[1];
300 *v++ = source[4] + r_origin[2];
306 static void R_SkySphere(void)
308 float speedscale, speedscale2;
309 float vert[33*33*4], tex[33*33*2], tex2[33*33*2];
310 static qboolean skysphereinitialized = false;
312 if (!skysphereinitialized)
314 skysphereinitialized = true;
315 skyspherecalc(skysphere, 1024, 1024, 1024 / 3);
317 memset(&m, 0, sizeof(m));
318 m.transparent = false;
319 m.blendfunc1 = GL_ONE;
320 m.blendfunc2 = GL_ZERO;
321 m.numtriangles = 32*32*2;
323 m.index = skysphereindices;
325 m.vertexstep = sizeof(float[4]);
330 m.texcoords[0] = tex;
331 m.texcoordstep[0] = sizeof(float[2]);
332 speedscale = cl.time*8.0/128.0;
333 speedscale -= (int)speedscale;
334 speedscale2 = cl.time*16.0/128.0;
335 speedscale2 -= (int)speedscale2;
336 skyspherearrays(vert, tex, tex2, skysphere, speedscale, speedscale2);
337 m.tex[0] = R_GetTexture(solidskytexture);
340 m.blendfunc1 = GL_SRC_ALPHA;
341 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
342 m.tex[0] = R_GetTexture(alphaskytexture);
343 m.texcoords[0] = tex2;
346 if (r_skyflush.integer)
348 // clear the zbuffer that was used while rendering the sky
349 glClear(GL_DEPTH_BUFFER_BIT);
350 if (r_skyflush.integer)
358 else if (skyrenderbox)
362 //===============================================================
368 A sky texture is 256*128, with the right side being a masked overlay
371 void R_InitSky (qbyte *src, int bytesperpixel)
373 int i, j, p, r, g, b;
374 qbyte skyupperlayerpixels[128*128*4], skylowerlayerpixels[128*128*4];
375 unsigned trans[128*128], transpix, *rgba;
377 strcpy(skyworldname, loadmodel->name);
379 // flush skytexturepool so we won't build up a leak from uploading textures multiple times
380 R_FreeTexturePool(&skytexturepool);
381 skytexturepool = R_AllocTexturePool();
382 solidskytexture = NULL;
383 alphaskytexture = NULL;
385 if (bytesperpixel == 4)
387 for (i = 0;i < 128;i++)
388 for (j = 0;j < 128;j++)
389 trans[(i*128) + j] = src[i*256+j+128];
393 // make an average value for the back to avoid
394 // a fringe on the top level
396 for (i=0 ; i<128 ; i++)
398 for (j=0 ; j<128 ; j++)
400 p = src[i*256 + j + 128];
401 rgba = &d_8to24table[p];
402 trans[(i*128) + j] = *rgba;
403 r += ((qbyte *)rgba)[0];
404 g += ((qbyte *)rgba)[1];
405 b += ((qbyte *)rgba)[2];
409 ((qbyte *)&transpix)[0] = r/(128*128);
410 ((qbyte *)&transpix)[1] = g/(128*128);
411 ((qbyte *)&transpix)[2] = b/(128*128);
412 ((qbyte *)&transpix)[3] = 0;
415 memcpy(skyupperlayerpixels, trans, 128*128*4);
417 solidskytexture = R_LoadTexture (skytexturepool, "sky_solidtexture", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_PRECACHE);
419 for (i = 0;i < 128*128;i++)
421 ((qbyte *)&trans[i])[0] >>= 1;
422 ((qbyte *)&trans[i])[1] >>= 1;
423 ((qbyte *)&trans[i])[2] >>= 1;
425 solidskytexture_half = R_LoadTexture (skytexturepool, "sky_solidtexture_half", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_PRECACHE);
428 if (bytesperpixel == 4)
430 for (i = 0;i < 128;i++)
431 for (j = 0;j < 128;j++)
432 trans[(i*128) + j] = src[i*256+j];
436 for (i=0 ; i<128 ; i++)
438 for (j=0 ; j<128 ; j++)
442 trans[(i*128) + j] = transpix;
444 trans[(i*128) + j] = d_8to24table[p];
449 memcpy(skylowerlayerpixels, trans, 128*128*4);
451 alphaskytexture = R_LoadTexture (skytexturepool, "sky_alphatexture", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
453 for (i = 0;i < 128*128;i++)
455 ((qbyte *)&trans[i])[0] >>= 1;
456 ((qbyte *)&trans[i])[1] >>= 1;
457 ((qbyte *)&trans[i])[2] >>= 1;
459 alphaskytexture_half = R_LoadTexture (skytexturepool, "sky_alphatexture_half", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);