set_sky improvements, set_sun, set_moon and set_stars

This commit is contained in:
Jordach 2019-08-21 21:47:45 +01:00 committed by sfan5
parent 580e7e8eb9
commit 946c03c69b
19 changed files with 1525 additions and 400 deletions

@ -5964,15 +5964,82 @@ object you are working with still exists.
* `hud_set_hotbar_selected_image(texturename)`
* sets image for selected item of hotbar
* `hud_get_hotbar_selected_image`: returns texturename
* `set_sky(bgcolor, type, {texture names}, clouds)`
* `bgcolor`: ColorSpec, defaults to white
* `type`: Available types:
* `"regular"`: Uses 0 textures, `bgcolor` ignored
* `"skybox"`: Uses 6 textures, `bgcolor` used
* `"plain"`: Uses 0 textures, `bgcolor` used
* `clouds`: Boolean for whether clouds appear in front of `"skybox"` or
`"plain"` custom skyboxes (default: `true`)
* `get_sky()`: returns bgcolor, type, table of textures, clouds
* `set_sky(parameters)`
* `parameters` is a table with the following optional fields:
* `base_color`: ColorSpec, changes fog in "skybox" and "plain".
* `type`: Available types:
* `"regular"`: Uses 0 textures, `base_color` ignored
* `"skybox"`: Uses 6 textures, `base_color` used as fog.
* `"plain"`: Uses 0 textures, `base_color` used as both fog and sky.
* `textures`: A table containing up to six textures in the following
order: Y+ (top), Y- (bottom), X- (west), X+ (east), Z+ (north), Z- (south).
* `clouds`: Boolean for whether clouds appear. (default: `true`)
* `sky_color`: A table containing the following values, alpha is ignored:
* `day_sky`: ColorSpec, for the top half of the `"regular"`
skybox during the day. (default: `#8cbafa`)
* `day_horizon`: ColorSpec, for the bottom half of the
`"regular"` skybox during the day. (default: `#9bc1f0`)
* `dawn_sky`: ColorSpec, for the top half of the `"regular"`
skybox during dawn/sunset. (default: `#b4bafa`)
* `dawn_horizon`: ColorSpec, for the bottom half of the `"regular"`
skybox during dawn/sunset. (default: `#bac1f0`)
* `night_sky`: ColorSpec, for the top half of the `"regular"`
skybox during the night. (default: `#006aff`)
* `night_horizon`: ColorSpec, for the bottom half of the `"regular"`
skybox during the night. (default: `#4090ff`)
* `indoors`: ColorSpec, for when you're either indoors or
underground. Only applies to the `"regular"` skybox.
(default: `#646464`)
* `fog_sun_tint`: ColorSpec, changes the fog tinting for the sun
at sunrise and sunset.
* `fog_moon_tint`: ColorSpec, changes the fog tinting for the moon
at sunrise and sunset.
* `fog_tint_type`: string, changes which mode the directional fog
abides by, `"custom"` uses `sun_tint` and `moon_tint`, while
`"default"` uses the classic Minetest sun and moon tinting.
Will use tonemaps, if set to `"default"`. (default: `"default"`)
* `get_sky()`: returns base_color, type, table of textures, clouds.
* `get_sky_color()`: returns a table with the `sky_color` parameters as in
`set_sky`.
* `set_sun(parameters)`:
* `parameters` is a table with the following optional fields:
* `visible`: Boolean for whether the sun is visible.
(default: `true`)
* `texture`: A regular texture for the sun. Setting to `""`
will re-enable the mesh sun. (default: `"sun.png"`)
* `tonemap`: A 512x1 texture containing the tonemap for the sun
(default: `"sun_tonemap.png"`)
* `sunrise`: A regular texture for the sunrise texture.
(default: `"sunrisebg.png"`)
* `sunrise_visible`: Boolean for whether the sunrise texture is visible.
(default: `true`)
* `scale`: Float controlling the overall size of the sun. (default: `1`)
* `get_sun()`: returns a table with the current sun parameters as in
`set_sun`.
* `set_moon(parameters)`:
* `parameters` is a table with the following optional fields:
* `visible`: Boolean for whether the moon is visible.
(default: `true`)
* `texture`: A regular texture for the moon. Setting to `""`
will re-enable the mesh moon. (default: `"moon.png"`)
* `tonemap`: A 512x1 texture containing the tonemap for the moon
(default: `"moon_tonemap.png"`)
* `scale`: Float controlling the overall size of the moon (default: `1`)
* `get_moon()`: returns a table with the current moon parameters as in
`set_moon`.
* `set_stars(parameters)`:
* `parameters` is a table with the following optional fields:
* `visible`: Boolean for whether the stars are visible.
(default: `true`)
* `count`: Integer number to set the number of stars in
the skybox. Only applies to `"skybox"` and `"regular"` skyboxes.
(default: `1000`)
* `star_color`: ColorSpec, sets the colors of the stars,
alpha channel is used to set overall star brightness.
(default: `#ebebff69`)
* `size`: Float controlling the overall size of the stars (default: `1`)
* `get_stars()`: returns a table with the current stars parameters as in
`set_stars`.
* `set_clouds(parameters)`: set cloud parameters
* `parameters` is a table with the following optional fields:
* `density`: from `0` (no clouds) to `1` (full clouds) (default `0.4`)

@ -218,6 +218,9 @@ public:
void handleCommand_HudSetFlags(NetworkPacket* pkt);
void handleCommand_HudSetParam(NetworkPacket* pkt);
void handleCommand_HudSetSky(NetworkPacket* pkt);
void handleCommand_HudSetSun(NetworkPacket* pkt);
void handleCommand_HudSetMoon(NetworkPacket* pkt);
void handleCommand_HudSetStars(NetworkPacket* pkt);
void handleCommand_CloudParams(NetworkPacket* pkt);
void handleCommand_OverrideDayNightRatio(NetworkPacket* pkt);
void handleCommand_LocalPlayerAnimations(NetworkPacket* pkt);

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include "irrlichttypes_bloated.h"
#include "hud.h"
#include "skyparams.h"
enum ClientEventType : u8
{
@ -38,6 +39,9 @@ enum ClientEventType : u8
CE_HUDRM,
CE_HUDCHANGE,
CE_SET_SKY,
CE_SET_SUN,
CE_SET_MOON,
CE_SET_STARS,
CE_OVERRIDE_DAY_NIGHT_RATIO,
CE_CLOUD_PARAMS,
CLIENTEVENT_MAX,
@ -147,13 +151,7 @@ struct ClientEvent
v3f *v3fdata;
v2s32 *v2s32data;
} hudchange;
struct
{
video::SColor *bgcolor;
std::string *type;
std::vector<std::string> *params;
bool clouds;
} set_sky;
SkyboxParams *set_sky;
struct
{
bool do_override;
@ -169,5 +167,8 @@ struct ClientEvent
f32 speed_x;
f32 speed_y;
} cloud_params;
SunParams *sun_params;
MoonParams *moon_params;
StarParams *star_params;
};
};

@ -811,6 +811,9 @@ private:
void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
CameraOrientation *cam);
void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
@ -2523,6 +2526,9 @@ const ClientEventHandler Game::clientEventHandler[CLIENTEVENT_MAX] = {
{&Game::handleClientEvent_HudRemove},
{&Game::handleClientEvent_HudChange},
{&Game::handleClientEvent_SetSky},
{&Game::handleClientEvent_SetSun},
{&Game::handleClientEvent_SetMoon},
{&Game::handleClientEvent_SetStars},
{&Game::handleClientEvent_OverrideDayNigthRatio},
{&Game::handleClientEvent_CloudParams},
};
@ -2744,41 +2750,85 @@ void Game::handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *ca
void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam)
{
sky->setVisible(false);
// Whether clouds are visible in front of a custom skybox
sky->setCloudsEnabled(event->set_sky.clouds);
// Whether clouds are visible in front of a custom skybox.
sky->setCloudsEnabled(event->set_sky->clouds);
if (skybox) {
skybox->remove();
skybox = NULL;
}
// Clear the old textures out in case we switch rendering type.
sky->clearSkyboxTextures();
// Handle according to type
if (*event->set_sky.type == "regular") {
if (event->set_sky->type == "regular") {
// Shows the mesh skybox
sky->setVisible(true);
sky->setCloudsEnabled(true);
} else if (*event->set_sky.type == "skybox" &&
event->set_sky.params->size() == 6) {
sky->setFallbackBgColor(*event->set_sky.bgcolor);
skybox = RenderingEngine::get_scene_manager()->addSkyBoxSceneNode(
texture_src->getTextureForMesh((*event->set_sky.params)[0]),
texture_src->getTextureForMesh((*event->set_sky.params)[1]),
texture_src->getTextureForMesh((*event->set_sky.params)[2]),
texture_src->getTextureForMesh((*event->set_sky.params)[3]),
texture_src->getTextureForMesh((*event->set_sky.params)[4]),
texture_src->getTextureForMesh((*event->set_sky.params)[5]));
}
// Handle everything else as plain color
else {
if (*event->set_sky.type != "plain")
// Update mesh based skybox colours if applicable.
sky->setSkyColors(*event->set_sky);
sky->setHorizonTint(
event->set_sky->sun_tint,
event->set_sky->moon_tint,
event->set_sky->tint_type
);
} else if (event->set_sky->type == "skybox" &&
event->set_sky->textures.size() == 6) {
// Disable the dyanmic mesh skybox:
sky->setVisible(false);
// Set fog colors:
sky->setFallbackBgColor(event->set_sky->bgcolor);
// Set sunrise and sunset fog tinting:
sky->setHorizonTint(
event->set_sky->sun_tint,
event->set_sky->moon_tint,
event->set_sky->tint_type
);
// Add textures to skybox.
for (int i = 0; i < 6; i++)
sky->addTextureToSkybox(event->set_sky->textures[i], i, texture_src);
} else {
// Handle everything else as plain color.
if (event->set_sky->type != "plain")
infostream << "Unknown sky type: "
<< (*event->set_sky.type) << std::endl;
sky->setFallbackBgColor(*event->set_sky.bgcolor);
<< (event->set_sky->type) << std::endl;
sky->setVisible(false);
sky->setFallbackBgColor(event->set_sky->bgcolor);
// Disable directional sun/moon tinting on plain or invalid skyboxes.
sky->setHorizonTint(
event->set_sky->bgcolor,
event->set_sky->bgcolor,
"custom"
);
}
delete event->set_sky;
}
delete event->set_sky.bgcolor;
delete event->set_sky.type;
delete event->set_sky.params;
void Game::handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam)
{
sky->setSunVisible(event->sun_params->visible);
sky->setSunTexture(event->sun_params->texture,
event->sun_params->tonemap, texture_src);
sky->setSunScale(event->sun_params->scale);
sky->setSunriseVisible(event->sun_params->sunrise_visible);
sky->setSunriseTexture(event->sun_params->sunrise, texture_src);
delete event->sun_params;
}
void Game::handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam)
{
sky->setMoonVisible(event->moon_params->visible);
sky->setMoonTexture(event->moon_params->texture,
event->moon_params->tonemap, texture_src);
sky->setMoonScale(event->moon_params->scale);
delete event->moon_params;
}
void Game::handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam)
{
sky->setStarsVisible(event->star_params->visible);
sky->setStarCount(event->star_params->count, false);
sky->setStarColor(event->star_params->starcolor);
sky->setStarScale(event->star_params->scale);
delete event->star_params;
}
void Game::handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
@ -3706,7 +3756,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
video::SColor clouds_dark = clouds->getColor()
.getInterpolated(video::SColor(255, 0, 0, 0), 0.9);
sky->overrideColors(clouds_dark, clouds->getColor());
sky->setBodiesVisible(false);
sky->setInClouds(true);
runData.fog_range = std::fmin(runData.fog_range * 0.5f, 32.0f * BS);
// do not draw clouds after all
clouds->setVisible(false);

