diff --git a/doc/lua_api.md b/doc/lua_api.md index 7ce6a543e6..c452de57a2 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8902,6 +8902,10 @@ child will follow movement and rotation of that bone. * `type`: Available types: * `"regular"`: Uses 0 textures, `base_color` ignored * `"skybox"`: Uses 6 textures, `base_color` used as fog. + * `"skybox_back"`: Uses 6 textures, `sky_color` used as fog, stars / sun / moon in foreground. + Note: Requires Luanti client version 5.13 or greater. + * `"skybox_front"`: Uses 6 textures, `sky_color` used as fog, stars / sun / moon in background. + Note: Requires Luanti client version 5.13 or greater. * `"plain"`: Uses 0 textures, `base_color` used as both fog and sky. (default: `"regular"`) * `textures`: A table containing up to six textures in the following @@ -8910,9 +8914,9 @@ child will follow movement and rotation of that bone. bottom texture and the bottom edge of the top texture touch the east face). Some top and bottom textures expect to be aligned with the north face and will need to be rotated by -90 and 90 degrees, respectively, to fit the eastward orientation. + For `"skybox_back"` and `"skybox_front"` types, the textures should have an alpha channel. * `clouds`: Boolean for whether clouds appear. (default: `true`) - * `sky_color`: A table used in `"regular"` type only, containing the - following values (alpha is ignored): + * `sky_color`: A table used in `"regular"` `"skybox_back"` `"skybox_front"` types, containing the following values: * `day_sky`: ColorSpec, for the top half of the sky during the day. (default: `#61b5f5`) * `day_horizon`: ColorSpec, for the bottom half of the sky during the day. diff --git a/src/client/game.cpp b/src/client/game.cpp index f133c634c6..cac731b45b 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -2831,46 +2831,29 @@ void Game::handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *ca void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam) { - sky->setVisible(false); + if (!event->set_sky->isTextured() && !event->set_sky->hasAlpha() && event->set_sky->type != "plain") + infostream << "Unknown sky type: " << (event->set_sky->type) << std::endl; + + // Show the mesh sky if transparent. + sky->setVisible(event->set_sky->hasAlpha()); + sky->setType(event->set_sky->type); // Whether clouds are visible in front of a custom skybox. sky->setCloudsEnabled(event->set_sky->clouds); - // Clear the old textures out in case we switch rendering type. - sky->clearSkyboxTextures(); - // Handle according to type - if (event->set_sky->type == "regular") { - // Shows the mesh skybox - sky->setVisible(true); - // Update mesh based skybox colours if applicable. + // Show the mesh sky and use skybox colours if transparent. + if (event->set_sky->hasAlpha()) sky->setSkyColors(event->set_sky->sky_color); - sky->setHorizonTint( - event->set_sky->fog_sun_tint, - event->set_sky->fog_moon_tint, - event->set_sky->fog_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: + else sky->setFallbackBgColor(event->set_sky->bgcolor); - // Set sunrise and sunset fog tinting: + + // Use horizon tint for regular or skybox skies. + if (event->set_sky->isTextured() || event->set_sky->hasAlpha()) { sky->setHorizonTint( event->set_sky->fog_sun_tint, event->set_sky->fog_moon_tint, event->set_sky->fog_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->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, @@ -2878,14 +2861,21 @@ void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam) ); } + // Clear the old textures out in case we switch rendering type. + sky->clearSkyboxTextures(); + // Add textures to skybox. + if (event->set_sky->isTextured()) { + for (int i = 0; i < 6; i++) + sky->addTextureToSkybox(event->set_sky->textures[i], i, texture_src, event->set_sky->hasAlpha()); + } + // Orbit Tilt: sky->setBodyOrbitTilt(event->set_sky->body_orbit_tilt); - // fog - // do not override a potentially smaller client setting. + // Fog, do not override a potentially smaller client setting. sky->setFogDistance(event->set_sky->fog_distance); - // if the fog distance is reset, switch back to the client's viewing_range + // If the fog distance is reset, switch back to the client's viewing_range if (event->set_sky->fog_distance < 0) draw_control->wanted_range = g_settings->getS16("viewing_range"); diff --git a/src/client/sky.cpp b/src/client/sky.cpp index 7dde1bb0dd..13eb39f76f 100644 --- a/src/client/sky.cpp +++ b/src/client/sky.cpp @@ -93,6 +93,45 @@ void Sky::OnRegisterSceneNode() scene::ISceneNode::OnRegisterSceneNode(); } +void Sky::renderTextures(video::IVideoDriver *driver) +{ + const f32 t = 1.0f; + const f32 o = 0.0f; + static const u16 indices[6] = {0, 1, 2, 0, 2, 3}; + video::S3DVertex vertices[4]; + + 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->drawIndexedTriangleList(&vertices[0], 4, indices, 2); + } +} + void Sky::render() { video::IVideoDriver *driver = SceneManager->getVideoDriver(); @@ -170,42 +209,13 @@ void Sky::render() if (m_in_clouds) return; - // 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->drawIndexedTriangleList(&vertices[0], 4, indices, 2); - } - } + // Draw the six sided skybox, solid or transparent background. + if (m_sky_params.type == "skybox" || m_sky_params.type == "skybox_back") + renderTextures(driver); // Draw far cloudy fog thing blended with skycolor - if (m_visible) { + // Disabled when using a textured skybox to prevent clipping + if (m_visible && !m_sky_params.isTextured()) { driver->setMaterial(m_materials[1]); for (u32 j = 0; j < 4; j++) { vertices[0] = video::S3DVertex(-1, -0.02, -1, 0, 0, 1, m_bgcolor, t, t); @@ -268,9 +278,9 @@ void Sky::render() if (m_moon_params.visible) draw_moon(driver, mooncolor, mooncolor2, wicked_time_of_day); - // Draw far cloudy fog thing below all horizons in front of sun, moon - // and stars. - if (m_visible) { + // Draw far cloudy fog thing below all horizons in front of sun, moon and stars. + // Disabled when using a textured skybox to prevent clipping + if (m_visible && !m_sky_params.isTextured()) { driver->setMaterial(m_materials[1]); for (u32 j = 0; j < 4; j++) { @@ -304,6 +314,10 @@ void Sky::render() vertices[3] = video::S3DVertex(-1, -1.0, 1, 0, 1, 0, c, t, o); driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2); } + + // Draw the six sided skybox, transparent foreground. + if (m_sky_params.type == "skybox_front") + renderTextures(driver); } } @@ -872,7 +886,7 @@ void Sky::setHorizonTint(video::SColor sun_tint, video::SColor moon_tint, } void Sky::addTextureToSkybox(const std::string &texture, int material_id, - ITextureSource *tsrc) + ITextureSource *tsrc, bool transparent) { // Sanity check for more than six textures. if (material_id + 5 >= SKY_MATERIAL_COUNT) @@ -882,7 +896,7 @@ void Sky::addTextureToSkybox(const std::string &texture, int material_id, video::ITexture *result = tsrc->getTextureForMesh(texture); m_materials[material_id+5] = baseMaterial(); m_materials[material_id+5].setTexture(0, result); - m_materials[material_id+5].MaterialType = video::EMT_SOLID; + m_materials[material_id+5].MaterialType = transparent ? video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_SOLID; } float getWickedTimeOfDay(float time_of_day) diff --git a/src/client/sky.h b/src/client/sky.h index e1eb32be3b..494fe089a2 100644 --- a/src/client/sky.h +++ b/src/client/sky.h @@ -82,6 +82,7 @@ public: const video::SColorf &getCloudColor() const { return m_cloudcolor_f; } void setVisible(bool visible) { m_visible = visible; } + void setType(const std::string &type) { m_sky_params.type = type; } // Set only from set_sky API void setCloudsEnabled(bool clouds_enabled) { m_clouds_enabled = clouds_enabled; } @@ -105,7 +106,7 @@ public: void setInClouds(bool clouds) { m_in_clouds = clouds; } void clearSkyboxTextures() { m_sky_params.textures.clear(); } void addTextureToSkybox(const std::string &texture, int material_id, - ITextureSource *tsrc); + ITextureSource *tsrc, bool transparent); // Note: the Sky class doesn't use these values. It just stores them. void setFogDistance(s16 fog_distance) { m_sky_params.fog_distance = fog_distance; } @@ -124,6 +125,8 @@ public: private: aabb3f m_box{{0.0f, 0.0f, 0.0f}}; video::SMaterial m_materials[SKY_MATERIAL_COUNT]; + void renderTextures(video::IVideoDriver *driver); + // How much sun & moon transition should affect horizon color float m_horizon_blend() { diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index dee2b4d33b..32af2115c4 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1337,8 +1337,8 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt) MoonParams moon = SkyboxDefaults::getMoonDefaults(); StarParams stars = SkyboxDefaults::getStarDefaults(); - // Fix for "regular" skies, as color isn't kept: - if (skybox.type == "regular") { + // Fix for "regular", "skybox_back", "skybox_front" skies as color isn't kept: + if (skybox.hasAlpha()) { skybox.sky_color = SkyboxDefaults::getSkyColorDefaults(); skybox.fog_tint_type = "default"; skybox.fog_moon_tint = video::SColor(255, 255, 255, 255); @@ -1378,7 +1378,7 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt) *pkt >> skybox.bgcolor >> skybox.type >> skybox.clouds >> skybox.fog_sun_tint >> skybox.fog_moon_tint >> skybox.fog_tint_type; - if (skybox.type == "skybox") { + if (skybox.isTextured()) { u16 texture_count; std::string texture; *pkt >> texture_count; @@ -1386,7 +1386,8 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt) *pkt >> texture; skybox.textures.emplace_back(texture); } - } else if (skybox.type == "regular") { + } + if (skybox.hasAlpha()) { auto &c = skybox.sky_color; *pkt >> c.day_sky >> c.day_horizon >> c.dawn_sky >> c.dawn_horizon >> c.night_sky >> c.night_horizon >> c.indoors; diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index eb9ee42bbe..0b6c11aeb8 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -2082,7 +2082,7 @@ int ObjectRef::l_set_sky(lua_State *L) lua_getfield(L, 2, "textures"); sky_params.textures.clear(); - if (lua_istable(L, -1) && sky_params.type == "skybox") { + if (lua_istable(L, -1) && sky_params.isTextured()) { lua_pushnil(L); while (lua_next(L, -2) != 0) { // Key is at index -2 and value at index -1 @@ -2176,7 +2176,7 @@ int ObjectRef::l_set_sky(lua_State *L) // Preserve old behavior of the sun, moon and stars // when using the old set_sky call. - if (sky_params.type == "regular") { + if (sky_params.hasAlpha()) { sun_params.visible = true; sun_params.sunrise_visible = true; moon_params.visible = true; @@ -2198,7 +2198,7 @@ int ObjectRef::l_set_sky(lua_State *L) lua_pop(L, 1); } } - if (sky_params.type == "skybox" && sky_params.textures.size() != 6) + if (sky_params.isTextured() && sky_params.textures.size() != 6) throw LuaError("Skybox expects 6 textures."); sky_params.clouds = true; @@ -2217,7 +2217,7 @@ int ObjectRef::l_set_sky(lua_State *L) static void push_sky_color(lua_State *L, const SkyboxParams ¶ms) { lua_newtable(L); - if (params.type == "regular") { + if (params.hasAlpha()) { push_ARGB8(L, params.sky_color.day_sky); lua_setfield(L, -2, "day_sky"); push_ARGB8(L, params.sky_color.day_horizon); diff --git a/src/server.cpp b/src/server.cpp index 3c03e68a63..325621f848 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1912,11 +1912,12 @@ void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms) << params.clouds << params.fog_sun_tint << params.fog_moon_tint << params.fog_tint_type; - if (params.type == "skybox") { + if (params.isTextured()) { pkt << (u16) params.textures.size(); for (const std::string &texture : params.textures) pkt << texture; - } else if (params.type == "regular") { + } + if (params.hasAlpha()) { auto &c = params.sky_color; pkt << c.day_sky << c.day_horizon << c.dawn_sky << c.dawn_horizon << c.night_sky << c.night_horizon << c.indoors; diff --git a/src/skyparams.h b/src/skyparams.h index 8c74e919c2..38edc49a76 100644 --- a/src/skyparams.h +++ b/src/skyparams.h @@ -37,6 +37,18 @@ struct SkyboxParams s16 fog_distance { -1 }; float fog_start { -1.0f }; video::SColor fog_color { 0 }; // override, only used if alpha > 0 + + // Check if this is a textured skybox + bool isTextured() const + { + return type == "skybox" || type == "skybox_back" || type == "skybox_front"; + } + + // Check whether transparency is used + bool hasAlpha() const + { + return type == "regular" || type == "skybox_back" || type == "skybox_front"; + } }; struct SunParams