diff --git a/doc/lua_api.md b/doc/lua_api.md index 66312d189..2d8e345c8 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8789,6 +8789,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. + * `textures_front`: Used by the `"skybox"` type. Enable to draw a skybox with an alpha channel in + front of the sun / moon / stars rather than behind them. The sky color will always be shown + behind the alpha channel (default: `false`) * `clouds`: Boolean for whether clouds appear. (default: `true`) * `sky_color`: A table used in `"regular"` and `"skybox"` types only. If used with the later, the `textures` should have an alpha channel. Contains the following values (alpha is ignored): diff --git a/src/client/game.cpp b/src/client/game.cpp index 8fa2ec48a..5143bbfcd 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -2850,6 +2850,7 @@ 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); + sky->setTexturesFront(event->set_sky->textures_front); // Clear the old textures out in case we switch rendering type. sky->clearSkyboxTextures(); diff --git a/src/client/sky.cpp b/src/client/sky.cpp index b553f2bb6..3a12d1baa 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(); @@ -171,39 +210,9 @@ void Sky::render() if (m_in_clouds) return; - // Draw the six sided skybox, - if (has_tex) { - 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, in the background. + if(has_tex && !m_textures_front) + renderTextures(driver); // Draw far cloudy fog thing blended with skycolor // Disabled when using a textured skybox to prevent clipping @@ -306,6 +315,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, in the foreground. + if(has_tex && m_textures_front) + renderTextures(driver); } } diff --git a/src/client/sky.h b/src/client/sky.h index 7d3cdba3d..cbf065b38 100644 --- a/src/client/sky.h +++ b/src/client/sky.h @@ -33,6 +33,7 @@ public: virtual void OnRegisterSceneNode(); //! renders the node. + virtual void renderTextures(video::IVideoDriver *driver); virtual void render(); virtual const aabb3f &getBoundingBox() const { return m_box; } @@ -103,6 +104,7 @@ public: void setHorizonTint(video::SColor sun_tint, video::SColor moon_tint, const std::string &use_sun_tint); void setInClouds(bool clouds) { m_in_clouds = clouds; } + void setTexturesFront(bool textures_front) { m_textures_front = textures_front; } void clearSkyboxTextures() { m_sky_params.textures.clear(); } void addTextureToSkybox(const std::string &texture, int material_id, ITextureSource *tsrc); @@ -174,6 +176,7 @@ private: bool m_clouds_enabled = true; // Initialised to true, reset only by set_sky API bool m_directional_colored_fog; bool m_in_clouds = true; // Prevent duplicating bools to remember old values + bool m_textures_front = false; // Whether textures are rendered behind the default sky 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); diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 777ac0406..9d3a504ab 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1295,6 +1295,7 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt) for (size_t i = 0; i < count; i++) skybox.textures.emplace_back(deSerializeString16(is)); + skybox.textures_front = false; skybox.clouds = readU8(is) != 0; // Use default skybox settings: @@ -1340,7 +1341,7 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt) SkyboxParams skybox; - *pkt >> skybox.bgcolor >> skybox.type >> skybox.clouds >> + *pkt >> skybox.bgcolor >> skybox.type >> skybox.textures_front >> skybox.clouds >> skybox.fog_sun_tint >> skybox.fog_moon_tint >> skybox.fog_tint_type; if (skybox.type == "skybox") { diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index ec0eeb3d3..ebf7b27d6 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -2061,6 +2061,7 @@ int ObjectRef::l_set_sky(lua_State *L) if (sky_params.textures.size() != 6 && !sky_params.textures.empty()) throw LuaError("Skybox expects 6 textures!"); + sky_params.textures_front = getboolfield_default(L, 2, "textures_front", sky_params.textures_front); sky_params.clouds = getboolfield_default(L, 2, "clouds", sky_params.clouds); lua_getfield(L, 2, "sky_color"); @@ -2250,6 +2251,8 @@ int ObjectRef::l_get_sky(lua_State *L) lua_rawseti(L, -2, i++); } lua_setfield(L, -2, "textures"); + lua_pushboolean(L, skybox_params.textures_front); + lua_setfield(L, -2, "textures_front"); lua_pushboolean(L, skybox_params.clouds); lua_setfield(L, -2, "clouds"); diff --git a/src/server.cpp b/src/server.cpp index a7535cbe7..6a681acbf 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1857,10 +1857,11 @@ void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms) for (const std::string& texture : params.textures) pkt << texture; + pkt << false; pkt << params.clouds; } else { // Handle current clients and future clients pkt << params.bgcolor << params.type - << params.clouds << params.fog_sun_tint + << params.textures_front << params.clouds << params.fog_sun_tint << params.fog_moon_tint << params.fog_tint_type; if (params.type == "skybox") { diff --git a/src/skyparams.h b/src/skyparams.h index c5cd574cd..84f74db84 100644 --- a/src/skyparams.h +++ b/src/skyparams.h @@ -29,6 +29,7 @@ struct SkyboxParams video::SColor bgcolor; std::string type; std::vector textures; + bool textures_front; bool clouds; SkyColor sky_color; video::SColor fog_sun_tint; @@ -89,6 +90,7 @@ public: SkyboxParams sky; sky.bgcolor = video::SColor(255, 255, 255, 255); sky.type = "regular"; + sky.textures_front = false; sky.clouds = true; sky.sky_color = getSkyColorDefaults(); sky.fog_sun_tint = video::SColor(255, 244, 125, 29);