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