]> git.lizzy.rs Git - dragonfireclient.git/blob - src/sky.cpp
Dynamic sky, fog and cloud colors; sun and moon
[dragonfireclient.git] / src / sky.cpp
1 #include "sky.h"
2 #include "IVideoDriver.h"
3 #include "ISceneManager.h"
4 #include "ICameraSceneNode.h"
5 #include "S3DVertex.h"
6 #include "utility.h" // MYMIN
7 #include "tile.h" // getTexturePath
8 #include "noise.h" // easeCurve
9 #include "main.h" // g_profiler
10 #include "profiler.h"
11
12 //! constructor
13 Sky::Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id):
14                 scene::ISceneNode(parent, mgr, id),
15                 m_first_update(true),
16                 m_brightness(0.5),
17                 m_cloud_brightness(0.5),
18                 m_bgcolor_bright_f(1,1,1,1),
19                 m_skycolor_bright_f(1,1,1,1),
20                 m_cloudcolor_bright_f(1,1,1,1)
21 {
22         setAutomaticCulling(scene::EAC_OFF);
23         Box.MaxEdge.set(0,0,0);
24         Box.MinEdge.set(0,0,0);
25
26         // create material
27
28         video::SMaterial mat;
29         mat.Lighting = false;
30         mat.ZBuffer = video::ECFN_NEVER;
31         mat.ZWriteEnable = false;
32         mat.AntiAliasing=0;
33         mat.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
34         mat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
35         mat.BackfaceCulling = false;
36
37         m_materials[0] = mat;
38
39         m_materials[1] = mat;
40         //m_materials[1].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
41         m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
42
43         m_materials[2] = mat;
44         m_materials[2].setTexture(0, mgr->getVideoDriver()->getTexture(
45                         getTexturePath("sunrisebg.png").c_str()));
46         m_materials[2].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
47         //m_materials[2].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
48
49         for(u32 i=0; i<SKY_STAR_COUNT; i++){
50                 m_stars[i] = v3f(
51                         myrand_range(-10000,10000),
52                         myrand_range(-10000,10000),
53                         myrand_range(-10000,10000)
54                 );
55                 m_stars[i].normalize();
56         }
57 }
58
59 void Sky::OnRegisterSceneNode()
60 {
61         if (IsVisible)
62                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SKY_BOX);
63
64         scene::ISceneNode::OnRegisterSceneNode();
65 }
66
67 const core::aabbox3d<f32>& Sky::getBoundingBox() const
68 {
69         return Box;
70 }
71
72 //! renders the node.
73 void Sky::render()
74 {
75         video::IVideoDriver* driver = SceneManager->getVideoDriver();
76         scene::ICameraSceneNode* camera = SceneManager->getActiveCamera();
77
78         if (!camera || !driver)
79                 return;
80         
81         ScopeProfiler sp(g_profiler, "Sky::render()", SPT_AVG);
82
83         // draw perspective skybox
84
85         core::matrix4 translate(AbsoluteTransformation);
86         translate.setTranslation(camera->getAbsolutePosition());
87
88         // Draw the sky box between the near and far clip plane
89         const f32 viewDistance = (camera->getNearValue() + camera->getFarValue()) * 0.5f;
90         core::matrix4 scale;
91         scale.setScale(core::vector3df(viewDistance, viewDistance, viewDistance));
92
93         driver->setTransform(video::ETS_WORLD, translate * scale);
94         
95         if(m_sunlight_seen)
96         {
97                 float sunsize = 0.07;
98                 video::SColorf suncolor_f(1, 1, 0, 1);
99                 suncolor_f.r = 1;
100                 suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.7+m_time_brightness*(0.5)));
101                 suncolor_f.b = MYMAX(0.0, m_brightness*0.95);
102                 video::SColorf suncolor2_f(1, 1, 1, 1);
103                 suncolor_f.r = 1;
104                 suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.85+m_time_brightness*(0.5)));
105                 suncolor_f.b = MYMAX(0.0, m_brightness);
106
107                 float moonsize = 0.04;
108                 video::SColorf mooncolor_f(0.50, 0.57, 0.65, 1);
109                 video::SColorf mooncolor2_f(0.85, 0.875, 0.9, 1);
110                 
111                 float nightlength = 0.41;
112                 float wn = nightlength / 2;
113                 float wicked_time_of_day = 0;
114                 if(m_time_of_day > wn && m_time_of_day < 1.0 - wn)
115                         wicked_time_of_day = (m_time_of_day - wn)/(1.0-wn*2)*0.5 + 0.25;
116                 else if(m_time_of_day < 0.5)
117                         wicked_time_of_day = m_time_of_day / wn * 0.25;
118                 else
119                         wicked_time_of_day = 1.0 - ((1.0-m_time_of_day) / wn * 0.25);
120                 /*std::cerr<<"time_of_day="<<m_time_of_day<<" -> "
121                                 <<"wicked_time_of_day="<<wicked_time_of_day<<std::endl;*/
122
123                 video::SColor suncolor = suncolor_f.toSColor();
124                 video::SColor suncolor2 = suncolor2_f.toSColor();
125                 video::SColor mooncolor = mooncolor_f.toSColor();
126                 video::SColor mooncolor2 = mooncolor2_f.toSColor();
127
128                 const f32 t = 1.0f;
129                 const f32 o = 0.0f;
130                 static const u16 indices[4] = {0,1,2,3};
131                 video::S3DVertex vertices[4];
132
133                 driver->setMaterial(m_materials[2]);
134                 {
135                         float mid1 = 0.25;
136                         float mid = (wicked_time_of_day < 0.5 ? mid1 : (1.0 - mid1));
137                         float a_ = 1.0 - fabs(wicked_time_of_day - mid) * 35.0;
138                         float a = easeCurve(MYMAX(0, MYMIN(1, a_)));
139                         //std::cerr<<"a_="<<a_<<" a="<<a<<std::endl;
140                         video::SColor c(255,255,255,255);
141                         float y = -(1.0 - a) * 0.2;
142                         vertices[0] = video::S3DVertex(-1,-0.05+y,-1, 0,0,1, c, t, t);
143                         vertices[1] = video::S3DVertex( 1,-0.05+y,-1, 0,0,1, c, o, t);
144                         vertices[2] = video::S3DVertex( 1, 0.2+y,-1, 0,0,1, c, o, o);
145                         vertices[3] = video::S3DVertex(-1, 0.2+y,-1, 0,0,1, c, t, o);
146                         for(u32 i=0; i<4; i++){
147                                 if(wicked_time_of_day < 0.5)
148                                         // Switch from -Z (south) to +X (east)
149                                         vertices[i].Pos.rotateXZBy(90);
150                                 else
151                                         // Switch from -Z (south) to -X (west)
152                                         vertices[i].Pos.rotateXZBy(-90);
153                         }
154                         driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
155                 }
156
157                 driver->setMaterial(m_materials[1]);
158                 
159                 // Draw sun
160                 if(wicked_time_of_day > 0.15 && wicked_time_of_day < 0.85)
161                 {
162                         float d = sunsize * 1.7;
163                         video::SColor c = suncolor;
164                         c.setAlpha(0.05*255);
165                         vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
166                         vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
167                         vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
168                         vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
169                         for(u32 i=0; i<4; i++){
170                                 // Switch from -Z (south) to +X (east)
171                                 vertices[i].Pos.rotateXZBy(90);
172                                 vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
173                         }
174                         driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
175
176                         d = sunsize * 1.2;
177                         c = suncolor;
178                         c.setAlpha(0.15*255);
179                         vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
180                         vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
181                         vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
182                         vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
183                         for(u32 i=0; i<4; i++){
184                                 // Switch from -Z (south) to +X (east)
185                                 vertices[i].Pos.rotateXZBy(90);
186                                 vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
187                         }
188                         driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
189
190                         d = sunsize;
191                         vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, suncolor, t, t);
192                         vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, suncolor, o, t);
193                         vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, suncolor, o, o);
194                         vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, suncolor, t, o);
195                         for(u32 i=0; i<4; i++){
196                                 // Switch from -Z (south) to +X (east)
197                                 vertices[i].Pos.rotateXZBy(90);
198                                 vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
199                         }
200                         driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
201
202                         d = sunsize * 0.7;
203                         vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, suncolor2, t, t);
204                         vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, suncolor2, o, t);
205                         vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, suncolor2, o, o);
206                         vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, suncolor2, t, o);
207                         for(u32 i=0; i<4; i++){
208                                 // Switch from -Z (south) to +X (east)
209                                 vertices[i].Pos.rotateXZBy(90);
210                                 vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
211                         }
212                         driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
213                 }
214                 // Draw moon
215                 if(wicked_time_of_day < 0.3 || wicked_time_of_day > 0.7)
216                 {
217                         float d = moonsize * 1.9;
218                         video::SColor c = mooncolor;
219                         c.setAlpha(0.05*255);
220                         vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
221                         vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
222                         vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
223                         vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
224                         for(u32 i=0; i<4; i++){
225                                 // Switch from -Z (south) to -X (west)
226                                 vertices[i].Pos.rotateXZBy(-90);
227                                 vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
228                         }
229                         driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
230                         
231                         d = moonsize * 1.3;
232                         c = mooncolor;
233                         c.setAlpha(0.15*255);
234                         vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
235                         vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
236                         vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
237                         vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
238                         for(u32 i=0; i<4; i++){
239                                 // Switch from -Z (south) to -X (west)
240                                 vertices[i].Pos.rotateXZBy(-90);
241                                 vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
242                         }
243                         driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
244                         
245                         d = moonsize;
246                         vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, mooncolor, t, t);
247                         vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, mooncolor, o, t);
248                         vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, mooncolor, o, o);
249                         vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, mooncolor, t, o);
250                         for(u32 i=0; i<4; i++){
251                                 // Switch from -Z (south) to -X (west)
252                                 vertices[i].Pos.rotateXZBy(-90);
253                                 vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
254                         }
255                         driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
256                         
257                         float d2 = moonsize * 0.6;
258                         vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, mooncolor2, t, t);
259                         vertices[1] = video::S3DVertex( d2,-d,-1, 0,0,1, mooncolor2, o, t);
260                         vertices[2] = video::S3DVertex( d2, d2,-1, 0,0,1, mooncolor2, o, o);
261                         vertices[3] = video::S3DVertex(-d, d2,-1, 0,0,1, mooncolor2, t, o);
262                         for(u32 i=0; i<4; i++){
263                                 // Switch from -Z (south) to -X (west)
264                                 vertices[i].Pos.rotateXZBy(-90);
265                                 vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
266                         }
267                         driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
268                 }
269                 // Stars
270                 do{
271                         float starbrightness = MYMAX(0, MYMIN(1,
272                                         (0.285 - fabs(wicked_time_of_day < 0.5 ?
273                                         wicked_time_of_day : (1.0 - wicked_time_of_day))) * 10));
274                         float f = starbrightness;
275                         video::SColor starcolor(255, f*120,f*120,f*120);
276                         if(starcolor.getBlue() < m_skycolor.getBlue())
277                                 break;
278                         u16 indices[SKY_STAR_COUNT*4];
279                         video::S3DVertex vertices[SKY_STAR_COUNT*4];
280                         for(u32 i=0; i<SKY_STAR_COUNT; i++){
281                                 indices[i*4+0] = i*4+0;
282                                 indices[i*4+1] = i*4+1;
283                                 indices[i*4+2] = i*4+2;
284                                 indices[i*4+3] = i*4+3;
285                                 v3f p = m_stars[i];
286                                 core::CMatrix4<f32> a;
287                                 float d = 0.005;
288                                 a.buildRotateFromTo(v3f(0,1,0), v3f(d,1,0));
289                                 v3f p1 = p;
290                                 a.rotateVect(p1);
291                                 a.buildRotateFromTo(v3f(0,1,0), v3f(d,1+d/2,d));
292                                 v3f p2 = p;
293                                 a.rotateVect(p2);
294                                 a.buildRotateFromTo(v3f(0,1,0), v3f(0,1,d));
295                                 v3f p3 = p;
296                                 a.rotateVect(p3);
297                                 p.rotateXYBy(wicked_time_of_day * 360 - 90);
298                                 p1.rotateXYBy(wicked_time_of_day * 360 - 90);
299                                 p2.rotateXYBy(wicked_time_of_day * 360 - 90);
300                                 p3.rotateXYBy(wicked_time_of_day * 360 - 90);
301                                 vertices[i*4+0].Pos = p;
302                                 vertices[i*4+0].Color = starcolor;
303                                 vertices[i*4+1].Pos = p1;
304                                 vertices[i*4+1].Color = starcolor;
305                                 vertices[i*4+2].Pos = p2;
306                                 vertices[i*4+2].Color = starcolor;
307                                 vertices[i*4+3].Pos = p3;
308                                 vertices[i*4+3].Color = starcolor;
309                         }
310                         driver->drawVertexPrimitiveList(vertices, SKY_STAR_COUNT*4,
311                                         indices, SKY_STAR_COUNT, video::EVT_STANDARD,
312                                         scene::EPT_QUADS, video::EIT_16BIT);
313                 }while(0);
314                 
315                 for(u32 j=0; j<2; j++)
316                 {
317                         vertices[0] = video::S3DVertex(-1,-1.0,-1, 0,0,1, m_skycolor, t, t);
318                         vertices[1] = video::S3DVertex( 1,-1.0,-1, 0,0,1, m_skycolor, o, t);
319                         vertices[2] = video::S3DVertex( 1,-0.02,-1, 0,0,1, m_skycolor, o, o);
320                         vertices[3] = video::S3DVertex(-1,-0.02,-1, 0,0,1, m_skycolor, t, o);
321                         for(u32 i=0; i<4; i++){
322                                 //if(wicked_time_of_day < 0.5)
323                                 if(j==0)
324                                         // Switch from -Z (south) to +X (east)
325                                         vertices[i].Pos.rotateXZBy(90);
326                                 else
327                                         // Switch from -Z (south) to -X (west)
328                                         vertices[i].Pos.rotateXZBy(-90);
329                         }
330                         driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
331                 }
332         }
333 }
334
335 void Sky::update(float time_of_day, float time_brightness,
336                 float direct_brightness, bool sunlight_seen)
337 {
338         // Stabilize initial brightness and color values by flooding updates
339         if(m_first_update){
340                 /*dstream<<"First update with time_of_day="<<time_of_day
341                                 <<" time_brightness="<<time_brightness
342                                 <<" direct_brightness="<<direct_brightness
343                                 <<" sunlight_seen="<<sunlight_seen<<std::endl;*/
344                 m_first_update = false;
345                 for(u32 i=0; i<100; i++){
346                         update(time_of_day, time_brightness, direct_brightness,
347                                         sunlight_seen);
348                 }
349                 return;
350         }
351
352         m_time_of_day = time_of_day;
353         m_time_brightness = time_brightness;
354         m_sunlight_seen = sunlight_seen;
355         
356         bool is_dawn = (time_brightness >= 0.20 && time_brightness < 0.50);
357
358         video::SColorf bgcolor_bright_normal_f(170./255,200./255,230./255, 1.0);
359         video::SColorf bgcolor_bright_indoor_f(100./255,100./255,100./255, 1.0);
360         //video::SColorf bgcolor_bright_dawn_f(0.666,200./255*0.7,230./255*0.5,1.0);
361         //video::SColorf bgcolor_bright_dawn_f(0.666,0.549,0.220,1.0);
362         //video::SColorf bgcolor_bright_dawn_f(0.666*1.2,0.549*1.0,0.220*1.0, 1.0);
363         video::SColorf bgcolor_bright_dawn_f(0.666*1.2,0.549*1.0,0.220*1.2,1.0);
364
365         video::SColorf skycolor_bright_normal_f =
366                         video::SColor(255, 140, 186, 250);
367         video::SColorf skycolor_bright_dawn_f =
368                         video::SColor(255, 180, 186, 250);
369         
370         video::SColorf cloudcolor_bright_normal_f =
371                         video::SColor(255, 240,240,255);
372         //video::SColorf cloudcolor_bright_dawn_f(1.0, 0.591, 0.4);
373         //video::SColorf cloudcolor_bright_dawn_f(1.0, 0.65, 0.44);
374         video::SColorf cloudcolor_bright_dawn_f(1.0, 0.7, 0.5);
375
376         if(sunlight_seen){
377                 //m_brightness = m_brightness * 0.95 + direct_brightness * 0.05;
378                 m_brightness = m_brightness * 0.95 + time_brightness * 0.05;
379         }
380         else{
381                 if(direct_brightness < m_brightness)
382                         m_brightness = m_brightness * 0.95 + direct_brightness * 0.05;
383                 else
384                         m_brightness = m_brightness * 0.98 + direct_brightness * 0.02;
385         }
386         
387         m_clouds_visible = true;
388         float color_change_fraction = 0.98;
389         if(sunlight_seen){
390                 if(is_dawn){
391                         m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
392                                         bgcolor_bright_dawn_f, color_change_fraction);
393                         m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
394                                         skycolor_bright_dawn_f, color_change_fraction);
395                         m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
396                                         cloudcolor_bright_dawn_f, color_change_fraction);
397                 } else {
398                         m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
399                                         bgcolor_bright_normal_f, color_change_fraction);
400                         m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
401                                         skycolor_bright_normal_f, color_change_fraction);
402                         m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
403                                         cloudcolor_bright_normal_f, color_change_fraction);
404                 }
405         } else {
406                 m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
407                                 bgcolor_bright_indoor_f, color_change_fraction);
408                 m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
409                                 cloudcolor_bright_normal_f, color_change_fraction);
410                 m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
411                                 bgcolor_bright_indoor_f, color_change_fraction);
412                 m_clouds_visible = false;
413         }
414         video::SColor bgcolor_bright = m_bgcolor_bright_f.toSColor();
415         m_bgcolor = video::SColor(
416                         255,
417                         bgcolor_bright.getRed() * m_brightness,
418                         bgcolor_bright.getGreen() * m_brightness,
419                         bgcolor_bright.getBlue() * m_brightness);
420         
421         video::SColor skycolor_bright = m_skycolor_bright_f.toSColor();
422         m_skycolor = video::SColor(
423                         255,
424                         skycolor_bright.getRed() * m_brightness,
425                         skycolor_bright.getGreen() * m_brightness,
426                         skycolor_bright.getBlue() * m_brightness);
427         
428         float cloud_direct_brightness = 0;
429         if(sunlight_seen){
430                 cloud_direct_brightness = time_brightness;
431                 if(time_brightness >= 0.2 && time_brightness < 0.7)
432                                 cloud_direct_brightness *= 1.3;
433         } else {
434                 cloud_direct_brightness = direct_brightness;
435         }
436         m_cloud_brightness = m_cloud_brightness * 0.95 +
437                         cloud_direct_brightness * (1.0 - 0.95);
438         m_cloudcolor_f = video::SColorf(
439                         m_cloudcolor_bright_f.getRed() * m_cloud_brightness,
440                         m_cloudcolor_bright_f.getGreen() * m_cloud_brightness,
441                         m_cloudcolor_bright_f.getBlue() * m_cloud_brightness,
442                         1.0);
443
444 }
445
446