you can now (try to) play in maps you don't have, and models you don't have are shown...
[divverent/darkplaces.git] / r_sky.c
1
2 #include "quakedef.h"
3
4 cvar_t r_sky = {CVAR_SAVE, "r_sky", "1"};
5 qboolean skyavailable_quake;
6 qboolean skyavailable_box;
7 int skyrendernow;
8 int skyrendermasked;
9
10 static rtexture_t *solidskytexture;
11 static rtexture_t *alphaskytexture;
12 static int skyrendersphere;
13 static int skyrenderbox;
14 static rtexturepool_t *skytexturepool;
15 static char skyname[256];
16 static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
17 static rtexture_t *skyboxside[6];
18 int R_SetSkyBox(char *sky);
19
20 void R_SkyStartFrame(void)
21 {
22         skyrendernow = false;
23         skyrendersphere = false;
24         skyrenderbox = false;
25         skyrendermasked = false;
26         if (r_sky.integer && !fogenabled)
27         {
28                 if (skyavailable_box)
29                         skyrenderbox = true;
30                 else if (skyavailable_quake)
31                         skyrendersphere = true;
32                 // for depth-masked sky, render the sky on the first sky surface encountered
33                 skyrendernow = true;
34                 skyrendermasked = true;
35         }
36 }
37
38 /*
39 ==================
40 R_SetSkyBox
41 ==================
42 */
43 int R_SetSkyBox(char *sky)
44 {
45         int i;
46         char name[1024];
47         qbyte *image_rgba;
48
49         if (strcmp(sky, skyname) == 0) // no change
50                 return true;
51
52         skyboxside[0] = skyboxside[1] = skyboxside[2] = skyboxside[3] = skyboxside[4] = skyboxside[5] = NULL;
53         skyavailable_box = false;
54         skyname[0] = 0;
55
56         if (!sky[0])
57                 return true;
58
59         if (strlen(sky) > 1000)
60         {
61                 Con_Printf ("sky name too long (%i, max is 1000)\n", strlen(sky));
62                 return false;
63         }
64
65         for (i = 0;i < 6;i++)
66         {
67                 sprintf (name, "env/%s%s", sky, suf[i]);
68                 if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
69                 {
70                         sprintf (name, "gfx/env/%s%s", sky, suf[i]);
71                         if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
72                         {
73                                 Con_Printf ("Couldn't load env/%s%s or gfx/env/%s%s\n", sky, suf[i], sky, suf[i]);
74                                 continue;
75                         }
76                 }
77                 skyboxside[i] = R_LoadTexture(skytexturepool, va("skyboxside%d", i), image_width, image_height, image_rgba, TEXTYPE_RGBA, TEXF_PRECACHE);
78                 Mem_Free(image_rgba);
79         }
80
81         if (skyboxside[0] || skyboxside[1] || skyboxside[2] || skyboxside[3] || skyboxside[4] || skyboxside[5])
82         {
83                 skyavailable_box = true;
84                 strcpy(skyname, sky);
85                 return true;
86         }
87         return false;
88 }
89
90 // LordHavoc: added LoadSky console command
91 void LoadSky_f (void)
92 {
93         switch (Cmd_Argc())
94         {
95         case 1:
96                 if (skyname[0])
97                         Con_Printf("current sky: %s\n", skyname);
98                 else
99                         Con_Printf("no skybox has been set\n");
100                 break;
101         case 2:
102                 if (R_SetSkyBox(Cmd_Argv(1)))
103                 {
104                         if (skyname[0])
105                                 Con_Printf("skybox set to %s\n", skyname);
106                         else
107                                 Con_Printf("skybox disabled\n");
108                 }
109                 else
110                         Con_Printf("failed to load skybox %s\n", Cmd_Argv(1));
111                 break;
112         default:
113                 Con_Printf("usage: loadsky skyname\n");
114                 break;
115         }
116 }
117
118 int skyboxindex[6] = {0, 1, 2, 0, 2, 3};
119
120 static void R_SkyBox(void)
121 {
122         rmeshbufferinfo_t m;
123
124 #define R_SkyBoxPolyVec(i,s,t,x,y,z) \
125         m.vertex[i * 4 + 0] = (x) * 16.0f;\
126         m.vertex[i * 4 + 1] = (y) * 16.0f;\
127         m.vertex[i * 4 + 2] = (z) * 16.0f;\
128         m.texcoords[0][i * 2 + 0] = (s) * (254.0f/256.0f) + (1.0f/256.0f);\
129         m.texcoords[0][i * 2 + 1] = (t) * (254.0f/256.0f) + (1.0f/256.0f);
130
131         memset(&m, 0, sizeof(m));
132         m.blendfunc1 = GL_ONE;
133         m.blendfunc2 = GL_ZERO;
134         m.depthdisable = true; // don't modify or read zbuffer
135         m.numtriangles = 2;
136         m.numverts = 4;
137         m.tex[0] = R_GetTexture(skyboxside[3]); // front
138         Matrix4x4_CreateTranslate(&m.matrix, r_origin[0], r_origin[1], r_origin[2]);
139         if (R_Mesh_Draw_GetBuffer(&m, false))
140         {
141                 memcpy(m.index, skyboxindex, sizeof(int[6]));
142                 m.color[0] = m.color[4] = m.color[8] = m.color[12] = m.colorscale;
143                 m.color[1] = m.color[5] = m.color[9] = m.color[13] = m.colorscale;
144                 m.color[2] = m.color[6] = m.color[10] = m.color[14] = m.colorscale;
145                 m.color[3] = m.color[7] = m.color[11] = m.color[15] = 1;
146                 R_SkyBoxPolyVec(0, 1, 0,  1, -1,  1);
147                 R_SkyBoxPolyVec(1, 1, 1,  1, -1, -1);
148                 R_SkyBoxPolyVec(2, 0, 1,  1,  1, -1);
149                 R_SkyBoxPolyVec(3, 0, 0,  1,  1,  1);
150                 R_Mesh_Render();
151         }
152         m.tex[0] = R_GetTexture(skyboxside[1]); // back
153         if (R_Mesh_Draw_GetBuffer(&m, false))
154         {
155                 memcpy(m.index, skyboxindex, sizeof(int[6]));
156                 m.color[0] = m.color[4] = m.color[8] = m.color[12] = m.colorscale;
157                 m.color[1] = m.color[5] = m.color[9] = m.color[13] = m.colorscale;
158                 m.color[2] = m.color[6] = m.color[10] = m.color[14] = m.colorscale;
159                 m.color[3] = m.color[7] = m.color[11] = m.color[15] = 1;
160                 R_SkyBoxPolyVec(0, 1, 0, -1,  1,  1);
161                 R_SkyBoxPolyVec(1, 1, 1, -1,  1, -1);
162                 R_SkyBoxPolyVec(2, 0, 1, -1, -1, -1);
163                 R_SkyBoxPolyVec(3, 0, 0, -1, -1,  1);
164                 R_Mesh_Render();
165         }
166         m.tex[0] = R_GetTexture(skyboxside[0]); // right
167         if (R_Mesh_Draw_GetBuffer(&m, false))
168         {
169                 memcpy(m.index, skyboxindex, sizeof(int[6]));
170                 m.color[0] = m.color[4] = m.color[8] = m.color[12] = m.colorscale;
171                 m.color[1] = m.color[5] = m.color[9] = m.color[13] = m.colorscale;
172                 m.color[2] = m.color[6] = m.color[10] = m.color[14] = m.colorscale;
173                 m.color[3] = m.color[7] = m.color[11] = m.color[15] = 1;
174                 R_SkyBoxPolyVec(0, 1, 0,  1,  1,  1);
175                 R_SkyBoxPolyVec(1, 1, 1,  1,  1, -1);
176                 R_SkyBoxPolyVec(2, 0, 1, -1,  1, -1);
177                 R_SkyBoxPolyVec(3, 0, 0, -1,  1,  1);
178                 R_Mesh_Render();
179         }
180         m.tex[0] = R_GetTexture(skyboxside[2]); // left
181         if (R_Mesh_Draw_GetBuffer(&m, false))
182         {
183                 memcpy(m.index, skyboxindex, sizeof(int[6]));
184                 m.color[0] = m.color[4] = m.color[8] = m.color[12] = m.colorscale;
185                 m.color[1] = m.color[5] = m.color[9] = m.color[13] = m.colorscale;
186                 m.color[2] = m.color[6] = m.color[10] = m.color[14] = m.colorscale;
187                 m.color[3] = m.color[7] = m.color[11] = m.color[15] = 1;
188                 R_SkyBoxPolyVec(0, 1, 0, -1, -1,  1);
189                 R_SkyBoxPolyVec(1, 1, 1, -1, -1, -1);
190                 R_SkyBoxPolyVec(2, 0, 1,  1, -1, -1);
191                 R_SkyBoxPolyVec(3, 0, 0,  1, -1,  1);
192                 R_Mesh_Render();
193         }
194         m.tex[0] = R_GetTexture(skyboxside[4]); // up
195         if (R_Mesh_Draw_GetBuffer(&m, false))
196         {
197                 memcpy(m.index, skyboxindex, sizeof(int[6]));
198                 m.color[0] = m.color[4] = m.color[8] = m.color[12] = m.colorscale;
199                 m.color[1] = m.color[5] = m.color[9] = m.color[13] = m.colorscale;
200                 m.color[2] = m.color[6] = m.color[10] = m.color[14] = m.colorscale;
201                 m.color[3] = m.color[7] = m.color[11] = m.color[15] = 1;
202                 R_SkyBoxPolyVec(0, 1, 0,  1, -1,  1);
203                 R_SkyBoxPolyVec(1, 1, 1,  1,  1,  1);
204                 R_SkyBoxPolyVec(2, 0, 1, -1,  1,  1);
205                 R_SkyBoxPolyVec(3, 0, 0, -1, -1,  1);
206                 R_Mesh_Render();
207         }
208         m.tex[0] = R_GetTexture(skyboxside[5]); // down
209         if (R_Mesh_Draw_GetBuffer(&m, false))
210         {
211                 memcpy(m.index, skyboxindex, sizeof(int[6]));
212                 m.color[0] = m.color[4] = m.color[8] = m.color[12] = m.colorscale;
213                 m.color[1] = m.color[5] = m.color[9] = m.color[13] = m.colorscale;
214                 m.color[2] = m.color[6] = m.color[10] = m.color[14] = m.colorscale;
215                 m.color[3] = m.color[7] = m.color[11] = m.color[15] = 1;
216                 R_SkyBoxPolyVec(0, 1, 0,  1,  1, -1);
217                 R_SkyBoxPolyVec(1, 1, 1,  1, -1, -1);
218                 R_SkyBoxPolyVec(2, 0, 1, -1, -1, -1);
219                 R_SkyBoxPolyVec(3, 0, 0, -1,  1, -1);
220                 R_Mesh_Render();
221         }
222 }
223
224 #define skygridx 16
225 #define skygridx1 (skygridx + 1)
226 #define skygridxrecip (1.0f / (skygridx))
227 #define skygridy 32
228 #define skygridy1 (skygridy + 1)
229 #define skygridyrecip (1.0f / (skygridy))
230
231 static float skysphere[skygridx1*skygridy1*5];
232 static int skysphereindices[skygridx*skygridy*6];
233 static void skyspherecalc(float *sphere, float dx, float dy, float dz)
234 {
235         float a, b, x, ax, ay, v[3], length;
236         int i, j, *index;
237         for (j = 0;j <= skygridy;j++)
238         {
239                 a = j * skygridyrecip;
240                 ax = cos(a * M_PI * 2);
241                 ay = -sin(a * M_PI * 2);
242                 for (i = 0;i <= skygridx;i++)
243                 {
244                         b = i * skygridxrecip;
245                         x = cos(b * M_PI * 2);
246                         v[0] = ax*x * dx;
247                         v[1] = ay*x * dy;
248                         v[2] = -sin(b * M_PI * 2) * dz;
249                         length = 3.0f / sqrt(v[0]*v[0]+v[1]*v[1]+(v[2]*v[2]*9));
250                         *sphere++ = v[0] * length;
251                         *sphere++ = v[1] * length;
252                         *sphere++ = v[0];
253                         *sphere++ = v[1];
254                         *sphere++ = v[2];
255                 }
256         }
257         index = skysphereindices;
258         for (j = 0;j < skygridy;j++)
259         {
260                 for (i = 0;i < skygridx;i++)
261                 {
262                         *index++ =  j      * skygridx1 + i;
263                         *index++ =  j      * skygridx1 + i + 1;
264                         *index++ = (j + 1) * skygridx1 + i;
265
266                         *index++ =  j      * skygridx1 + i + 1;
267                         *index++ = (j + 1) * skygridx1 + i + 1;
268                         *index++ = (j + 1) * skygridx1 + i;
269                 }
270                 i++;
271         }
272 }
273
274 static void skyspherearrays(float *v, float *t, float *c, float *source, float s, float colorscale)
275 {
276         int i;
277         for (i = 0;i < (skygridx1*skygridy1);i++, c += 4, t += 2, v += 4, source += 5)
278         {
279                 c[0] = colorscale;
280                 c[1] = colorscale;
281                 c[2] = colorscale;
282                 c[3] = 1;
283                 t[0] = source[0] + s;
284                 t[1] = source[1] + s;
285                 v[0] = source[2];
286                 v[1] = source[3];
287                 v[2] = source[4];
288         }
289 }
290
291 static void R_SkySphere(void)
292 {
293         float speedscale, speedscale2;
294         static qboolean skysphereinitialized = false;
295         rmeshbufferinfo_t m;
296         if (!skysphereinitialized)
297         {
298                 skysphereinitialized = true;
299                 skyspherecalc(skysphere, 16, 16, 16 / 3);
300         }
301
302         speedscale = cl.time*8.0/128.0;
303         speedscale -= (int)speedscale;
304         speedscale2 = cl.time*16.0/128.0;
305         speedscale2 -= (int)speedscale2;
306
307         memset(&m, 0, sizeof(m));
308         m.blendfunc1 = GL_ONE;
309         m.blendfunc2 = GL_ZERO;
310         m.depthdisable = true; // don't modify or read zbuffer
311         m.numtriangles = skygridx*skygridy*2;
312         m.numverts = skygridx1*skygridy1;
313         m.tex[0] = R_GetTexture(solidskytexture);
314         Matrix4x4_CreateTranslate(&m.matrix, r_origin[0], r_origin[1], r_origin[2]);
315         if (R_Mesh_Draw_GetBuffer(&m, false))
316         {
317                 memcpy(m.index, skysphereindices, m.numtriangles * sizeof(int[3]));
318                 skyspherearrays(m.vertex, m.texcoords[0], m.color, skysphere, speedscale, m.colorscale);
319                 R_Mesh_Render();
320         }
321         m.blendfunc1 = GL_SRC_ALPHA;
322         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
323         m.tex[0] = R_GetTexture(alphaskytexture);
324         if (R_Mesh_Draw_GetBuffer(&m, false))
325         {
326                 memcpy(m.index, skysphereindices, m.numtriangles * sizeof(int[3]));
327                 skyspherearrays(m.vertex, m.texcoords[0], m.color, skysphere, speedscale2, m.colorscale);
328                 R_Mesh_Render();
329         }
330 }
331
332 void R_Sky(void)
333 {
334         if (skyrendermasked)
335         {
336                 if (skyrendersphere)
337                 {
338                         // this does not modify depth buffer
339                         R_SkySphere();
340                 }
341                 else if (skyrenderbox)
342                 {
343                         // this does not modify depth buffer
344                         R_SkyBox();
345                 }
346                 /* this will be skyroom someday
347                 else
348                 {
349                         // this modifies the depth buffer so we have to clear it afterward
350                         //R_SkyRoom();
351                         // clear the depthbuffer that was used while rendering the skyroom
352                         //R_Mesh_ClearDepth();
353                 }
354                 */
355         }
356 }
357
358 //===============================================================
359
360 /*
361 =============
362 R_InitSky
363
364 A sky texture is 256*128, with the right side being a masked overlay
365 ==============
366 */
367 void R_InitSky (qbyte *src, int bytesperpixel)
368 {
369         int i, j, p, r, g, b;
370         qbyte skyupperlayerpixels[128*128*4], skylowerlayerpixels[128*128*4];
371         unsigned trans[128*128], transpix, *rgba;
372
373         skyavailable_quake = true;
374
375         // flush skytexturepool so we won't build up a leak from uploading textures multiple times
376         R_FreeTexturePool(&skytexturepool);
377         skytexturepool = R_AllocTexturePool();
378         solidskytexture = NULL;
379         alphaskytexture = NULL;
380
381         if (bytesperpixel == 4)
382         {
383                 for (i = 0;i < 128;i++)
384                         for (j = 0;j < 128;j++)
385                                 trans[(i*128) + j] = src[i*256+j+128];
386         }
387         else
388         {
389                 // make an average value for the back to avoid
390                 // a fringe on the top level
391                 r = g = b = 0;
392                 for (i=0 ; i<128 ; i++)
393                 {
394                         for (j=0 ; j<128 ; j++)
395                         {
396                                 p = src[i*256 + j + 128];
397                                 rgba = &d_8to24table[p];
398                                 trans[(i*128) + j] = *rgba;
399                                 r += ((qbyte *)rgba)[0];
400                                 g += ((qbyte *)rgba)[1];
401                                 b += ((qbyte *)rgba)[2];
402                         }
403                 }
404
405                 ((qbyte *)&transpix)[0] = r/(128*128);
406                 ((qbyte *)&transpix)[1] = g/(128*128);
407                 ((qbyte *)&transpix)[2] = b/(128*128);
408                 ((qbyte *)&transpix)[3] = 0;
409         }
410
411         memcpy(skyupperlayerpixels, trans, 128*128*4);
412
413         solidskytexture = R_LoadTexture (skytexturepool, "sky_solidtexture", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_PRECACHE);
414
415         if (bytesperpixel == 4)
416         {
417                 for (i = 0;i < 128;i++)
418                         for (j = 0;j < 128;j++)
419                                 trans[(i*128) + j] = src[i*256+j];
420         }
421         else
422         {
423                 for (i=0 ; i<128 ; i++)
424                 {
425                         for (j=0 ; j<128 ; j++)
426                         {
427                                 p = src[i*256 + j];
428                                 if (p == 0)
429                                         trans[(i*128) + j] = transpix;
430                                 else
431                                         trans[(i*128) + j] = d_8to24table[p];
432                         }
433                 }
434         }
435
436         memcpy(skylowerlayerpixels, trans, 128*128*4);
437
438         alphaskytexture = R_LoadTexture (skytexturepool, "sky_alphatexture", 128, 128, (qbyte *) trans, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE);
439 }
440
441 void R_ResetQuakeSky(void)
442 {
443         skyavailable_quake = false;
444 }
445
446 void R_ResetSkyBox(void)
447 {
448         skyboxside[0] = skyboxside[1] = skyboxside[2] = skyboxside[3] = skyboxside[4] = skyboxside[5] = NULL;
449         skyname[0] = 0;
450         skyavailable_box = false;
451 }
452
453 static void r_sky_start(void)
454 {
455         skytexturepool = R_AllocTexturePool();
456         solidskytexture = NULL;
457         alphaskytexture = NULL;
458 }
459
460 static void r_sky_shutdown(void)
461 {
462         R_FreeTexturePool(&skytexturepool);
463         solidskytexture = NULL;
464         alphaskytexture = NULL;
465 }
466
467 static void r_sky_newmap(void)
468 {
469 }
470
471 void R_Sky_Init(void)
472 {
473         Cmd_AddCommand ("loadsky", &LoadSky_f);
474         Cvar_RegisterVariable (&r_sky);
475         R_RegisterModule("R_Sky", r_sky_start, r_sky_shutdown, r_sky_newmap);
476 }