minetest/src/sky.cpp
Lars Hofhansl 739ef175aa Sky: Draw bottom of the sky box in 'cloudy fog color'
To be identical to the lower half of the skybox sides.
Now needed as the skybox base is often seen due to increasingly vertical
mapgens.
2016-11-08 15:20:01 +00:00

694 lines
25 KiB
C++

#include "sky.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
#include "S3DVertex.h"
#include "client/tile.h"
#include "noise.h" // easeCurve
#include "profiler.h"
#include "util/numeric.h"
#include <cmath>
#include "settings.h"
#include "camera.h" // CameraModes
Sky::Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id,
ITextureSource *tsrc):
scene::ISceneNode(parent, mgr, id),
m_visible(true),
m_fallback_bg_color(255, 255, 255, 255),
m_first_update(true),
m_brightness(0.5),
m_cloud_brightness(0.5),
m_bgcolor_bright_f(1, 1, 1, 1),
m_skycolor_bright_f(1, 1, 1, 1),
m_cloudcolor_bright_f(1, 1, 1, 1)
{
setAutomaticCulling(scene::EAC_OFF);
m_box.MaxEdge.set(0, 0, 0);
m_box.MinEdge.set(0, 0, 0);
// Create material
video::SMaterial mat;
mat.Lighting = false;
mat.ZBuffer = video::ECFN_NEVER;
mat.ZWriteEnable = false;
mat.AntiAliasing = 0;
mat.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
mat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
mat.BackfaceCulling = false;
m_materials[0] = mat;
m_materials[1] = mat;
//m_materials[1].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
m_materials[2] = mat;
m_materials[2].setTexture(0, tsrc->getTextureForMesh("sunrisebg.png"));
m_materials[2].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
//m_materials[2].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
m_sun_texture = tsrc->isKnownSourceImage("sun.png") ?
tsrc->getTextureForMesh("sun.png") : NULL;
m_moon_texture = tsrc->isKnownSourceImage("moon.png") ?
tsrc->getTextureForMesh("moon.png") : NULL;
m_sun_tonemap = tsrc->isKnownSourceImage("sun_tonemap.png") ?
tsrc->getTexture("sun_tonemap.png") : NULL;
m_moon_tonemap = tsrc->isKnownSourceImage("moon_tonemap.png") ?
tsrc->getTexture("moon_tonemap.png") : NULL;
if (m_sun_texture) {
m_materials[3] = mat;
m_materials[3].setTexture(0, m_sun_texture);
m_materials[3].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
if (m_sun_tonemap)
m_materials[3].Lighting = true;
}
if (m_moon_texture) {
m_materials[4] = mat;
m_materials[4].setTexture(0, m_moon_texture);
m_materials[4].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
if (m_moon_tonemap)
m_materials[4].Lighting = true;
}
for (u32 i = 0; i < SKY_STAR_COUNT; i++) {
m_stars[i] = v3f(
myrand_range(-10000, 10000),
myrand_range(-10000, 10000),
myrand_range(-10000, 10000)
);
m_stars[i].normalize();
}
m_directional_colored_fog = g_settings->getBool("directional_colored_fog");
}
void Sky::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this, scene::ESNRP_SKY_BOX);
scene::ISceneNode::OnRegisterSceneNode();
}
void Sky::render()
{
if (!m_visible)
return;
video::IVideoDriver* driver = SceneManager->getVideoDriver();
scene::ICameraSceneNode* camera = SceneManager->getActiveCamera();
if (!camera || !driver)
return;
ScopeProfiler sp(g_profiler, "Sky::render()", SPT_AVG);
// Draw perspective skybox
core::matrix4 translate(AbsoluteTransformation);
translate.setTranslation(camera->getAbsolutePosition());
// Draw the sky box between the near and far clip plane
const f32 viewDistance = (camera->getNearValue() + camera->getFarValue()) * 0.5f;
core::matrix4 scale;
scale.setScale(core::vector3df(viewDistance, viewDistance, viewDistance));
driver->setTransform(video::ETS_WORLD, translate * scale);
if (m_sunlight_seen) {
float sunsize = 0.07;
video::SColorf suncolor_f(1, 1, 0, 1);
suncolor_f.r = 1;
suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.7 + m_time_brightness * 0.5));
suncolor_f.b = MYMAX(0.0, m_brightness * 0.95);
video::SColorf suncolor2_f(1, 1, 1, 1);
suncolor_f.r = 1;
suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.85 + m_time_brightness * 0.5));
suncolor_f.b = MYMAX(0.0, m_brightness);
float moonsize = 0.04;
video::SColorf mooncolor_f(0.50, 0.57, 0.65, 1);
video::SColorf mooncolor2_f(0.85, 0.875, 0.9, 1);
float nightlength = 0.415;
float wn = nightlength / 2;
float wicked_time_of_day = 0;
if (m_time_of_day > wn && m_time_of_day < 1.0 - wn)
wicked_time_of_day = (m_time_of_day - wn) / (1.0 - wn * 2) * 0.5 + 0.25;
else if (m_time_of_day < 0.5)
wicked_time_of_day = m_time_of_day / wn * 0.25;
else
wicked_time_of_day = 1.0 - ((1.0 - m_time_of_day) / wn * 0.25);
/*std::cerr<<"time_of_day="<<m_time_of_day<<" -> "
<<"wicked_time_of_day="<<wicked_time_of_day<<std::endl;*/
video::SColor suncolor = suncolor_f.toSColor();
video::SColor suncolor2 = suncolor2_f.toSColor();
video::SColor mooncolor = mooncolor_f.toSColor();
video::SColor mooncolor2 = mooncolor2_f.toSColor();
// Calculate offset normalized to the X dimension of a 512x1 px tonemap
float offset = (1.0 - fabs(sin((m_time_of_day - 0.5) * irr::core::PI))) * 511;
if (m_sun_tonemap) {
u8 * texels = (u8 *)m_sun_tonemap->lock();
video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4);
video::SColor texel_color (255, texel->getRed(),
texel->getGreen(), texel->getBlue());
m_sun_tonemap->unlock();
m_materials[3].EmissiveColor = texel_color;
}
if (m_moon_tonemap) {
u8 * texels = (u8 *)m_moon_tonemap->lock();
video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4);
video::SColor texel_color (255, texel->getRed(),
texel->getGreen(), texel->getBlue());
m_moon_tonemap->unlock();
m_materials[4].EmissiveColor = texel_color;
}
const f32 t = 1.0f;
const f32 o = 0.0f;
static const u16 indices[4] = {0, 1, 2, 3};
video::S3DVertex vertices[4];
driver->setMaterial(m_materials[1]);
video::SColor cloudyfogcolor = m_bgcolor;
// Draw far cloudy fog thing blended with skycolor
for (u32 j = 0; j < 4; j++) {
video::SColor c = cloudyfogcolor.getInterpolated(m_skycolor, 0.45);
vertices[0] = video::S3DVertex(-1, 0.08, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( 1, 0.08, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( 1, 0.12, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-1, 0.12, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
if (j == 0)
// Don't switch
{}
else if (j == 1)
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
else if (j == 2)
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
else
// Switch from -Z (south) to +Z (north)
vertices[i].Pos.rotateXZBy(-180);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
// Draw far cloudy fog thing
for (u32 j = 0; j < 4; j++) {
video::SColor c = cloudyfogcolor;
vertices[0] = video::S3DVertex(-1, -1.0, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( 1, -1.0, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( 1, 0.08, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-1, 0.08, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
if (j == 0)
// Don't switch
{}
else if (j == 1)
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
else if (j == 2)
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
else
// Switch from -Z (south) to +Z (north)
vertices[i].Pos.rotateXZBy(-180);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
// Draw bottom far cloudy fog thing
video::SColor c = cloudyfogcolor;
vertices[0] = video::S3DVertex(-1, -1.0, -1, 0, 1, 0, c, t, t);
vertices[1] = video::S3DVertex( 1, -1.0, -1, 0, 1, 0, c, o, t);
vertices[2] = video::S3DVertex( 1, -1.0, 1, 0, 1, 0, c, o, o);
vertices[3] = video::S3DVertex(-1, -1.0, 1, 0, 1, 0, c, t, o);
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
driver->setMaterial(m_materials[2]);
// Draw sunrise/sunset horizon glow texture (textures/base/pack/sunrisebg.png)
{
float mid1 = 0.25;
float mid = wicked_time_of_day < 0.5 ? mid1 : (1.0 - mid1);
float a_ = 1.0 - fabs(wicked_time_of_day - mid) * 35.0;
float a = easeCurve(MYMAX(0, MYMIN(1, a_)));
//std::cerr<<"a_="<<a_<<" a="<<a<<std::endl;
video::SColor c(255, 255, 255, 255);
float y = -(1.0 - a) * 0.22;
vertices[0] = video::S3DVertex(-1, -0.05 + y, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( 1, -0.05 + y, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( 1, 0.2 + y, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-1, 0.2 + y, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
if (wicked_time_of_day < 0.5)
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
else
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
// Draw sun
if (wicked_time_of_day > 0.15 && wicked_time_of_day < 0.85) {
if (!m_sun_texture) {
driver->setMaterial(m_materials[1]);
float d = sunsize * 1.7;
video::SColor c = suncolor;
c.setAlpha(0.05 * 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
d = sunsize * 1.2;
c = suncolor;
c.setAlpha(0.15 * 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
d = sunsize;
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, suncolor, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, suncolor, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, suncolor, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, suncolor, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
d = sunsize * 0.7;
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, suncolor2, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, suncolor2, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, suncolor2, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, suncolor2, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
} else {
driver->setMaterial(m_materials[3]);
float d = sunsize * 1.7;
video::SColor c;
if (m_sun_tonemap)
c = video::SColor (0, 0, 0, 0);
else
c = video::SColor (255, 255, 255, 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for(u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
}
// Draw moon
if (wicked_time_of_day < 0.3 || wicked_time_of_day > 0.7) {
if (!m_moon_texture) {
driver->setMaterial(m_materials[1]);
float d = moonsize * 1.9;
video::SColor c = mooncolor;
c.setAlpha(0.05 * 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
d = moonsize * 1.3;
c = mooncolor;
c.setAlpha(0.15 * 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
d = moonsize;
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, mooncolor, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, mooncolor, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, mooncolor, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, mooncolor, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
float d2 = moonsize * 0.6;
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, mooncolor2, t, t);
vertices[1] = video::S3DVertex( d2,-d, -1, 0, 0, 1, mooncolor2, o, t);
vertices[2] = video::S3DVertex( d2, d2, -1, 0, 0, 1, mooncolor2, o, o);
vertices[3] = video::S3DVertex(-d, d2, -1, 0, 0, 1, mooncolor2, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
} else {
driver->setMaterial(m_materials[4]);
float d = moonsize * 1.9;
video::SColor c;
if (m_moon_tonemap)
c = video::SColor (0, 0, 0, 0);
else
c = video::SColor (255, 255, 255, 255);
vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
}
// Draw stars
driver->setMaterial(m_materials[1]);
do {
float starbrightness = MYMAX(0, MYMIN(1,
(0.285 - fabs(wicked_time_of_day < 0.5 ?
wicked_time_of_day : (1.0 - wicked_time_of_day))) * 10));
float f = starbrightness;
float d = 0.007;
video::SColor starcolor(255, f * 90, f * 90, f * 90);
if (starcolor.getBlue() < m_skycolor.getBlue())
break;
u16 indices[SKY_STAR_COUNT * 4];
video::S3DVertex vertices[SKY_STAR_COUNT * 4];
for (u32 i = 0; i < SKY_STAR_COUNT; i++) {
indices[i * 4 + 0] = i * 4 + 0;
indices[i * 4 + 1] = i * 4 + 1;
indices[i * 4 + 2] = i * 4 + 2;
indices[i * 4 + 3] = i * 4 + 3;
v3f p = m_stars[i];
core::CMatrix4<f32> a;
a.buildRotateFromTo(v3f(0, 1, 0), v3f(d, 1 + d / 2, 0));
v3f p1 = p;
a.rotateVect(p1);
a.buildRotateFromTo(v3f(0, 1, 0), v3f(d, 1, d));
v3f p2 = p;
a.rotateVect(p2);
a.buildRotateFromTo(v3f(0, 1, 0), v3f(0, 1 - d / 2, d));
v3f p3 = p;
a.rotateVect(p3);
p.rotateXYBy(wicked_time_of_day * 360 - 90);
p1.rotateXYBy(wicked_time_of_day * 360 - 90);
p2.rotateXYBy(wicked_time_of_day * 360 - 90);
p3.rotateXYBy(wicked_time_of_day * 360 - 90);
vertices[i * 4 + 0].Pos = p;
vertices[i * 4 + 0].Color = starcolor;
vertices[i * 4 + 1].Pos = p1;
vertices[i * 4 + 1].Color = starcolor;
vertices[i * 4 + 2].Pos = p2;
vertices[i * 4 + 2].Color = starcolor;
vertices[i * 4 + 3].Pos = p3;
vertices[i * 4 + 3].Color = starcolor;
}
driver->drawVertexPrimitiveList(vertices, SKY_STAR_COUNT * 4,
indices, SKY_STAR_COUNT, video::EVT_STANDARD,
scene::EPT_QUADS, video::EIT_16BIT);
} while(0);
// Draw far cloudy fog thing below east and west horizons
for (u32 j = 0; j < 2; j++) {
video::SColor c = cloudyfogcolor;
vertices[0] = video::S3DVertex(-1, -1.0, -1, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( 1, -1.0, -1, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( 1, -0.02, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-1, -0.02, -1, 0, 0, 1, c, t, o);
for (u32 i = 0; i < 4; i++) {
//if (wicked_time_of_day < 0.5)
if (j == 0)
// Switch from -Z (south) to +X (east)
vertices[i].Pos.rotateXZBy(90);
else
// Switch from -Z (south) to -X (west)
vertices[i].Pos.rotateXZBy(-90);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
}
}
void Sky::update(float time_of_day, float time_brightness,
float direct_brightness, bool sunlight_seen,
CameraMode cam_mode, float yaw, float pitch)
{
// Stabilize initial brightness and color values by flooding updates
if (m_first_update) {
/*dstream<<"First update with time_of_day="<<time_of_day
<<" time_brightness="<<time_brightness
<<" direct_brightness="<<direct_brightness
<<" sunlight_seen="<<sunlight_seen<<std::endl;*/
m_first_update = false;
for (u32 i = 0; i < 100; i++) {
update(time_of_day, time_brightness, direct_brightness,
sunlight_seen, cam_mode, yaw, pitch);
}
return;
}
m_time_of_day = time_of_day;
m_time_brightness = time_brightness;
m_sunlight_seen = sunlight_seen;
bool is_dawn = (time_brightness >= 0.20 && time_brightness < 0.35);
/*
Development colours
video::SColorf bgcolor_bright_normal_f(170. / 255, 200. / 255, 230. / 255, 1.0);
video::SColorf bgcolor_bright_dawn_f(0.666, 200. / 255 * 0.7, 230. / 255 * 0.5, 1.0);
video::SColorf bgcolor_bright_dawn_f(0.666, 0.549, 0.220, 1.0);
video::SColorf bgcolor_bright_dawn_f(0.666 * 1.2, 0.549 * 1.0, 0.220 * 1.0, 1.0);
video::SColorf bgcolor_bright_dawn_f(0.666 * 1.2, 0.549 * 1.0, 0.220 * 1.2, 1.0);
video::SColorf cloudcolor_bright_dawn_f(1.0, 0.591, 0.4);
video::SColorf cloudcolor_bright_dawn_f(1.0, 0.65, 0.44);
video::SColorf cloudcolor_bright_dawn_f(1.0, 0.7, 0.5);
*/
video::SColorf bgcolor_bright_normal_f = video::SColor(255, 155, 193, 240);
video::SColorf bgcolor_bright_indoor_f = video::SColor(255, 100, 100, 100);
video::SColorf bgcolor_bright_dawn_f = video::SColor(255, 186, 193, 240);
video::SColorf bgcolor_bright_night_f = video::SColor(255, 64, 144, 255);
video::SColorf skycolor_bright_normal_f = video::SColor(255, 140, 186, 250);
video::SColorf skycolor_bright_dawn_f = video::SColor(255, 180, 186, 250);
video::SColorf skycolor_bright_night_f = video::SColor(255, 0, 107, 255);
video::SColorf cloudcolor_bright_normal_f = video::SColor(255, 240, 240, 255);
video::SColorf cloudcolor_bright_dawn_f = video::SColor(255, 255, 223, 191);
float cloud_color_change_fraction = 0.95;
if (sunlight_seen) {
if (fabs(time_brightness - m_brightness) < 0.2) {
m_brightness = m_brightness * 0.95 + time_brightness * 0.05;
} else {
m_brightness = m_brightness * 0.80 + time_brightness * 0.20;
cloud_color_change_fraction = 0.0;
}
} else {
if (direct_brightness < m_brightness)
m_brightness = m_brightness * 0.95 + direct_brightness * 0.05;
else
m_brightness = m_brightness * 0.98 + direct_brightness * 0.02;
}
m_clouds_visible = true;
float color_change_fraction = 0.98;
if (sunlight_seen) {
if (is_dawn) { // Dawn
m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
bgcolor_bright_dawn_f, color_change_fraction);
m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
skycolor_bright_dawn_f, color_change_fraction);
m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
cloudcolor_bright_dawn_f, color_change_fraction);
} else {
if (time_brightness < 0.07) { // Night
m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
bgcolor_bright_night_f, color_change_fraction);
m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
skycolor_bright_night_f, color_change_fraction);
} else { // Day
m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
bgcolor_bright_normal_f, color_change_fraction);
m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
skycolor_bright_normal_f, color_change_fraction);
}
m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
cloudcolor_bright_normal_f, color_change_fraction);
}
} else {
m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
bgcolor_bright_indoor_f, color_change_fraction);
m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
bgcolor_bright_indoor_f, color_change_fraction);
m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
cloudcolor_bright_normal_f, color_change_fraction);
m_clouds_visible = false;
}
video::SColor bgcolor_bright = m_bgcolor_bright_f.toSColor();
m_bgcolor = video::SColor(
255,
bgcolor_bright.getRed() * m_brightness,
bgcolor_bright.getGreen() * m_brightness,
bgcolor_bright.getBlue() * m_brightness
);
video::SColor skycolor_bright = m_skycolor_bright_f.toSColor();
m_skycolor = video::SColor(
255,
skycolor_bright.getRed() * m_brightness,
skycolor_bright.getGreen() * m_brightness,
skycolor_bright.getBlue() * m_brightness
);
// Horizon coloring based on sun and moon direction during sunset and sunrise
video::SColor pointcolor = video::SColor(255, 255, 255, m_bgcolor.getAlpha());
if (m_directional_colored_fog) {
if (m_horizon_blend() != 0) {
// Calculate hemisphere value from yaw, (inverted in third person front view)
s8 dir_factor = 1;
if (cam_mode > CAMERA_MODE_THIRD)
dir_factor = -1;
f32 pointcolor_blend = wrapDegrees_0_360(yaw * dir_factor + 90);
if (pointcolor_blend > 180)
pointcolor_blend = 360 - pointcolor_blend;
pointcolor_blend /= 180;
// Bound view angle to determine where transition starts and ends
pointcolor_blend = rangelim(1 - pointcolor_blend * 1.375, 0, 1 / 1.375) *
1.375;
// Combine the colors when looking up or down, otherwise turning looks weird
pointcolor_blend += (0.5 - pointcolor_blend) *
(1 - MYMIN((90 - std::fabs(pitch)) / 90 * 1.5, 1));
// Invert direction to match where the sun and moon are rising
if (m_time_of_day > 0.5)
pointcolor_blend = 1 - pointcolor_blend;
// Horizon colors of sun and moon
f32 pointcolor_light = rangelim(m_time_brightness * 3, 0.2, 1);
video::SColorf pointcolor_sun_f(1, 1, 1, 1);
if (m_sun_tonemap) {
pointcolor_sun_f.r = pointcolor_light *
(float)m_materials[3].EmissiveColor.getRed() / 255;
pointcolor_sun_f.b = pointcolor_light *
(float)m_materials[3].EmissiveColor.getBlue() / 255;
pointcolor_sun_f.g = pointcolor_light *
(float)m_materials[3].EmissiveColor.getGreen() / 255;
} else {
pointcolor_sun_f.r = pointcolor_light * 1;
pointcolor_sun_f.b = pointcolor_light *
(0.25 + (rangelim(m_time_brightness, 0.25, 0.75) - 0.25) * 2 * 0.75);
pointcolor_sun_f.g = pointcolor_light * (pointcolor_sun_f.b * 0.375 +
(rangelim(m_time_brightness, 0.05, 0.15) - 0.05) * 10 * 0.625);
}
video::SColorf pointcolor_moon_f(0.5 * pointcolor_light,
0.6 * pointcolor_light, 0.8 * pointcolor_light, 1);
if (m_moon_tonemap) {
pointcolor_moon_f.r = pointcolor_light *
(float)m_materials[4].EmissiveColor.getRed() / 255;
pointcolor_moon_f.b = pointcolor_light *
(float)m_materials[4].EmissiveColor.getBlue() / 255;
pointcolor_moon_f.g = pointcolor_light *
(float)m_materials[4].EmissiveColor.getGreen() / 255;
}
video::SColor pointcolor_sun = pointcolor_sun_f.toSColor();
video::SColor pointcolor_moon = pointcolor_moon_f.toSColor();
// Calculate the blend color
pointcolor = m_mix_scolor(pointcolor_moon, pointcolor_sun, pointcolor_blend);
}
m_bgcolor = m_mix_scolor(m_bgcolor, pointcolor, m_horizon_blend() * 0.5);
m_skycolor = m_mix_scolor(m_skycolor, pointcolor, m_horizon_blend() * 0.25);
}
float cloud_direct_brightness = 0;
if (sunlight_seen) {
if (!m_directional_colored_fog) {
cloud_direct_brightness = time_brightness;
if (time_brightness >= 0.2 && time_brightness < 0.7)
cloud_direct_brightness *= 1.3;
} else {
cloud_direct_brightness = MYMIN(m_horizon_blend() * 0.15 +
m_time_brightness, 1);
}
} else {
cloud_direct_brightness = direct_brightness;
}
m_cloud_brightness = m_cloud_brightness * cloud_color_change_fraction +
cloud_direct_brightness * (1.0 - cloud_color_change_fraction);
m_cloudcolor_f = video::SColorf(
m_cloudcolor_bright_f.r * m_cloud_brightness,
m_cloudcolor_bright_f.g * m_cloud_brightness,
m_cloudcolor_bright_f.b * m_cloud_brightness,
1.0
);
if (m_directional_colored_fog) {
m_cloudcolor_f = m_mix_scolorf(m_cloudcolor_f,
video::SColorf(pointcolor), m_horizon_blend() * 0.25);
}
}