@ -18,22 +18,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "sky.h"
#include "ITexture.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
#include "S3DVertex.h"
#include "client/tile.h"
#include "noise.h" // easeCurve
#include "noise.h" // easeCurve
#include "profiler.h"
#include "util/numeric.h"
#include <cmath>
#include "client/renderingengine.h"
#include "settings.h"
#include "camera.h" // CameraModes
#include "camera.h" // CameraModes
#include "config.h"
using namespace irr::core;
Sky::Sky(s32 id, ITextureSource *tsrc):
Sky::Sky(s32 id, ITextureSource *tsrc) :
scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
RenderingEngine::get_scene_manager(), id)
{
@ -67,44 +68,51 @@ Sky::Sky(s32 id, ITextureSource *tsrc):
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;
// Ensures that sun and moon textures and tonemaps are correct.
setSkyDefaults();
m_sun_texture = tsrc->isKnownSourceImage(m_sun_params.texture) ?
tsrc->getTextureForMesh(m_sun_params.texture) : NULL;
m_moon_texture = tsrc->isKnownSourceImage(m_moon_params.texture) ?
tsrc->getTextureForMesh(m_moon_params.texture) : NULL;
m_sun_tonemap = tsrc->isKnownSourceImage(m_sun_params.tonemap) ?
tsrc->getTexture(m_sun_params.tonemap) : NULL;
m_moon_tonemap = tsrc->isKnownSourceImage(m_moon_params.tonemap) ?
tsrc->getTexture(m_moon_params.tonemap) : 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;
// Disables texture filtering
m_materials[3].setFlag(video::E_MATERIAL_FLAG::EMF_BILINEAR_FILTER, false);
m_materials[3].setFlag(video::E_MATERIAL_FLAG::EMF_TRILINEAR_FILTER, false);
m_materials[3].setFlag(video::E_MATERIAL_FLAG::EMF_ANISOTROPIC_FILTER, false);
// Use tonemaps if available
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;
// Disables texture filtering
m_materials[4].setFlag(video::E_MATERIAL_FLAG::EMF_BILINEAR_FILTER, false);
m_materials[4].setFlag(video::E_MATERIAL_FLAG::EMF_TRILINEAR_FILTER, false);
m_materials[4].setFlag(video::E_MATERIAL_FLAG::EMF_ANISOTROPIC_FILTER, false);
// Use tonemaps if available
if (m_moon_tonemap)
m_materials[4].Lighting = true;
}
for (v3f &star : m_stars) {
star = v3f(
myrand_range(-10000, 10000),
myrand_range(-10000, 10000),
myrand_range(-10000, 10000)
);
star.normalize();
for (int i = 5; i < 11; i++) {
m_materials[i] = mat;
m_materials[i].Lighting = true;
m_materials[i].MaterialType = video::EMT_SOLID;
}
m_directional_colored_fog = g_settings->getBool("directional_colored_fog");
setStarCount(1000, true);
}
void Sky::OnRegisterSceneNode()
{
if (IsVisible)
@ -113,12 +121,8 @@ void Sky::OnRegisterSceneNode()
scene::ISceneNode::OnRegisterSceneNode();
}
void Sky::render()
{
if (!m_visible)
return;
video::IVideoDriver *driver = SceneManager->getVideoDriver();
scene::ICameraSceneNode *camera = SceneManager->getActiveCamera();
@ -205,143 +209,103 @@ void Sky::render()
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 (video::S3DVertex &vertex : vertices) {
if (j == 0)
// Don't switch
{}
else if (j == 1)
// Switch from -Z (south) to +X (east)
vertex.Pos.rotateXZBy(90);
else if (j == 2)
// Switch from -Z (south) to -X (west)
vertex.Pos.rotateXZBy(-90);
else
// Switch from -Z (south) to +Z (north)
vertex.Pos.rotateXZBy(-180);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
// Draw far cloudy fog thing at and below all horizons
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 (video::S3DVertex &vertex : vertices) {
if (j == 0)
// Don't switch
{}
else if (j == 1)
// Switch from -Z (south) to +X (east)
vertex.Pos.rotateXZBy(90);
else if (j == 2)
// Switch from -Z (south) to -X (west)
vertex.Pos.rotateXZBy(-90);
else
// Switch from -Z (south) to +Z (north)
vertex.Pos.rotateXZBy(-180);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
// If sun, moon and stars are (temporarily) disabled, abort here
if (!m_bodies_visible)
// Abort rendering if we're in the clouds.
// Stops rendering a pure white hole in the bottom of the skybox.
if (m_in_clouds)
return;
// Draw stars before sun and moon to be behind them
do {
driver->setMaterial(m_materials[1]);
// Tune values so that stars first appear just after the sun
// disappears over the horizon, and disappear just before the sun
// appears over the horizon.
// Also tune so that stars are at full brightness from time 20000 to
// time 4000.
float starbrightness = MYMAX(0, MYMIN(1,
(0.25 - fabs(wicked_time_of_day < 0.5 ?
wicked_time_of_day : (1.0 - wicked_time_of_day))) * 20));
float f = starbrightness;
float d = 0.006f / 2.0f;
video::SColor starcolor(255, f * 90, f * 90, f * 90);
// Stars are only drawn when brighter than skycolor
if (starcolor.getBlue() < m_skycolor.getBlue())
break;
#if ENABLE_GLES
u16 indices[SKY_STAR_COUNT * 3];
video::S3DVertex vertices[SKY_STAR_COUNT * 3];
for (u32 i = 0; i < SKY_STAR_COUNT; i++) {
indices[i * 3 + 0] = i * 3 + 0;
indices[i * 3 + 1] = i * 3 + 1;
indices[i * 3 + 2] = i * 3 + 2;
v3f r = m_stars[i];
core::CMatrix4<f32> a;
a.buildRotateFromTo(v3f(0, 1, 0), r);
v3f p = v3f(-d, 1, -d);
v3f p1 = v3f(d, 1, 0);
v3f p2 = v3f(-d, 1, d);
a.rotateVect(p);
a.rotateVect(p1);
a.rotateVect(p2);
p.rotateXYBy(wicked_time_of_day * 360 - 90);
p1.rotateXYBy(wicked_time_of_day * 360 - 90);
p2.rotateXYBy(wicked_time_of_day * 360 - 90);
vertices[i * 3 + 0].Pos = p;
vertices[i * 3 + 0].Color = starcolor;
vertices[i * 3 + 1].Pos = p1;
vertices[i * 3 + 1].Color = starcolor;
vertices[i * 3 + 2].Pos = p2;
vertices[i * 3 + 2].Color = starcolor;
// Draw the six sided skybox,
if (m_sky_params.textures.size() == 6) {
for (u32 j = 5; j < 11; j++) {
video::SColor c(255, 255, 255, 255);
driver->setMaterial(m_materials[j]);
// Use 1.05 rather than 1.0 to avoid colliding with the
// sun, moon and stars, as this is a background skybox.
vertices[0] = video::S3DVertex(-1.05, -1.05, -1.05, 0, 0, 1, c, t, t);
vertices[1] = video::S3DVertex( 1.05, -1.05, -1.05, 0, 0, 1, c, o, t);
vertices[2] = video::S3DVertex( 1.05, 1.05, -1.05, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-1.05, 1.05, -1.05, 0, 0, 1, c, t, o);
for (video::S3DVertex &vertex : vertices) {
if (j == 5) { // Top texture
vertex.Pos.rotateYZBy(90);
vertex.Pos.rotateXZBy(90);
} else if (j == 6) { // Bottom texture
vertex.Pos.rotateYZBy(-90);
vertex.Pos.rotateXZBy(90);
} else if (j == 7) { // Left texture
vertex.Pos.rotateXZBy(90);
} else if (j == 8) { // Right texture
vertex.Pos.rotateXZBy(-90);
} else if (j == 9) { // Front texture, do nothing
// Irrlicht doesn't like it when vertexes are left
// alone and not rotated for some reason.
vertex.Pos.rotateXZBy(0);
} else {// Back texture
vertex.Pos.rotateXZBy(180);
}
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
driver->drawIndexedTriangleList(vertices, SKY_STAR_COUNT * 3,
indices, SKY_STAR_COUNT);
#else
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 r = m_stars[i];
core::CMatrix4<f32> a;
a.buildRotateFromTo(v3f(0, 1, 0), r);
v3f p = v3f(-d, 1, -d);
v3f p1 = v3f( d, 1, -d);
v3f p2 = v3f( d, 1, d);
v3f p3 = v3f(-d, 1, d);
a.rotateVect(p);
a.rotateVect(p1);
a.rotateVect(p2);
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);
#endif
} while (false);
}
// Draw sunrise/sunset horizon glow texture (textures/base/pack/sunrisebg.png)
{
// Draw far cloudy fog thing blended with skycolor
if (m_visible) {
driver->setMaterial(m_materials[1]);
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 (video::S3DVertex &vertex : vertices) {
if (j == 0)
// Don't switch
{}
else if (j == 1)
// Switch from -Z (south) to +X (east)
vertex.Pos.rotateXZBy(90);
else if (j == 2)
// Switch from -Z (south) to -X (west)
vertex.Pos.rotateXZBy(-90);
else
// Switch from -Z (south) to +Z (north)
vertex.Pos.rotateXZBy(-180);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
// Draw far cloudy fog thing at and below all horizons
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 (video::S3DVertex &vertex : vertices) {
if (j == 0)
// Don't switch
{}
else if (j == 1)
// Switch from -Z (south) to +X (east)
vertex.Pos.rotateXZBy(90);
else if (j == 2)
// Switch from -Z (south) to -X (west)
vertex.Pos.rotateXZBy(-90);
else
// Switch from -Z (south) to +Z (north)
vertex.Pos.rotateXZBy(-180);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
}
// Draw stars before sun and moon to be behind them
if (m_star_params.visible)
draw_stars(driver, wicked_time_of_day);
// Draw sunrise/sunset horizon glow texture
// (textures/base/pack/sunrisebg.png)
if (m_sun_params.sunrise_visible) {
driver->setMaterial(m_materials[2]);
float mid1 = 0.25;
float mid = wicked_time_of_day < 0.5 ? mid1 : (1.0 - mid1);
@ -366,53 +330,52 @@ void Sky::render()
}
// Draw sun
if (wicked_time_of_day > 0.15 && wicked_time_of_day < 0.85) {
if (m_sun_params.visible)
draw_sun(driver, sunsize, suncolor, suncolor2, wicked_time_of_day);
}
// Draw moon
if (wicked_time_of_day < 0.3 || wicked_time_of_day > 0.7) {
if (m_moon_params.visible)
draw_moon(driver, moonsize, mooncolor, mooncolor2, wicked_time_of_day);
}
// Draw far cloudy fog thing below all horizons in front of sun, moon
// and stars.
driver->setMaterial(m_materials[1]);
if (m_visible) {
driver->setMaterial(m_materials[1]);
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.02, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-1, -0.02, -1, 0, 0, 1, c, t, o);
for (video::S3DVertex &vertex : vertices) {
if (j == 0)
// Don't switch
{}
else if (j == 1)
// Switch from -Z (south) to +X (east)
vertex.Pos.rotateXZBy(90);
else if (j == 2)
// Switch from -Z (south) to -X (west)
vertex.Pos.rotateXZBy(-90);
else
// Switch from -Z (south) to +Z (north)
vertex.Pos.rotateXZBy(-180);
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.02, -1, 0, 0, 1, c, o, o);
vertices[3] = video::S3DVertex(-1, -0.02, -1, 0, 0, 1, c, t, o);
for (video::S3DVertex &vertex : vertices) {
if (j == 0)
// Don't switch
{}
else if (j == 1)
// Switch from -Z (south) to +X (east)
vertex.Pos.rotateXZBy(90);
else if (j == 2)
// Switch from -Z (south) to -X (west)
vertex.Pos.rotateXZBy(-90);
else
// Switch from -Z (south) to +Z (north)
vertex.Pos.rotateXZBy(-180);
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
// Draw bottom far cloudy fog thing in front of sun, moon and stars
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);
}
// Draw bottom far cloudy fog thing in front of sun, moon and stars
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);
}
}
void Sky::update(float time_of_day, float time_brightness,
float direct_brightness, bool sunlight_seen,
CameraMode cam_mode, float yaw, float pitch)
@ -426,7 +389,7 @@ void Sky::update(float time_of_day, float time_brightness,
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);
sunlight_seen, cam_mode, yaw, pitch);
}
return;
}
@ -434,7 +397,7 @@ void Sky::update(float time_of_day, float time_brightness,
m_time_of_day = time_of_day;
m_time_brightness = time_brightness;
m_sunlight_seen = sunlight_seen;
m_bodies_visible = true;
m_in_clouds = false;
bool is_dawn = (time_brightness >= 0.20 && time_brightness < 0.35);
@ -452,19 +415,17 @@ void Sky::update(float time_of_day, float time_brightness,
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 bgcolor_bright_normal_f = m_sky_params.sky_color.day_horizon;
video::SColorf bgcolor_bright_indoor_f = m_sky_params.sky_color.indoors;
video::SColorf bgcolor_bright_dawn_f = m_sky_params.sky_color.dawn_horizon;
video::SColorf bgcolor_bright_night_f = m_sky_params.sky_color.night_horizon;
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 skycolor_bright_normal_f = m_sky_params.sky_color.day_sky;
video::SColorf skycolor_bright_dawn_f = m_sky_params.sky_color.dawn_sky;
video::SColorf skycolor_bright_night_f = m_sky_params.sky_color.night_sky;
// pure white: becomes "diffuse light component" for clouds
video::SColorf cloudcolor_bright_normal_f = video::SColor(255, 255, 255, 255);
// dawn-factoring version of pure white (note: R is above 1.0)
video::SColorf cloudcolor_bright_dawn_f(255.0f/240.0f, 223.0f/240.0f, 191.0f/255.0f);
video::SColorf cloudcolor_bright_normal_f = m_cloudcolor_day_f;
video::SColorf cloudcolor_bright_dawn_f = m_cloudcolor_dawn_f;
float cloud_color_change_fraction = 0.95;
if (sunlight_seen) {
@ -558,13 +519,17 @@ void Sky::update(float time_of_day, float time_brightness,
f32 pointcolor_light = rangelim(m_time_brightness * 3, 0.2, 1);
video::SColorf pointcolor_sun_f(1, 1, 1, 1);
if (m_sun_tonemap) {
// Use tonemap only if default sun/moon tinting is used
// which keeps previous behaviour.
if (m_sun_tonemap && m_default_tint) {
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 if (!m_default_tint) {
pointcolor_sun_f = m_sky_params.sun_tint;
} else {
pointcolor_sun_f.r = pointcolor_light * 1;
pointcolor_sun_f.b = pointcolor_light *
@ -573,9 +538,23 @@ void Sky::update(float time_of_day, float time_brightness,
(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) {
video::SColorf pointcolor_moon_f;
if (m_default_tint) {
pointcolor_moon_f = video::SColorf(
0.5 * pointcolor_light,
0.6 * pointcolor_light,
0.8 * pointcolor_light,
1
);
} else {
pointcolor_moon_f = video::SColorf(
(m_sky_params.moon_tint.getRed() / 255) * pointcolor_light,
(m_sky_params.moon_tint.getGreen() / 255) * pointcolor_light,
(m_sky_params.moon_tint.getBlue() / 255) * pointcolor_light,
1
);
}
if (m_moon_tonemap && m_default_tint) {
pointcolor_moon_f.r = pointcolor_light *
(float)m_materials[4].EmissiveColor.getRed() / 255;
pointcolor_moon_f.b = pointcolor_light *
@ -640,7 +619,12 @@ void Sky::draw_sun(video::IVideoDriver *driver, float sunsize, const video::SCol
std::array<video::S3DVertex, 4> vertices;
if (!m_sun_texture) {
driver->setMaterial(m_materials[1]);
const float sunsizes[4] = {sunsize * 1.7f, sunsize * 1.2f, sunsize, sunsize * 0.7f};
const float sunsizes[4] = {
(sunsize * 1.7f) * m_sun_params.scale,
(sunsize * 1.2f) * m_sun_params.scale,
(sunsize) * m_sun_params.scale,
(sunsize * 0.7f) * m_sun_params.scale
};
video::SColor c1 = suncolor;
video::SColor c2 = suncolor;
c1.setAlpha(0.05 * 255);
@ -653,7 +637,7 @@ void Sky::draw_sun(video::IVideoDriver *driver, float sunsize, const video::SCol
}
} else {
driver->setMaterial(m_materials[3]);
float d = sunsize * 1.7;
float d = (sunsize * 1.7) * m_sun_params.scale;
video::SColor c;
if (m_sun_tonemap)
c = video::SColor(0, 0, 0, 0);
@ -668,31 +652,32 @@ void Sky::draw_sun(video::IVideoDriver *driver, float sunsize, const video::SCol
void Sky::draw_moon(video::IVideoDriver *driver, float moonsize, const video::SColor &mooncolor,
const video::SColor &mooncolor2, float wicked_time_of_day)
/*
* Draw moon in the sky.
* driver: Video driver object used to draw
* moonsize: the default size of the moon
* mooncolor: main moon color
* mooncolor2: second moon color
* wicked_time_of_day: current time of day, to know where should be the moon in the sky
*/
/*
* Draw moon in the sky.
* driver: Video driver object used to draw
* moonsize: the default size of the moon
* mooncolor: main moon color
* mooncolor2: second moon color
* wicked_time_of_day: current time of day, to know where should be the moon in
* the sky
*/
{
static const u16 indices[4] = {0, 1, 2, 3};
std::array<video::S3DVertex, 4> vertices;
if (!m_moon_texture) {
driver->setMaterial(m_materials[1]);
const float moonsizes_1[4] = {
-moonsize * 1.9f,
-moonsize * 1.3f,
-moonsize,
-moonsize
};
(-moonsize * 1.9f) * m_moon_params.scale,
(-moonsize * 1.3f) * m_moon_params.scale,
(-moonsize) * m_moon_params.scale,
(-moonsize) * m_moon_params.scale
};
const float moonsizes_2[4] = {
moonsize * 1.9f,
moonsize * 1.3f,
moonsize,
moonsize * 0.6f
};
(moonsize * 1.9f) * m_moon_params.scale,
(moonsize * 1.3f) * m_moon_params.scale,
(moonsize) *m_moon_params.scale,
(moonsize * 0.6f) * m_moon_params.scale
};
video::SColor c1 = mooncolor;
video::SColor c2 = mooncolor;
c1.setAlpha(0.05 * 255);
@ -705,7 +690,7 @@ void Sky::draw_moon(video::IVideoDriver *driver, float moonsize, const video::SC
}
} else {
driver->setMaterial(m_materials[4]);
float d = moonsize * 1.9;
float d = (moonsize * 1.9) * m_moon_params.scale;
video::SColor c;
if (m_moon_tonemap)
c = video::SColor(0, 0, 0, 0);
@ -717,14 +702,106 @@ void Sky::draw_moon(video::IVideoDriver *driver, float moonsize, const video::SC
}
}
void Sky::draw_stars(video::IVideoDriver * driver, float wicked_time_of_day)
{
driver->setMaterial(m_materials[1]);
// Tune values so that stars first appear just after the sun
// disappears over the horizon, and disappear just before the sun
// appears over the horizon.
// Also tune so that stars are at full brightness from time 20000
// to time 4000.
float tod = wicked_time_of_day < 0.5f ? wicked_time_of_day : (1.0f - wicked_time_of_day);
float starbrightness = clamp((0.25f - fabsf(tod)) * 20.0f, 0.0f, 1.0f);
float f = starbrightness;
float d = (0.006 / 2) * m_star_params.scale;
video::SColor starcolor = m_star_params.starcolor;
starcolor.setAlpha(f * m_star_params.starcolor.getAlpha());
// Stars are only drawn when not fully transparent
if (m_star_params.starcolor.getAlpha() < 1)
return;
#if ENABLE_GLES
u16 *indices = new u16[m_star_count * 3];
video::S3DVertex *vertices =
new video::S3DVertex[m_star_count * 3];
for (u32 i = 0; i < m_star_count; i++) {
indices[i * 3 + 0] = i * 3 + 0;
indices[i * 3 + 1] = i * 3 + 1;
indices[i * 3 + 2] = i * 3 + 2;
v3f r = m_stars[i];
core::CMatrix4<f32> a;
a.buildRotateFromTo(v3f(0, 1, 0), r);
v3f p = v3f(-d, 1, -d);
v3f p1 = v3f(d, 1, 0);
v3f p2 = v3f(-d, 1, d);
a.rotateVect(p);
a.rotateVect(p1);
a.rotateVect(p2);
p.rotateXYBy(wicked_time_of_day * 360 - 90);
p1.rotateXYBy(wicked_time_of_day * 360 - 90);
p2.rotateXYBy(wicked_time_of_day * 360 - 90);
vertices[i * 3 + 0].Pos = p;
vertices[i * 3 + 0].Color = starcolor;
vertices[i * 3 + 1].Pos = p1;
vertices[i * 3 + 1].Color = starcolor;
vertices[i * 3 + 2].Pos = p2;
vertices[i * 3 + 2].Color = starcolor;
}
driver->drawIndexedTriangleList(vertices.data(), m_star_count * 3,
indices.data(), m_star_count);
delete[] indices;
delete[] vertices;
#else
u16 *indices = new u16[m_star_params.count * 4];
video::S3DVertex *vertices =
new video::S3DVertex[m_star_params.count * 4];
for (u32 i = 0; i < m_star_params.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 r = m_stars[i];
core::CMatrix4<f32> a;
a.buildRotateFromTo(v3f(0, 1, 0), r);
v3f p = v3f(-d, 1, -d);
v3f p1 = v3f(d, 1, -d);
v3f p2 = v3f(d, 1, d);
v3f p3 = v3f(-d, 1, d);
a.rotateVect(p);
a.rotateVect(p1);
a.rotateVect(p2);
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, m_star_params.count * 4,
indices, m_star_params.count, video::EVT_STANDARD,
scene::EPT_QUADS, video::EIT_16BIT);
delete[] indices;
delete[] vertices;
#endif
}
void Sky::draw_sky_body(std::array<video::S3DVertex, 4> &vertices, float pos_1, float pos_2, const video::SColor &c)
{
/*
* Create an array of vertices with the dimensions specified.
* pos_1, pos_2: position of the body's vertices
* c: color of the body
*/
* Create an array of vertices with the dimensions specified.
* pos_1, pos_2: position of the body's vertices
* c: color of the body
*/
const f32 t = 1.0f;
const f32 o = 0.0f;
@ -738,11 +815,11 @@ void Sky::draw_sky_body(std::array<video::S3DVertex, 4> &vertices, float pos_1,
void Sky::place_sky_body(
std::array<video::S3DVertex, 4> &vertices, float horizon_position, float day_position)
/*
* Place body in the sky.
* vertices: The body as a rectangle of 4 vertices
* horizon_position: turn the body around the Y axis
* day_position: turn the body around the Z axis, to place it depending of the time of the day
*/
* Place body in the sky.
* vertices: The body as a rectangle of 4 vertices
* horizon_position: turn the body around the Y axis
* day_position: turn the body around the Z axis, to place it depending of the time of the day
*/
{
for (video::S3DVertex &vertex : vertices) {
// Body is directed to -Z (south) by default
@ -750,3 +827,168 @@ void Sky::place_sky_body(
vertex.Pos.rotateXYBy(day_position);
}
}
void Sky::setSunTexture(std::string sun_texture,
std::string sun_tonemap, ITextureSource *tsrc)
{
// Ignore matching textures (with modifiers) entirely,
// but lets at least update the tonemap before hand.
m_sun_params.tonemap = sun_tonemap;
m_sun_tonemap = tsrc->isKnownSourceImage(m_sun_params.tonemap) ?
tsrc->getTexture(m_sun_params.tonemap) : NULL;
m_materials[3].Lighting = !!m_sun_tonemap;
if (m_sun_params.texture == sun_texture)
return;
m_sun_params.texture = sun_texture;
if (sun_texture != "") {
// We want to ensure the texture exists first.
m_sun_texture = tsrc->getTextureForMesh(m_sun_params.texture);
if (m_sun_texture) {
m_materials[3] = m_materials[0];
m_materials[3].setTexture(0, m_sun_texture);
m_materials[3].MaterialType = video::
EMT_TRANSPARENT_ALPHA_CHANNEL;
// Disables texture filtering
m_materials[3].setFlag(
video::E_MATERIAL_FLAG::EMF_BILINEAR_FILTER, false);
m_materials[3].setFlag(
video::E_MATERIAL_FLAG::EMF_TRILINEAR_FILTER, false);
m_materials[3].setFlag(
video::E_MATERIAL_FLAG::EMF_ANISOTROPIC_FILTER, false);
}
} else {
m_sun_texture = nullptr;
}
}
void Sky::setSunriseTexture(std::string sunglow_texture,
ITextureSource* tsrc)
{
// Ignore matching textures (with modifiers) entirely.
if (m_sun_params.sunrise == sunglow_texture)
return;
m_sun_params.sunrise = sunglow_texture;
m_materials[2].setTexture(0, tsrc->getTextureForMesh(
sunglow_texture.empty() ? "sunrisebg.png" : sunglow_texture)
);
}
void Sky::setMoonTexture(std::string moon_texture,
std::string moon_tonemap, ITextureSource *tsrc)
{
// Ignore matching textures (with modifiers) entirely,
// but lets at least update the tonemap before hand.
m_moon_params.tonemap = moon_tonemap;
m_moon_tonemap = tsrc->isKnownSourceImage(m_moon_params.tonemap) ?
tsrc->getTexture(m_moon_params.tonemap) : NULL;
m_materials[4].Lighting = !!m_moon_tonemap;
if (m_moon_params.texture == moon_texture)
return;
m_moon_params.texture = moon_texture;
if (moon_texture != "") {
// We want to ensure the texture exists first.
m_moon_texture = tsrc->getTextureForMesh(m_moon_params.texture);
if (m_moon_texture) {
m_materials[4] = m_materials[0];
m_materials[4].setTexture(0, m_moon_texture);
m_materials[4].MaterialType = video::
EMT_TRANSPARENT_ALPHA_CHANNEL;
// Disables texture filtering
m_materials[4].setFlag(
video::E_MATERIAL_FLAG::EMF_BILINEAR_FILTER, false);
m_materials[4].setFlag(
video::E_MATERIAL_FLAG::EMF_TRILINEAR_FILTER, false);
m_materials[4].setFlag(
video::E_MATERIAL_FLAG::EMF_ANISOTROPIC_FILTER, false);
}
} else {
m_moon_texture = nullptr;
}
}
void Sky::setStarCount(u16 star_count, bool force_update)
{
// Force updating star count at game init.
if (force_update) {
m_star_params.count = star_count;
m_stars.clear();
// Rebuild the stars surrounding the camera
for (u16 i = 0; i < star_count; i++) {
v3f star = v3f(
myrand_range(-10000, 10000),
myrand_range(-10000, 10000),
myrand_range(-10000, 10000)
);
star.normalize();
m_stars.emplace_back(star);
}
// Ignore changing star count if the new value is identical
} else if (m_star_params.count == star_count)
return;
else {
m_star_params.count = star_count;
m_stars.clear();
// Rebuild the stars surrounding the camera
for (u16 i = 0; i < star_count; i++) {
v3f star = v3f(
myrand_range(-10000, 10000),
myrand_range(-10000, 10000),
myrand_range(-10000, 10000)
);
star.normalize();
m_stars.emplace_back(star);
}
}
}
void Sky::setSkyColors(const SkyboxParams sky)
{
m_sky_params.sky_color = sky.sky_color;
}
void Sky::setHorizonTint(video::SColor sun_tint, video::SColor moon_tint,
std::string use_sun_tint)
{
// Change sun and moon tinting:
m_sky_params.sun_tint = sun_tint;
m_sky_params.moon_tint = moon_tint;
// Faster than comparing strings every rendering frame
if (use_sun_tint == "default")
m_default_tint = true;
else if (use_sun_tint == "custom")
m_default_tint = false;
else
m_default_tint = true;
}
void Sky::addTextureToSkybox(std::string texture, int material_id,
ITextureSource *tsrc)
{
// Sanity check for more than six textures.
if (material_id + 5 >= SKY_MATERIAL_COUNT)
return;
// Keep a list of texture names handy.
m_sky_params.textures.emplace_back(texture);
video::ITexture *result = tsrc->getTextureForMesh(texture);
m_materials[material_id+5] = m_materials[0];
m_materials[material_id+5].setTexture(0, result);
m_materials[material_id+5].MaterialType = video::EMT_SOLID;
}
// To be called once at game init to setup default values.
void Sky::setSkyDefaults()
{
SkyboxDefaults sky_defaults;
m_sky_params.sky_color = sky_defaults.getSkyColorDefaults();
m_sun_params = sky_defaults.getSunDefaults();
m_moon_params = sky_defaults.getMoonDefaults();
m_star_params = sky_defaults.getStarDefaults();
}

@ -21,11 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <array>
#include "camera.h"
#include "irrlichttypes_extrabloated.h"
#include "skyparams.h"
#pragma once
#define SKY_MATERIAL_COUNT 5
#define SKY_STAR_COUNT 1000
#define SKY_MATERIAL_COUNT 12
class ITextureSource;
@ -45,8 +45,6 @@ public:
// Used by Irrlicht for optimizing rendering
virtual video::SMaterial &getMaterial(u32 i) { return m_materials[i]; }
// Used by Irrlicht for optimizing rendering
virtual u32 getMaterialCount() const { return SKY_MATERIAL_COUNT; }
void update(float m_time_of_day, float time_brightness, float direct_brightness,
@ -64,6 +62,23 @@ public:
return m_visible ? m_skycolor : m_fallback_bg_color;
}
void setSunVisible(bool sun_visible) { m_sun_params.visible = sun_visible; }
void setSunTexture(std::string sun_texture,
std::string sun_tonemap, ITextureSource *tsrc);
void setSunScale(f32 sun_scale) { m_sun_params.scale = sun_scale; }
void setSunriseVisible(bool glow_visible) { m_sun_params.sunrise_visible = glow_visible; }
void setSunriseTexture(std::string sunglow_texture, ITextureSource* tsrc);
void setMoonVisible(bool moon_visible) { m_moon_params.visible = moon_visible; }
void setMoonTexture(std::string moon_texture,
std::string moon_tonemap, ITextureSource *tsrc);
void setMoonScale(f32 moon_scale) { m_moon_params.scale = moon_scale; }
void setStarsVisible(bool stars_visible) { m_star_params.visible = stars_visible; }
void setStarCount(u16 star_count, bool force_update);
void setStarColor(video::SColor star_color) { m_star_params.starcolor = star_color; }
void setStarScale(f32 star_scale) { m_star_params.scale = star_scale; }
bool getCloudsVisible() const { return m_clouds_visible && m_clouds_enabled; }
const video::SColorf &getCloudColor() const { return m_cloudcolor_f; }
@ -79,12 +94,16 @@ public:
m_bgcolor = bgcolor;
m_skycolor = skycolor;
}
void setBodiesVisible(bool visible) { m_bodies_visible = visible; }
void setSkyColors(const SkyboxParams sky);
void setHorizonTint(video::SColor sun_tint, video::SColor moon_tint,
std::string use_sun_tint);
void setInClouds(bool clouds) { m_in_clouds = clouds; }
void clearSkyboxTextures() { m_sky_params.textures.clear(); }
void addTextureToSkybox(std::string texture, int material_id,
ITextureSource *tsrc);
private:
aabb3f m_box;
video::SMaterial m_materials[SKY_MATERIAL_COUNT];
// How much sun & moon transition should affect horizon color
float m_horizon_blend()
{
@ -134,25 +153,46 @@ private:
bool m_clouds_visible; // Whether clouds are disabled due to player underground
bool m_clouds_enabled = true; // Initialised to true, reset only by set_sky API
bool m_directional_colored_fog;
bool m_bodies_visible = true; // sun, moon, stars
bool m_in_clouds = true; // Prevent duplicating bools to remember old values
video::SColorf m_bgcolor_bright_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
video::SColorf m_skycolor_bright_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
video::SColorf m_cloudcolor_bright_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
video::SColor m_bgcolor;
video::SColor m_skycolor;
video::SColorf m_cloudcolor_f;
v3f m_stars[SKY_STAR_COUNT];
// pure white: becomes "diffuse light component" for clouds
video::SColorf m_cloudcolor_day_f = video::SColorf(1, 1, 1, 1);
// dawn-factoring version of pure white (note: R is above 1.0)
video::SColorf m_cloudcolor_dawn_f = video::SColorf(
255.0f/240.0f,
223.0f/240.0f,
191.0f/255.0f
);
SkyboxParams m_sky_params;
SunParams m_sun_params;
MoonParams m_moon_params;
StarParams m_star_params;
bool m_default_tint = true;
std::vector<v3f> m_stars;
video::ITexture *m_sun_texture;
video::ITexture *m_moon_texture;
video::ITexture *m_sun_tonemap;
video::ITexture *m_moon_tonemap;
void draw_sun(video::IVideoDriver *driver, float sunsize, const video::SColor &suncolor,
const video::SColor &suncolor2, float wicked_time_of_day);
const video::SColor &suncolor2, float wicked_time_of_day);
void draw_moon(video::IVideoDriver *driver, float moonsize, const video::SColor &mooncolor,
const video::SColor &mooncolor2, float wicked_time_of_day);
const video::SColor &mooncolor2, float wicked_time_of_day);
void draw_sky_body(std::array<video::S3DVertex, 4> &vertices,
float pos_1, float pos_2, const video::SColor &c);
void place_sky_body(
std::array<video::S3DVertex, 4> &vertices, float horizon_position,
float day_position);
float pos_1, float pos_2, const video::SColor &c);
void draw_stars(video::IVideoDriver *driver, float wicked_time_of_day);
void place_sky_body(std::array<video::S3DVertex, 4> &vertices,
float horizon_position, float day_position);
void setSkyDefaults();
};

@ -114,9 +114,9 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_MODCHANNEL_MSG", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_ModChannelMsg }, // 0x57
{ "TOCLIENT_MODCHANNEL_SIGNAL", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_ModChannelSignal }, // 0x58
{ "TOCLIENT_NODEMETA_CHANGED", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_NodemetaChanged }, // 0x59
null_command_handler,
null_command_handler,
null_command_handler,
{ "TOCLIENT_SET_SUN", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudSetSun }, // 0x5a
{ "TOCLIENT_SET_MOON", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudSetMoon }, // 0x5b
{ "TOCLIENT_SET_STARS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudSetStars }, // 0x5c
null_command_handler,
null_command_handler,
null_command_handler,

@ -40,6 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/srp.h"
#include "tileanimation.h"
#include "gettext.h"
#include "skyparams.h"
void Client::handleCommand_Deprecated(NetworkPacket* pkt)
{
@ -1233,28 +1234,132 @@ void Client::handleCommand_HudSetParam(NetworkPacket* pkt)
void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
{
std::string datastring(pkt->getString(0), pkt->getSize());
std::istringstream is(datastring, std::ios_base::binary);
if (m_proto_ver < 39) {
// Handle Protocol 38 and below servers with old set_sky,
// ensuring the classic look is kept.
std::string datastring(pkt->getString(0), pkt->getSize());
std::istringstream is(datastring, std::ios_base::binary);
video::SColor *bgcolor = new video::SColor(readARGB8(is));
std::string *type = new std::string(deSerializeString(is));
u16 count = readU16(is);
std::vector<std::string> *params = new std::vector<std::string>;
SkyboxParams skybox;
skybox.bgcolor = video::SColor(readARGB8(is));
skybox.type = std::string(deSerializeString(is));
u16 count = readU16(is);
std::vector<std::string>* params = new std::vector<std::string>;
for (size_t i = 0; i < count; i++)
params->push_back(deSerializeString(is));
for (size_t i = 0; i < count; i++)
skybox.textures.emplace_back(deSerializeString(is));
bool clouds = true;
try {
clouds = readU8(is);
} catch (...) {}
bool clouds = true;
try {
skybox.clouds = readU8(is);
} catch (...) {}
// Use default skybox settings:
SkyboxDefaults sky_defaults;
SunParams sun = sky_defaults.getSunDefaults();
MoonParams moon = sky_defaults.getMoonDefaults();
StarParams stars = sky_defaults.getStarDefaults();
// Fix for "regular" skies, as color isn't kept:
if (skybox.type == "regular") {
skybox.sky_color = sky_defaults.getSkyColorDefaults();
skybox.tint_type = "default";
skybox.moon_tint = video::SColor(255, 255, 255, 255);
skybox.sun_tint = video::SColor(255, 255, 255, 255);
}
else {
sun.visible = false;
sun.sunrise_visible = false;
moon.visible = false;
stars.visible = false;
}
// Skybox, sun, moon and stars ClientEvents:
ClientEvent *sky_event = new ClientEvent();
sky_event->type = CE_SET_SKY;
sky_event->set_sky = new SkyboxParams(skybox);
m_client_event_queue.push(sky_event);
ClientEvent *sun_event = new ClientEvent();
sun_event->type = CE_SET_SUN;
sun_event->sun_params = new SunParams(sun);
m_client_event_queue.push(sun_event);
ClientEvent *moon_event = new ClientEvent();
moon_event->type = CE_SET_MOON;
moon_event->moon_params = new MoonParams(moon);
m_client_event_queue.push(moon_event);
ClientEvent *star_event = new ClientEvent();
star_event->type = CE_SET_STARS;
star_event->star_params = new StarParams(stars);
m_client_event_queue.push(star_event);
} else {
SkyboxParams skybox;
u16 texture_count;
std::string texture;
*pkt >> skybox.bgcolor >> skybox.type >> skybox.clouds >>
skybox.sun_tint >> skybox.moon_tint >> skybox.tint_type;
if (skybox.type == "skybox") {
*pkt >> texture_count;
for (int i = 0; i < texture_count; i++) {
*pkt >> texture;
skybox.textures.emplace_back(texture);
}
}
else if (skybox.type == "regular") {
*pkt >> skybox.sky_color.day_sky >> skybox.sky_color.day_horizon
>> skybox.sky_color.dawn_sky >> skybox.sky_color.dawn_horizon
>> skybox.sky_color.night_sky >> skybox.sky_color.night_horizon
>> skybox.sky_color.indoors;
}
ClientEvent *event = new ClientEvent();
event->type = CE_SET_SKY;
event->set_sky = new SkyboxParams(skybox);
m_client_event_queue.push(event);
}
}
void Client::handleCommand_HudSetSun(NetworkPacket *pkt)
{
SunParams sun;
*pkt >> sun.visible >> sun.texture>> sun.tonemap
>> sun.sunrise >> sun.sunrise_visible >> sun.scale;
ClientEvent *event = new ClientEvent();
event->type = CE_SET_SKY;
event->set_sky.bgcolor = bgcolor;
event->set_sky.type = type;
event->set_sky.params = params;
event->set_sky.clouds = clouds;
event->type = CE_SET_SUN;
event->sun_params = new SunParams(sun);
m_client_event_queue.push(event);
}
void Client::handleCommand_HudSetMoon(NetworkPacket *pkt)
{
MoonParams moon;
*pkt >> moon.visible >> moon.texture
>> moon.tonemap >> moon.scale;
ClientEvent *event = new ClientEvent();
event->type = CE_SET_MOON;
event->moon_params = new MoonParams(moon);
m_client_event_queue.push(event);
}
void Client::handleCommand_HudSetStars(NetworkPacket *pkt)
{
StarParams stars;
*pkt >> stars.visible >> stars.count
>> stars.starcolor >> stars.scale;
ClientEvent *event = new ClientEvent();
event->type = CE_SET_STARS;
event->star_params = new StarParams(stars);
m_client_event_queue.push(event);
}

@ -201,9 +201,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Mod-specific formspec version
Player FOV override API
"ephemeral" added to TOCLIENT_PLAY_SOUND
PROTOCOL VERSION 39:
Updated set_sky packet
Adds new sun, moon and stars packets
*/
#define LATEST_PROTOCOL_VERSION 38
#define LATEST_PROTOCOL_VERSION 39
#define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION)
// Server's supported network protocol range
@ -605,7 +608,8 @@ enum ToClientCommand
TOCLIENT_SET_SKY = 0x4f,
/*
u8[4] color (ARGB)
Protocol 38:
u8[4] base_color (ARGB)
u8 len
u8[len] type
u16 count
@ -613,6 +617,24 @@ enum ToClientCommand
u8 len
u8[len] param
u8 clouds (boolean)
Protocol 39:
u8[4] bgcolor (ARGB)
std::string type
int texture_count
std::string[6] param
bool clouds
bool bgcolor_fog
u8[4] day_sky (ARGB)
u8[4] day_horizon (ARGB)
u8[4] dawn_sky (ARGB)
u8[4] dawn_horizon (ARGB)
u8[4] night_sky (ARGB)
u8[4] night_horizon (ARGB)
u8[4] indoors (ARGB)
u8[4] sun_tint (ARGB)
u8[4] moon_tint (ARGB)
std::string tint_type
*/
TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO = 0x50,
@ -688,6 +710,31 @@ enum ToClientCommand
serialized and compressed node metadata
*/
TOCLIENT_SET_SUN = 0x5a,
/*
bool visible
std::string texture
std::string tonemap
std::string sunrise
f32 scale
*/
TOCLIENT_SET_MOON = 0x5b,
/*
bool visible
std::string texture
std::string tonemap
f32 scale
*/
TOCLIENT_SET_STARS = 0x5c,
/*
bool visible
u32 count
u8[4] starcolor (ARGB)
f32 scale
*/
TOCLIENT_SRP_BYTES_S_B = 0x60,
/*
Belonging to AUTH_MECHANISM_SRP.

@ -203,12 +203,12 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_MODCHANNEL_MSG", 0, true }, // 0x57
{ "TOCLIENT_MODCHANNEL_SIGNAL", 0, true }, // 0x58
{ "TOCLIENT_NODEMETA_CHANGED", 0, true }, // 0x59
null_command_factory, // 0x5A
null_command_factory, // 0x5B
null_command_factory, // 0x5C
null_command_factory, // 0x5D
null_command_factory, // 0x5E
null_command_factory, // 0x5F
{ "TOCLIENT_SET_SUN", 0, true }, // 0x5a
{ "TOCLIENT_SET_MOON", 0, true }, // 0x5b
{ "TOCLIENT_SET_STARS", 0, true }, // 0x5c
null_command_factory, // 0x5d
null_command_factory, // 0x5e
null_command_factory, // 0x5f
{ "TOSERVER_SRP_BYTES_S_B", 0, true }, // 0x60
{ "TOCLIENT_FORMSPEC_PREPEND", 0, true }, // 0x61
};

@ -66,6 +66,21 @@ RemotePlayer::RemotePlayer(const char *name, IItemDefManager *idef):
m_cloud_params.height = 120.0f;
m_cloud_params.thickness = 16.0f;
m_cloud_params.speed = v2f(0.0f, -2.0f);
// Skybox defaults:
SkyboxDefaults sky_defaults;
m_skybox_params.sky_color = sky_defaults.getSkyColorDefaults();
m_skybox_params.type = "regular";
m_skybox_params.clouds = true;
m_skybox_params.sun_tint = video::SColor(255, 244, 125, 29);
m_skybox_params.moon_tint = video::SColorf(0.5, 0.6, 0.8, 1).toSColor();
m_skybox_params.tint_type = "default";
m_sun_params = sky_defaults.getSunDefaults();
m_moon_params = sky_defaults.getMoonDefaults();
m_star_params = sky_defaults.getStarDefaults();
}
void RemotePlayer::serializeExtraAttributes(std::string &output)

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "player.h"
#include "cloudparams.h"
#include "skyparams.h"
class PlayerSAO;
@ -83,23 +84,21 @@ public:
return hud_hotbar_selected_image;
}
void setSky(const video::SColor &bgcolor, const std::string &type,
const std::vector<std::string> &params, bool &clouds)
{
m_sky_bgcolor = bgcolor;
m_sky_type = type;
m_sky_params = params;
m_sky_clouds = clouds;
}
void setSky(const SkyboxParams &skybox_params) { m_skybox_params = skybox_params; }
void getSky(video::SColor *bgcolor, std::string *type,
std::vector<std::string> *params, bool *clouds)
{
*bgcolor = m_sky_bgcolor;
*type = m_sky_type;
*params = m_sky_params;
*clouds = m_sky_clouds;
}
const SkyboxParams &getSkyParams() const { return m_skybox_params; }
void setSun(const SunParams &sun_params) { m_sun_params = sun_params; }
const SunParams &getSunParams() const { return m_sun_params; }
void setMoon(const MoonParams &moon_params) { m_moon_params = moon_params; }
const MoonParams &getMoonParams() const { return m_moon_params; }
void setStars(const StarParams &star_params) { m_star_params = star_params; }
const StarParams &getStarParams() const { return m_star_params; }
void setCloudParams(const CloudParams &cloud_params)
{
@ -164,12 +163,12 @@ private:
std::string hud_hotbar_image = "";
std::string hud_hotbar_selected_image = "";
std::string m_sky_type;
video::SColor m_sky_bgcolor;
std::vector<std::string> m_sky_params;
bool m_sky_clouds;
CloudParams m_cloud_params;
SkyboxParams m_skybox_params;
SunParams m_sun_params;
MoonParams m_moon_params;
StarParams m_star_params;
session_t m_peer_id = PEER_ID_INEXISTENT;
};

@ -335,6 +335,28 @@ video::SColor read_ARGB8(lua_State *L, int index)
return color;
}
bool is_color_table(lua_State *L, int index)
{
// Check whole table in case of missing ColorSpec keys:
// This check does not remove the checked value from the stack.
// Only update the value if we know we have a valid ColorSpec key pair.
if (!lua_istable(L, index))
return false;
bool is_color_table = false;
lua_getfield(L, index, "r");
if (!is_color_table)
is_color_table = lua_isnumber(L, -1);
lua_getfield(L, index, "g");
if (!is_color_table)
is_color_table = lua_isnumber(L, -1);
lua_getfield(L, index, "b");
if (!is_color_table)
is_color_table = lua_isnumber(L, -1);
lua_pop(L, 3); // b, g, r values
return is_color_table;
}
aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
{
aabb3f box;

@ -110,6 +110,7 @@ v2s32 read_v2s32 (lua_State *L, int index);
video::SColor read_ARGB8 (lua_State *L, int index);
bool read_color (lua_State *L, int index,
video::SColor *color);
bool is_color_table (lua_State *L, int index);
aabb3f read_aabb3f (lua_State *L, int index, f32 scale);
v3s16 read_v3s16 (lua_State *L, int index);

@ -1708,42 +1708,157 @@ int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L)
return 1;
}
// set_sky(self, bgcolor, type, list, clouds = true)
// set_sky(self, {base_color=, type=, textures=, clouds=, sky_colors={}})
int ObjectRef::l_set_sky(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (player == NULL)
if (!player)
return 0;
video::SColor bgcolor(255,255,255,255);
read_color(L, 2, &bgcolor);
bool is_colorspec = is_color_table(L, 2);
std::string type = luaL_checkstring(L, 3);
SkyboxParams skybox_params = player->getSkyParams();
if (lua_istable(L, 2) && !is_colorspec) {
lua_getfield(L, 2, "base_color");
if (!lua_isnil(L, -1))
read_color(L, -1, &skybox_params.bgcolor);
lua_pop(L, 1);
std::vector<std::string> params;
if (lua_istable(L, 4)) {
lua_pushnil(L);
while (lua_next(L, 4) != 0) {
// key at index -2 and value at index -1
if (lua_isstring(L, -1))
params.emplace_back(readParam<std::string>(L, -1));
else
params.emplace_back("");
// removes value, keeps key for next iteration
lua_getfield(L, 2, "type");
if (!lua_isnil(L, -1))
skybox_params.type = luaL_checkstring(L, -1);
lua_pop(L, 1);
lua_getfield(L, 2, "textures");
skybox_params.textures.clear();
if (lua_istable(L, -1) && skybox_params.type == "skybox") {
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
// Key is at index -2 and value at index -1
skybox_params.textures.emplace_back(readParam<std::string>(L, -1));
// Removes the value, but keeps the key for iteration
lua_pop(L, 1);
}
}
lua_pop(L, 1);
/*
We want to avoid crashes, so we're checking even if we're not using them.
However, we want to ensure that the skybox can be set to nil when
using "regular" or "plain" skybox modes as textures aren't needed.
*/
if (skybox_params.textures.size() != 6 && skybox_params.textures.size() > 0)
throw LuaError("Skybox expects 6 textures!");
skybox_params.clouds = getboolfield_default(L, 2,
"clouds", skybox_params.clouds);
lua_getfield(L, 2, "sky_color");
if (lua_istable(L, -1)) {
lua_getfield(L, -1, "day_sky");
read_color(L, -1, &skybox_params.sky_color.day_sky);
lua_pop(L, 1);
lua_getfield(L, -1, "day_horizon");
read_color(L, -1, &skybox_params.sky_color.day_horizon);
lua_pop(L, 1);
lua_getfield(L, -1, "dawn_sky");
read_color(L, -1, &skybox_params.sky_color.dawn_sky);
lua_pop(L, 1);
lua_getfield(L, -1, "dawn_horizon");
read_color(L, -1, &skybox_params.sky_color.dawn_horizon);
lua_pop(L, 1);
lua_getfield(L, -1, "night_sky");
read_color(L, -1, &skybox_params.sky_color.night_sky);
lua_pop(L, 1);
lua_getfield(L, -1, "night_horizon");
read_color(L, -1, &skybox_params.sky_color.night_horizon);
lua_pop(L, 1);
lua_getfield(L, -1, "indoors");
read_color(L, -1, &skybox_params.sky_color.indoors);
lua_pop(L, 1);
// Prevent flickering clouds at dawn/dusk:
skybox_params.sun_tint = video::SColor(255, 255, 255, 255);
lua_getfield(L, -1, "fog_sun_tint");
read_color(L, -1, &skybox_params.sun_tint);
lua_pop(L, 1);
skybox_params.moon_tint = video::SColor(255, 255, 255, 255);
lua_getfield(L, -1, "fog_moon_tint");
read_color(L, -1, &skybox_params.moon_tint);
lua_pop(L, 1);
lua_getfield(L, -1, "fog_tint_type");
if (!lua_isnil(L, -1))
skybox_params.tint_type = luaL_checkstring(L, -1);
lua_pop(L, 1);
// Because we need to leave the "sky_color" table.
lua_pop(L, 1);
}
} else {
// Handle old set_sky calls, and log deprecated:
log_deprecated(L, "Deprecated call to set_sky, please check lua_api.txt");
// Fix sun, moon and stars showing when classic textured skyboxes are used
SunParams sun_params = player->getSunParams();
MoonParams moon_params = player->getMoonParams();
StarParams star_params = player->getStarParams();
// Prevent erroneous background colors
skybox_params.bgcolor = video::SColor(255, 255, 255, 255);
read_color(L, 2, &skybox_params.bgcolor);
skybox_params.type = luaL_checkstring(L, 3);
// Preserve old behaviour of the sun, moon and stars
// when using the old set_sky call.
if (skybox_params.type == "regular") {
sun_params.visible = true;
sun_params.sunrise_visible = true;
moon_params.visible = true;
star_params.visible = true;
} else {
sun_params.visible = false;
sun_params.sunrise_visible = false;
moon_params.visible = false;
star_params.visible = false;
}
skybox_params.textures.clear();
if (lua_istable(L, 4)) {
lua_pushnil(L);
while (lua_next(L, 4) != 0) {
// Key at index -2, and value at index -1
if (lua_isstring(L, -1))
skybox_params.textures.emplace_back(readParam<std::string>(L, -1));
else
skybox_params.textures.emplace_back("");
// Remove the value, keep the key for the next iteration
lua_pop(L, 1);
}
}
if (skybox_params.type == "skybox" && skybox_params.textures.size() != 6)
throw LuaError("Skybox expects 6 textures.");
skybox_params.clouds = true;
if (lua_isboolean(L, 5))
skybox_params.clouds = readParam<bool>(L, 5);
getServer(L)->setSun(player, sun_params);
getServer(L)->setMoon(player, moon_params);
getServer(L)->setStars(player, star_params);
}
if (type == "skybox" && params.size() != 6)
throw LuaError("skybox expects 6 textures");
bool clouds = true;
if (lua_isboolean(L, 5))
clouds = readParam<bool>(L, 5);
getServer(L)->setSky(player, bgcolor, type, params, clouds);
getServer(L)->setSky(player, skybox_params);
lua_pushboolean(L, true);
return 1;
}
@ -1754,28 +1869,226 @@ int ObjectRef::l_get_sky(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (player == NULL)
if (!player)
return 0;
video::SColor bgcolor(255, 255, 255, 255);
std::string type;
std::vector<std::string> params;
bool clouds;
SkyboxParams skybox_params;
skybox_params = player->getSkyParams();
player->getSky(&bgcolor, &type, &params, &clouds);
type = type.empty() ? "regular" : type;
push_ARGB8(L, skybox_params.bgcolor);
lua_pushlstring(L, skybox_params.type.c_str(), skybox_params.type.size());
push_ARGB8(L, bgcolor);
lua_pushlstring(L, type.c_str(), type.size());
lua_newtable(L);
s16 i = 1;
for (const std::string &param : params) {
lua_pushlstring(L, param.c_str(), param.size());
for (const std::string& texture : skybox_params.textures) {
lua_pushlstring(L, texture.c_str(), texture.size());
lua_rawseti(L, -2, i++);
}
lua_pushboolean(L, clouds);
lua_pushboolean(L, skybox_params.clouds);
return 4;
}
// get_sky_color(self)
int ObjectRef::l_get_sky_color(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (!player)
return 0;
const SkyboxParams& skybox_params = player->getSkyParams();
lua_newtable(L);
if (skybox_params.type == "regular") {
push_ARGB8(L, skybox_params.sky_color.day_sky);
lua_setfield(L, -2, "day_sky");
push_ARGB8(L, skybox_params.sky_color.day_horizon);
lua_setfield(L, -2, "day_horizon");
push_ARGB8(L, skybox_params.sky_color.dawn_sky);
lua_setfield(L, -2, "dawn_sky");
push_ARGB8(L, skybox_params.sky_color.dawn_horizon);
lua_setfield(L, -2, "dawn_horizon");
push_ARGB8(L, skybox_params.sky_color.night_sky);
lua_setfield(L, -2, "night_sky");
push_ARGB8(L, skybox_params.sky_color.night_horizon);
lua_setfield(L, -2, "night_horizon");
push_ARGB8(L, skybox_params.sky_color.indoors);
lua_setfield(L, -2, "indoors");
}
push_ARGB8(L, skybox_params.sun_tint);
lua_setfield(L, -2, "sun_tint");
push_ARGB8(L, skybox_params.moon_tint);
lua_setfield(L, -2, "moon_tint");
lua_pushstring(L, skybox_params.tint_type.c_str());
lua_setfield(L, -2, "tint_type");
return 1;
}
// set_sun(self, {visible, texture=, tonemap=, sunrise=, rotation=, scale=})
int ObjectRef::l_set_sun(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (!player)
return 0;
if (!lua_istable(L, 2))
return 0;
SunParams sun_params = player->getSunParams();
sun_params.visible = getboolfield_default(L, 2,
"visible", sun_params.visible);
sun_params.texture = getstringfield_default(L, 2,
"texture", sun_params.texture);
sun_params.tonemap = getstringfield_default(L, 2,
"tonemap", sun_params.tonemap);
sun_params.sunrise = getstringfield_default(L, 2,
"sunrise", sun_params.sunrise);
sun_params.sunrise_visible = getboolfield_default(L, 2,
"sunrise_visible", sun_params.sunrise_visible);
sun_params.scale = getfloatfield_default(L, 2,
"scale", sun_params.scale);
getServer(L)->setSun(player, sun_params);
lua_pushboolean(L, true);
return 1;
}
//get_sun(self)
int ObjectRef::l_get_sun(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (!player)
return 0;
const SunParams &sun_params = player->getSunParams();
lua_newtable(L);
lua_pushboolean(L, sun_params.visible);
lua_setfield(L, -2, "visible");
lua_pushstring(L, sun_params.texture.c_str());
lua_setfield(L, -2, "texture");
lua_pushstring(L, sun_params.tonemap.c_str());
lua_setfield(L, -2, "tonemap");
lua_pushstring(L, sun_params.sunrise.c_str());
lua_setfield(L, -2, "sunrise");
lua_pushboolean(L, sun_params.sunrise_visible);
lua_setfield(L, -2, "sunrise_visible");
lua_pushnumber(L, sun_params.scale);
lua_setfield(L, -2, "scale");
return 1;
}
// set_moon(self, {visible, texture=, tonemap=, sunrise=, rotation=, scale=})
int ObjectRef::l_set_moon(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (!player)
return 0;
if (!lua_istable(L, 2))
return 0;
MoonParams moon_params = player->getMoonParams();
moon_params.visible = getboolfield_default(L, 2,
"visible", moon_params.visible);
moon_params.texture = getstringfield_default(L, 2,
"texture", moon_params.texture);
moon_params.tonemap = getstringfield_default(L, 2,
"tonemap", moon_params.tonemap);
moon_params.scale = getfloatfield_default(L, 2,
"scale", moon_params.scale);
getServer(L)->setMoon(player, moon_params);
lua_pushboolean(L, true);
return 1;
}
// get_moon(self)
int ObjectRef::l_get_moon(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (!player)
return 0;
const MoonParams &moon_params = player->getMoonParams();
lua_newtable(L);
lua_pushboolean(L, moon_params.visible);
lua_setfield(L, -2, "visible");
lua_pushstring(L, moon_params.texture.c_str());
lua_setfield(L, -2, "texture");
lua_pushstring(L, moon_params.tonemap.c_str());
lua_setfield(L, -2, "tonemap");
lua_pushnumber(L, moon_params.scale);
lua_setfield(L, -2, "scale");
return 1;
}
// set_stars(self, {visible, count=, starcolor=, rotation=, scale=})
int ObjectRef::l_set_stars(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (!player)
return 0;
if (!lua_istable(L, 2))
return 0;
StarParams star_params = player->getStarParams();
star_params.visible = getboolfield_default(L, 2,
"visible", star_params.visible);
star_params.count = getintfield_default(L, 2,
"count", star_params.count);
lua_getfield(L, 2, "star_color");
if (!lua_isnil(L, -1))
read_color(L, -1, &star_params.starcolor);
lua_pop(L, 1);
star_params.scale = getfloatfield_default(L, 2,
"size", star_params.scale);
getServer(L)->setStars(player, star_params);
lua_pushboolean(L, true);
return 1;
}
// get_stars(self)
int ObjectRef::l_get_stars(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (!player)
return 0;
const StarParams &star_params = player->getStarParams();
lua_newtable(L);
lua_pushboolean(L, star_params.visible);
lua_setfield(L, -2, "visible");
lua_pushnumber(L, star_params.count);
lua_setfield(L, -2, "count");
push_ARGB8(L, star_params.starcolor);
lua_setfield(L, -2, "star_color");
lua_pushnumber(L, star_params.scale);
lua_setfield(L, -2, "scale");
return 1;
}
// set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=})
int ObjectRef::l_set_clouds(lua_State *L)
{
@ -2032,6 +2345,13 @@ luaL_Reg ObjectRef::methods[] = {
luamethod(ObjectRef, hud_get_hotbar_selected_image),
luamethod(ObjectRef, set_sky),
luamethod(ObjectRef, get_sky),
luamethod(ObjectRef, get_sky_color),
luamethod(ObjectRef, set_sun),
luamethod(ObjectRef, get_sun),
luamethod(ObjectRef, set_moon),
luamethod(ObjectRef, get_moon),
luamethod(ObjectRef, set_stars),
luamethod(ObjectRef, get_stars),
luamethod(ObjectRef, set_clouds),
luamethod(ObjectRef, get_clouds),
luamethod(ObjectRef, override_day_night_ratio),

@ -324,12 +324,33 @@ private:
// hud_get_hotbar_selected_image(self)
static int l_hud_get_hotbar_selected_image(lua_State *L);
// set_sky(self, bgcolor, type, list, clouds = true)
// set_sky({base_color=, type=, textures=, clouds=, sky_colors={}})
static int l_set_sky(lua_State *L);
// get_sky(self)
static int l_get_sky(lua_State *L);
// get_sky_color(self)
static int l_get_sky_color(lua_State* L);
// set_sun(self, {visible, texture=, tonemap=, sunrise=, rotation=, scale=})
static int l_set_sun(lua_State *L);
// get_sun(self)
static int l_get_sun(lua_State *L);
// set_moon(self, {visible, texture=, tonemap=, rotation, scale=})
static int l_set_moon(lua_State *L);
// get_moon(self)
static int l_get_moon(lua_State *L);
// set_stars(self, {visible, count=, starcolor=, rotation, scale=})
static int l_set_stars(lua_State *L);
// get_stars(self)
static int l_get_stars(lua_State *L);
// set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=})
static int l_set_clouds(lua_State *L);

@ -1718,17 +1718,62 @@ void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &va
Send(&pkt);
}
void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
const std::string &type, const std::vector<std::string> &params,
bool &clouds)
void Server::SendSetSky(session_t peer_id, const SkyboxParams &params)
{
NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
pkt << bgcolor << type << (u16) params.size();
for (const std::string &param : params)
pkt << param;
// Handle prior clients here
if (m_clients.getProtocolVersion(peer_id) < 39) {
pkt << params.bgcolor << params.type << (u16) params.textures.size();
pkt << clouds;
for (const std::string& texture : params.textures)
pkt << texture;
pkt << params.clouds;
} else { // Handle current clients and future clients
pkt << params.bgcolor << params.type
<< params.clouds << params.sun_tint
<< params.moon_tint << params.tint_type;
if (params.type == "skybox") {
pkt << (u16) params.textures.size();
for (const std::string &texture : params.textures)
pkt << texture;
} else if (params.type == "regular") {
pkt << params.sky_color.day_sky << params.sky_color.day_horizon
<< params.sky_color.dawn_sky << params.sky_color.dawn_horizon
<< params.sky_color.night_sky << params.sky_color.night_horizon
<< params.sky_color.indoors;
}
}
Send(&pkt);
}
void Server::SendSetSun(session_t peer_id, const SunParams &params)
{
NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
pkt << params.visible << params.texture
<< params.tonemap << params.sunrise
<< params.sunrise_visible << params.scale;
Send(&pkt);
}
void Server::SendSetMoon(session_t peer_id, const MoonParams &params)
{
NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
pkt << params.visible << params.texture
<< params.tonemap << params.scale;
Send(&pkt);
}
void Server::SendSetStars(session_t peer_id, const StarParams &params)
{
NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
pkt << params.visible << params.count
<< params.starcolor << params.scale;
Send(&pkt);
}
@ -3320,13 +3365,32 @@ void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3
SendEyeOffset(player->getPeerId(), first, third);
}
void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
const std::string &type, const std::vector<std::string> &params,
bool &clouds)
void Server::setSky(RemotePlayer *player, const SkyboxParams &params)
{
sanity_check(player);
player->setSky(bgcolor, type, params, clouds);
SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
player->setSky(params);
SendSetSky(player->getPeerId(), params);
}
void Server::setSun(RemotePlayer *player, const SunParams &params)
{
sanity_check(player);
player->setSun(params);
SendSetSun(player->getPeerId(), params);
}
void Server::setMoon(RemotePlayer *player, const MoonParams &params)
{
sanity_check(player);
player->setMoon(params);
SendSetMoon(player->getPeerId(), params);
}
void Server::setStars(RemotePlayer *player, const StarParams &params)
{
sanity_check(player);
player->setStars(params);
SendSetStars(player->getPeerId(), params);
}
void Server::setClouds(RemotePlayer *player, const CloudParams &params)

@ -61,6 +61,10 @@ class ServerScripting;
class ServerEnvironment;
struct SimpleSoundSpec;
struct CloudParams;
struct SkyboxParams;
struct SunParams;
struct MoonParams;
struct StarParams;
class ServerThread;
class ServerModManager;
@ -307,9 +311,11 @@ public:
f32 frame_speed);
void setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third);
void setSky(RemotePlayer *player, const video::SColor &bgcolor,
const std::string &type, const std::vector<std::string> &params,
bool &clouds);
void setSky(RemotePlayer *player, const SkyboxParams &params);
void setSun(RemotePlayer *player, const SunParams &params);
void setMoon(RemotePlayer *player, const MoonParams &params);
void setStars(RemotePlayer *player, const StarParams &params);
void setClouds(RemotePlayer *player, const CloudParams &params);
bool overrideDayNightRatio(RemotePlayer *player, bool do_override, float brightness);
@ -413,9 +419,10 @@ private:
void SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value);
void SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask);
void SendHUDSetParam(session_t peer_id, u16 param, const std::string &value);
void SendSetSky(session_t peer_id, const video::SColor &bgcolor,
const std::string &type, const std::vector<std::string> &params,
bool &clouds);
void SendSetSky(session_t peer_id, const SkyboxParams &params);
void SendSetSun(session_t peer_id, const SunParams &params);
void SendSetMoon(session_t peer_id, const MoonParams &params);
void SendSetStars(session_t peer_id, const StarParams &params);
void SendCloudParams(session_t peer_id, const CloudParams &params);
void SendOverrideDayNightRatio(session_t peer_id, bool do_override, float ratio);
void broadcastModChannelMessage(const std::string &channel,

121
src/skyparams.h Normal file

@ -0,0 +1,121 @@
/*
Minetest
Copyright (C) 2019 Jordach, Jordan Snelling <jordach.snelling@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
struct skycolor
{
video::SColor day_sky;
video::SColor day_horizon;
video::SColor dawn_sky;
video::SColor dawn_horizon;
video::SColor night_sky;
video::SColor night_horizon;
video::SColor indoors;
};
struct SkyboxParams
{
video::SColor bgcolor;
std::string type;
std::vector<std::string> textures;
bool clouds;
skycolor sky_color;
video::SColor sun_tint;
video::SColor moon_tint;
std::string tint_type;
};
struct SunParams
{
bool visible;
std::string texture;
std::string tonemap;
std::string sunrise;
bool sunrise_visible;
f32 scale;
};
struct MoonParams
{
bool visible;
std::string texture;
std::string tonemap;
f32 scale;
};
struct StarParams
{
bool visible;
u32 count;
video::SColor starcolor;
f32 scale;
};
// Utility class for setting default sky, sun, moon, stars values:
class SkyboxDefaults
{
public:
const skycolor getSkyColorDefaults()
{
skycolor sky;
// Horizon colors
sky.day_horizon = video::SColor(255, 155, 193, 240);
sky.indoors = video::SColor(255, 100, 100, 100);
sky.dawn_horizon = video::SColor(255, 186, 193, 240);
sky.night_horizon = video::SColor(255, 64, 144, 255);
// Sky colors
sky.day_sky = video::SColor(255, 140, 186, 250);
sky.dawn_sky = video::SColor(255, 180, 186, 250);
sky.night_sky = video::SColor(255, 0, 107, 255);
return sky;
}
const SunParams getSunDefaults()
{
SunParams sun;
sun.visible = true;
sun.sunrise_visible = true;
sun.texture = "sun.png";
sun.tonemap = "sun_tonemap.png";
sun.sunrise = "sunrisebg.png";
sun.scale = 1;
return sun;
}
const MoonParams getMoonDefaults()
{
MoonParams moon;
moon.visible = true;
moon.texture = "moon.png";
moon.tonemap = "moon_tonemap.png";
moon.scale = 1;
return moon;
}
const StarParams getStarDefaults()
{
StarParams stars;
stars.count = 1000;
stars.starcolor = video::SColor(105, 235, 235, 255);
stars.scale = 1;
return stars;
}
};