diff --git a/doc/lua_api.md b/doc/lua_api.md index 438769085..4d6bed2e1 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8828,6 +8828,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 @@ -8837,8 +8841,8 @@ child will follow movement and rotation of that bone. 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. * `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 only. For a skybox + the `textures` should have an alpha channel. Contains the following values (alpha is ignored): * `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 ebfc3f1c8..476013715 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -2858,61 +2858,51 @@ void Game::handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *ca void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam) { - sky->setVisible(false); + // Handle invalid sky type. + if (!event->set_sky->isSkybox() && !event->set_sky->isTransparent() && 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->isTransparent()); + 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->isTransparent()) sky->setSkyColors(event->set_sky->sky_color); + else + sky->setFallbackBgColor(event->set_sky->bgcolor); + + // Use horizon tint for regular or skybox skies. + if (event->set_sky->isSkybox() || event->set_sky->isTransparent()) 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: - sky->setFallbackBgColor(event->set_sky->bgcolor); - // Set sunrise and sunset fog tinting: - 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. + else sky->setHorizonTint( event->set_sky->bgcolor, event->set_sky->bgcolor, "custom" ); + + // Clear the old textures out in case we switch rendering type. + sky->clearSkyboxTextures(); + // Add textures to skybox. + if(event->set_sky->isSkybox()) { + for (int i = 0; i < 6; i++) + sky->addTextureToSkybox(event->set_sky->textures[i], i, texture_src, event->set_sky->isTransparent()); } // 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 958ffa953..f190f8210 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.isSkybox()) { 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.isSkybox()) { 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); } } @@ -871,7 +885,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) @@ -881,7 +895,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 7d3cdba3d..f10cb203f 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(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]; + virtual 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 6cd7150c6..4ee39bd56 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1303,8 +1303,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.isTransparent()) { skybox.sky_color = SkyboxDefaults::getSkyColorDefaults(); skybox.fog_tint_type = "default"; skybox.fog_moon_tint = video::SColor(255, 255, 255, 255); @@ -1344,7 +1344,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.isSkybox()) { u16 texture_count; std::string texture; *pkt >> texture_count; @@ -1352,7 +1352,8 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt) *pkt >> texture; skybox.textures.emplace_back(texture); } - } else if (skybox.type == "regular") { + } + if (skybox.isTransparent()) { 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 eed2215ac..8c03e07a8 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -2067,7 +2067,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.isSkybox()) { lua_pushnil(L); while (lua_next(L, -2) != 0) { // Key is at index -2 and value at index -1 @@ -2161,7 +2161,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.isTransparent()) { sun_params.visible = true; sun_params.sunrise_visible = true; moon_params.visible = true; @@ -2183,7 +2183,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.isSkybox() && sky_params.textures.size() != 6) throw LuaError("Skybox expects 6 textures."); sky_params.clouds = true; @@ -2202,7 +2202,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.isTransparent()) { 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 16434f447..4e07d4001 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1868,11 +1868,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.isSkybox()) { pkt << (u16) params.textures.size(); for (const std::string &texture : params.textures) pkt << texture; - } else if (params.type == "regular") { + } + if (params.isTransparent()) { 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 c5cd574cd..16925a53f 100644 --- a/src/skyparams.h +++ b/src/skyparams.h @@ -38,6 +38,16 @@ 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 and whether transparency is used + bool isSkybox() const + { + return type == "skybox" || type == "skybox_back" || type == "skybox_front"; + } + bool isTransparent() const + { + return type == "regular" || type == "skybox_back" || type == "skybox_front"; + } }; struct SunParams