1 #include "engine.h"
2 
3 Texture *sky[6] = { 0, 0, 0, 0, 0, 0 }, *clouds[6] = { 0, 0, 0, 0, 0, 0 };
4 
loadsky(const char * basename,Texture * texs[6])5 void loadsky(const char *basename, Texture *texs[6])
6 {
7     const char *wildcard = strchr(basename, '*');
8     loopi(6)
9     {
10         const char *side = cubemapsides[i].name;
11         string name;
12         copystring(name, makerelpath("packages", basename));
13         if(wildcard)
14         {
15             char *chop = strchr(name, '*');
16             if(chop) { *chop = '\0'; concatstring(name, side); concatstring(name, wildcard+1); }
17             texs[i] = textureload(name, 3, true, false);
18         }
19         else
20         {
21             defformatstring(ext, "_%s.jpg", side);
22             concatstring(name, ext);
23             if((texs[i] = textureload(name, 3, true, false))==notexture)
24             {
25                 strcpy(name+strlen(name)-3, "png");
26                 texs[i] = textureload(name, 3, true, false);
27             }
28         }
29         if(texs[i]==notexture) conoutf(CON_ERROR, "could not load side %s of sky texture %s", side, basename);
30     }
31 }
32 
33 Texture *cloudoverlay = NULL;
34 
loadskyoverlay(const char * basename)35 Texture *loadskyoverlay(const char *basename)
36 {
37     const char *ext = strrchr(basename, '.');
38     string name;
39     copystring(name, makerelpath("packages", basename));
40     Texture *t = notexture;
41     if(ext) t = textureload(name, 0, true, false);
42     else
43     {
44         concatstring(name, ".jpg");
45         if((t = textureload(name, 0, true, false)) == notexture)
46         {
47             strcpy(name+strlen(name)-3, "png");
48             t = textureload(name, 0, true, false);
49         }
50     }
51     if(t==notexture) conoutf(CON_ERROR, "could not load sky overlay texture %s", basename);
52     return t;
53 }
54 
55 SVARFR(skybox, "", { if(skybox[0]) loadsky(skybox, sky); });
56 HVARR(skyboxcolour, 0, 0xFFFFFF, 0xFFFFFF);
57 FVARR(spinsky, -720, 0, 720);
58 VARR(yawsky, 0, 0, 360);
59 SVARFR(cloudbox, "", { if(cloudbox[0]) loadsky(cloudbox, clouds); });
60 HVARR(cloudboxcolour, 0, 0xFFFFFF, 0xFFFFFF);
61 FVARR(cloudboxalpha, 0, 1, 1);
62 FVARR(spinclouds, -720, 0, 720);
63 VARR(yawclouds, 0, 0, 360);
64 FVARR(cloudclip, 0, 0.5f, 1);
65 SVARFR(cloudlayer, "", { if(cloudlayer[0]) cloudoverlay = loadskyoverlay(cloudlayer); });
66 FVARR(cloudoffsetx, 0, 0, 1);
67 FVARR(cloudoffsety, 0, 0, 1);
68 FVARR(cloudscrollx, -16, 0, 16);
69 FVARR(cloudscrolly, -16, 0, 16);
70 FVARR(cloudscale, 0.001, 1, 64);
71 FVARR(spincloudlayer, -720, 0, 720);
72 VARR(yawcloudlayer, 0, 0, 360);
73 FVARR(cloudheight, -1, 0.2f, 1);
74 FVARR(cloudfade, 0, 0.2f, 1);
75 FVARR(cloudalpha, 0, 1, 1);
76 VARR(cloudsubdiv, 4, 16, 64);
77 HVARR(cloudcolour, 0, 0xFFFFFF, 0xFFFFFF);
78 
drawenvboxface(float s0,float t0,int x0,int y0,int z0,float s1,float t1,int x1,int y1,int z1,float s2,float t2,int x2,int y2,int z2,float s3,float t3,int x3,int y3,int z3,Texture * tex)79 void drawenvboxface(float s0, float t0, int x0, int y0, int z0,
80                     float s1, float t1, int x1, int y1, int z1,
81                     float s2, float t2, int x2, int y2, int z2,
82                     float s3, float t3, int x3, int y3, int z3,
83                     Texture *tex)
84 {
85     glBindTexture(GL_TEXTURE_2D, (tex ? tex : notexture)->id);
86     gle::begin(GL_TRIANGLE_STRIP);
87     gle::attribf(x3, y3, z3); gle::attribf(s3, t3);
88     gle::attribf(x2, y2, z2); gle::attribf(s2, t2);
89     gle::attribf(x0, y0, z0); gle::attribf(s0, t0);
90     gle::attribf(x1, y1, z1); gle::attribf(s1, t1);
91     xtraverts += gle::end();
92 }
93 
drawenvbox(int w,float z1clip=0.0f,float z2clip=1.0f,int faces=0x3F,Texture ** sky=NULL)94 void drawenvbox(int w, float z1clip = 0.0f, float z2clip = 1.0f, int faces = 0x3F, Texture **sky = NULL)
95 {
96     if(z1clip >= z2clip) return;
97 
98     float v1 = 1-z1clip, v2 = 1-z2clip;
99     int z1 = int(ceil(2*w*(z1clip-0.5f))), z2 = int(ceil(2*w*(z2clip-0.5f)));
100 
101     gle::defvertex();
102     gle::deftexcoord0();
103 
104     if(faces&0x01)
105         drawenvboxface(0.0f, v2,  -w, -w, z2,
106                        1.0f, v2,  -w,  w, z2,
107                        1.0f, v1,  -w,  w, z1,
108                        0.0f, v1,  -w, -w, z1, sky[0]);
109 
110     if(faces&0x02)
111         drawenvboxface(1.0f, v1, w, -w, z1,
112                        0.0f, v1, w,  w, z1,
113                        0.0f, v2, w,  w, z2,
114                        1.0f, v2, w, -w, z2, sky[1]);
115 
116     if(faces&0x04)
117         drawenvboxface(1.0f, v1, -w, -w, z1,
118                        0.0f, v1,  w, -w, z1,
119                        0.0f, v2,  w, -w, z2,
120                        1.0f, v2, -w, -w, z2, sky[2]);
121 
122     if(faces&0x08)
123         drawenvboxface(1.0f, v1,  w,  w, z1,
124                        0.0f, v1, -w,  w, z1,
125                        0.0f, v2, -w,  w, z2,
126                        1.0f, v2,  w,  w, z2, sky[3]);
127 
128     if(z1clip <= 0 && faces&0x10)
129         drawenvboxface(0.0f, 1.0f, -w,  w,  -w,
130                        0.0f, 0.0f,  w,  w,  -w,
131                        1.0f, 0.0f,  w, -w,  -w,
132                        1.0f, 1.0f, -w, -w,  -w, sky[4]);
133 
134     if(z2clip >= 1 && faces&0x20)
135         drawenvboxface(0.0f, 1.0f,  w,  w, w,
136                        0.0f, 0.0f, -w,  w, w,
137                        1.0f, 0.0f, -w, -w, w,
138                        1.0f, 1.0f,  w, -w, w, sky[5]);
139 }
140 
drawenvoverlay(int w,Texture * overlay=NULL,float tx=0,float ty=0)141 void drawenvoverlay(int w, Texture *overlay = NULL, float tx = 0, float ty = 0)
142 {
143     float z = w*cloudheight, tsz = 0.5f*(1-cloudfade)/cloudscale, psz = w*(1-cloudfade);
144     glBindTexture(GL_TEXTURE_2D, overlay ? overlay->id : notexture->id);
145     vec color = vec::hexcolor(cloudcolour);
146     gle::color(color, cloudalpha);
147     gle::defvertex();
148     gle::deftexcoord0();
149     gle::begin(GL_TRIANGLE_FAN);
150     loopi(cloudsubdiv+1)
151     {
152         vec p(1, 1, 0);
153         p.rotate_around_z((-2.0f*M_PI*i)/cloudsubdiv);
154         gle::attribf(p.x*psz, p.y*psz, z);
155             gle::attribf(tx + p.x*tsz, ty + p.y*tsz);
156     }
157     xtraverts += gle::end();
158     float tsz2 = 0.5f/cloudscale;
159     gle::defvertex();
160     gle::deftexcoord0();
161     gle::defcolor(4);
162     gle::begin(GL_TRIANGLE_STRIP);
163     loopi(cloudsubdiv+1)
164     {
165         vec p(1, 1, 0);
166         p.rotate_around_z((-2.0f*M_PI*i)/cloudsubdiv);
167         gle::attribf(p.x*psz, p.y*psz, z);
168             gle::attribf(tx + p.x*tsz, ty + p.y*tsz);
169             gle::attrib(color, cloudalpha);
170         gle::attribf(p.x*w, p.y*w, z);
171             gle::attribf(tx + p.x*tsz2, ty + p.y*tsz2);
172             gle::attrib(color, 0.0f);
173     }
174     xtraverts += gle::end();
175 }
176 
177 FVARR(fogdomeheight, -1, -0.5f, 1);
178 FVARR(fogdomemin, 0, 0, 1);
179 FVARR(fogdomemax, 0, 0, 1);
180 VARR(fogdomecap, 0, 1, 1);
181 FVARR(fogdomeclip, 0, 1, 1);
182 bvec fogdomecolor(0, 0, 0);
183 HVARFR(fogdomecolour, 0, 0, 0xFFFFFF,
184 {
185     fogdomecolor = bvec((fogdomecolour>>16)&0xFF, (fogdomecolour>>8)&0xFF, fogdomecolour&0xFF);
186 });
187 VARR(fogdomeclouds, 0, 1, 1);
188 
189 namespace fogdome
190 {
191     struct vert
192     {
193         vec pos;
194         bvec4 color;
195 
vertfogdome::vert196     	vert() {}
vertfogdome::vert197     	vert(const vec &pos, const bvec &fcolor, float alpha) : pos(pos), color(fcolor, uchar(alpha*255))
198     	{
199     	}
vertfogdome::vert200         vert(const vert &v0, const vert &v1) : pos(vec(v0.pos).add(v1.pos).normalize()), color(v0.color)
201     	{
202             if(v0.pos.z != v1.pos.z) color.a += uchar((v1.color.a - v0.color.a) * (pos.z - v0.pos.z) / (v1.pos.z - v0.pos.z));
203     	}
204     } *verts = NULL;
205     GLushort *indices = NULL;
206     int numverts = 0, numindices = 0, capindices = 0;
207     GLuint vbuf = 0, ebuf = 0;
208     bvec lastcolor(0, 0, 0);
209     float lastminalpha = 0, lastmaxalpha = 0, lastcapsize = -1, lastclipz = 1;
210 
211     void subdivide(int depth, int face);
212 
genface(int depth,int i1,int i2,int i3)213     void genface(int depth, int i1, int i2, int i3)
214     {
215         int face = numindices; numindices += 3;
216         indices[face]   = i3;
217         indices[face+1] = i2;
218         indices[face+2] = i1;
219         subdivide(depth, face);
220     }
221 
subdivide(int depth,int face)222     void subdivide(int depth, int face)
223     {
224         if(depth-- <= 0) return;
225         int idx[6];
226         loopi(3) idx[i] = indices[face+2-i];
227         loopi(3)
228         {
229             int curvert = numverts++;
230             verts[curvert] = vert(verts[idx[i]], verts[idx[(i+1)%3]]); //push on to unit sphere
231             idx[3+i] = curvert;
232             indices[face+2-i] = curvert;
233         }
234         subdivide(depth, face);
235         loopi(3) genface(depth, idx[i], idx[3+i], idx[3+(i+2)%3]);
236     }
237 
sortcap(GLushort x,GLushort y)238     int sortcap(GLushort x, GLushort y)
239     {
240         const vec &xv = verts[x].pos, &yv = verts[y].pos;
241         return xv.y < 0 ? yv.y >= 0 || xv.x < yv.x : yv.y >= 0 && xv.x > yv.x;
242     }
243 
init(const bvec & color,float minalpha=0.0f,float maxalpha=1.0f,float capsize=-1,float clipz=1,int hres=16,int depth=2)244     void init(const bvec &color, float minalpha = 0.0f, float maxalpha = 1.0f, float capsize = -1, float clipz = 1, int hres = 16, int depth = 2)
245     {
246         const int tris = hres << (2*depth);
247         numverts = numindices = capindices = 0;
248         verts = new vert[tris+1 + (capsize >= 0 ? 1 : 0)];
249         indices = new GLushort[(tris + (capsize >= 0 ? hres<<depth : 0))*3];
250         if(clipz >= 1)
251         {
252             verts[numverts++] = vert(vec(0.0f, 0.0f, 1.0f), color, minalpha); //build initial 'hres' sided pyramid
253             loopi(hres) verts[numverts++] = vert(vec(sincos360[(360*i)/hres], 0.0f), color, maxalpha);
254             loopi(hres) genface(depth, 0, i+1, 1+(i+1)%hres);
255         }
256         else if(clipz <= 0)
257         {
258             loopi(hres<<depth) verts[numverts++] = vert(vec(sincos360[(360*i)/(hres<<depth)], 0.0f), color, maxalpha);
259         }
260         else
261         {
262             float clipxy = sqrtf(1 - clipz*clipz);
263             const vec2 &scm = sincos360[180/hres];
264             loopi(hres)
265             {
266                 const vec2 &sc = sincos360[(360*i)/hres];
267                 verts[numverts++] = vert(vec(sc.x*clipxy, sc.y*clipxy, clipz), color, minalpha);
268                 verts[numverts++] = vert(vec(sc.x, sc.y, 0.0f), color, maxalpha);
269                 verts[numverts++] = vert(vec(sc.x*scm.x - sc.y*scm.y, sc.y*scm.x + sc.x*scm.y, 0.0f), color, maxalpha);
270             }
271             loopi(hres)
272             {
273                 genface(depth-1, 3*i, 3*i+1, 3*i+2);
274                 genface(depth-1, 3*i, 3*i+2, 3*((i+1)%hres));
275                 genface(depth-1, 3*i+2, 3*((i+1)%hres)+1, 3*((i+1)%hres));
276             }
277         }
278 
279         if(capsize >= 0)
280         {
281             GLushort *cap = &indices[numindices];
282             int capverts = 0;
283             loopi(numverts) if(!verts[i].pos.z) cap[capverts++] = i;
284             verts[numverts++] = vert(vec(0.0f, 0.0f, -capsize), color, maxalpha);
285             quicksort(cap, capverts, sortcap);
286             loopi(capverts)
287             {
288                 int n = capverts-1-i;
289                 cap[n*3] = cap[n];
290                 cap[n*3+1] = cap[(n+1)%capverts];
291                 cap[n*3+2] = numverts-1;
292                 capindices += 3;
293             }
294         }
295 
296         if(!vbuf) glGenBuffers_(1, &vbuf);
297         gle::bindvbo(vbuf);
298         glBufferData_(GL_ARRAY_BUFFER, numverts*sizeof(vert), verts, GL_STATIC_DRAW);
299         DELETEA(verts);
300 
301         if(!ebuf) glGenBuffers_(1, &ebuf);
302         gle::bindebo(ebuf);
303         glBufferData_(GL_ELEMENT_ARRAY_BUFFER, (numindices + capindices)*sizeof(GLushort), indices, GL_STATIC_DRAW);
304         DELETEA(indices);
305     }
306 
cleanup()307     void cleanup()
308     {
309     	numverts = numindices = 0;
310         if(vbuf) { glDeleteBuffers_(1, &vbuf); vbuf = 0; }
311         if(ebuf) { glDeleteBuffers_(1, &ebuf); ebuf = 0; }
312     }
313 
draw()314     void draw()
315     {
316         float capsize = fogdomecap && fogdomeheight < 1 ? (1 + fogdomeheight) / (1 - fogdomeheight) : -1;
317         bvec color = fogdomecolour ? fogdomecolor : fogcolor;
318         if(!numverts || lastcolor != color || lastminalpha != fogdomemin || lastmaxalpha != fogdomemax || lastcapsize != capsize || lastclipz != fogdomeclip)
319         {
320             init(color, min(fogdomemin, fogdomemax), fogdomemax, capsize, fogdomeclip);
321             lastcolor = color;
322             lastminalpha = fogdomemin;
323             lastmaxalpha = fogdomemax;
324             lastcapsize = capsize;
325             lastclipz = fogdomeclip;
326         }
327 
328         gle::bindvbo(vbuf);
329         gle::bindebo(ebuf);
330 
331         gle::vertexpointer(sizeof(vert), &verts->pos);
332         gle::colorpointer(sizeof(vert), &verts->color);
333         gle::enablevertex();
334         gle::enablecolor();
335 
336         glDrawRangeElements_(GL_TRIANGLES, 0, numverts-1, numindices + fogdomecap*capindices, GL_UNSIGNED_SHORT, indices);
337         xtraverts += numverts;
338         glde++;
339 
340         gle::disablevertex();
341         gle::disablecolor();
342 
343         gle::clearvbo();
344         gle::clearebo();
345     }
346 }
347 
drawfogdome(int farplane)348 static void drawfogdome(int farplane)
349 {
350     SETSHADER(skyfog);
351 
352     glEnable(GL_BLEND);
353     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
354 
355     matrix4 skymatrix = cammatrix, skyprojmatrix;
356     skymatrix.settranslation(vec(cammatrix.c).mul(farplane*fogdomeheight*0.5f));
357     skymatrix.scale(farplane/2, farplane/2, farplane*(0.5f - fogdomeheight*0.5f));
358     skyprojmatrix.mul(projmatrix, skymatrix);
359     LOCALPARAM(skymatrix, skyprojmatrix);
360 
361     fogdome::draw();
362 
363     glDisable(GL_BLEND);
364 }
365 
cleanupsky()366 void cleanupsky()
367 {
368     fogdome::cleanup();
369 }
370 
371 extern int atmo;
372 
preloadatmoshaders(bool force=false)373 void preloadatmoshaders(bool force = false)
374 {
375     static bool needatmo = false;
376     if(force) needatmo = true;
377     if(!atmo || !needatmo) return;
378 
379     useshaderbyname("atmosphere");
380     useshaderbyname("atmosphereglare");
381 }
382 
setupsky()383 void setupsky()
384 {
385     preloadatmoshaders(true);
386 }
387 
388 VARFR(atmo, 0, 0, 1, preloadatmoshaders());
389 FVARR(atmoplanetsize, 1e-3f, 1, 1e3f);
390 FVARR(atmoheight, 1e-3f, 1, 1e3f);
391 FVARR(atmobright, 0, 1, 16);
392 bvec atmosunlightcolor(0, 0, 0);
393 HVARFR(atmosunlight, 0, 0, 0xFFFFFF,
394 {
395     if(atmosunlight <= 255) atmosunlight |= (atmosunlight<<8) | (atmosunlight<<16);
396     atmosunlightcolor = bvec((atmosunlight>>16)&0xFF, (atmosunlight>>8)&0xFF, atmosunlight&0xFF);
397 });
398 FVARR(atmosunlightscale, 0, 1, 16);
399 bvec atmosundiskcolor(0, 0, 0);
400 HVARFR(atmosundisk, 0, 0, 0xFFFFFF,
401 {
402     if(atmosundisk <= 255) atmosundisk |= (atmosundisk<<8) | (atmosundisk<<16);
403     atmosundiskcolor = bvec((atmosundisk>>16)&0xFF, (atmosundisk>>8)&0xFF, atmosundisk&0xFF);
404 });
405 FVARR(atmosundisksize, 0, 12, 90);
406 FVARR(atmosundiskcorona, 0, 0.4f, 1);
407 FVARR(atmosundiskbright, 0, 1, 16);
408 FVARR(atmohaze, 0, 0.1f, 16);
409 FVARR(atmodensity, 0, 1, 16);
410 FVARR(atmoozone, 0, 1, 16);
411 FVARR(atmoalpha, 0, 1, 1);
412 
drawatmosphere(int w,float z1clip=0.0f,float z2clip=1.0f,int faces=0x3F)413 static void drawatmosphere(int w, float z1clip = 0.0f, float z2clip = 1.0f, int faces = 0x3F)
414 {
415     if(z1clip >= z2clip) return;
416 
417     if(glaring) SETSHADER(atmosphereglare);
418     else SETSHADER(atmosphere);
419 
420     matrix4 skymatrix = cammatrix, skyprojmatrix;
421     skymatrix.settranslation(0, 0, 0);
422     skyprojmatrix.mul(projmatrix, skymatrix);
423     LOCALPARAM(skymatrix, skyprojmatrix);
424 
425     // optical depth scales for 3 different shells of atmosphere - air, haze, ozone
426     const float earthradius = 6371e3f, earthairheight = 8.4e3f, earthhazeheight = 1.25e3f, earthozoneheight = 50e3f;
427     float planetradius = earthradius*atmoplanetsize;
428     vec atmoshells = vec(earthairheight, earthhazeheight, earthozoneheight).mul(atmoheight).add(planetradius).square().sub(planetradius*planetradius);
429     LOCALPARAM(opticaldepthparams, vec4(atmoshells, planetradius));
430 
431     // Henyey-Greenstein approximation, 1/(4pi) * (1 - g^2)/(1 + g^2 - 2gcos)]^1.5
432     // Hoffman-Preetham variation uses (1-g)^2 instead of 1-g^2 which avoids excessive glare
433     // clamp values near 0 angle to avoid spotlight artifact inside sundisk
434     float gm = max(0.95f - 0.2f*atmohaze, 0.65f), miescale = pow((1-gm)*(1-gm)/(4*M_PI), -2.0f/3.0f);
435     LOCALPARAMF(mieparams, miescale*(1 + gm*gm), miescale*-2*gm, 1 - (1 - cosf(0.5f*atmosundisksize*(1 - atmosundiskcorona)*RAD)));
436 
437     static const vec lambda(680e-9f, 550e-9f, 450e-9f),
438                      k(0.686f, 0.678f, 0.666f),
439                      ozone(3.426f, 8.298f, 0.356f);
440     vec betar = vec(lambda).square().square().recip().mul(1.241e-30f/M_LN2 * atmodensity),
441         betam = vec(lambda).recip().square().mul(k).mul(9.072e-17f/M_LN2 * atmohaze),
442         betao = vec(ozone).mul(1.5e-7f/M_LN2 * atmoozone);
443     LOCALPARAM(betarayleigh, betar);
444     LOCALPARAM(betamie, betam);
445     LOCALPARAM(betaozone, betao);
446 
447     // extinction in direction of sun
448     float sunoffset = sunlightdir.z*planetradius;
449     vec sundepth = vec(atmoshells).add(sunoffset*sunoffset).sqrt().sub(sunoffset);
450     vec sunweight = vec(betar).mul(sundepth.x).madd(betam, sundepth.y).madd(betao, sundepth.z - sundepth.x);
451     vec sunextinction = vec(sunweight).neg().exp2();
452     vec suncolor = atmosunlight ? atmosunlightcolor.tocolor().mul(atmosunlightscale) : sunlightcolor.tocolor().mul(sunlightscale);
453     // assume sunlight color is gamma encoded, so decode to linear light, then apply extinction
454     vec sunscale = vec(suncolor).square().mul(atmobright * 16).mul(sunextinction);
455     float maxsunweight = max(max(sunweight.x, sunweight.y), sunweight.z);
456     if(maxsunweight > 127) sunweight.mul(127/maxsunweight);
457     sunweight.add(1e-4f);
458     LOCALPARAM(sunweight, sunweight);
459     LOCALPARAM(sunlight, vec4(sunscale, atmoalpha));
460     LOCALPARAM(sundir, sunlightdir);
461 
462     // invert extinction at zenith to get an approximation of how bright the sun disk should be
463     vec zenithdepth = vec(atmoshells).add(planetradius*planetradius).sqrt().sub(planetradius);
464     vec zenithweight = vec(betar).mul(zenithdepth.x).madd(betam, zenithdepth.y).madd(betao, zenithdepth.z - zenithdepth.x);
465     vec zenithextinction = vec(zenithweight).sub(sunweight).exp2();
466     vec diskcolor = (atmosundisk ? atmosundiskcolor.tocolor() : suncolor).square().mul(zenithextinction).mul(atmosundiskbright * (glaring ? 1 : 1.5f)).min(1);
467     LOCALPARAM(sundiskcolor, diskcolor);
468 
469     // convert from view cosine into mu^2 for limb darkening, where mu = sqrt(1 - sin^2) and sin^2 = 1 - cos^2, thus mu^2 = 1 - (1 - cos^2*scale)
470     // convert corona offset into scale for mu^2, where sin = (1-corona) and thus mu^2 = 1 - (1-corona^2)
471     float sundiskscale = sinf(0.5f*atmosundisksize*RAD);
472     float coronamu = 1 - (1-atmosundiskcorona)*(1-atmosundiskcorona);
473     if(sundiskscale > 0) LOCALPARAMF(sundiskparams, 1.0f/(sundiskscale*sundiskscale), 1.0f/max(coronamu, 1e-3f));
474     else LOCALPARAMF(sundiskparams, 0, 0);
475 
476     float z1 = 2*w*(z1clip-0.5f), z2 = ceil(2*w*(z2clip-0.5f));
477 
478     gle::defvertex();
479 
480     if(glaring)
481     {
482         if(sundiskscale > 0 && sunlightdir.z*w + sundiskscale > z1 && sunlightdir.z*w - sundiskscale < z2)
483         {
484             gle::begin(GL_TRIANGLE_FAN);
485             vec spoke;
486             spoke.orthogonal(sunlightdir);
487             spoke.rescale(2*sundiskscale);
488             loopi(4) gle::attrib(vec(spoke).rotate(-2*M_PI*i/4.0f, sunlightdir).add(sunlightdir).mul(w));
489             xtraverts += gle::end();
490         }
491         return;
492     }
493 
494     gle::begin(GL_QUADS);
495 
496     if(faces&0x01)
497     {
498         gle::attribf(-w, -w, z1);
499         gle::attribf(-w,  w, z1);
500         gle::attribf(-w,  w, z2);
501         gle::attribf(-w, -w, z2);
502     }
503 
504     if(faces&0x02)
505     {
506         gle::attribf(w, -w, z2);
507         gle::attribf(w,  w, z2);
508         gle::attribf(w,  w, z1);
509         gle::attribf(w, -w, z1);
510     }
511 
512     if(faces&0x04)
513     {
514         gle::attribf(-w, -w, z2);
515         gle::attribf( w, -w, z2);
516         gle::attribf( w, -w, z1);
517         gle::attribf(-w, -w, z1);
518     }
519 
520     if(faces&0x08)
521     {
522         gle::attribf( w, w, z2);
523         gle::attribf(-w, w, z2);
524         gle::attribf(-w, w, z1);
525         gle::attribf( w, w, z1);
526     }
527 
528     if(z1clip <= 0 && faces&0x10)
529     {
530         gle::attribf(-w, -w, -w);
531         gle::attribf( w, -w, -w);
532         gle::attribf( w,  w, -w);
533         gle::attribf(-w,  w, -w);
534     }
535 
536     if(z2clip >= 1 && faces&0x20)
537     {
538         gle::attribf( w, -w, w);
539         gle::attribf(-w, -w, w);
540         gle::attribf(-w,  w, w);
541         gle::attribf( w,  w, w);
542     }
543 
544     xtraverts += gle::end();
545 }
546 
547 VARP(sparklyfix, 0, 0, 1);
548 VAR(showsky, 0, 1, 1);
549 VAR(clipsky, 0, 1, 1);
550 
drawskylimits(bool explicitonly)551 bool drawskylimits(bool explicitonly)
552 {
553     nocolorshader->set();
554 
555     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
556     bool rendered = rendersky(explicitonly);
557     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
558 
559     return rendered;
560 }
561 
drawskyoutline()562 void drawskyoutline()
563 {
564     notextureshader->set();
565 
566     glDepthMask(GL_FALSE);
567     extern int wireframe;
568     if(!wireframe)
569     {
570         enablepolygonoffset(GL_POLYGON_OFFSET_LINE);
571         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
572     }
573     gle::colorf(0.5f, 0.0f, 0.5f);
574     rendersky(true);
575     if(!wireframe)
576     {
577         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
578         disablepolygonoffset(GL_POLYGON_OFFSET_LINE);
579     }
580     glDepthMask(GL_TRUE);
581 }
582 
583 VAR(clampsky, 0, 1, 1);
584 
yawskyfaces(int faces,int yaw,float spin=0)585 static int yawskyfaces(int faces, int yaw, float spin = 0)
586 {
587     if(spin || yaw%90) return faces&0x0F ? faces | 0x0F : faces;
588     static const int faceidxs[3][4] =
589     {
590         { 3, 2, 0, 1 },
591         { 1, 0, 3, 2 },
592         { 2, 3, 1, 0 }
593     };
594     yaw /= 90;
595     if(yaw < 1 || yaw > 3) return faces;
596     const int *idxs = faceidxs[yaw - 1];
597     return (faces & ~0x0F) | (((faces>>idxs[0])&1)<<0) | (((faces>>idxs[1])&1)<<1) | (((faces>>idxs[2])&1)<<2) | (((faces>>idxs[3])&1)<<3);
598 }
599 
drawskybox(int farplane,bool limited,bool force)600 void drawskybox(int farplane, bool limited, bool force)
601 {
602     extern int renderedskyfaces, renderedskyclip; // , renderedsky, renderedexplicitsky;
603     bool alwaysrender = editmode || !insideworld(camera1->o) || reflecting || force,
604          explicitonly = false;
605     if(limited)
606     {
607         explicitonly = alwaysrender || !sparklyfix || refracting;
608         if(!drawskylimits(explicitonly) && !alwaysrender) return;
609         extern int ati_skybox_bug;
610         if(!alwaysrender && !renderedskyfaces && !ati_skybox_bug) explicitonly = false;
611     }
612     else if(!alwaysrender)
613     {
614         renderedskyfaces = 0;
615         renderedskyclip = INT_MAX;
616         for(vtxarray *va = visibleva; va; va = va->next)
617         {
618             if(va->occluded >= OCCLUDE_BB && va->skyfaces&0x80) continue;
619             renderedskyfaces |= va->skyfaces&0x3F;
620             if(!(va->skyfaces&0x1F) || camera1->o.z < va->skyclip) renderedskyclip = min(renderedskyclip, va->skyclip);
621             else renderedskyclip = 0;
622         }
623         if(!renderedskyfaces) return;
624     }
625 
626     if(alwaysrender)
627     {
628         renderedskyfaces = 0x3F;
629         renderedskyclip = 0;
630     }
631 
632     float skyclip = clipsky ? max(renderedskyclip-1, 0) : 0, topclip = 1;
633     if(reflectz<worldsize)
634     {
635         if(refracting<0) topclip = 0.5f + 0.5f*(reflectz-camera1->o.z)/float(worldsize);
636         else if(reflectz>skyclip) skyclip = reflectz;
637     }
638     if(skyclip) skyclip = 0.5f + 0.5f*(skyclip-camera1->o.z)/float(worldsize);
639 
640     if(limited)
641     {
642         if(explicitonly) glDisable(GL_DEPTH_TEST);
643         else glDepthFunc(GL_GEQUAL);
644     }
645     else glDepthFunc(GL_LEQUAL);
646 
647     glDepthMask(GL_FALSE);
648 
649     if(clampsky) glDepthRange(1, 1);
650 
651     if(!atmo || (skybox[0] && atmoalpha < 1))
652     {
653         if(glaring) SETSHADER(skyboxglare);
654         else SETSHADER(skybox);
655 
656         gle::color(vec::hexcolor(skyboxcolour));
657 
658         matrix4 skymatrix = cammatrix, skyprojmatrix;
659         skymatrix.settranslation(0, 0, 0);
660         skymatrix.rotate_around_z((spinsky*lastmillis/1000.0f+yawsky)*-RAD);
661         skyprojmatrix.mul(projmatrix, skymatrix);
662         LOCALPARAM(skymatrix, skyprojmatrix);
663 
664         drawenvbox(farplane/2, skyclip, topclip, yawskyfaces(renderedskyfaces, yawsky, spinsky), sky);
665     }
666 
667     if(atmo)
668     {
669         if(atmoalpha < 1)
670         {
671             if(fading) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
672             glEnable(GL_BLEND);
673             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
674         }
675 
676         drawatmosphere(farplane/2, skyclip, topclip, renderedskyfaces);
677 
678         if(atmoalpha < 1) glDisable(GL_BLEND);
679     }
680 
681     if(!glaring)
682     {
683         if(fogdomemax && !fogdomeclouds)
684         {
685             if(fading) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
686             drawfogdome(farplane);
687         }
688 
689         if(cloudbox[0])
690         {
691             SETSHADER(skybox);
692 
693             if(fading) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
694 
695             glEnable(GL_BLEND);
696             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
697 
698             gle::color(vec::hexcolor(cloudboxcolour), cloudboxalpha);
699 
700             matrix4 skymatrix = cammatrix, skyprojmatrix;
701             skymatrix.settranslation(0, 0, 0);
702             skymatrix.rotate_around_z((spinclouds*lastmillis/1000.0f+yawclouds)*-RAD);
703             skyprojmatrix.mul(projmatrix, skymatrix);
704             LOCALPARAM(skymatrix, skyprojmatrix);
705 
706             drawenvbox(farplane/2, skyclip ? skyclip : cloudclip, topclip, yawskyfaces(renderedskyfaces, yawclouds, spinclouds), clouds);
707 
708             glDisable(GL_BLEND);
709         }
710 
711         if(cloudlayer[0] && cloudheight && renderedskyfaces&(cloudheight < 0 ? 0x1F : 0x2F))
712         {
713             SETSHADER(skybox);
714 
715             if(fading) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
716 
717             glDisable(GL_CULL_FACE);
718 
719             glEnable(GL_BLEND);
720             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
721 
722             matrix4 skymatrix = cammatrix, skyprojmatrix;
723             skymatrix.settranslation(0, 0, 0);
724             skymatrix.rotate_around_z((spincloudlayer*lastmillis/1000.0f+yawcloudlayer)*-RAD);
725             skyprojmatrix.mul(projmatrix, skymatrix);
726             LOCALPARAM(skymatrix, skyprojmatrix);
727 
728             drawenvoverlay(farplane/2, cloudoverlay, cloudoffsetx + cloudscrollx * lastmillis/1000.0f, cloudoffsety + cloudscrolly * lastmillis/1000.0f);
729 
730             glDisable(GL_BLEND);
731 
732             glEnable(GL_CULL_FACE);
733         }
734 
735 	    if(fogdomemax && fogdomeclouds)
736 	    {
737             if(fading) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
738             drawfogdome(farplane);
739 	    }
740     }
741 
742     if(clampsky) glDepthRange(0, 1);
743 
744     glDepthMask(GL_TRUE);
745 
746     if(limited)
747     {
748         if(explicitonly) glEnable(GL_DEPTH_TEST);
749         else glDepthFunc(GL_LESS);
750         if(!reflecting && !refracting && !drawtex && editmode && showsky) drawskyoutline();
751     }
752     else glDepthFunc(GL_LESS);
753 }
754 
755 VARNR(skytexture, useskytexture, 0, 1, 1);
756 
757 int explicitsky = 0;
758 double skyarea = 0;
759 
limitsky()760 bool limitsky()
761 {
762     return (explicitsky && (useskytexture || editmode)) || (sparklyfix && skyarea / (double(worldsize)*double(worldsize)*6) < 0.9);
763 }
764 
shouldrenderskyenvmap()765 bool shouldrenderskyenvmap()
766 {
767     return atmo != 0;
768 }
769 
shouldclearskyboxglare()770 bool shouldclearskyboxglare()
771 {
772     return atmo && (!skybox[0] || atmoalpha >= 1);
773 }
774 
775