5 // FIXME: fix skybox after vid_restart
6 cvar_t r_sky = {CVAR_SAVE, "r_sky", "1"};
7 qboolean skyavailable_quake;
8 qboolean skyavailable_box;
12 static rtexture_t *solidskytexture;
13 static rtexture_t *alphaskytexture;
14 static int skyrendersphere;
15 static int skyrenderbox;
16 static rtexturepool_t *skytexturepool;
17 static char skyname[256];
18 static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
19 static rtexture_t *skyboxside[6];
21 void R_SkyStartFrame(void)
24 skyrendersphere = false;
26 skyrendermasked = false;
27 if (r_sky.integer && !fogenabled)
31 else if (skyavailable_quake)
32 skyrendersphere = true;
33 // for depth-masked sky, render the sky on the first sky surface encountered
35 skyrendermasked = true;
44 void R_UnloadSkyBox(void)
50 R_FreeTexture(skyboxside[i]);
51 skyboxside[i] = NULL;;
55 void R_LoadSkyBox(void)
65 if (snprintf(name, sizeof(name), "env/%s%s", skyname, suf[i]) >= (int)sizeof(name) || !(image_rgba = loadimagepixels(name, false, 0, 0)))
67 if (snprintf(name, sizeof(name), "gfx/env/%s%s", skyname, suf[i]) >= (int)sizeof(name) || !(image_rgba = loadimagepixels(name, false, 0, 0)))
69 Con_Printf ("Couldn't load env/%s%s or gfx/env/%s%s\n", skyname, suf[i], skyname, suf[i]);
73 skyboxside[i] = R_LoadTexture2D(skytexturepool, va("skyboxside%d", i), image_width, image_height, image_rgba, TEXTYPE_RGBA, TEXF_CLAMP | TEXF_PRECACHE, NULL);
78 int R_SetSkyBox(const char *sky)
80 if (strcmp(sky, skyname) == 0) // no change
83 if (strlen(sky) > 1000)
85 Con_Printf ("sky name too long (%i, max is 1000)\n", strlen(sky));
89 skyavailable_box = false;
98 if (skyboxside[0] || skyboxside[1] || skyboxside[2] || skyboxside[3] || skyboxside[4] || skyboxside[5])
100 skyavailable_box = true;
106 // LordHavoc: added LoadSky console command
107 void LoadSky_f (void)
113 Con_Printf("current sky: %s\n", skyname);
115 Con_Printf("no skybox has been set\n");
118 if (R_SetSkyBox(Cmd_Argv(1)))
121 Con_Printf("skybox set to %s\n", skyname);
123 Con_Printf("skybox disabled\n");
126 Con_Printf("failed to load skybox %s\n", Cmd_Argv(1));
129 Con_Printf("usage: loadsky skyname\n");
134 float skyboxvertex3f[6*4*3] =
168 float skyboxtexcoord2f[6*4*2] =
202 int skyboxelements[6*2*3] =
224 static void R_SkyBox(void)
228 GL_Color(1, 1, 1, 1);
229 memset(&m, 0, sizeof(m));
230 GL_BlendFunc(GL_ONE, GL_ZERO);
232 GL_DepthTest(false); // don't modify or read zbuffer
233 GL_VertexPointer(skyboxvertex3f);
234 m.pointer_texcoord[0] = skyboxtexcoord2f;
235 for (i = 0;i < 6;i++)
237 m.tex[0] = R_GetTexture(skyboxside[i]);
238 R_Mesh_State_Texture(&m);
239 R_Mesh_Draw(6*4, 2, skyboxelements + i * 6);
244 #define skygridx1 (skygridx + 1)
245 #define skygridxrecip (1.0f / (skygridx))
247 #define skygridy1 (skygridy + 1)
248 #define skygridyrecip (1.0f / (skygridy))
249 #define skysphere_numverts (skygridx1 * skygridy1)
250 #define skysphere_numtriangles (skygridx * skygridy * 2)
251 static float skysphere_vertex3f[skysphere_numverts * 3];
252 static float skysphere_texcoord2f[skysphere_numverts * 2];
253 static int skysphere_element3i[skysphere_numtriangles * 3];
255 static void skyspherecalc(void)
258 float a, b, x, ax, ay, v[3], length, *vertex3f, *texcoord2f;
263 vertex3f = skysphere_vertex3f;
264 texcoord2f = skysphere_texcoord2f;
265 for (j = 0;j <= skygridy;j++)
267 a = j * skygridyrecip;
268 ax = cos(a * M_PI * 2);
269 ay = -sin(a * M_PI * 2);
270 for (i = 0;i <= skygridx;i++)
272 b = i * skygridxrecip;
273 x = cos((b + 0.5) * M_PI);
276 v[2] = -sin((b + 0.5) * M_PI) * dz;
277 length = 3.0f / sqrt(v[0]*v[0]+v[1]*v[1]+(v[2]*v[2]*9));
278 *texcoord2f++ = v[0] * length;
279 *texcoord2f++ = v[1] * length;
285 e = skysphere_element3i;
286 for (j = 0;j < skygridy;j++)
288 for (i = 0;i < skygridx;i++)
290 *e++ = j * skygridx1 + i;
291 *e++ = j * skygridx1 + i + 1;
292 *e++ = (j + 1) * skygridx1 + i;
294 *e++ = j * skygridx1 + i + 1;
295 *e++ = (j + 1) * skygridx1 + i + 1;
296 *e++ = (j + 1) * skygridx1 + i;
301 static void R_SkySphere(void)
304 static qboolean skysphereinitialized = false;
306 matrix4x4_t scroll1matrix, scroll2matrix, identitymatrix;
307 if (!skysphereinitialized)
309 skysphereinitialized = true;
313 // scroll speed for upper layer
314 speedscale = cl.time*8.0/128.0;
315 // wrap the scroll just to be extra kind to float accuracy
316 speedscale -= (int)speedscale;
318 // scroll the lower cloud layer twice as fast (just like quake did)
319 Matrix4x4_CreateTranslate(&scroll1matrix, speedscale, speedscale, 0);
320 Matrix4x4_CreateTranslate(&scroll2matrix, speedscale * 2, speedscale * 2, 0);
321 Matrix4x4_CreateIdentity(&identitymatrix);
323 GL_VertexPointer(skysphere_vertex3f);
324 GL_Color(1, 1, 1, 1);
325 GL_BlendFunc(GL_ONE, GL_ZERO);
327 GL_DepthTest(false); // don't modify or read zbuffer
328 memset(&m, 0, sizeof(m));
329 m.tex[0] = R_GetTexture(solidskytexture);
330 m.pointer_texcoord[0] = skysphere_texcoord2f;
331 R_Mesh_TextureMatrix(0, &scroll1matrix);
332 if (r_textureunits.integer >= 2)
334 // one pass using GL_DECAL or GL_INTERPOLATE_ARB for alpha layer
335 // LordHavoc: note that color is not set here because it does not
336 // matter with GL_REPLACE
337 m.tex[1] = R_GetTexture(alphaskytexture);
338 m.texcombinergb[1] = gl_combine.integer ? GL_INTERPOLATE_ARB : GL_DECAL;
339 m.pointer_texcoord[1] = skysphere_texcoord2f;
340 R_Mesh_State_Texture(&m);
341 R_Mesh_TextureMatrix(1, &scroll2matrix);
342 R_Mesh_Draw(skysphere_numverts, skysphere_numtriangles, skysphere_element3i);
343 R_Mesh_TextureMatrix(1, &identitymatrix);
348 R_Mesh_State_Texture(&m);
349 R_Mesh_Draw(skysphere_numverts, skysphere_numtriangles, skysphere_element3i);
351 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
352 m.tex[0] = R_GetTexture(alphaskytexture);
353 R_Mesh_State_Texture(&m);
354 R_Mesh_TextureMatrix(0, &scroll2matrix);
355 R_Mesh_Draw(skysphere_numverts, skysphere_numtriangles, skysphere_element3i);
357 R_Mesh_TextureMatrix(0, &identitymatrix);
362 matrix4x4_t skymatrix;
365 Matrix4x4_CreateTranslate(&skymatrix, r_vieworigin[0], r_vieworigin[1], r_vieworigin[2]);
366 R_Mesh_Matrix(&skymatrix);
369 // this does not modify depth buffer
372 else if (skyrenderbox)
374 // this does not modify depth buffer
377 /* this will be skyroom someday
380 // this modifies the depth buffer so we have to clear it afterward
382 // clear the depthbuffer that was used while rendering the skyroom
383 //qglClear(GL_DEPTH_BUFFER_BIT);
389 //===============================================================
395 A sky texture is 256*128, with the right side being a masked overlay
398 void R_InitSky (qbyte *src, int bytesperpixel)
400 int i, j, p, r, g, b;
401 qbyte skyupperlayerpixels[128*128*4], skylowerlayerpixels[128*128*4];
402 unsigned trans[128*128], transpix, *rgba;
410 skyavailable_quake = true;
412 // flush skytexturepool so we won't build up a leak from uploading textures multiple times
413 R_FreeTexturePool(&skytexturepool);
414 skytexturepool = R_AllocTexturePool();
415 solidskytexture = NULL;
416 alphaskytexture = NULL;
418 if (bytesperpixel == 4)
421 for (i = 0;i < 128;i++)
422 for (j = 0;j < 128;j++)
423 trans[(i*128) + j] = ((unsigned *)src)[i*256+j+128];
427 // make an average value for the back to avoid
428 // a fringe on the top level
430 for (i=0 ; i<128 ; i++)
432 for (j=0 ; j<128 ; j++)
434 p = src[i*256 + j + 128];
435 rgba = &palette_complete[p];
436 trans[(i*128) + j] = *rgba;
437 r += ((qbyte *)rgba)[0];
438 g += ((qbyte *)rgba)[1];
439 b += ((qbyte *)rgba)[2];
444 transpixunion.b[0] = r/(128*128);
445 transpixunion.b[1] = g/(128*128);
446 transpixunion.b[2] = b/(128*128);
447 transpixunion.b[3] = 0;
449 transpix = transpixunion.i;
451 memcpy(skyupperlayerpixels, trans, 128*128*4);
453 solidskytexture = R_LoadTexture2D(skytexturepool, "sky_solidtexture", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
455 if (bytesperpixel == 4)
457 for (i = 0;i < 128;i++)
458 for (j = 0;j < 128;j++)
459 trans[(i*128) + j] = ((unsigned *)src)[i*256+j];
463 for (i=0 ; i<128 ; i++)
465 for (j=0 ; j<128 ; j++)
469 trans[(i*128) + j] = transpix;
471 trans[(i*128) + j] = palette_complete[p];
476 memcpy(skylowerlayerpixels, trans, 128*128*4);
478 alphaskytexture = R_LoadTexture2D(skytexturepool, "sky_alphatexture", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
481 void R_ResetQuakeSky(void)
483 skyavailable_quake = false;
486 void R_ResetSkyBox(void)
488 skyboxside[0] = skyboxside[1] = skyboxside[2] = skyboxside[3] = skyboxside[4] = skyboxside[5] = NULL;
490 skyavailable_box = false;
493 static void r_sky_start(void)
495 skytexturepool = R_AllocTexturePool();
496 solidskytexture = NULL;
497 alphaskytexture = NULL;
501 static void r_sky_shutdown(void)
504 R_FreeTexturePool(&skytexturepool);
505 solidskytexture = NULL;
506 alphaskytexture = NULL;
509 static void r_sky_newmap(void)
513 void R_Sky_Init(void)
515 Cmd_AddCommand ("loadsky", &LoadSky_f);
516 Cvar_RegisterVariable (&r_sky);
519 R_RegisterModule("R_Sky", r_sky_start, r_sky_shutdown, r_sky_newmap);