From eb512cc36abf436fa19585cc7938c9077034f3bc Mon Sep 17 00:00:00 2001 From: JosiahWI <41302989+JosiahWI@users.noreply.github.com> Date: Sat, 4 Jan 2025 05:38:38 -0600 Subject: [PATCH 01/44] Eliminate superfluous null check in CGUIEnvironment::getNextElement --- irr/src/CGUIEnvironment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irr/src/CGUIEnvironment.cpp b/irr/src/CGUIEnvironment.cpp index b40896327..31e7038f4 100644 --- a/irr/src/CGUIEnvironment.cpp +++ b/irr/src/CGUIEnvironment.cpp @@ -948,7 +948,7 @@ IGUIElement *CGUIEnvironment::getNextElement(bool reverse, bool group) // this element is not part of the tab cycle, // but its parent might be... IGUIElement *el = Focus; - while (el && el->getParent() && startOrder == -1) { + while (el->getParent() && startOrder == -1) { el = el->getParent(); startOrder = el->getTabOrder(); } From 81f51492ff128492b083f98536e4d3b4352afa84 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 4 Jan 2025 12:39:16 +0100 Subject: [PATCH 02/44] Don't silence errorstream in tests (#15629) --- src/unittest/test.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index 8c20b0ed5..8f0eaf855 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -212,8 +212,6 @@ bool run_tests() u64 t1 = porting::getTimeMs(); TestGameDef gamedef; - g_logger.setLevelSilenced(LL_ERROR, true); - u32 num_modules_failed = 0; u32 num_total_tests_failed = 0; u32 num_total_tests_run = 0; @@ -243,11 +241,9 @@ bool run_tests() u64 tdiff = porting::getTimeMs() - t1; - g_logger.setLevelSilenced(LL_ERROR, false); - const char *overall_status = (num_modules_failed == 0) ? "PASSED" : "FAILED"; - rawstream + rawstream << "\n" << "++++++++++++++++++++++++++++++++++++++++" << "++++++++++++++++++++++++++++++++++++++++" << std::endl << "Unit Test Results: " << overall_status << std::endl @@ -283,17 +279,15 @@ bool run_tests(const std::string &module_name) return catch_test_failures == 0; } - g_logger.setLevelSilenced(LL_ERROR, true); u64 t1 = porting::getTimeMs(); bool ok = testmod->testModule(&gamedef); u64 tdiff = porting::getTimeMs() - t1; - g_logger.setLevelSilenced(LL_ERROR, false); const char *overall_status = ok ? "PASSED" : "FAILED"; - rawstream + rawstream << "\n" << "++++++++++++++++++++++++++++++++++++++++" << "++++++++++++++++++++++++++++++++++++++++" << std::endl << "Unit Test Results: " << overall_status << std::endl From e8f6127779423dbe417184a629a65e9723a155e7 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Sat, 4 Jan 2025 12:39:34 +0100 Subject: [PATCH 03/44] Reduce irrlicht_extrabloated.h includes in header files --- irr/include/IGUIButton.h | 1 + irr/include/IGUIElement.h | 3 ++- irr/include/IGUIImage.h | 1 + src/activeobjectmgr.h | 1 - src/chat_interface.h | 5 ++--- src/client/client.cpp | 1 + src/client/content_cao.h | 16 ++++++++++++---- src/client/inputhandler.h | 1 + src/client/joystick_controller.h | 4 +++- src/client/mapblock_mesh.h | 9 ++++++++- src/client/mesh.cpp | 4 +++- src/client/mesh.h | 12 +++++++++++- src/client/minimap.h | 23 ++++++++++++++++++++--- src/client/particles.cpp | 2 ++ src/client/particles.h | 13 +++++++++++-- src/content/content.h | 3 +-- src/debug.h | 3 +-- src/emerge.h | 1 - src/gui/mainmenumanager.h | 6 ++++++ src/gui/modalMenu.h | 4 +++- src/gui/touchscreeneditor.h | 1 + src/network/serverpackethandler.cpp | 1 + src/objdef.cpp | 3 +++ src/objdef.h | 5 +++-- src/reflowscan.h | 3 ++- src/server.cpp | 1 + src/server/clientiface.cpp | 1 + src/server/clientiface.h | 18 +++++++++--------- src/servermap.h | 4 ++-- src/unittest/test.h | 2 +- src/unittest/test_compression.cpp | 1 - 31 files changed, 113 insertions(+), 40 deletions(-) diff --git a/irr/include/IGUIButton.h b/irr/include/IGUIButton.h index 8870f8b1c..fdee609d9 100644 --- a/irr/include/IGUIButton.h +++ b/irr/include/IGUIButton.h @@ -5,6 +5,7 @@ #pragma once #include "IGUIElement.h" +#include "SColor.h" namespace irr { diff --git a/irr/include/IGUIElement.h b/irr/include/IGUIElement.h index 429bc06b3..cdd3d7487 100644 --- a/irr/include/IGUIElement.h +++ b/irr/include/IGUIElement.h @@ -10,7 +10,6 @@ #include "IEventReceiver.h" #include "EGUIElementTypes.h" #include "EGUIAlignment.h" -#include "IGUIEnvironment.h" #include #include #include @@ -19,6 +18,8 @@ namespace irr { namespace gui { +class IGUIEnvironment; + //! Base class of all GUI elements. class IGUIElement : virtual public IReferenceCounted, public IEventReceiver { diff --git a/irr/include/IGUIImage.h b/irr/include/IGUIImage.h index 33453a3cd..cc3c66eb9 100644 --- a/irr/include/IGUIImage.h +++ b/irr/include/IGUIImage.h @@ -5,6 +5,7 @@ #pragma once #include "IGUIElement.h" +#include "SColor.h" namespace irr { diff --git a/src/activeobjectmgr.h b/src/activeobjectmgr.h index 943147160..a9b007018 100644 --- a/src/activeobjectmgr.h +++ b/src/activeobjectmgr.h @@ -5,7 +5,6 @@ #pragma once #include -#include "debug.h" #include "util/container.h" #include "irrlichttypes.h" #include "util/basic_macros.h" diff --git a/src/chat_interface.h b/src/chat_interface.h index 1276c3a23..6ee1451db 100644 --- a/src/chat_interface.h +++ b/src/chat_interface.h @@ -4,10 +4,9 @@ #pragma once -#include "util/container.h" -#include -#include #include "irrlichttypes.h" +#include "util/container.h" // MutexedQueue +#include enum ChatEventType { CET_CHAT, diff --git a/src/client/client.cpp b/src/client/client.cpp index 222c1a2ac..b709f8cbf 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -37,6 +37,7 @@ #include "profiler.h" #include "shader.h" #include "gettext.h" +#include "gettime.h" #include "clientdynamicinfo.h" #include "clientmap.h" #include "clientmedia.h" diff --git a/src/client/content_cao.h b/src/client/content_cao.h index 1115b6819..a6b9beeab 100644 --- a/src/client/content_cao.h +++ b/src/client/content_cao.h @@ -4,15 +4,23 @@ #pragma once -#include -#include "irrlichttypes_extrabloated.h" -#include "clientobject.h" +#include "EMaterialTypes.h" +#include "IDummyTransformationSceneNode.h" +#include "irrlichttypes.h" + #include "object_properties.h" -#include "itemgroup.h" +#include "clientobject.h" #include "constants.h" +#include "itemgroup.h" #include +#include #include +namespace irr::scene { + class IMeshSceneNode; + class IBillboardSceneNode; +} + class Camera; class Client; struct Nametag; diff --git a/src/client/inputhandler.h b/src/client/inputhandler.h index b34c22d78..542c41bc7 100644 --- a/src/client/inputhandler.h +++ b/src/client/inputhandler.h @@ -5,6 +5,7 @@ #pragma once #include "irrlichttypes.h" +#include "irr_v2d.h" #include "joystick_controller.h" #include #include "keycode.h" diff --git a/src/client/joystick_controller.h b/src/client/joystick_controller.h index c5302b533..d7bf4230e 100644 --- a/src/client/joystick_controller.h +++ b/src/client/joystick_controller.h @@ -4,7 +4,9 @@ #pragma once -#include "irrlichttypes_extrabloated.h" +#include +#include "irrlichttypes.h" + #include "keys.h" #include #include diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h index e7cadb3db..0b9b437db 100644 --- a/src/client/mapblock_mesh.h +++ b/src/client/mapblock_mesh.h @@ -4,8 +4,11 @@ #pragma once -#include "irrlichttypes_extrabloated.h" +#include "irrlichttypes.h" #include "irr_ptr.h" +#include "IMesh.h" +#include "SMeshBuffer.h" + #include "util/numeric.h" #include "client/tile.h" #include "voxel.h" @@ -13,6 +16,10 @@ #include #include +namespace irr::video { + class IVideoDriver; +} + class Client; class NodeDefManager; class IShaderSource; diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp index cd2e9a91d..a2c0ae327 100644 --- a/src/client/mesh.cpp +++ b/src/client/mesh.cpp @@ -3,7 +3,6 @@ // Copyright (C) 2010-2013 celeron55, Perttu Ahola #include "mesh.h" -#include "S3DVertex.h" #include "debug.h" #include "log.h" #include @@ -11,6 +10,9 @@ #include #include #include +#include "S3DVertex.h" +#include "SMesh.h" +#include "SMeshBuffer.h" inline static void applyShadeFactor(video::SColor& color, float factor) { diff --git a/src/client/mesh.h b/src/client/mesh.h index 3345e24f7..d8eb6080e 100644 --- a/src/client/mesh.h +++ b/src/client/mesh.h @@ -4,10 +4,20 @@ #pragma once +#include "SColor.h" #include "SMaterialLayer.h" -#include "irrlichttypes_extrabloated.h" #include "nodedef.h" +namespace irr { + namespace scene { + class IAnimatedMesh; + class IMesh; + class IMeshBuffer; + } +} + +using namespace irr; + /*! * Applies shading to a color based on the surface's * normal vector. diff --git a/src/client/minimap.h b/src/client/minimap.h index 15112d565..36c900134 100644 --- a/src/client/minimap.h +++ b/src/client/minimap.h @@ -4,18 +4,35 @@ #pragma once -#include "../hud.h" -#include "irrlichttypes_extrabloated.h" +#include "irrlichttypes.h" #include "irr_ptr.h" +#include "rect.h" +#include "SMeshBuffer.h" + +#include "../hud.h" +#include "mapnode.h" #include "util/thread.h" -#include "voxel.h" #include #include #include +namespace irr { + namespace video { + class IVideoDriver; + class IImage; + class ITexture; + } + + namespace scene { + class ISceneNode; + } +} + class Client; +class NodeDefManager; class ITextureSource; class IShaderSource; +class VoxelManipulator; #define MINIMAP_MAX_SX 512 #define MINIMAP_MAX_SY 512 diff --git a/src/client/particles.cpp b/src/client/particles.cpp index cd9b9b736..693e5f00c 100644 --- a/src/client/particles.cpp +++ b/src/client/particles.cpp @@ -22,6 +22,8 @@ #include "settings.h" #include "profiler.h" +#include "SMeshBuffer.h" + using BlendMode = ParticleParamTypes::BlendMode; ClientParticleTexture::ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *tsrc) diff --git a/src/client/particles.h b/src/client/particles.h index 619877744..72294a552 100644 --- a/src/client/particles.h +++ b/src/client/particles.h @@ -4,12 +4,21 @@ #pragma once +#include "irrlichttypes_bloated.h" +#include "irr_ptr.h" +#include "ISceneNode.h" +#include "S3DVertex.h" +#include "SMeshBuffer.h" + +#include #include #include -#include "irrlichttypes_extrabloated.h" -#include "irr_ptr.h" #include "../particles.h" +namespace irr::video { + class ITexture; +} + struct ClientEvent; class ParticleManager; class ClientEnvironment; diff --git a/src/content/content.h b/src/content/content.h index 2a98efe11..215a28174 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -3,9 +3,8 @@ // Copyright (C) 2018 rubenwardy #pragma once -#include "config.h" -#include "convert_json.h" #include "irrlichttypes.h" +#include enum class ContentType { diff --git a/src/debug.h b/src/debug.h index e1c9c6298..ecd3f8e18 100644 --- a/src/debug.h +++ b/src/debug.h @@ -6,8 +6,7 @@ #include #include -#include "gettime.h" -#include "log.h" +#include "log.h" // unused. for convenience. #ifdef _MSC_VER #define FUNCTION_NAME __FUNCTION__ diff --git a/src/emerge.h b/src/emerge.h index 85ce9875f..c7a7d62d4 100644 --- a/src/emerge.h +++ b/src/emerge.h @@ -8,7 +8,6 @@ #include #include "network/networkprotocol.h" #include "irr_v3d.h" -#include "util/container.h" #include "util/metricsbackend.h" #include "mapgen/mapgen.h" // for MapgenParams #include "map.h" diff --git a/src/gui/mainmenumanager.h b/src/gui/mainmenumanager.h index 9d10e3960..87751bb62 100644 --- a/src/gui/mainmenumanager.h +++ b/src/gui/mainmenumanager.h @@ -11,6 +11,12 @@ #include #include +#include "IGUIEnvironment.h" + +namespace irr::gui { + class IGUIStaticText; +} + class IGameCallback { public: diff --git a/src/gui/modalMenu.h b/src/gui/modalMenu.h index 62cbcfc1d..81888e866 100644 --- a/src/gui/modalMenu.h +++ b/src/gui/modalMenu.h @@ -4,8 +4,10 @@ #pragma once -#include "irrlichttypes_extrabloated.h" +#include "IGUIElement.h" +#include "irrlichttypes_bloated.h" #include "irr_ptr.h" + #include "util/string.h" #ifdef __ANDROID__ #include diff --git a/src/gui/touchscreeneditor.h b/src/gui/touchscreeneditor.h index dc06fb224..6c70eb693 100644 --- a/src/gui/touchscreeneditor.h +++ b/src/gui/touchscreeneditor.h @@ -13,6 +13,7 @@ class ISimpleTextureSource; namespace irr::gui { + class IGUIButton; class IGUIImage; } diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index cf1dcacb1..89fe3bf22 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -18,6 +18,7 @@ #include "version.h" #include "irrlicht_changes/printing.h" #include "network/connection.h" +#include "network/networkpacket.h" #include "network/networkprotocol.h" #include "network/serveropcodes.h" #include "server/player_sao.h" diff --git a/src/objdef.cpp b/src/objdef.cpp index f61d12f30..b8b11b7b7 100644 --- a/src/objdef.cpp +++ b/src/objdef.cpp @@ -6,6 +6,9 @@ #include "util/numeric.h" #include "log.h" #include "gamedef.h" +#include "porting.h" // strcasecmp + +#include ObjDefManager::ObjDefManager(IGameDef *gamedef, ObjDefType type) { diff --git a/src/objdef.h b/src/objdef.h index 93dd78837..ec52aa831 100644 --- a/src/objdef.h +++ b/src/objdef.h @@ -4,8 +4,9 @@ #pragma once -#include "util/basic_macros.h" -#include "porting.h" +#include "util/basic_macros.h" // DISABLE_CLASS_COPY +#include "irrlichttypes.h" +#include #include class IGameDef; diff --git a/src/reflowscan.h b/src/reflowscan.h index 66fec9ea6..70890c9bc 100644 --- a/src/reflowscan.h +++ b/src/reflowscan.h @@ -5,7 +5,8 @@ #pragma once #include "util/container.h" -#include "irrlichttypes_bloated.h" +#include "irrlichttypes.h" +#include "irr_v3d.h" class NodeDefManager; class Map; diff --git a/src/server.cpp b/src/server.cpp index 1556de406..92860cbbf 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -8,6 +8,7 @@ #include #include "irr_v2d.h" #include "network/connection.h" +#include "network/networkpacket.h" #include "network/networkprotocol.h" #include "network/serveropcodes.h" #include "server/ban.h" diff --git a/src/server/clientiface.cpp b/src/server/clientiface.cpp index b114c6c84..d05fedbb2 100644 --- a/src/server/clientiface.cpp +++ b/src/server/clientiface.cpp @@ -6,6 +6,7 @@ #include "clientiface.h" #include "debug.h" #include "network/connection.h" +#include "network/networkpacket.h" #include "network/serveropcodes.h" #include "remoteplayer.h" #include "serialization.h" // SER_FMT_VER_INVALID diff --git a/src/server/clientiface.h b/src/server/clientiface.h index 294bcbd26..5324ee727 100644 --- a/src/server/clientiface.h +++ b/src/server/clientiface.h @@ -6,25 +6,25 @@ #include "irr_v3d.h" // for irrlicht datatypes -#include "constants.h" -#include "network/networkpacket.h" -#include "network/networkprotocol.h" #include "network/address.h" +#include "network/networkprotocol.h" // session_t #include "porting.h" #include "threading/mutex_auto_lock.h" #include "clientdynamicinfo.h" #include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include -class MapBlock; -class ServerEnvironment; class EmergeManager; +class MapBlock; +class NetworkPacket; +class ServerEnvironment; /* * State Transitions diff --git a/src/servermap.h b/src/servermap.h index 203020006..73b35e38f 100644 --- a/src/servermap.h +++ b/src/servermap.h @@ -8,8 +8,8 @@ #include #include "map.h" -#include "util/container.h" -#include "util/metricsbackend.h" +#include "util/container.h" // UniqueQueue +#include "util/metricsbackend.h" // ptr typedefs #include "map_settings_manager.h" class Settings; diff --git a/src/unittest/test.h b/src/unittest/test.h index cc772f670..dcecb9fb4 100644 --- a/src/unittest/test.h +++ b/src/unittest/test.h @@ -9,7 +9,7 @@ #include #include -#include "irrlichttypes_extrabloated.h" +#include "irrlichttypes_bloated.h" #include "porting.h" #include "filesys.h" #include "mapnode.h" diff --git a/src/unittest/test_compression.cpp b/src/unittest/test_compression.cpp index ad8dba2fc..35c500a52 100644 --- a/src/unittest/test_compression.cpp +++ b/src/unittest/test_compression.cpp @@ -6,7 +6,6 @@ #include -#include "irrlichttypes_extrabloated.h" #include "log.h" #include "serialization.h" #include "nodedef.h" From d2004d32f6561e59754f90dc50f774ed8f768afe Mon Sep 17 00:00:00 2001 From: wrrrzr <161970349+wrrrzr@users.noreply.github.com> Date: Sat, 4 Jan 2025 14:39:52 +0300 Subject: [PATCH 04/44] Move AutoExposure constructor to header --- src/CMakeLists.txt | 1 - src/lighting.cpp | 14 -------------- src/lighting.h | 9 ++++++++- 3 files changed, 8 insertions(+), 16 deletions(-) delete mode 100644 src/lighting.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 692651049..88c0c5a45 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -417,7 +417,6 @@ set(independent_SRCS hud.cpp inventory.cpp itemstackmetadata.cpp - lighting.cpp log.cpp metadata.cpp modchannels.cpp diff --git a/src/lighting.cpp b/src/lighting.cpp deleted file mode 100644 index b8def7728..000000000 --- a/src/lighting.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// Luanti -// SPDX-License-Identifier: LGPL-2.1-or-later -// Copyright (C) 2021 x2048, Dmitry Kostenko - -#include "lighting.h" - -AutoExposure::AutoExposure() - : luminance_min(-3.f), - luminance_max(-3.f), - exposure_correction(0.0f), - speed_dark_bright(1000.f), - speed_bright_dark(1000.f), - center_weight_power(1.f) -{} diff --git a/src/lighting.h b/src/lighting.h index ab40d546d..4ba1b37ef 100644 --- a/src/lighting.h +++ b/src/lighting.h @@ -30,7 +30,14 @@ struct AutoExposure /// @brief Power value for center-weighted metering. Value of 1.0 measures entire screen uniformly float center_weight_power; - AutoExposure(); + constexpr AutoExposure() + : luminance_min(-3.f), + luminance_max(-3.f), + exposure_correction(0.0f), + speed_dark_bright(1000.f), + speed_bright_dark(1000.f), + center_weight_power(1.f) + {} }; /** Describes ambient light settings for a player From 9554e3d43a72a55de06d4f1b9168af29a929600a Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 29 Dec 2024 19:24:33 +0100 Subject: [PATCH 05/44] Add support for glObjectLabel to aid debugging --- irr/src/COpenGLCoreTexture.h | 6 ++++++ irr/src/COpenGLExtensionHandler.h | 4 ++++ irr/src/OpenGL/Driver.cpp | 23 +++++++++++++++-------- irr/src/OpenGL/ExtensionHandler.h | 13 +++++++++++++ irr/src/OpenGL/MaterialRenderer.cpp | 7 ++++++- irr/src/OpenGL/MaterialRenderer.h | 5 ++++- irr/src/OpenGL/Renderer2D.cpp | 4 ++-- irr/src/OpenGL3/Driver.cpp | 3 +++ irr/src/OpenGLES2/Driver.cpp | 3 +++ 9 files changed, 56 insertions(+), 12 deletions(-) diff --git a/irr/src/COpenGLCoreTexture.h b/irr/src/COpenGLCoreTexture.h index d8a813d5d..2254076a7 100644 --- a/irr/src/COpenGLCoreTexture.h +++ b/irr/src/COpenGLCoreTexture.h @@ -137,6 +137,9 @@ public: Images.clear(); } + if (!name.empty()) + Driver->irrGlObjectLabel(GL_TEXTURE, TextureName, name.c_str()); + Driver->getCacheHandler()->getTextureCache().set(0, prevTexture); TEST_GL_ERROR(Driver); @@ -247,6 +250,9 @@ public: break; } + if (!name.empty()) + Driver->irrGlObjectLabel(GL_TEXTURE, TextureName, name.c_str()); + Driver->getCacheHandler()->getTextureCache().set(0, prevTexture); if (TEST_GL_ERROR(Driver)) { char msg[256]; diff --git a/irr/src/COpenGLExtensionHandler.h b/irr/src/COpenGLExtensionHandler.h index a1754a328..63c55f26c 100644 --- a/irr/src/COpenGLExtensionHandler.h +++ b/irr/src/COpenGLExtensionHandler.h @@ -1065,6 +1065,10 @@ public: void irrGlCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); + inline void irrGlObjectLabel(GLenum identifier, GLuint name, const char *label) + { + // unimplemented + } // shader programming void extGlGenPrograms(GLsizei n, GLuint *programs); diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index c33b3c9d9..31fb7a177 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -164,13 +164,6 @@ COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters ¶ms ExposedData = ContextManager->getContext(); ContextManager->activateContext(ExposedData, false); GL.LoadAllProcedures(ContextManager); - if (EnableErrorTest && GL.IsExtensionPresent("GL_KHR_debug")) { - GL.Enable(GL_DEBUG_OUTPUT); - GL.DebugMessageCallback(debugCb, this); - } else if (EnableErrorTest) { - os::Printer::log("GL debug extension not available"); - } - initQuadsIndices(); TEST_GL_ERROR(this); } @@ -248,6 +241,20 @@ bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d &screenS initFeatures(); printTextureFormats(); + if (EnableErrorTest) { + if (KHRDebugSupported) { + GL.Enable(GL_DEBUG_OUTPUT); + GL.DebugMessageCallback(debugCb, this); + } else { + os::Printer::log("GL debug extension not available"); + } + } else { + // don't do debug things if they are not wanted (even if supported) + KHRDebugSupported = false; + } + + initQuadsIndices(); + // reset cache handler delete CacheHandler; CacheHandler = new COpenGL3CacheHandler(this); @@ -1615,7 +1622,7 @@ s32 COpenGL3DriverBase::addHighLevelShaderMaterial( s32 nr = -1; COpenGL3MaterialRenderer *r = new COpenGL3MaterialRenderer( this, nr, vertexShaderProgram, - pixelShaderProgram, + pixelShaderProgram, shaderName, callback, baseMaterial, userData); r->drop(); diff --git a/irr/src/OpenGL/ExtensionHandler.h b/irr/src/OpenGL/ExtensionHandler.h index 0e3a0af2d..209fd415b 100644 --- a/irr/src/OpenGL/ExtensionHandler.h +++ b/irr/src/OpenGL/ExtensionHandler.h @@ -161,10 +161,23 @@ public: GL.BlendEquation(mode); } + inline void irrGlObjectLabel(GLenum identifier, GLuint name, const char *label) + { + if (KHRDebugSupported) { + u32 len = strlen(label); + // Since our texture strings can get quite long we also truncate + // to a hardcoded limit of 82 + len = std::min(len, std::min(MaxLabelLength, 82U)); + GL.ObjectLabel(identifier, name, len, label); + } + } + bool LODBiasSupported = false; bool AnisotropicFilterSupported = false; bool BlendMinMaxSupported = false; bool TextureMultisampleSupported = false; + bool KHRDebugSupported = false; + u32 MaxLabelLength = 0; }; } diff --git a/irr/src/OpenGL/MaterialRenderer.cpp b/irr/src/OpenGL/MaterialRenderer.cpp index 7439dba61..269f28ae9 100644 --- a/irr/src/OpenGL/MaterialRenderer.cpp +++ b/irr/src/OpenGL/MaterialRenderer.cpp @@ -24,6 +24,7 @@ COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase *driver, s32 &outMaterialTypeNr, const c8 *vertexShaderProgram, const c8 *pixelShaderProgram, + const c8 *debugName, IShaderConstantSetCallBack *callback, E_MATERIAL_TYPE baseMaterial, s32 userData) : @@ -45,7 +46,7 @@ COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase *driver, if (CallBack) CallBack->grab(); - init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram); + init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram, debugName); } COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase *driver, @@ -98,6 +99,7 @@ GLuint COpenGL3MaterialRenderer::getProgram() const void COpenGL3MaterialRenderer::init(s32 &outMaterialTypeNr, const c8 *vertexShaderProgram, const c8 *pixelShaderProgram, + const c8 *debugName, bool addMaterial) { outMaterialTypeNr = -1; @@ -121,6 +123,9 @@ void COpenGL3MaterialRenderer::init(s32 &outMaterialTypeNr, if (!linkProgram()) return; + if (debugName) + Driver->irrGlObjectLabel(GL_PROGRAM, Program, debugName); + if (addMaterial) outMaterialTypeNr = Driver->addMaterialRenderer(this); } diff --git a/irr/src/OpenGL/MaterialRenderer.h b/irr/src/OpenGL/MaterialRenderer.h index fca71478a..0916f1ad5 100644 --- a/irr/src/OpenGL/MaterialRenderer.h +++ b/irr/src/OpenGL/MaterialRenderer.h @@ -28,6 +28,7 @@ public: s32 &outMaterialTypeNr, const c8 *vertexShaderProgram = 0, const c8 *pixelShaderProgram = 0, + const c8 *debugName = nullptr, IShaderConstantSetCallBack *callback = 0, E_MATERIAL_TYPE baseMaterial = EMT_SOLID, s32 userData = 0); @@ -66,7 +67,9 @@ protected: E_MATERIAL_TYPE baseMaterial = EMT_SOLID, s32 userData = 0); - void init(s32 &outMaterialTypeNr, const c8 *vertexShaderProgram, const c8 *pixelShaderProgram, bool addMaterial = true); + void init(s32 &outMaterialTypeNr, const c8 *vertexShaderProgram, + const c8 *pixelShaderProgram, const c8 *debugName = nullptr, + bool addMaterial = true); bool createShader(GLenum shaderType, const char *shader); bool linkProgram(); diff --git a/irr/src/OpenGL/Renderer2D.cpp b/irr/src/OpenGL/Renderer2D.cpp index b7b8edf1b..ec53cc9f9 100644 --- a/irr/src/OpenGL/Renderer2D.cpp +++ b/irr/src/OpenGL/Renderer2D.cpp @@ -23,8 +23,8 @@ COpenGL3Renderer2D::COpenGL3Renderer2D(const c8 *vertexShaderProgram, const c8 * WithTexture(withTexture) { int Temp = 0; - - init(Temp, vertexShaderProgram, pixelShaderProgram, false); + init(Temp, vertexShaderProgram, pixelShaderProgram, + withTexture ? "2DTexture" : "2DNoTexture", false); COpenGL3CacheHandler *cacheHandler = Driver->getCacheHandler(); diff --git a/irr/src/OpenGL3/Driver.cpp b/irr/src/OpenGL3/Driver.cpp index 767ce5992..7a62f4a12 100644 --- a/irr/src/OpenGL3/Driver.cpp +++ b/irr/src/OpenGL3/Driver.cpp @@ -72,6 +72,9 @@ void COpenGL3Driver::initFeatures() LODBiasSupported = true; BlendMinMaxSupported = true; TextureMultisampleSupported = true; + KHRDebugSupported = isVersionAtLeast(4, 6) || queryExtension("GL_KHR_debug"); + if (KHRDebugSupported) + MaxLabelLength = GetInteger(GL.MAX_LABEL_LENGTH); // COGLESCoreExtensionHandler::Feature static_assert(MATERIAL_MAX_TEXTURES <= 16, "Only up to 16 textures are guaranteed"); diff --git a/irr/src/OpenGLES2/Driver.cpp b/irr/src/OpenGLES2/Driver.cpp index 25c4f485d..6b234842a 100644 --- a/irr/src/OpenGLES2/Driver.cpp +++ b/irr/src/OpenGLES2/Driver.cpp @@ -124,6 +124,9 @@ void COpenGLES2Driver::initFeatures() AnisotropicFilterSupported = queryExtension("GL_EXT_texture_filter_anisotropic"); BlendMinMaxSupported = (Version.Major >= 3) || FeatureAvailable[IRR_GL_EXT_blend_minmax]; TextureMultisampleSupported = isVersionAtLeast(3, 1); + KHRDebugSupported = queryExtension("GL_KHR_debug"); + if (KHRDebugSupported) + MaxLabelLength = GetInteger(GL.MAX_LABEL_LENGTH); // COGLESCoreExtensionHandler::Feature static_assert(MATERIAL_MAX_TEXTURES <= 8, "Only up to 8 textures are guaranteed"); From 4e2ca05f0895776ecc8e2b9464faf6f9cd7d398c Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 2 Jan 2025 11:18:37 +0100 Subject: [PATCH 06/44] Add debug mode that shows mesh buffer bounding boxes --- irr/include/EDebugSceneTypes.h | 2 +- irr/include/ISceneManager.h | 8 +++++ irr/include/ISceneNode.h | 12 +++---- irr/src/CAnimatedMeshSceneNode.cpp | 6 ++-- irr/src/CMeshSceneNode.cpp | 8 +++-- irr/src/CSceneManager.cpp | 18 ++++++---- irr/src/CSceneManager.h | 8 +++++ src/client/game.cpp | 54 +++++++++++++++--------------- 8 files changed, 70 insertions(+), 46 deletions(-) diff --git a/irr/include/EDebugSceneTypes.h b/irr/include/EDebugSceneTypes.h index 29ca8ad0e..2994eca6c 100644 --- a/irr/include/EDebugSceneTypes.h +++ b/irr/include/EDebugSceneTypes.h @@ -34,7 +34,7 @@ enum E_DEBUG_SCENE_TYPE EDS_BBOX_ALL = EDS_BBOX | EDS_BBOX_BUFFERS, //! Show all debug infos - EDS_FULL = 0xffffffff + EDS_FULL = 0xffff }; } // end namespace scene diff --git a/irr/include/ISceneManager.h b/irr/include/ISceneManager.h index 25e1e5fe4..31604214f 100644 --- a/irr/include/ISceneManager.h +++ b/irr/include/ISceneManager.h @@ -387,6 +387,14 @@ public: pass currently is active they can render the correct part of their geometry. */ virtual E_SCENE_NODE_RENDER_PASS getSceneNodeRenderPass() const = 0; + /** + * Sets debug data flags that will be set on every rendered scene node. + * Refer to `E_DEBUG_SCENE_TYPE`. + * @param setBits bit mask of types to enable + * @param unsetBits bit mask of types to disable + */ + virtual void setGlobalDebugData(u16 setBits, u16 unsetBits) = 0; + //! Creates a new scene manager. /** This can be used to easily draw and/or store two independent scenes at the same time. The mesh cache will be diff --git a/irr/include/ISceneNode.h b/irr/include/ISceneNode.h index 0438d855f..897cfb350 100644 --- a/irr/include/ISceneNode.h +++ b/irr/include/ISceneNode.h @@ -403,14 +403,14 @@ public: their geometry because it is their only reason for existence, for example the OctreeSceneNode. \param state The culling state to be used. Check E_CULLING_TYPE for possible values.*/ - void setAutomaticCulling(u32 state) + void setAutomaticCulling(u16 state) { AutomaticCullingState = state; } //! Gets the automatic culling state. /** \return The automatic culling state. */ - u32 getAutomaticCulling() const + u16 getAutomaticCulling() const { return AutomaticCullingState; } @@ -419,7 +419,7 @@ public: /** A bitwise OR of the types from @ref irr::scene::E_DEBUG_SCENE_TYPE. Please note that not all scene nodes support all debug data types. \param state The debug data visibility state to be used. */ - virtual void setDebugDataVisible(u32 state) + virtual void setDebugDataVisible(u16 state) { DebugDataVisible = state; } @@ -427,7 +427,7 @@ public: //! Returns if debug data like bounding boxes are drawn. /** \return A bitwise OR of the debug data values from @ref irr::scene::E_DEBUG_SCENE_TYPE that are currently visible. */ - u32 isDebugDataVisible() const + u16 isDebugDataVisible() const { return DebugDataVisible; } @@ -581,10 +581,10 @@ protected: s32 ID; //! Automatic culling state - u32 AutomaticCullingState; + u16 AutomaticCullingState; //! Flag if debug data should be drawn, such as Bounding Boxes. - u32 DebugDataVisible; + u16 DebugDataVisible; //! Is the node visible? bool IsVisible; diff --git a/irr/src/CAnimatedMeshSceneNode.cpp b/irr/src/CAnimatedMeshSceneNode.cpp index 3871d52a3..dffc867de 100644 --- a/irr/src/CAnimatedMeshSceneNode.cpp +++ b/irr/src/CAnimatedMeshSceneNode.cpp @@ -276,9 +276,6 @@ void CAnimatedMeshSceneNode::render() debug_mat.ZBuffer = video::ECFN_DISABLED; driver->setMaterial(debug_mat); - if (DebugDataVisible & scene::EDS_BBOX) - driver->draw3DBox(Box, video::SColor(255, 255, 255, 255)); - // show bounding box if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) { for (u32 g = 0; g < m->getMeshBufferCount(); ++g) { @@ -290,6 +287,9 @@ void CAnimatedMeshSceneNode::render() } } + if (DebugDataVisible & scene::EDS_BBOX) + driver->draw3DBox(Box, video::SColor(255, 255, 255, 255)); + // show skeleton if (DebugDataVisible & scene::EDS_SKELETON) { if (Mesh->getMeshType() == EAMT_SKINNED) { diff --git a/irr/src/CMeshSceneNode.cpp b/irr/src/CMeshSceneNode.cpp index 2d9e400e9..cffdbf855 100644 --- a/irr/src/CMeshSceneNode.cpp +++ b/irr/src/CMeshSceneNode.cpp @@ -110,11 +110,9 @@ void CMeshSceneNode::render() if (DebugDataVisible && PassCount == 1) { video::SMaterial m; m.AntiAliasing = 0; + m.ZBuffer = video::ECFN_DISABLED; driver->setMaterial(m); - if (DebugDataVisible & scene::EDS_BBOX) { - driver->draw3DBox(Box, video::SColor(255, 255, 255, 255)); - } if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) { for (u32 g = 0; g < Mesh->getMeshBufferCount(); ++g) { driver->draw3DBox( @@ -123,6 +121,10 @@ void CMeshSceneNode::render() } } + if (DebugDataVisible & scene::EDS_BBOX) { + driver->draw3DBox(Box, video::SColor(255, 255, 255, 255)); + } + if (DebugDataVisible & scene::EDS_NORMALS) { // draw normals const f32 debugNormalLength = 1.f; diff --git a/irr/src/CSceneManager.cpp b/irr/src/CSceneManager.cpp index d8a147b34..23e5335ce 100644 --- a/irr/src/CSceneManager.cpp +++ b/irr/src/CSceneManager.cpp @@ -490,13 +490,19 @@ void CSceneManager::drawAll() // let all nodes register themselves OnRegisterSceneNode(); + const auto &render_node = [this] (ISceneNode *node) { + u32 flags = node->isDebugDataVisible(); + node->setDebugDataVisible((flags & DebugDataMask) | DebugDataBits); + node->render(); + }; + // render camera scenes { CurrentRenderPass = ESNRP_CAMERA; Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); for (auto *node : CameraList) - node->render(); + render_node(node); CameraList.clear(); } @@ -507,7 +513,7 @@ void CSceneManager::drawAll() Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); for (auto *node : SkyBoxList) - node->render(); + render_node(node); SkyBoxList.clear(); } @@ -520,7 +526,7 @@ void CSceneManager::drawAll() std::sort(SolidNodeList.begin(), SolidNodeList.end()); for (auto &it : SolidNodeList) - it.Node->render(); + render_node(it.Node); SolidNodeList.clear(); } @@ -533,7 +539,7 @@ void CSceneManager::drawAll() std::sort(TransparentNodeList.begin(), TransparentNodeList.end()); for (auto &it : TransparentNodeList) - it.Node->render(); + render_node(it.Node); TransparentNodeList.clear(); } @@ -546,7 +552,7 @@ void CSceneManager::drawAll() std::sort(TransparentEffectNodeList.begin(), TransparentEffectNodeList.end()); for (auto &it : TransparentEffectNodeList) - it.Node->render(); + render_node(it.Node); TransparentEffectNodeList.clear(); } @@ -557,7 +563,7 @@ void CSceneManager::drawAll() Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); for (auto *node : GuiNodeList) - node->render(); + render_node(node); GuiNodeList.clear(); } diff --git a/irr/src/CSceneManager.h b/irr/src/CSceneManager.h index 2a4fb7f7b..8f03a1fec 100644 --- a/irr/src/CSceneManager.h +++ b/irr/src/CSceneManager.h @@ -179,6 +179,11 @@ public: //! Set current render time. void setCurrentRenderPass(E_SCENE_NODE_RENDER_PASS nextPass) override { CurrentRenderPass = nextPass; } + void setGlobalDebugData(u16 setBits, u16 unsetBits) override { + DebugDataMask = ~unsetBits; + DebugDataBits = setBits; + } + //! returns if node is culled bool isCulled(const ISceneNode *node) const override; @@ -268,6 +273,9 @@ private: //! Mesh cache IMeshCache *MeshCache; + //! Global debug render state + u16 DebugDataMask = 0, DebugDataBits = 0; + E_SCENE_NODE_RENDER_PASS CurrentRenderPass; }; diff --git a/src/client/game.cpp b/src/client/game.cpp index c5f67a745..f04e265e9 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -427,6 +427,8 @@ public: const static float object_hit_delay = 0.2; +const static u16 bbox_debug_flag = scene::EDS_BBOX_ALL; + /* The reason the following structs are not anonymous structs within the * class is that they are not used by the majority of member functions and * many functions that do require objects of thse types do not modify them @@ -635,6 +637,8 @@ protected: private: struct Flags { bool disable_camera_update = false; + /// 0 = no debug text active, see toggleDebug() for the rest + int debug_state = 0; }; void pauseAnimation(); @@ -1663,6 +1667,7 @@ void Game::updateDebugState() hud->disableBlockBounds(); if (!has_debug) { draw_control->show_wireframe = false; + smgr->setGlobalDebugData(0, bbox_debug_flag); m_flags.disable_camera_update = false; m_game_formspec.disableDebugView(); } @@ -2222,46 +2227,41 @@ void Game::toggleDebug() LocalPlayer *player = client->getEnv().getLocalPlayer(); bool has_debug = client->checkPrivilege("debug"); bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG); + // Initial: No debug info // 1x toggle: Debug text // 2x toggle: Debug text with profiler graph // 3x toggle: Debug text and wireframe (needs "debug" priv) - // Next toggle: Back to initial + // 4x toggle: Debug text and bbox (needs "debug" priv) // // The debug text can be in 2 modes: minimal and basic. // * Minimal: Only technical client info that not gameplay-relevant // * Basic: Info that might give gameplay advantage, e.g. pos, angle // Basic mode is used when player has the debug HUD flag set, // otherwise the Minimal mode is used. - if (!m_game_ui->m_flags.show_minimal_debug) { - m_game_ui->m_flags.show_minimal_debug = true; - if (has_basic_debug) - m_game_ui->m_flags.show_basic_debug = true; - m_game_ui->m_flags.show_profiler_graph = false; - draw_control->show_wireframe = false; + + auto &state = m_flags.debug_state; + state = (state + 1) % 5; + if (state >= 3 && !has_debug) + state = 0; + + m_game_ui->m_flags.show_minimal_debug = state > 0; + m_game_ui->m_flags.show_basic_debug = state > 0 && has_basic_debug; + m_game_ui->m_flags.show_profiler_graph = state == 2; + draw_control->show_wireframe = state == 3; + smgr->setGlobalDebugData(state == 4 ? bbox_debug_flag : 0, + state == 4 ? 0 : bbox_debug_flag); + + if (state == 1) m_game_ui->showTranslatedStatusText("Debug info shown"); - } else if (!m_game_ui->m_flags.show_profiler_graph && !draw_control->show_wireframe) { - if (has_basic_debug) - m_game_ui->m_flags.show_basic_debug = true; - m_game_ui->m_flags.show_profiler_graph = true; + else if (state == 2) m_game_ui->showTranslatedStatusText("Profiler graph shown"); - } else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) { - if (has_basic_debug) - m_game_ui->m_flags.show_basic_debug = true; - m_game_ui->m_flags.show_profiler_graph = false; - draw_control->show_wireframe = true; + else if (state == 3) m_game_ui->showTranslatedStatusText("Wireframe shown"); - } else { - m_game_ui->m_flags.show_minimal_debug = false; - m_game_ui->m_flags.show_basic_debug = false; - m_game_ui->m_flags.show_profiler_graph = false; - draw_control->show_wireframe = false; - if (has_debug) { - m_game_ui->showTranslatedStatusText("Debug info, profiler graph, and wireframe hidden"); - } else { - m_game_ui->showTranslatedStatusText("Debug info and profiler graph hidden"); - } - } + else if (state == 4) + m_game_ui->showTranslatedStatusText("Bounding boxes shown"); + else + m_game_ui->showTranslatedStatusText("All debug info hidden"); } From 0614b175b5e3913d041e23904f4cdc2a6339b567 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 2 Jan 2025 12:32:45 +0100 Subject: [PATCH 07/44] Optimize draw3DBox generic case --- irr/src/CNullDriver.cpp | 23 +++++++-------- irr/src/COpenGLDriver.cpp | 60 --------------------------------------- irr/src/COpenGLDriver.h | 3 -- 3 files changed, 10 insertions(+), 76 deletions(-) diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index 385e978b1..7a0e006c9 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -619,20 +619,17 @@ void CNullDriver::draw3DBox(const core::aabbox3d &box, SColor color) core::vector3df edges[8]; box.getEdges(edges); - // TODO: optimize into one big drawIndexPrimitive call. + video::S3DVertex v[8]; + for (u32 i = 0; i < 8; i++) { + v[i].Pos = edges[i]; + v[i].Color = color; + } - draw3DLine(edges[5], edges[1], color); - draw3DLine(edges[1], edges[3], color); - draw3DLine(edges[3], edges[7], color); - draw3DLine(edges[7], edges[5], color); - draw3DLine(edges[0], edges[2], color); - draw3DLine(edges[2], edges[6], color); - draw3DLine(edges[6], edges[4], color); - draw3DLine(edges[4], edges[0], color); - draw3DLine(edges[1], edges[0], color); - draw3DLine(edges[3], edges[2], color); - draw3DLine(edges[7], edges[6], color); - draw3DLine(edges[5], edges[4], color); + const static u16 box_indices[24] = { + 5, 1, 1, 3, 3, 7, 7, 5, 0, 2, 2, 6, 6, 4, 4, 0, 1, 0, 3, 2, 7, 6, 5, 4 + }; + + drawVertexPrimitiveList(v, 8, box_indices, 12, EVT_STANDARD, scene::EPT_LINES); } //! draws an 2d image diff --git a/irr/src/COpenGLDriver.cpp b/irr/src/COpenGLDriver.cpp index 73eb22095..e9cd10b49 100644 --- a/irr/src/COpenGLDriver.cpp +++ b/irr/src/COpenGLDriver.cpp @@ -2462,66 +2462,6 @@ void COpenGLDriver::setFog(SColor c, E_FOG_TYPE fogType, f32 start, glFogfv(GL_FOG_COLOR, data); } -//! Draws a 3d box. -void COpenGLDriver::draw3DBox(const core::aabbox3d &box, SColor color) -{ - core::vector3df edges[8]; - box.getEdges(edges); - - setRenderStates3DMode(); - - video::S3DVertex v[24]; - - for (u32 i = 0; i < 24; i++) - v[i].Color = color; - - v[0].Pos = edges[5]; - v[1].Pos = edges[1]; - v[2].Pos = edges[1]; - v[3].Pos = edges[3]; - v[4].Pos = edges[3]; - v[5].Pos = edges[7]; - v[6].Pos = edges[7]; - v[7].Pos = edges[5]; - v[8].Pos = edges[0]; - v[9].Pos = edges[2]; - v[10].Pos = edges[2]; - v[11].Pos = edges[6]; - v[12].Pos = edges[6]; - v[13].Pos = edges[4]; - v[14].Pos = edges[4]; - v[15].Pos = edges[0]; - v[16].Pos = edges[1]; - v[17].Pos = edges[0]; - v[18].Pos = edges[3]; - v[19].Pos = edges[2]; - v[20].Pos = edges[7]; - v[21].Pos = edges[6]; - v[22].Pos = edges[5]; - v[23].Pos = edges[4]; - - if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) - getColorBuffer(v, 24, EVT_STANDARD); - - CacheHandler->setClientState(true, false, true, false); - - glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast(v))[0].Pos); - -#ifdef GL_BGRA - const GLint colorSize = (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) ? GL_BGRA : 4; -#else - const GLint colorSize = 4; -#endif - if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) - glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(v))[0].Color); - else { - _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0); - glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); - } - - glDrawArrays(GL_LINES, 0, 24); -} - //! Draws a 3d line. void COpenGLDriver::draw3DLine(const core::vector3df &start, const core::vector3df &end, SColor color) diff --git a/irr/src/COpenGLDriver.h b/irr/src/COpenGLDriver.h index 0fdd15d16..1b5c0c6d3 100644 --- a/irr/src/COpenGLDriver.h +++ b/irr/src/COpenGLDriver.h @@ -170,9 +170,6 @@ public: const core::position2d &end, SColor color = SColor(255, 255, 255, 255)) override; - //! Draws a 3d box - void draw3DBox(const core::aabbox3d &box, SColor color = SColor(255, 255, 255, 255)) override; - //! Draws a 3d line. virtual void draw3DLine(const core::vector3df &start, const core::vector3df &end, From 5bcb7983ec1648b9993e4092be014308726af383 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 2 Jan 2025 13:48:39 +0100 Subject: [PATCH 08/44] Fix missing bounding box for upright_sprite (also simplifies the mesh building) fixes #15616 --- src/client/content_cao.cpp | 70 +++++++++++++++----------------------- 1 file changed, 27 insertions(+), 43 deletions(-) diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index d90d4e8b0..5307047c4 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -656,25 +656,33 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) } } else if (m_prop.visual == "upright_sprite") { grabMatrixNode(); - scene::SMesh *mesh = new scene::SMesh(); - double dx = BS * m_prop.visual_size.X / 2; - double dy = BS * m_prop.visual_size.Y / 2; + auto mesh = make_irr(); + f32 dx = BS * m_prop.visual_size.X / 2; + f32 dy = BS * m_prop.visual_size.Y / 2; video::SColor c(0xFFFFFFFF); - { // Front - scene::IMeshBuffer *buf = new scene::SMeshBuffer(); - video::S3DVertex vertices[4] = { - video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1), - video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1), - video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0), - video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0), - }; - if (m_is_player) { - // Move minimal Y position to 0 (feet position) - for (video::S3DVertex &vertex : vertices) - vertex.Pos.Y += dy; + video::S3DVertex vertices[4] = { + video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1), + video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1), + video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0), + video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0), + }; + if (m_is_player) { + // Move minimal Y position to 0 (feet position) + for (auto &vertex : vertices) + vertex.Pos.Y += dy; + } + const u16 indices[] = {0,1,2,2,3,0}; + + for (int face : {0, 1}) { + auto buf = make_irr(); + // Front (0) or Back (1) + if (face == 1) { + for (auto &v : vertices) + v.Normal *= -1; + for (int i : {0, 2}) + std::swap(vertices[i].Pos, vertices[i+1].Pos); } - u16 indices[] = {0,1,2,2,3,0}; buf->append(vertices, 4, indices, 6); // Set material @@ -682,36 +690,12 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) buf->getMaterial().ColorParam = c; // Add to mesh - mesh->addMeshBuffer(buf); - buf->drop(); + mesh->addMeshBuffer(buf.get()); } - { // Back - scene::IMeshBuffer *buf = new scene::SMeshBuffer(); - video::S3DVertex vertices[4] = { - video::S3DVertex( dx,-dy, 0, 0,0,-1, c, 1,1), - video::S3DVertex(-dx,-dy, 0, 0,0,-1, c, 0,1), - video::S3DVertex(-dx, dy, 0, 0,0,-1, c, 0,0), - video::S3DVertex( dx, dy, 0, 0,0,-1, c, 1,0), - }; - if (m_is_player) { - // Move minimal Y position to 0 (feet position) - for (video::S3DVertex &vertex : vertices) - vertex.Pos.Y += dy; - } - u16 indices[] = {0,1,2,2,3,0}; - buf->append(vertices, 4, indices, 6); - // Set material - setMaterial(buf->getMaterial()); - buf->getMaterial().ColorParam = c; - - // Add to mesh - mesh->addMeshBuffer(buf); - buf->drop(); - } - m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode); + mesh->recalculateBoundingBox(); + m_meshnode = m_smgr->addMeshSceneNode(mesh.get(), m_matrixnode); m_meshnode->grab(); - mesh->drop(); } else if (m_prop.visual == "cube") { grabMatrixNode(); scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS)); From 4c4918b1545c8e53c671ac23529776767a1e343b Mon Sep 17 00:00:00 2001 From: DS Date: Sun, 5 Jan 2025 13:20:21 +0100 Subject: [PATCH 09/44] Fix show_debug setting causing inconsistency between debug control and shown debug info --- src/client/game.cpp | 4 ++++ src/client/gameui.cpp | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/client/game.cpp b/src/client/game.cpp index f04e265e9..b7fa7c471 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -896,6 +896,10 @@ bool Game::startup(bool *kill, runData.time_from_last_punch = 10.0; m_game_ui->initFlags(); + if (g_settings->getBool("show_debug")) { + m_flags.debug_state = 1; + m_game_ui->m_flags.show_minimal_debug = true; + } m_first_loop_after_window_activation = true; diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp index 6fc7ac267..53fae50c0 100644 --- a/src/client/gameui.cpp +++ b/src/client/gameui.cpp @@ -215,7 +215,6 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_ void GameUI::initFlags() { m_flags = GameUI::Flags(); - m_flags.show_minimal_debug = g_settings->getBool("show_debug"); } void GameUI::showTranslatedStatusText(const char *str) From dfd7628950df0a47f2903028b58b5c69ea2ae0d4 Mon Sep 17 00:00:00 2001 From: wrrrzr <161970349+wrrrzr@users.noreply.github.com> Date: Sun, 5 Jan 2025 15:20:37 +0300 Subject: [PATCH 10/44] Rename getGameMinetestConfig to getGameConfig --- src/content/subgames.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp index d0644248e..980f0188c 100644 --- a/src/content/subgames.cpp +++ b/src/content/subgames.cpp @@ -22,9 +22,8 @@ namespace { -bool getGameMinetestConfig(const std::string &game_path, Settings &conf) +bool getGameConfig(const std::string &game_path, Settings &conf) { - // TODO: rename this std::string conf_path = game_path + DIR_DELIM + "minetest.conf"; return conf.readConfigFile(conf_path.c_str()); } @@ -355,7 +354,7 @@ void loadGameConfAndInitWorld(const std::string &path, const std::string &name, game_settings = Settings::createLayer(SL_GAME); } - getGameMinetestConfig(gamespec.path, *game_settings); + getGameConfig(gamespec.path, *game_settings); game_settings->removeSecureSettings(); infostream << "Initializing world at " << final_path << std::endl; From 5b14c03301efdfe5c3a6d4bcae68ea595a621b38 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 4 Jan 2025 17:51:04 +0100 Subject: [PATCH 11/44] Use polygon offset to fix z-fighting for overlay tiles --- src/client/mapblock_mesh.cpp | 10 ++++++++ src/client/tile.h | 5 ++++ src/client/wieldmesh.cpp | 46 ++++++++++++++++++++++++++---------- src/client/wieldmesh.h | 11 --------- 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 43c6e22e2..627afac3b 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -702,6 +702,16 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; tex.MagFilter = video::ETMAGF_NEAREST; }); + /* + * The second layer is for overlays, but uses the same vertex positions + * as the first, which quickly leads to z-fighting. + * To fix this we can offset the polygons in the direction of the camera. + * This only affects the depth buffer and leads to no visual gaps in geometry. + */ + if (layer == 1) { + material.PolygonOffsetSlopeScale = -1; + material.PolygonOffsetDepthBias = -1; + } { material.MaterialType = m_shdrsrc->getShaderInfo( diff --git a/src/client/tile.h b/src/client/tile.h index cb42efa02..4f5691bc5 100644 --- a/src/client/tile.h +++ b/src/client/tile.h @@ -50,6 +50,11 @@ struct FrameSpec video::ITexture *texture = nullptr; }; +/** + * We have two tile layers: + * layer 0 = base + * layer 1 = overlay + */ #define MAX_TILE_LAYERS 2 //! Defines a layer of a tile. diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index 4239c4121..504fcda7d 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -27,6 +27,18 @@ #define MIN_EXTRUSION_MESH_RESOLUTION 16 #define MAX_EXTRUSION_MESH_RESOLUTION 512 +/*! + * Applies overlays, textures and optionally materials to the given mesh and + * extracts tile colors for colorization. + * \param mattype overrides the buffer's material type, but can also + * be NULL to leave the original material. + * \param colors returns the colors of the mesh buffers in the mesh. + */ +static void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, + bool set_material, const video::E_MATERIAL_TYPE *mattype, + std::vector *colors, bool apply_scale = false); + + static scene::IMesh *createExtrusionMesh(int resolution_x, int resolution_y) { const f32 r = 0.5; @@ -317,25 +329,32 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n, colors->clear(); scene::SMesh *mesh = new scene::SMesh(); - for (auto &prebuffers : collector.prebuffers) + for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) { + auto &prebuffers = collector.prebuffers[layer]; for (PreMeshBuffer &p : prebuffers) { if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) { const FrameSpec &frame = (*p.layer.frames)[0]; p.layer.texture = frame.texture; } - for (video::S3DVertex &v : p.vertices) { + for (video::S3DVertex &v : p.vertices) v.Color.setAlpha(255); - } - scene::SMeshBuffer *buf = new scene::SMeshBuffer(); - buf->Material.setTexture(0, p.layer.texture); - p.layer.applyMaterialOptions(buf->Material); - mesh->addMeshBuffer(buf); + + auto buf = make_irr(); buf->append(&p.vertices[0], p.vertices.size(), &p.indices[0], p.indices.size()); - buf->drop(); - colors->push_back( - ItemPartColor(p.layer.has_color, p.layer.color)); + + // Set up material + buf->Material.setTexture(0, p.layer.texture); + if (layer == 1) { + buf->Material.PolygonOffsetSlopeScale = -1; + buf->Material.PolygonOffsetDepthBias = -1; + } + p.layer.applyMaterialOptions(buf->Material); + + mesh->addMeshBuffer(buf.get()); + colors->emplace_back(p.layer.has_color, p.layer.color); } + } return mesh; } @@ -688,13 +707,15 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, return mesh; } -void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, +static void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, bool set_material, const video::E_MATERIAL_TYPE *mattype, std::vector *colors, bool apply_scale) { + // FIXME: this function is weirdly inconsistent with what MapBlockMesh does. + // also set_material is never true + const u32 mc = mesh->getMeshBufferCount(); // Allocate colors for existing buffers - colors->clear(); colors->resize(mc); for (u32 i = 0; i < mc; ++i) { @@ -705,6 +726,7 @@ void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, if (layer->texture_id == 0) continue; if (layernum != 0) { + // FIXME: why do this? scene::IMeshBuffer *copy = cloneMeshBuffer(buf); copy->getMaterial() = buf->getMaterial(); mesh->addMeshBuffer(copy); diff --git a/src/client/wieldmesh.h b/src/client/wieldmesh.h index 6e92af9f6..a3d8c3af1 100644 --- a/src/client/wieldmesh.h +++ b/src/client/wieldmesh.h @@ -143,14 +143,3 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result); scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename, const std::string &overlay_name); - -/*! - * Applies overlays, textures and optionally materials to the given mesh and - * extracts tile colors for colorization. - * \param mattype overrides the buffer's material type, but can also - * be NULL to leave the original material. - * \param colors returns the colors of the mesh buffers in the mesh. - */ -void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, - bool set_material, const video::E_MATERIAL_TYPE *mattype, - std::vector *colors, bool apply_scale = false); From 4774e65ed913729605edf4306ee20d81de6afb35 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 4 Jan 2025 18:10:29 +0100 Subject: [PATCH 12/44] Implement polygon offset in GL3 driver --- irr/include/SMaterial.h | 6 +----- irr/src/OpenGL/Driver.cpp | 12 +++++++++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/irr/include/SMaterial.h b/irr/include/SMaterial.h index 867557154..2329e2761 100644 --- a/irr/include/SMaterial.h +++ b/irr/include/SMaterial.h @@ -304,11 +304,7 @@ public: //! A constant z-buffer offset for a polygon/line/point /** The range of the value is driver specific. - On OpenGL you get units which are multiplied by the smallest value that is guaranteed to produce a resolvable offset. - On D3D9 you can pass a range between -1 and 1. But you should likely divide it by the range of the depthbuffer. - Like dividing by 65535.0 for a 16 bit depthbuffer. Thought it still might produce too large of a bias. - Some article (https://aras-p.info/blog/2008/06/12/depth-bias-and-the-power-of-deceiving-yourself/) - recommends multiplying by 2.0*4.8e-7 (and strangely on both 16 bit and 24 bit). */ + On OpenGL you get units which are multiplied by the smallest value that is guaranteed to produce a resolvable offset. */ f32 PolygonOffsetDepthBias; //! Variable Z-Buffer offset based on the slope of the polygon. diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index 31fb7a177..dec24c824 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -1313,7 +1313,17 @@ void COpenGL3DriverBase::setBasicRenderStates(const SMaterial &material, const S getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact)); } - // TODO: Polygon Offset. Not sure if it was left out deliberately or if it won't work with this driver. + // Polygon Offset + if (resetAllRenderStates || + lastmaterial.PolygonOffsetDepthBias != material.PolygonOffsetDepthBias || + lastmaterial.PolygonOffsetSlopeScale != material.PolygonOffsetSlopeScale) { + if (material.PolygonOffsetDepthBias || material.PolygonOffsetSlopeScale) { + GL.Enable(GL.POLYGON_OFFSET_FILL); + GL.PolygonOffset(material.PolygonOffsetSlopeScale, material.PolygonOffsetDepthBias); + } else { + GL.Disable(GL.POLYGON_OFFSET_FILL); + } + } if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness) GL.LineWidth(core::clamp(static_cast(material.Thickness), DimAliasedLine[0], DimAliasedLine[1])); From 06f39e19152f3f8d6bff6871d8c6069ad3b74496 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 5 Jan 2025 02:53:13 +0100 Subject: [PATCH 13/44] Fix missing bounding box for CAO 'wielditem' visual --- src/client/wieldmesh.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index 504fcda7d..3ba18711e 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -244,6 +244,7 @@ void WieldMeshSceneNode::setCube(const ContentFeatures &f, scene::SMesh *copy = cloneMesh(cubemesh); cubemesh->drop(); postProcessNodeMesh(copy, f, false, &m_material_type, &m_colors, true); + copy->recalculateBoundingBox(); changeToMesh(copy); copy->drop(); m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR); @@ -279,6 +280,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, mesh->addMeshBuffer(copy); copy->drop(); } + mesh->recalculateBoundingBox(); changeToMesh(mesh); mesh->drop(); @@ -355,6 +357,7 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n, colors->emplace_back(p.layer.has_color, p.layer.color); } } + mesh->recalculateBoundingBox(); return mesh; } From f467bde6ac3f906fcb3cf0a7e80b25f4db3beca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Sun, 5 Jan 2025 16:32:09 +0100 Subject: [PATCH 14/44] Add unit test for raycasts falsely skipping nodes (#15555) --- games/devtest/mods/unittests/raycast.lua | 45 ++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/games/devtest/mods/unittests/raycast.lua b/games/devtest/mods/unittests/raycast.lua index 08d6a1120..db5e78b34 100644 --- a/games/devtest/mods/unittests/raycast.lua +++ b/games/devtest/mods/unittests/raycast.lua @@ -34,3 +34,48 @@ local function test_raycast_pointabilities(player, pos1) end unittests.register("test_raycast_pointabilities", test_raycast_pointabilities, {map=true}) + +local function test_raycast_noskip(_, pos) + local function cuboid_minmax(extent) + return pos:offset(-extent, -extent, -extent), + pos:offset(extent, extent, extent) + end + + -- Carve out a 3x3x3 dirt cuboid in a larger air cuboid + local r = 8 + local min, max = cuboid_minmax(r + 1) + local vm = core.get_voxel_manip(min, max) + local old_data = vm:get_data() + local data = vm:get_data() + local emin, emax = vm:get_emerged_area() + local va = VoxelArea:new({MinEdge = emin, MaxEdge = emax}) + for index in va:iterp(min, max) do + data[index] = core.CONTENT_AIR + end + for index in va:iterp(cuboid_minmax(1)) do + data[index] = core.get_content_id("basenodes:dirt") + end + vm:set_data(data) + vm:write_to_map() + + -- Raycast many times from outside the cuboid + for _ = 1, 100 do + local ray_start + repeat + ray_start = vector.random_in_area(cuboid_minmax(r)) + until not ray_start:in_area(cuboid_minmax(1.501)) + -- Pick a random position inside the dirt + local ray_end = vector.random_in_area(cuboid_minmax(1.499)) + -- The first pointed thing should have only air "in front" of it, + -- or a dirt node got falsely skipped. + local pt = core.raycast(ray_start, ray_end, false, false):next() + if pt then + assert(core.get_node(pt.above).name == "air") + end + end + + vm:set_data(old_data) + vm:write_to_map() +end + +unittests.register("test_raycast_noskip", test_raycast_noskip, {map = true}) From 431c5c8b366dbf59d9ad1a58afd68c19713798ca Mon Sep 17 00:00:00 2001 From: DS Date: Mon, 6 Jan 2025 19:39:17 +0100 Subject: [PATCH 15/44] Fix wireframe mode in opengl3 driver (#15626) `GL_LINES` isn't suitable, because it makes lines between pairs of 2 vertices, not loops around 3 vertices. Support for OpenGL ES isn't simple, as it has no `glPolygonMode`. And showing broken wireframe (i.e. with `GL_LINES`) would cause confusion. --- irr/src/OpenGL/Driver.cpp | 15 ++++++++++++--- src/client/game.cpp | 16 ++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index dec24c824..25c9a14f6 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -1032,9 +1032,7 @@ void COpenGL3DriverBase::drawGeneric(const void *vertices, const void *indexList GL.DrawElements(GL_TRIANGLE_FAN, primitiveCount + 2, indexSize, indexList); break; case scene::EPT_TRIANGLES: - GL.DrawElements((LastMaterial.Wireframe) ? GL_LINES : (LastMaterial.PointCloud) ? GL_POINTS - : GL_TRIANGLES, - primitiveCount * 3, indexSize, indexList); + GL.DrawElements(GL_TRIANGLES, primitiveCount * 3, indexSize, indexList); break; default: break; @@ -1313,6 +1311,17 @@ void COpenGL3DriverBase::setBasicRenderStates(const SMaterial &material, const S getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact)); } + // fillmode + if (Version.Spec != OpenGLSpec::ES && // not supported in gles + (resetAllRenderStates || + lastmaterial.Wireframe != material.Wireframe || + lastmaterial.PointCloud != material.PointCloud)) { + GL.PolygonMode(GL_FRONT_AND_BACK, + material.Wireframe ? GL_LINE : + material.PointCloud ? GL_POINT : + GL_FILL); + } + // Polygon Offset if (resetAllRenderStates || lastmaterial.PolygonOffsetDepthBias != material.PolygonOffsetDepthBias || diff --git a/src/client/game.cpp b/src/client/game.cpp index b7fa7c471..1166cfee7 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -2256,16 +2256,20 @@ void Game::toggleDebug() smgr->setGlobalDebugData(state == 4 ? bbox_debug_flag : 0, state == 4 ? 0 : bbox_debug_flag); - if (state == 1) + if (state == 1) { m_game_ui->showTranslatedStatusText("Debug info shown"); - else if (state == 2) + } else if (state == 2) { m_game_ui->showTranslatedStatusText("Profiler graph shown"); - else if (state == 3) - m_game_ui->showTranslatedStatusText("Wireframe shown"); - else if (state == 4) + } else if (state == 3) { + if (driver->getDriverType() == video::EDT_OGLES2) + m_game_ui->showTranslatedStatusText("Wireframe not supported by video driver"); + else + m_game_ui->showTranslatedStatusText("Wireframe shown"); + } else if (state == 4) { m_game_ui->showTranslatedStatusText("Bounding boxes shown"); - else + } else { m_game_ui->showTranslatedStatusText("All debug info hidden"); + } } From c3466124684771b27ed34c0b5e65b57ea30ff795 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Mon, 6 Jan 2025 19:42:11 +0100 Subject: [PATCH 16/44] Fix falling nodes digging nodes they aren't supposed to (#15638) --- builtin/game/falling.lua | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/builtin/game/falling.lua b/builtin/game/falling.lua index bb6ca1a64..6abd16c58 100644 --- a/builtin/game/falling.lua +++ b/builtin/game/falling.lua @@ -308,23 +308,26 @@ core.register_entity(":__builtin:falling_node", { core.remove_node(bcp) else + -- We are placing on top so check what's there np.y = np.y + 1 - end - -- Check what's here - local n2 = core.get_node(np) - local nd = core.registered_nodes[n2.name] - -- If it's not air or liquid, remove node and replace it with - -- it's drops - if n2.name ~= "air" and (not nd or nd.liquidtype ~= "source") then - if nd and nd.buildable_to == false then + local n2 = core.get_node(np) + local nd = core.registered_nodes[n2.name] + if not nd or nd.buildable_to then + core.remove_node(np) + else + -- 'walkable' is used to mean "falling nodes can't replace this" + -- here. Normally we would collide with the walkable node itself + -- and place our node on top (so `n2.name == "air"`), but we + -- re-check this in case we ended up inside a node. + if not nd.diggable or nd.walkable then + return false + end nd.on_dig(np, n2, nil) -- If it's still there, it might be protected if core.get_node(np).name == n2.name then return false end - else - core.remove_node(np) end end From 7f1316236bafef9dae1a80aa6de6df4482942cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:56:05 +0100 Subject: [PATCH 17/44] Silence failing raycast unit test (#15644) The cause for the test failure is an edge case bug in the raycast implementation (perfectly diagonal raycasts). This is fixed by switching to a continuous random distribution which makes it extremely unlikely that the buggy edge case occurs. Additionally, devtest unit test failures now print their random seed to be easier to reproduce in the future. --- games/devtest/mods/unittests/init.lua | 27 +++++++++++++++++------ games/devtest/mods/unittests/raycast.lua | 28 +++++++++++++++++++++--- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/games/devtest/mods/unittests/init.lua b/games/devtest/mods/unittests/init.lua index 724334326..a971632c9 100644 --- a/games/devtest/mods/unittests/init.lua +++ b/games/devtest/mods/unittests/init.lua @@ -12,6 +12,7 @@ unittests.list = {} -- player = false, -- Does test require a player? -- map = false, -- Does test require map access? -- async = false, -- Does the test run asynchronously? (read notes above!) +-- random = false, -- Does the test use math.random directly or indirectly? -- } function unittests.register(name, func, opts) local def = table.copy(opts or {}) @@ -47,8 +48,18 @@ local function await(invoke) return coroutine.yield() end +local function printf(fmt, ...) + print(fmt:format(...)) +end + function unittests.run_one(idx, counters, out_callback, player, pos) local def = unittests.list[idx] + local seed + if def.random then + seed = core.get_us_time() + math.randomseed(seed) + end + if not def.player then player = nil elseif player == nil then @@ -70,8 +81,10 @@ function unittests.run_one(idx, counters, out_callback, player, pos) if not status then core.log("error", err) end - print(string.format("[%s] %s - %dms", - status and "PASS" or "FAIL", def.name, ms_taken)) + printf("[%s] %s - %dms", status and "PASS" or "FAIL", def.name, ms_taken) + if seed and not status then + printf("Random was seeded to %d", seed) + end counters.time = counters.time + ms_taken counters.total = counters.total + 1 if status then @@ -160,11 +173,11 @@ function unittests.run_all() -- Print stats assert(#unittests.list == counters.total) print(string.rep("+", 80)) - print(string.format("Devtest Unit Test Results: %s", - counters.total == counters.passed and "PASSED" or "FAILED")) - print(string.format(" %d / %d failed tests.", - counters.total - counters.passed, counters.total)) - print(string.format(" Testing took %dms total.", counters.time)) + local passed = counters.total == counters.passed + printf("Devtest Unit Test Results: %s", passed and "PASSED" or "FAILED") + printf(" %d / %d failed tests.", + counters.total - counters.passed, counters.total) + printf(" Testing took %dms total.", counters.time) print(string.rep("+", 80)) unittests.on_finished(counters.total == counters.passed) return counters.total == counters.passed diff --git a/games/devtest/mods/unittests/raycast.lua b/games/devtest/mods/unittests/raycast.lua index db5e78b34..1dc196cc5 100644 --- a/games/devtest/mods/unittests/raycast.lua +++ b/games/devtest/mods/unittests/raycast.lua @@ -36,6 +36,28 @@ end unittests.register("test_raycast_pointabilities", test_raycast_pointabilities, {map=true}) local function test_raycast_noskip(_, pos) + local function random_point_in_area(min, max) + local extents = max - min + local v = extents:multiply(vector.new( + math.random(), + math.random(), + math.random() + )) + return min + v + end + + -- FIXME a variation of this unit test fails in an edge case. + -- This is because Luanti does not handle perfectly diagonal raycasts correctly: + -- Perfect diagonals collide with neither "outside" face and may thus "pierce" nodes. + -- Enable the following code to reproduce: + if 0 == 1 then + pos = vector.new(6, 32, -3) + math.randomseed(1596190898) + function random_point_in_area(min, max) + return min:combine(max, math.random) + end + end + local function cuboid_minmax(extent) return pos:offset(-extent, -extent, -extent), pos:offset(extent, extent, extent) @@ -62,10 +84,10 @@ local function test_raycast_noskip(_, pos) for _ = 1, 100 do local ray_start repeat - ray_start = vector.random_in_area(cuboid_minmax(r)) + ray_start = random_point_in_area(cuboid_minmax(r)) until not ray_start:in_area(cuboid_minmax(1.501)) -- Pick a random position inside the dirt - local ray_end = vector.random_in_area(cuboid_minmax(1.499)) + local ray_end = random_point_in_area(cuboid_minmax(1.499)) -- The first pointed thing should have only air "in front" of it, -- or a dirt node got falsely skipped. local pt = core.raycast(ray_start, ray_end, false, false):next() @@ -78,4 +100,4 @@ local function test_raycast_noskip(_, pos) vm:write_to_map() end -unittests.register("test_raycast_noskip", test_raycast_noskip, {map = true}) +unittests.register("test_raycast_noskip", test_raycast_noskip, {map = true, random = true}) From 41f7031e49adfb4accd8df2986dd68ece44711f6 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 8 Jan 2025 10:56:28 +0100 Subject: [PATCH 18/44] Fix reduced bloom at 10 bits forgotten in eb8beb335e30ba6e3a35a56ace665ec59cd840dd --- src/client/render/secondstage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/render/secondstage.cpp b/src/client/render/secondstage.cpp index 42858fa84..616077942 100644 --- a/src/client/render/secondstage.cpp +++ b/src/client/render/secondstage.cpp @@ -196,7 +196,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep } if (enable_volumetric_light) { - buffer->setTexture(TEXTURE_VOLUME, scale, "volume", color_format); + buffer->setTexture(TEXTURE_VOLUME, scale, "volume", bloom_format); shader_id = client->getShaderSource()->getShaderRaw("volumetric_light"); auto volume = pipeline->addStep(shader_id, std::vector { source, TEXTURE_DEPTH }); From e5542e5b024719bc5f1b111fb2e3eded3fbffca6 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 8 Jan 2025 10:56:45 +0100 Subject: [PATCH 19/44] Remove or restrict some client settings (#15633) --- builtin/settingtypes.txt | 37 ++------------- src/client/clientlauncher.cpp | 3 +- src/client/clouds.cpp | 4 +- src/client/game.cpp | 84 +++++++++------------------------ src/client/game_formspec.cpp | 7 ++- src/client/guiscalingfilter.cpp | 3 +- src/client/mapblock_mesh.cpp | 14 +----- src/defaultsettings.cpp | 7 --- src/gui/guiEngine.cpp | 2 +- src/mapblock.cpp | 10 +++- src/server.cpp | 5 +- 11 files changed, 48 insertions(+), 128 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index b09df4b29..a2d37df5f 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -377,17 +377,12 @@ fog_start (Fog start) float 0.4 0.0 0.99 [**Clouds] -# Clouds are a client-side effect. -enable_clouds (Clouds) bool true - -# Use 3D cloud look instead of flat. -# -# Requires: enable_clouds +# Allow clouds to look 3D instead of flat. enable_3d_clouds (3D clouds) bool true # Use smooth cloud shading. # -# Requires: enable_3d_clouds, enable_clouds +# Requires: enable_3d_clouds soft_clouds (Soft clouds) bool false [**Filtering and Antialiasing] @@ -472,9 +467,6 @@ smooth_lighting (Smooth lighting) bool true # at the expense of minor visual glitches that do not impact game playability. performance_tradeoffs (Tradeoffs for performance) bool false -# Adds particles when digging a node. -enable_particles (Digging particles) bool true - [**Waving Nodes] @@ -642,8 +634,7 @@ sound_volume (Volume) float 0.8 0.0 1.0 # Volume multiplier when the window is unfocused. sound_volume_unfocused (Volume when unfocused) float 0.3 0.0 1.0 -# Whether to mute sounds. You can unmute sounds at any time, unless the -# sound system is disabled (enable_sound=false). +# Whether to mute sounds. You can unmute sounds at any time. # In-game, you can toggle the mute state with the mute key or by using the # pause menu. mute_sound (Mute sound) bool false @@ -684,12 +675,6 @@ formspec_fullscreen_bg_color (Formspec Full-Screen Background Color) string (0,0 # to hardware (e.g. render-to-texture for nodes in inventory). gui_scaling_filter (GUI scaling filter) bool false -# When gui_scaling_filter_txr2img is true, copy those images -# from hardware to software for scaling. When false, fall back -# to the old scaling method, for video drivers that don't -# properly support downloading textures back from hardware. -gui_scaling_filter_txr2img (GUI scaling filter txr2img) bool true - # Delay showing tooltips, stated in milliseconds. tooltip_show_delay (Tooltip delay) int 400 0 18446744073709551615 @@ -1844,10 +1829,7 @@ transparency_sorting_group_by_buffers (Transparency Sorting Group by Buffers) bo # Radius of cloud area stated in number of 64 node cloud squares. # Values larger than 26 will start to produce sharp cutoffs at cloud area corners. -cloud_radius (Cloud radius) int 12 1 62 - -# Whether node texture animations should be desynchronized per mapblock. -desynchronize_mapblock_texture_animation (Desynchronize block animation) bool false +cloud_radius (Cloud radius) int 12 8 62 # Delay between mesh updates on the client in ms. Increasing this will slow # down the rate of mesh updates, thus reducing jitter on slower clients. @@ -2101,9 +2083,6 @@ max_block_send_distance (Max block send distance) int 12 1 65535 # Set this to -1 to disable the limit. max_forceloaded_blocks (Maximum forceloaded blocks) int 16 -1 -# Interval of sending time of day to clients, stated in seconds. -time_send_interval (Time send interval) float 5.0 0.001 - # Interval of saving important changes in the world, stated in seconds. server_map_save_interval (Map save interval) float 5.3 0.001 @@ -2112,7 +2091,7 @@ server_map_save_interval (Map save interval) float 5.3 0.001 server_unload_unused_data_timeout (Unload unused server data) int 29 0 4294967295 # Maximum number of statically stored objects in a block. -max_objects_per_block (Maximum objects per block) int 256 1 65535 +max_objects_per_block (Maximum objects per block) int 256 256 65535 # Length of time between active block management cycles, stated in seconds. active_block_mgmt_interval (Active block management interval) float 2.0 0.0 @@ -2331,12 +2310,6 @@ show_technical_names (Show technical names) bool false # Controlled by a checkbox in the settings menu. show_advanced (Show advanced settings) bool false -# Enables the sound system. -# If disabled, this completely disables all sounds everywhere and the in-game -# sound controls will be non-functional. -# Changing this setting requires a restart. -enable_sound (Sound) bool true - # Key for moving the player forward. keymap_forward (Forward key) key KEY_KEY_W diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index b68edb790..725ff4323 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -91,8 +91,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) init_args(start_data, cmd_args); #if USE_SOUND - if (g_settings->getBool("enable_sound")) - g_sound_manager_singleton = createSoundManagerSingleton(); + g_sound_manager_singleton = createSoundManagerSingleton(); #endif if (!init_engine()) diff --git a/src/client/clouds.cpp b/src/client/clouds.cpp index 55e89410d..b65970f95 100644 --- a/src/client/clouds.cpp +++ b/src/client/clouds.cpp @@ -445,8 +445,8 @@ void Clouds::readSettings() // chosen to avoid exactly that. // refer to vertex_count in updateMesh() m_enable_3d = g_settings->getBool("enable_3d_clouds"); - const u16 maximum = m_enable_3d ? 62 : 25; - m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 1, maximum); + const u16 maximum = !m_enable_3d ? 62 : 25; + m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 8, maximum); invalidateMesh(); } diff --git a/src/client/game.cpp b/src/client/game.cpp index 1166cfee7..6886abb45 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -741,11 +741,8 @@ private: * (as opposed to the this local caching). This can be addressed in * a later release. */ - bool m_cache_disable_escape_sequences; bool m_cache_doubletap_jump; - bool m_cache_enable_clouds; bool m_cache_enable_joysticks; - bool m_cache_enable_particles; bool m_cache_enable_fog; bool m_cache_enable_noclip; bool m_cache_enable_free_move; @@ -787,16 +784,10 @@ Game::Game() : { g_settings->registerChangedCallback("chat_log_level", &settingChangedCallback, this); - g_settings->registerChangedCallback("disable_escape_sequences", - &settingChangedCallback, this); g_settings->registerChangedCallback("doubletap_jump", &settingChangedCallback, this); - g_settings->registerChangedCallback("enable_clouds", - &settingChangedCallback, this); g_settings->registerChangedCallback("enable_joysticks", &settingChangedCallback, this); - g_settings->registerChangedCallback("enable_particles", - &settingChangedCallback, this); g_settings->registerChangedCallback("enable_fog", &settingChangedCallback, this); g_settings->registerChangedCallback("mouse_sensitivity", @@ -1138,7 +1129,7 @@ bool Game::init( bool Game::initSound() { #if USE_SOUND - if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) { + if (g_sound_manager_singleton.get()) { infostream << "Attempting to use OpenAL audio" << std::endl; sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(), std::make_unique()); @@ -1296,8 +1287,7 @@ bool Game::createClient(const GameStartData &start_data) /* Clouds */ - if (m_cache_enable_clouds) - clouds = make_irr(smgr, shader_src, -1, rand()); + clouds = make_irr(smgr, shader_src, -1, myrand()); /* Skybox */ @@ -1873,34 +1863,22 @@ void Game::processKeyInput() toggleNoClip(); #if USE_SOUND } else if (wasKeyDown(KeyType::MUTE)) { - if (g_settings->getBool("enable_sound")) { - bool new_mute_sound = !g_settings->getBool("mute_sound"); - g_settings->setBool("mute_sound", new_mute_sound); - if (new_mute_sound) - m_game_ui->showTranslatedStatusText("Sound muted"); - else - m_game_ui->showTranslatedStatusText("Sound unmuted"); - } else { - m_game_ui->showTranslatedStatusText("Sound system is disabled"); - } + bool new_mute_sound = !g_settings->getBool("mute_sound"); + g_settings->setBool("mute_sound", new_mute_sound); + if (new_mute_sound) + m_game_ui->showTranslatedStatusText("Sound muted"); + else + m_game_ui->showTranslatedStatusText("Sound unmuted"); } else if (wasKeyDown(KeyType::INC_VOLUME)) { - if (g_settings->getBool("enable_sound")) { - float new_volume = g_settings->getFloat("sound_volume", 0.0f, 0.9f) + 0.1f; - g_settings->setFloat("sound_volume", new_volume); - std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100)); - m_game_ui->showStatusText(msg); - } else { - m_game_ui->showTranslatedStatusText("Sound system is disabled"); - } + float new_volume = g_settings->getFloat("sound_volume", 0.0f, 0.9f) + 0.1f; + g_settings->setFloat("sound_volume", new_volume); + std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100)); + m_game_ui->showStatusText(msg); } else if (wasKeyDown(KeyType::DEC_VOLUME)) { - if (g_settings->getBool("enable_sound")) { - float new_volume = g_settings->getFloat("sound_volume", 0.1f, 1.0f) - 0.1f; - g_settings->setFloat("sound_volume", new_volume); - std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100)); - m_game_ui->showStatusText(msg); - } else { - m_game_ui->showTranslatedStatusText("Sound system is disabled"); - } + float new_volume = g_settings->getFloat("sound_volume", 0.1f, 1.0f) - 0.1f; + g_settings->setFloat("sound_volume", new_volume); + std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100)); + m_game_ui->showStatusText(msg); #else } else if (wasKeyDown(KeyType::MUTE) || wasKeyDown(KeyType::INC_VOLUME) || wasKeyDown(KeyType::DEC_VOLUME)) { @@ -2859,9 +2837,6 @@ void Game::handleClientEvent_OverrideDayNigthRatio(ClientEvent *event, void Game::handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam) { - if (!clouds) - return; - clouds->setDensity(event->cloud_params.density); clouds->setColorBright(video::SColor(event->cloud_params.color_bright)); clouds->setColorAmbient(video::SColor(event->cloud_params.color_ambient)); @@ -2898,10 +2873,7 @@ void Game::updateChat(f32 dtime) std::vector entries = m_chat_log_buf.take(); for (const auto& entry : entries) { std::string line; - if (!m_cache_disable_escape_sequences) { - line.append(color_for(entry.level)); - } - line.append(entry.combined); + line.append(color_for(entry.level)).append(entry.combined); chat_backend->addMessage(L"", utf8_to_wide(line)); } @@ -2986,8 +2958,7 @@ void Game::updateCamera(f32 dtime) client->updateCameraOffset(camera_offset); client->getEnv().updateCameraOffset(camera_offset); - if (clouds) - clouds->updateCameraOffset(camera_offset); + clouds->updateCameraOffset(camera_offset); } } } @@ -3646,10 +3617,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, } else { runData.dig_time_complete = params.time; - if (m_cache_enable_particles) { - client->getParticleManager()->addNodeParticle(client, - player, nodepos, n, features); - } + client->getParticleManager()->addNodeParticle(client, + player, nodepos, n, features); } if (!runData.digging) { @@ -3734,11 +3703,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, client->interact(INTERACT_DIGGING_COMPLETED, pointed); - if (m_cache_enable_particles) { - client->getParticleManager()->addDiggingParticles(client, - player, nodepos, n, features); - } - + client->getParticleManager()->addDiggingParticles(client, + player, nodepos, n, features); // Send event to trigger sound client->getEventManager()->put(new NodeDugEvent(nodepos, n)); @@ -3829,8 +3795,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, /* Update clouds */ - if (clouds) - updateClouds(dtime); + updateClouds(dtime); /* Update particles @@ -4092,11 +4057,8 @@ void Game::readSettings() } m_chat_log_buf.setLogLevel(chat_log_level); - m_cache_disable_escape_sequences = g_settings->getBool("disable_escape_sequences"); m_cache_doubletap_jump = g_settings->getBool("doubletap_jump"); - m_cache_enable_clouds = g_settings->getBool("enable_clouds"); m_cache_enable_joysticks = g_settings->getBool("enable_joysticks"); - m_cache_enable_particles = g_settings->getBool("enable_particles"); m_cache_enable_fog = g_settings->getBool("enable_fog"); m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity", 0.001f, 10.0f); m_cache_joystick_frustum_sensitivity = std::max(g_settings->getFloat("joystick_frustum_sensitivity"), 0.001f); diff --git a/src/client/game_formspec.cpp b/src/client/game_formspec.cpp index 4c3bbb04a..cc5ddc0ed 100644 --- a/src/client/game_formspec.cpp +++ b/src/client/game_formspec.cpp @@ -333,12 +333,11 @@ void GameFormSpec::showPauseMenu() #ifndef __ANDROID__ #if USE_SOUND - if (g_settings->getBool("enable_sound")) { - os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;" - << strgettext("Sound Volume") << "]"; - } + os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;" + << strgettext("Sound Volume") << "]"; #endif #endif + if (g_touchcontrols) { os << "button_exit[4," << (ypos++) << ";3,0.5;btn_touchscreen_layout;" << strgettext("Touchscreen Layout") << "]"; diff --git a/src/client/guiscalingfilter.cpp b/src/client/guiscalingfilter.cpp index a8d17722b..33b175d09 100644 --- a/src/client/guiscalingfilter.cpp +++ b/src/client/guiscalingfilter.cpp @@ -94,8 +94,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver, auto it_img = g_imgCache.find(origname); video::IImage *srcimg = (it_img != g_imgCache.end()) ? it_img->second : nullptr; if (!srcimg) { - if (!g_settings->getBool("gui_scaling_filter_txr2img")) - return src; + // Download image from GPU srcimg = driver->createImageFromData(src->getColorFormat(), src->getSize(), src->lock(video::ETLM_READ_ONLY), false); src->unlock(); diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 627afac3b..d26457996 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -640,9 +640,6 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs Convert MeshCollector to SMesh */ - const bool desync_animations = g_settings->getBool( - "desynchronize_mapblock_texture_animation"); - m_bounding_radius = std::sqrt(collector.m_bounding_radius_sq); for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) { @@ -679,16 +676,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs auto &info = m_animation_info[{layer, i}]; info.tile = p.layer; info.frame = 0; - if (desync_animations) { - // Get starting position from noise - info.frame_offset = - 100000 * (2.0 + noise3d( - data->m_blockpos.X, data->m_blockpos.Y, - data->m_blockpos.Z, 0)); - } else { - // Play all synchronized - info.frame_offset = 0; - } + info.frame_offset = 0; // Replace tile texture with the first animation frame p.layer.texture = (*p.layer.frames)[0].texture; } diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index ca569486f..f2bcea1b5 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -82,7 +82,6 @@ void set_default_settings() // Client settings->setDefault("address", ""); - settings->setDefault("enable_sound", "true"); #if defined(__unix__) && !defined(__APPLE__) && !defined (__ANDROID__) // On Linux+X11 (not Linux+Wayland or Linux+XWayland), I've encountered a bug // where fake mouse events were generated from touch events if in relative @@ -270,7 +269,6 @@ void set_default_settings() settings->setDefault("cinematic", "false"); settings->setDefault("camera_smoothing", "0.0"); settings->setDefault("cinematic_camera_smoothing", "0.7"); - settings->setDefault("enable_clouds", "true"); settings->setDefault("view_bobbing_amount", "1.0"); settings->setDefault("fall_bobbing_amount", "0.03"); settings->setDefault("enable_3d_clouds", "true"); @@ -292,14 +290,11 @@ void set_default_settings() settings->setDefault("hud_scaling", "1.0"); settings->setDefault("gui_scaling", "1.0"); settings->setDefault("gui_scaling_filter", "false"); - settings->setDefault("gui_scaling_filter_txr2img", "true"); settings->setDefault("smooth_scrolling", "true"); - settings->setDefault("desynchronize_mapblock_texture_animation", "false"); settings->setDefault("hud_hotbar_max_width", "1.0"); settings->setDefault("enable_local_map_saving", "false"); settings->setDefault("show_entity_selectionbox", "false"); settings->setDefault("ambient_occlusion_gamma", "1.8"); - settings->setDefault("enable_particles", "true"); settings->setDefault("arm_inertia", "true"); settings->setDefault("show_nametag_backgrounds", "true"); settings->setDefault("show_block_bounds_radius_near", "4"); @@ -415,7 +410,6 @@ void set_default_settings() #endif // Server - settings->setDefault("disable_escape_sequences", "false"); settings->setDefault("strip_color_codes", "false"); #ifndef NDEBUG settings->setDefault("random_mod_load_order", "true"); @@ -435,7 +429,6 @@ void set_default_settings() settings->setDefault("protocol_version_min", "1"); settings->setDefault("player_transfer_distance", "0"); settings->setDefault("max_simultaneous_block_sends_per_client", "40"); - settings->setDefault("time_send_interval", "5"); settings->setDefault("motd", ""); settings->setDefault("max_users", "15"); diff --git a/src/gui/guiEngine.cpp b/src/gui/guiEngine.cpp index 912bdbc75..21b529d0b 100644 --- a/src/gui/guiEngine.cpp +++ b/src/gui/guiEngine.cpp @@ -130,7 +130,7 @@ GUIEngine::GUIEngine(JoystickController *joystick, // create soundmanager #if USE_SOUND - if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) { + if (g_sound_manager_singleton.get()) { m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(), std::make_unique()); } diff --git a/src/mapblock.cpp b/src/mapblock.cpp index f68657d9d..3039ff3e1 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -73,6 +73,12 @@ MapBlock::~MapBlock() porting::TrackFreedMemory(sizeof(MapNode) * nodecount); } +static inline size_t get_max_objects_per_block() +{ + u16 ret = g_settings->getU16("max_objects_per_block"); + return MYMAX(256, ret); +} + bool MapBlock::onObjectsActivation() { // Ignore if no stored objects (to not set changed flag) @@ -84,7 +90,7 @@ bool MapBlock::onObjectsActivation() << "activating " << count << " objects in block " << getPos() << std::endl; - if (count > g_settings->getU16("max_objects_per_block")) { + if (count > get_max_objects_per_block()) { errorstream << "suspiciously large amount of objects detected: " << count << " in " << getPos() << "; removing all of them." << std::endl; @@ -99,7 +105,7 @@ bool MapBlock::onObjectsActivation() bool MapBlock::saveStaticObject(u16 id, const StaticObject &obj, u32 reason) { - if (m_static_objects.getStoredSize() >= g_settings->getU16("max_objects_per_block")) { + if (m_static_objects.getStoredSize() >= get_max_objects_per_block()) { warningstream << "MapBlock::saveStaticObject(): Trying to store id = " << id << " statically but block " << getPos() << " already contains " << m_static_objects.getStoredSize() << " objects." diff --git a/src/server.cpp b/src/server.cpp index 92860cbbf..092528d7a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -650,9 +650,10 @@ void Server::AsyncRunStep(float dtime, bool initial_step) Send to clients at constant intervals */ + static const float time_send_interval = 5.0f; m_time_of_day_send_timer -= dtime; - if (m_time_of_day_send_timer < 0.0) { - m_time_of_day_send_timer = g_settings->getFloat("time_send_interval"); + if (m_time_of_day_send_timer < 0) { + m_time_of_day_send_timer = time_send_interval; u16 time = m_env->getTimeOfDay(); float time_speed = g_settings->getFloat("time_speed"); SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed); From 37899f7a14826ec78df3cad8d2b0dca44490d757 Mon Sep 17 00:00:00 2001 From: cosin15 <143353310+cosin15@users.noreply.github.com> Date: Sat, 11 Jan 2025 16:42:36 +0100 Subject: [PATCH 20/44] Fix CFileSystem::FileSystemType related UB (#15669) --- irr/src/CFileSystem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irr/src/CFileSystem.h b/irr/src/CFileSystem.h index 9400d85a3..d2a627e49 100644 --- a/irr/src/CFileSystem.h +++ b/irr/src/CFileSystem.h @@ -91,7 +91,7 @@ public: private: //! Currently used FileSystemType - EFileSystemType FileSystemType; + EFileSystemType FileSystemType = FILESYSTEM_NATIVE; //! WorkingDirectory for Native and Virtual filesystems io::path WorkingDirectory[2]; //! currently attached ArchiveLoaders From 436b391a800c267f6caabfe4adaee055120225e2 Mon Sep 17 00:00:00 2001 From: DS Date: Sat, 11 Jan 2025 16:43:20 +0100 Subject: [PATCH 21/44] VoxelArea: Fix missing cacheExtent calls in helpers (#15657) --- src/unittest/test_voxelarea.cpp | 15 +++++++++++++++ src/voxel.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/src/unittest/test_voxelarea.cpp b/src/unittest/test_voxelarea.cpp index f594a9be7..d9380caf9 100644 --- a/src/unittest/test_voxelarea.cpp +++ b/src/unittest/test_voxelarea.cpp @@ -98,10 +98,12 @@ void TestVoxelArea::test_addarea() void TestVoxelArea::test_pad() { VoxelArea v1(v3s16(-1447, -9547, -875), v3s16(-147, 8854, 669)); + auto old_extent = v1.getExtent(); v1.pad(v3s16(100, 200, 300)); UASSERT(v1.MinEdge == v3s16(-1547, -9747, -1175)); UASSERT(v1.MaxEdge == v3s16(-47, 9054, 969)); + UASSERT(v1.getExtent() > old_extent); } void TestVoxelArea::test_extent() @@ -165,6 +167,12 @@ void TestVoxelArea::test_contains_point() UASSERTEQ(bool, v1.contains(v3s16(-100, 100, 10000)), false); UASSERTEQ(bool, v1.contains(v3s16(-100, 100, -10000)), false); UASSERTEQ(bool, v1.contains(v3s16(10000, 100, 10)), false); + + VoxelArea v2; + UASSERTEQ(bool, v2.contains(v3s16(-200, 10, 10)), false); + UASSERTEQ(bool, v2.contains(v3s16(0, 0, 0)), false); + UASSERTEQ(bool, v2.contains(v3s16(1, 1, 1)), false); + UASSERTEQ(bool, v2.contains(v3s16(-1, -1, -1)), false); } void TestVoxelArea::test_contains_i() @@ -180,6 +188,12 @@ void TestVoxelArea::test_contains_i() UASSERTEQ(bool, v2.contains(10), true); UASSERTEQ(bool, v2.contains(0), true); UASSERTEQ(bool, v2.contains(-1), false); + + VoxelArea v3; + UASSERTEQ(bool, v3.contains(0), false); + UASSERTEQ(bool, v3.contains(-1), false); + UASSERTEQ(bool, v3.contains(1), false); + UASSERTEQ(bool, v3.contains(2), false); } void TestVoxelArea::test_equal() @@ -244,6 +258,7 @@ void TestVoxelArea::test_intersect() VoxelArea v3({11, 11, 11}, {11, 11, 11}); VoxelArea v4({-11, -2, -10}, {10, 2, 11}); UASSERT(v2.intersect(v1) == v2); + UASSERT(!v2.intersect(v1).hasEmptyExtent()); UASSERT(v1.intersect(v2) == v2.intersect(v1)); UASSERT(v1.intersect(v3).hasEmptyExtent()); UASSERT(v3.intersect(v1) == v1.intersect(v3)); diff --git a/src/voxel.h b/src/voxel.h index a35be3e19..63775040d 100644 --- a/src/voxel.h +++ b/src/voxel.h @@ -103,6 +103,7 @@ public: { MinEdge -= d; MaxEdge += d; + cacheExtent(); } /* @@ -188,6 +189,7 @@ public: ret.MaxEdge.Y = std::min(a.MaxEdge.Y, MaxEdge.Y); ret.MinEdge.Z = std::max(a.MinEdge.Z, MinEdge.Z); ret.MaxEdge.Z = std::min(a.MaxEdge.Z, MaxEdge.Z); + ret.cacheExtent(); return ret; } From cbc074feb5e3e1bbb7e53011622ea7b09e16fe3b Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 7 Jan 2025 12:46:59 +0100 Subject: [PATCH 22/44] Remove the unnecessary MeshCollector::append overload --- src/client/content_mapblock.cpp | 21 ++++++++++------- src/client/meshgen/collector.cpp | 39 -------------------------------- src/client/meshgen/collector.h | 9 -------- 3 files changed, 13 insertions(+), 56 deletions(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 4d1eeec47..3b30d5170 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -1685,22 +1685,27 @@ void MapblockMeshGenerator::drawMeshNode() video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices(); u32 vertex_count = buf->getVertexCount(); + // Mesh is always private here. So the lighting is applied to each + // vertex right here. if (data->m_smooth_lighting) { - // Mesh is always private here. So the lighting is applied to each - // vertex right here. for (u32 k = 0; k < vertex_count; k++) { video::S3DVertex &vertex = vertices[k]; vertex.Color = blendLightColor(vertex.Pos, vertex.Normal); vertex.Pos += cur_node.origin; } - collector->append(cur_node.tile, vertices, vertex_count, - buf->getIndices(), buf->getIndexCount()); } else { - // Let the collector process colors, etc. - collector->append(cur_node.tile, vertices, vertex_count, - buf->getIndices(), buf->getIndexCount(), cur_node.origin, - cur_node.color, cur_node.f->light_source); + bool is_light_source = cur_node.f->light_source != 0; + for (u32 k = 0; k < vertex_count; k++) { + video::S3DVertex &vertex = vertices[k]; + video::SColor color = cur_node.color; + if (!is_light_source) + applyFacesShading(color, vertex.Normal); + vertex.Color = color; + vertex.Pos += cur_node.origin; + } } + collector->append(cur_node.tile, vertices, vertex_count, + buf->getIndices(), buf->getIndexCount()); } mesh->drop(); } diff --git a/src/client/meshgen/collector.cpp b/src/client/meshgen/collector.cpp index 476f3112b..5a4fb8489 100644 --- a/src/client/meshgen/collector.cpp +++ b/src/client/meshgen/collector.cpp @@ -41,45 +41,6 @@ void MeshCollector::append(const TileLayer &layer, const video::S3DVertex *verti p.indices.push_back(indices[i] + vertex_count); } -void MeshCollector::append(const TileSpec &tile, const video::S3DVertex *vertices, - u32 numVertices, const u16 *indices, u32 numIndices, v3f pos, - video::SColor c, u8 light_source) -{ - for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) { - const TileLayer *layer = &tile.layers[layernum]; - if (layer->texture_id == 0) - continue; - append(*layer, vertices, numVertices, indices, numIndices, pos, c, - light_source, layernum, tile.world_aligned); - } -} - -void MeshCollector::append(const TileLayer &layer, const video::S3DVertex *vertices, - u32 numVertices, const u16 *indices, u32 numIndices, v3f pos, - video::SColor c, u8 light_source, u8 layernum, bool use_scale) -{ - PreMeshBuffer &p = findBuffer(layer, layernum, numVertices); - - f32 scale = 1.0f; - if (use_scale) - scale = 1.0f / layer.scale; - - u32 vertex_count = p.vertices.size(); - for (u32 i = 0; i < numVertices; i++) { - video::SColor color = c; - if (!light_source) - applyFacesShading(color, vertices[i].Normal); - auto vpos = vertices[i].Pos + pos + offset; - p.vertices.emplace_back(vpos, vertices[i].Normal, color, - scale * vertices[i].TCoords); - m_bounding_radius_sq = std::max(m_bounding_radius_sq, - (vpos - m_center_pos).getLengthSQ()); - } - - for (u32 i = 0; i < numIndices; i++) - p.indices.push_back(indices[i] + vertex_count); -} - PreMeshBuffer &MeshCollector::findBuffer( const TileLayer &layer, u8 layernum, u32 numVertices) { diff --git a/src/client/meshgen/collector.h b/src/client/meshgen/collector.h index 79256e262..693e2be04 100644 --- a/src/client/meshgen/collector.h +++ b/src/client/meshgen/collector.h @@ -35,21 +35,12 @@ struct MeshCollector void append(const TileSpec &material, const video::S3DVertex *vertices, u32 numVertices, const u16 *indices, u32 numIndices); - void append(const TileSpec &material, - const video::S3DVertex *vertices, u32 numVertices, - const u16 *indices, u32 numIndices, - v3f pos, video::SColor c, u8 light_source); private: void append(const TileLayer &material, const video::S3DVertex *vertices, u32 numVertices, const u16 *indices, u32 numIndices, u8 layernum, bool use_scale = false); - void append(const TileLayer &material, - const video::S3DVertex *vertices, u32 numVertices, - const u16 *indices, u32 numIndices, - v3f pos, video::SColor c, u8 light_source, - u8 layernum, bool use_scale = false); PreMeshBuffer &findBuffer(const TileLayer &layer, u8 layernum, u32 numVertices); }; From 1e81c454c8ed459c76c3bbae25e74f62a372e4a4 Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 7 Jan 2025 12:57:27 +0100 Subject: [PATCH 23/44] transformNodeBox(): Replace BOXESPUSHBACK macro with a lambda --- src/mapnode.cpp | 74 +++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/src/mapnode.cpp b/src/mapnode.cpp index 5f706a489..e893125bd 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -419,57 +419,47 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox, boxes.reserve(boxes_size); -#define BOXESPUSHBACK(c) \ - for (std::vector::const_iterator \ - it = (c).begin(); \ - it != (c).end(); ++it) \ - (boxes).push_back(*it); + auto boxes_insert = [&](const std::vector &boxes_src) { + boxes.insert(boxes.end(), boxes_src.begin(), boxes_src.end()); + }; - BOXESPUSHBACK(nodebox.fixed); + boxes_insert(nodebox.fixed); - if (neighbors & 1) { - BOXESPUSHBACK(c.connect_top); - } else { - BOXESPUSHBACK(c.disconnected_top); - } + if (neighbors & 1) + boxes_insert(c.connect_top); + else + boxes_insert(c.disconnected_top); - if (neighbors & 2) { - BOXESPUSHBACK(c.connect_bottom); - } else { - BOXESPUSHBACK(c.disconnected_bottom); - } + if (neighbors & 2) + boxes_insert(c.connect_bottom); + else + boxes_insert(c.disconnected_bottom); - if (neighbors & 4) { - BOXESPUSHBACK(c.connect_front); - } else { - BOXESPUSHBACK(c.disconnected_front); - } + if (neighbors & 4) + boxes_insert(c.connect_front); + else + boxes_insert(c.disconnected_front); - if (neighbors & 8) { - BOXESPUSHBACK(c.connect_left); - } else { - BOXESPUSHBACK(c.disconnected_left); - } + if (neighbors & 8) + boxes_insert(c.connect_left); + else + boxes_insert(c.disconnected_left); - if (neighbors & 16) { - BOXESPUSHBACK(c.connect_back); - } else { - BOXESPUSHBACK(c.disconnected_back); - } + if (neighbors & 16) + boxes_insert(c.connect_back); + else + boxes_insert(c.disconnected_back); - if (neighbors & 32) { - BOXESPUSHBACK(c.connect_right); - } else { - BOXESPUSHBACK(c.disconnected_right); - } + if (neighbors & 32) + boxes_insert(c.connect_right); + else + boxes_insert(c.disconnected_right); - if (neighbors == 0) { - BOXESPUSHBACK(c.disconnected); - } + if (neighbors == 0) + boxes_insert(c.disconnected); - if (neighbors < 4) { - BOXESPUSHBACK(c.disconnected_sides); - } + if (neighbors < 4) + boxes_insert(c.disconnected_sides); } else // NODEBOX_REGULAR From 966abc85da49379726e28a9a82c99e33e41b3b8e Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 7 Jan 2025 13:09:12 +0100 Subject: [PATCH 24/44] transformNodeBox(): Rotate first by facedir --- src/mapnode.cpp | 106 +++++++----------------------------------------- 1 file changed, 14 insertions(+), 92 deletions(-) diff --git a/src/mapnode.cpp b/src/mapnode.cpp index e893125bd..22fc36086 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -179,130 +179,52 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox, if (nodebox.type == NODEBOX_FIXED || nodebox.type == NODEBOX_LEVELED) { const auto &fixed = nodebox.fixed; int facedir = n.getFaceDir(nodemgr, true); - u8 axisdir = facedir>>2; - facedir&=0x03; + u8 axisdir = facedir >> 2; + facedir &= 0x03; boxes.reserve(boxes.size() + fixed.size()); for (aabb3f box : fixed) { if (nodebox.type == NODEBOX_LEVELED) box.MaxEdge.Y = (-0.5f + n.getLevel(nodemgr) / 64.0f) * BS; + if(facedir == 1) { + box.MinEdge.rotateXZBy(-90); + box.MaxEdge.rotateXZBy(-90); + } else if(facedir == 2) { + box.MinEdge.rotateXZBy(180); + box.MaxEdge.rotateXZBy(180); + } else if(facedir == 3) { + box.MinEdge.rotateXZBy(90); + box.MaxEdge.rotateXZBy(90); + } + switch (axisdir) { case 0: - if(facedir == 1) - { - box.MinEdge.rotateXZBy(-90); - box.MaxEdge.rotateXZBy(-90); - } - else if(facedir == 2) - { - box.MinEdge.rotateXZBy(180); - box.MaxEdge.rotateXZBy(180); - } - else if(facedir == 3) - { - box.MinEdge.rotateXZBy(90); - box.MaxEdge.rotateXZBy(90); - } break; case 1: // z+ box.MinEdge.rotateYZBy(90); box.MaxEdge.rotateYZBy(90); - if(facedir == 1) - { - box.MinEdge.rotateXYBy(90); - box.MaxEdge.rotateXYBy(90); - } - else if(facedir == 2) - { - box.MinEdge.rotateXYBy(180); - box.MaxEdge.rotateXYBy(180); - } - else if(facedir == 3) - { - box.MinEdge.rotateXYBy(-90); - box.MaxEdge.rotateXYBy(-90); - } break; case 2: //z- box.MinEdge.rotateYZBy(-90); box.MaxEdge.rotateYZBy(-90); - if(facedir == 1) - { - box.MinEdge.rotateXYBy(-90); - box.MaxEdge.rotateXYBy(-90); - } - else if(facedir == 2) - { - box.MinEdge.rotateXYBy(180); - box.MaxEdge.rotateXYBy(180); - } - else if(facedir == 3) - { - box.MinEdge.rotateXYBy(90); - box.MaxEdge.rotateXYBy(90); - } break; case 3: //x+ box.MinEdge.rotateXYBy(-90); box.MaxEdge.rotateXYBy(-90); - if(facedir == 1) - { - box.MinEdge.rotateYZBy(90); - box.MaxEdge.rotateYZBy(90); - } - else if(facedir == 2) - { - box.MinEdge.rotateYZBy(180); - box.MaxEdge.rotateYZBy(180); - } - else if(facedir == 3) - { - box.MinEdge.rotateYZBy(-90); - box.MaxEdge.rotateYZBy(-90); - } break; case 4: //x- box.MinEdge.rotateXYBy(90); box.MaxEdge.rotateXYBy(90); - if(facedir == 1) - { - box.MinEdge.rotateYZBy(-90); - box.MaxEdge.rotateYZBy(-90); - } - else if(facedir == 2) - { - box.MinEdge.rotateYZBy(180); - box.MaxEdge.rotateYZBy(180); - } - else if(facedir == 3) - { - box.MinEdge.rotateYZBy(90); - box.MaxEdge.rotateYZBy(90); - } break; case 5: box.MinEdge.rotateXYBy(-180); box.MaxEdge.rotateXYBy(-180); - if(facedir == 1) - { - box.MinEdge.rotateXZBy(90); - box.MaxEdge.rotateXZBy(90); - } - else if(facedir == 2) - { - box.MinEdge.rotateXZBy(180); - box.MaxEdge.rotateXZBy(180); - } - else if(facedir == 3) - { - box.MinEdge.rotateXZBy(-90); - box.MaxEdge.rotateXZBy(-90); - } break; default: break; } + box.repair(); boxes.push_back(box); } From a14b8d09769ff20ff77815e3ab26d076437183e4 Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 7 Jan 2025 14:05:06 +0100 Subject: [PATCH 25/44] Get rid of MapblockMeshGenerator::cur_node.tile There is more than one tile per node, so it shouldn't be stored like this. This makes MapblockMeshGenerator less stateful. --- src/client/content_mapblock.cpp | 199 +++++++++++++++++--------------- src/client/content_mapblock.h | 23 ++-- 2 files changed, 118 insertions(+), 104 deletions(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 3b30d5170..76b18e4d1 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -68,40 +68,41 @@ MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector { } -void MapblockMeshGenerator::useTile(int index, u8 set_flags, u8 reset_flags, bool special) +void MapblockMeshGenerator::useTile(TileSpec *tile_ret, int index, u8 set_flags, + u8 reset_flags, bool special) { if (special) - getSpecialTile(index, &cur_node.tile, cur_node.p == data->m_crack_pos_relative); + getSpecialTile(index, tile_ret, cur_node.p == data->m_crack_pos_relative); else - getTile(index, &cur_node.tile); + getTile(index, tile_ret); if (!data->m_smooth_lighting) cur_node.color = encode_light(cur_node.light, cur_node.f->light_source); - for (auto &layer : cur_node.tile.layers) { + for (auto &layer : tile_ret->layers) { layer.material_flags |= set_flags; layer.material_flags &= ~reset_flags; } } // Returns a tile, ready for use, non-rotated. -void MapblockMeshGenerator::getTile(int index, TileSpec *tile) +void MapblockMeshGenerator::getTile(int index, TileSpec *tile_ret) { - getNodeTileN(cur_node.n, cur_node.p, index, data, *tile); + getNodeTileN(cur_node.n, cur_node.p, index, data, *tile_ret); } // Returns a tile, ready for use, rotated according to the node facedir. -void MapblockMeshGenerator::getTile(v3s16 direction, TileSpec *tile) +void MapblockMeshGenerator::getTile(v3s16 direction, TileSpec *tile_ret) { - getNodeTile(cur_node.n, cur_node.p, direction, data, *tile); + getNodeTile(cur_node.n, cur_node.p, direction, data, *tile_ret); } // Returns a special tile, ready for use, non-rotated. -void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile, bool apply_crack) +void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile_ret, bool apply_crack) { - *tile = cur_node.f->special_tiles[index]; + *tile_ret = cur_node.f->special_tiles[index]; TileLayer *top_layer = nullptr; - for (auto &layernum : tile->layers) { + for (auto &layernum : tile_ret->layers) { TileLayer *layer = &layernum; if (layer->texture_id == 0) continue; @@ -114,7 +115,7 @@ void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile, bool apply top_layer->material_flags |= MATERIAL_FLAG_CRACK; } -void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal, +void MapblockMeshGenerator::drawQuad(const TileSpec &tile, v3f *coords, const v3s16 &normal, float vertical_tiling) { const v2f tcoords[4] = {v2f(0.0, 0.0), v2f(1.0, 0.0), @@ -133,10 +134,12 @@ void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal, applyFacesShading(vertices[j].Color, normal2); vertices[j].TCoords = tcoords[j]; } - collector->append(cur_node.tile, vertices, 4, quad_indices, 6); + collector->append(tile, vertices, 4, quad_indices, 6); } -static std::array setupCuboidVertices(const aabb3f &box, const f32 *txc, TileSpec *tiles, int tilecount) { +static std::array setupCuboidVertices(const aabb3f &box, + const f32 *txc, const TileSpec *tiles, int tilecount) +{ v3f min = box.MinEdge; v3f max = box.MaxEdge; @@ -218,7 +221,7 @@ enum class QuadDiagonal { // and to choose diagonal to split the quad at. template void MapblockMeshGenerator::drawCuboid(const aabb3f &box, - TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter) + const TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter) { assert(tilecount >= 1 && tilecount <= 6); // pre-condition @@ -323,8 +326,14 @@ static inline int lightDiff(LightPair a, LightPair b) return abs(a.lightDay - b.lightDay) + abs(a.lightNight - b.lightNight); } -void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc, - TileSpec *tiles, int tile_count, u8 mask) +void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const TileSpec &tile, + const f32 *txc, u8 mask) +{ + drawAutoLightedCuboid(box, &tile, 1, txc, mask); +} + +void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, + const TileSpec *tiles, int tile_count, const f32 *txc, u8 mask) { bool scale = std::fabs(cur_node.f->visual_scale - 1.0f) > 1e-3f; f32 texture_coord_buf[24]; @@ -348,10 +357,6 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc, generateCuboidTextureCoords(box, texture_coord_buf); txc = texture_coord_buf; } - if (!tiles) { - tiles = &cur_node.tile; - tile_count = 1; - } if (data->m_smooth_lighting) { LightInfo lights[8]; for (int j = 0; j < 8; ++j) { @@ -816,7 +821,8 @@ void MapblockMeshGenerator::drawLiquidNode() void MapblockMeshGenerator::drawGlasslikeNode() { - useTile(0, 0, 0); + TileSpec tile; + useTile(&tile, 0, 0, 0); for (int face = 0; face < 6; face++) { // Check this neighbor @@ -850,7 +856,7 @@ void MapblockMeshGenerator::drawGlasslikeNode() vertex.rotateXZBy(-90); break; } } - drawQuad(vertices, dir); + drawQuad(tile, vertices, dir); } } @@ -934,7 +940,6 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode() {0, 1, 8}, {0, 4, 16}, {3, 4, 17}, {3, 1, 9}, }; - cur_node.tile = tiles[1]; for (int edge = 0; edge < FRAMED_EDGE_COUNT; edge++) { bool edge_invisible; if (nb[nb_triplet[edge][2]]) @@ -943,14 +948,13 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode() edge_invisible = nb[nb_triplet[edge][0]] ^ nb[nb_triplet[edge][1]]; if (edge_invisible) continue; - drawAutoLightedCuboid(frame_edges[edge]); + drawAutoLightedCuboid(frame_edges[edge], tiles[1]); } for (int face = 0; face < 6; face++) { if (nb[face]) continue; - cur_node.tile = glass_tiles[face]; // Face at Z- v3f vertices[4] = { v3f(-a, a, -g), @@ -976,7 +980,7 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode() } } v3s16 dir = g_6dirs[face]; - drawQuad(vertices, dir); + drawQuad(glass_tiles[face], vertices, dir); } // Optionally render internal liquid level defined by param2 @@ -986,13 +990,18 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode() // Internal liquid level has param2 range 0 .. 63, // convert it to -0.5 .. 0.5 float vlev = (param2 / 63.0f) * 2.0f - 1.0f; - getSpecialTile(0, &cur_node.tile); - drawAutoLightedCuboid(aabb3f(-(nb[5] ? g : b), - -(nb[4] ? g : b), - -(nb[3] ? g : b), - (nb[2] ? g : b), - (nb[1] ? g : b) * vlev, - (nb[0] ? g : b))); + TileSpec tile; + getSpecialTile(0, &tile); + drawAutoLightedCuboid( + aabb3f( + -(nb[5] ? g : b), + -(nb[4] ? g : b), + -(nb[3] ? g : b), + (nb[2] ? g : b), + (nb[1] ? g : b) * vlev, + (nb[0] ? g : b) + ), + tile); } } @@ -1007,7 +1016,8 @@ void MapblockMeshGenerator::drawTorchlikeNode() case DWM_S2: tileindex = 0; break; // floor, but rotated default: tileindex = 2; // side (or invalid, shouldn't happen) } - useTile(tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING); + TileSpec tile; + useTile(&tile, tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING); float size = BS / 2 * cur_node.f->visual_scale; v3f vertices[4] = { @@ -1054,13 +1064,14 @@ void MapblockMeshGenerator::drawTorchlikeNode() break; } } - drawQuad(vertices); + drawQuad(tile, vertices); } void MapblockMeshGenerator::drawSignlikeNode() { u8 wall = cur_node.n.getWallMounted(nodedef); - useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING); + TileSpec tile; + useTile(&tile, 0, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING); static const float offset = BS / 16; float size = BS / 2 * cur_node.f->visual_scale; // Wall at X+ of node @@ -1091,11 +1102,11 @@ void MapblockMeshGenerator::drawSignlikeNode() vertex.rotateXYBy(-90); vertex.rotateXZBy(-90); break; } } - drawQuad(vertices); + drawQuad(tile, vertices); } -void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset, - bool offset_top_only) +void MapblockMeshGenerator::drawPlantlikeQuad(const TileSpec &tile, + float rotation, float quad_offset, bool offset_top_only) { const f32 scale = cur_node.scale; v3f vertices[4] = { @@ -1147,10 +1158,10 @@ void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset, } } - drawQuad(vertices, v3s16(0, 0, 0), cur_plant.plant_height); + drawQuad(tile, vertices, v3s16(0, 0, 0), cur_plant.plant_height); } -void MapblockMeshGenerator::drawPlantlike(bool is_rooted) +void MapblockMeshGenerator::drawPlantlike(const TileSpec &tile, bool is_rooted) { cur_plant.draw_style = PLANT_STYLE_CROSS; cur_node.scale = BS / 2 * cur_node.f->visual_scale; @@ -1205,47 +1216,49 @@ void MapblockMeshGenerator::drawPlantlike(bool is_rooted) switch (cur_plant.draw_style) { case PLANT_STYLE_CROSS: - drawPlantlikeQuad(46); - drawPlantlikeQuad(-44); + drawPlantlikeQuad(tile, 46); + drawPlantlikeQuad(tile, -44); break; case PLANT_STYLE_CROSS2: - drawPlantlikeQuad(91); - drawPlantlikeQuad(1); + drawPlantlikeQuad(tile, 91); + drawPlantlikeQuad(tile, 1); break; case PLANT_STYLE_STAR: - drawPlantlikeQuad(121); - drawPlantlikeQuad(241); - drawPlantlikeQuad(1); + drawPlantlikeQuad(tile, 121); + drawPlantlikeQuad(tile, 241); + drawPlantlikeQuad(tile, 1); break; case PLANT_STYLE_HASH: - drawPlantlikeQuad( 1, BS / 4); - drawPlantlikeQuad( 91, BS / 4); - drawPlantlikeQuad(181, BS / 4); - drawPlantlikeQuad(271, BS / 4); + drawPlantlikeQuad(tile, 1, BS / 4); + drawPlantlikeQuad(tile, 91, BS / 4); + drawPlantlikeQuad(tile, 181, BS / 4); + drawPlantlikeQuad(tile, 271, BS / 4); break; case PLANT_STYLE_HASH2: - drawPlantlikeQuad( 1, -BS / 2, true); - drawPlantlikeQuad( 91, -BS / 2, true); - drawPlantlikeQuad(181, -BS / 2, true); - drawPlantlikeQuad(271, -BS / 2, true); + drawPlantlikeQuad(tile, 1, -BS / 2, true); + drawPlantlikeQuad(tile, 91, -BS / 2, true); + drawPlantlikeQuad(tile, 181, -BS / 2, true); + drawPlantlikeQuad(tile, 271, -BS / 2, true); break; } } void MapblockMeshGenerator::drawPlantlikeNode() { - useTile(); - drawPlantlike(); + TileSpec tile; + useTile(&tile); + drawPlantlike(tile); } void MapblockMeshGenerator::drawPlantlikeRootedNode() { drawSolidNode(); - useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, 0, true); + TileSpec tile; + useTile(&tile, 0, MATERIAL_FLAG_CRACK_OVERLAY, 0, true); cur_node.origin += v3f(0.0, BS, 0.0); cur_node.p.Y++; if (data->m_smooth_lighting) { @@ -1254,12 +1267,12 @@ void MapblockMeshGenerator::drawPlantlikeRootedNode() MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p); cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef)); } - drawPlantlike(true); + drawPlantlike(tile, true); cur_node.p.Y--; } -void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle, - float offset_h, float offset_v) +void MapblockMeshGenerator::drawFirelikeQuad(const TileSpec &tile, float rotation, + float opening_angle, float offset_h, float offset_v) { const f32 scale = cur_node.scale; v3f vertices[4] = { @@ -1275,12 +1288,13 @@ void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle vertex.rotateXZBy(rotation); vertex.Y += offset_v; } - drawQuad(vertices); + drawQuad(tile, vertices); } void MapblockMeshGenerator::drawFirelikeNode() { - useTile(); + TileSpec tile; + useTile(&tile); cur_node.scale = BS / 2 * cur_node.f->visual_scale; // Check for adjacent nodes @@ -1300,41 +1314,41 @@ void MapblockMeshGenerator::drawFirelikeNode() bool drawBottomFire = neighbor[D6D_YP]; if (drawBasicFire || neighbor[D6D_ZP]) - drawFirelikeQuad(0, -10, 0.4 * BS); + drawFirelikeQuad(tile, 0, -10, 0.4 * BS); else if (drawBottomFire) - drawFirelikeQuad(0, 70, 0.47 * BS, 0.484 * BS); + drawFirelikeQuad(tile, 0, 70, 0.47 * BS, 0.484 * BS); if (drawBasicFire || neighbor[D6D_XN]) - drawFirelikeQuad(90, -10, 0.4 * BS); + drawFirelikeQuad(tile, 90, -10, 0.4 * BS); else if (drawBottomFire) - drawFirelikeQuad(90, 70, 0.47 * BS, 0.484 * BS); + drawFirelikeQuad(tile, 90, 70, 0.47 * BS, 0.484 * BS); if (drawBasicFire || neighbor[D6D_ZN]) - drawFirelikeQuad(180, -10, 0.4 * BS); + drawFirelikeQuad(tile, 180, -10, 0.4 * BS); else if (drawBottomFire) - drawFirelikeQuad(180, 70, 0.47 * BS, 0.484 * BS); + drawFirelikeQuad(tile, 180, 70, 0.47 * BS, 0.484 * BS); if (drawBasicFire || neighbor[D6D_XP]) - drawFirelikeQuad(270, -10, 0.4 * BS); + drawFirelikeQuad(tile, 270, -10, 0.4 * BS); else if (drawBottomFire) - drawFirelikeQuad(270, 70, 0.47 * BS, 0.484 * BS); + drawFirelikeQuad(tile, 270, 70, 0.47 * BS, 0.484 * BS); if (drawBasicFire) { - drawFirelikeQuad(45, 0, 0.0); - drawFirelikeQuad(-45, 0, 0.0); + drawFirelikeQuad(tile, 45, 0, 0.0); + drawFirelikeQuad(tile, -45, 0, 0.0); } } void MapblockMeshGenerator::drawFencelikeNode() { - useTile(0, 0, 0); - TileSpec tile_nocrack = cur_node.tile; + TileSpec tile_nocrack; + useTile(&tile_nocrack, 0, 0, 0); for (auto &layer : tile_nocrack.layers) layer.material_flags &= ~MATERIAL_FLAG_CRACK; // Put wood the right way around in the posts - TileSpec tile_rot = cur_node.tile; + TileSpec tile_rot = tile_nocrack; tile_rot.rotation = TileRotation::R90; static const f32 post_rad = BS / 8; @@ -1352,10 +1366,7 @@ void MapblockMeshGenerator::drawFencelikeNode() 0.500, 0.000, 0.750, 1.000, 0.750, 0.000, 1.000, 1.000, }; - cur_node.tile = tile_rot; - drawAutoLightedCuboid(post, postuv); - - cur_node.tile = tile_nocrack; + drawAutoLightedCuboid(post, tile_rot, postuv); // Now a section of fence, +X, if there's a post there v3s16 p2 = cur_node.p; @@ -1375,8 +1386,8 @@ void MapblockMeshGenerator::drawFencelikeNode() 0.000, 0.500, 1.000, 0.625, 0.000, 0.875, 1.000, 1.000, }; - drawAutoLightedCuboid(bar_x1, xrailuv); - drawAutoLightedCuboid(bar_x2, xrailuv); + drawAutoLightedCuboid(bar_x1, tile_nocrack, xrailuv); + drawAutoLightedCuboid(bar_x2, tile_nocrack, xrailuv); } // Now a section of fence, +Z, if there's a post there @@ -1397,8 +1408,8 @@ void MapblockMeshGenerator::drawFencelikeNode() 0.3750, 0.3750, 0.5000, 0.5000, 0.6250, 0.6250, 0.7500, 0.7500, }; - drawAutoLightedCuboid(bar_z1, zrailuv); - drawAutoLightedCuboid(bar_z2, zrailuv); + drawAutoLightedCuboid(bar_z1, tile_nocrack, zrailuv); + drawAutoLightedCuboid(bar_z2, tile_nocrack, zrailuv); } } @@ -1480,7 +1491,8 @@ void MapblockMeshGenerator::drawRaillikeNode() angle = rail_kinds[code].angle; } - useTile(tile_index, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING); + TileSpec tile; + useTile(&tile, tile_index, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING); static const float offset = BS / 64; static const float size = BS / 2; @@ -1494,7 +1506,7 @@ void MapblockMeshGenerator::drawRaillikeNode() if (angle) for (v3f &vertex : vertices) vertex.rotateXZBy(angle); - drawQuad(vertices); + drawQuad(tile, vertices); } namespace { @@ -1526,7 +1538,7 @@ void MapblockMeshGenerator::drawAllfacesNode() getTile(nodebox_tile_dirs[face], &tiles[face]); if (data->m_smooth_lighting) getSmoothLightFrame(); - drawAutoLightedCuboid(box, nullptr, tiles, 6); + drawAutoLightedCuboid(box, tiles, 6); } void MapblockMeshGenerator::drawNodeboxNode() @@ -1633,7 +1645,7 @@ void MapblockMeshGenerator::drawNodeboxNode() for (auto &box : boxes) { u8 mask = getNodeBoxMask(box, solid_neighbors, sametype_neighbors); - drawAutoLightedCuboid(box, nullptr, tiles, 6, mask); + drawAutoLightedCuboid(box, tiles, 6, nullptr, mask); } } @@ -1678,8 +1690,9 @@ void MapblockMeshGenerator::drawMeshNode() for (u32 j = 0; j < mesh->getMeshBufferCount(); j++) { // Only up to 6 tiles are supported - const u32 tile = mesh->getTextureSlot(j); - useTile(MYMIN(tile, 5)); + const u32 tile_idx = mesh->getTextureSlot(j); + TileSpec tile; + useTile(&tile, MYMIN(tile_idx, 5)); scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices(); @@ -1704,7 +1717,7 @@ void MapblockMeshGenerator::drawMeshNode() vertex.Pos += cur_node.origin; } } - collector->append(cur_node.tile, vertices, vertex_count, + collector->append(tile, vertices, vertex_count, buf->getIndices(), buf->getIndexCount()); } mesh->drop(); diff --git a/src/client/content_mapblock.h b/src/client/content_mapblock.h index 327a7ea05..e7fc2aa37 100644 --- a/src/client/content_mapblock.h +++ b/src/client/content_mapblock.h @@ -66,7 +66,6 @@ private: LightPair light; LightFrame frame; video::SColor color; - TileSpec tile; f32 scale; } cur_node; @@ -76,21 +75,23 @@ private: video::SColor blendLightColor(const v3f &vertex_pos); video::SColor blendLightColor(const v3f &vertex_pos, const v3f &vertex_normal); - void useTile(int index = 0, u8 set_flags = MATERIAL_FLAG_CRACK_OVERLAY, + void useTile(TileSpec *tile_ret, int index = 0, u8 set_flags = MATERIAL_FLAG_CRACK_OVERLAY, u8 reset_flags = 0, bool special = false); - void getTile(int index, TileSpec *tile); - void getTile(v3s16 direction, TileSpec *tile); - void getSpecialTile(int index, TileSpec *tile, bool apply_crack = false); + void getTile(int index, TileSpec *tile_ret); + void getTile(v3s16 direction, TileSpec *tile_ret); + void getSpecialTile(int index, TileSpec *tile_ret, bool apply_crack = false); // face drawing - void drawQuad(v3f *vertices, const v3s16 &normal = v3s16(0, 0, 0), + void drawQuad(const TileSpec &tile, v3f *vertices, const v3s16 &normal = v3s16(0, 0, 0), float vertical_tiling = 1.0); // cuboid drawing! template - void drawCuboid(const aabb3f &box, TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter); + void drawCuboid(const aabb3f &box, const TileSpec *tiles, int tilecount, + const f32 *txc, u8 mask, Fn &&face_lighter); void generateCuboidTextureCoords(aabb3f const &box, f32 *coords); - void drawAutoLightedCuboid(aabb3f box, f32 const *txc = nullptr, TileSpec *tiles = nullptr, int tile_count = 0, u8 mask = 0); + void drawAutoLightedCuboid(aabb3f box, const TileSpec &tile, f32 const *txc = nullptr, u8 mask = 0); + void drawAutoLightedCuboid(aabb3f box, const TileSpec *tiles, int tile_count, f32 const *txc = nullptr, u8 mask = 0); u8 getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const; // liquid-specific @@ -143,12 +144,12 @@ private: }; PlantlikeData cur_plant; - void drawPlantlikeQuad(float rotation, float quad_offset = 0, + void drawPlantlikeQuad(const TileSpec &tile, float rotation, float quad_offset = 0, bool offset_top_only = false); - void drawPlantlike(bool is_rooted = false); + void drawPlantlike(const TileSpec &tile, bool is_rooted = false); // firelike-specific - void drawFirelikeQuad(float rotation, float opening_angle, + void drawFirelikeQuad(const TileSpec &tile, float rotation, float opening_angle, float offset_h, float offset_v = 0.0); // drawtypes From 3becbda0aa87626b8aff4b3f61d3f90c636c2f98 Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 7 Jan 2025 14:16:40 +0100 Subject: [PATCH 26/44] Get rid of MapblockMeshGenerator::cur_node.scale --- src/client/content_mapblock.cpp | 9 ++++----- src/client/content_mapblock.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 76b18e4d1..6237f2e94 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -1108,7 +1108,7 @@ void MapblockMeshGenerator::drawSignlikeNode() void MapblockMeshGenerator::drawPlantlikeQuad(const TileSpec &tile, float rotation, float quad_offset, bool offset_top_only) { - const f32 scale = cur_node.scale; + const f32 scale = cur_plant.scale; v3f vertices[4] = { v3f(-scale, -BS / 2 + 2.0 * scale * cur_plant.plant_height, 0), v3f( scale, -BS / 2 + 2.0 * scale * cur_plant.plant_height, 0), @@ -1164,8 +1164,8 @@ void MapblockMeshGenerator::drawPlantlikeQuad(const TileSpec &tile, void MapblockMeshGenerator::drawPlantlike(const TileSpec &tile, bool is_rooted) { cur_plant.draw_style = PLANT_STYLE_CROSS; - cur_node.scale = BS / 2 * cur_node.f->visual_scale; cur_plant.offset = v3f(0, 0, 0); + cur_plant.scale = BS / 2 * cur_node.f->visual_scale; cur_plant.rotate_degree = 0.0f; cur_plant.random_offset_Y = false; cur_plant.face_num = 0; @@ -1175,7 +1175,7 @@ void MapblockMeshGenerator::drawPlantlike(const TileSpec &tile, bool is_rooted) case CPT2_MESHOPTIONS: cur_plant.draw_style = PlantlikeStyle(cur_node.n.param2 & MO_MASK_STYLE); if (cur_node.n.param2 & MO_BIT_SCALE_SQRT2) - cur_node.scale *= 1.41421; + cur_plant.scale *= 1.41421; if (cur_node.n.param2 & MO_BIT_RANDOM_OFFSET) { PseudoRandom rng(cur_node.p.X << 8 | cur_node.p.Z | cur_node.p.Y << 16); cur_plant.offset.X = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145); @@ -1274,7 +1274,7 @@ void MapblockMeshGenerator::drawPlantlikeRootedNode() void MapblockMeshGenerator::drawFirelikeQuad(const TileSpec &tile, float rotation, float opening_angle, float offset_h, float offset_v) { - const f32 scale = cur_node.scale; + const f32 scale = BS / 2 * cur_node.f->visual_scale; v3f vertices[4] = { v3f(-scale, -BS / 2 + scale * 2, 0), v3f( scale, -BS / 2 + scale * 2, 0), @@ -1295,7 +1295,6 @@ void MapblockMeshGenerator::drawFirelikeNode() { TileSpec tile; useTile(&tile); - cur_node.scale = BS / 2 * cur_node.f->visual_scale; // Check for adjacent nodes bool neighbors = false; diff --git a/src/client/content_mapblock.h b/src/client/content_mapblock.h index e7fc2aa37..400577a08 100644 --- a/src/client/content_mapblock.h +++ b/src/client/content_mapblock.h @@ -66,7 +66,6 @@ private: LightPair light; LightFrame frame; video::SColor color; - f32 scale; } cur_node; // lighting @@ -137,6 +136,7 @@ private: struct PlantlikeData { PlantlikeStyle draw_style; v3f offset; + float scale; float rotate_degree; bool random_offset_Y; int face_num; From 6a1b4a93c70cb1d363c92028f8b62cd53c83c5e3 Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 7 Jan 2025 14:49:45 +0100 Subject: [PATCH 27/44] MapblockMeshGenerator: Move unsmooth lighting color out of useTile, and instead compute it once per node --- src/client/content_mapblock.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 6237f2e94..ad15fcb2e 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -75,8 +75,6 @@ void MapblockMeshGenerator::useTile(TileSpec *tile_ret, int index, u8 set_flags, getSpecialTile(index, tile_ret, cur_node.p == data->m_crack_pos_relative); else getTile(index, tile_ret); - if (!data->m_smooth_lighting) - cur_node.color = encode_light(cur_node.light, cur_node.f->light_source); for (auto &layer : tile_ret->layers) { layer.material_flags |= set_flags; @@ -283,7 +281,6 @@ LightInfo MapblockMeshGenerator::blendLight(const v3f &vertex_pos) // Calculates vertex color to be used in mapblock mesh // vertex_pos - vertex position in the node (coordinates are clamped to [0.0, 1.0] or so) -// tile_color - node's tile color video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos) { LightInfo light = blendLight(vertex_pos); @@ -382,7 +379,7 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, }); } else { drawCuboid(box, tiles, tile_count, txc, mask, [&] (int face, video::S3DVertex vertices[4]) { - video::SColor color = encode_light(cur_node.light, cur_node.f->light_source); + video::SColor color = cur_node.color; if (!cur_node.f->light_source) applyFacesShading(color, vertices[0].Normal); for (int j = 0; j < 4; j++) { @@ -700,10 +697,18 @@ void MapblockMeshGenerator::drawLiquidSides() v += 0.5f - cur_liquid.corner_levels[base.Z][base.X]; } + video::SColor color; if (data->m_smooth_lighting) - cur_node.color = blendLightColor(pos); + color = blendLightColor(pos); + else + color = cur_node.color; + pos += cur_node.origin; - vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z, face.dir.X, face.dir.Y, face.dir.Z, cur_node.color, vertex.u, v); + + vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z, + face.dir.X, face.dir.Y, face.dir.Z, + color, + vertex.u, v); }; collector->append(cur_liquid.tile, vertices, 4, quad_indices, 6); } @@ -866,9 +871,6 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode() for (int face = 0; face < 6; face++) getTile(g_6dirs[face], &tiles[face]); - if (!data->m_smooth_lighting) - cur_node.color = encode_light(cur_node.light, cur_node.f->light_source); - TileSpec glass_tiles[6]; for (auto &glass_tile : glass_tiles) glass_tile = tiles[4]; @@ -1265,7 +1267,7 @@ void MapblockMeshGenerator::drawPlantlikeRootedNode() getSmoothLightFrame(); } else { MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p); - cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef)); + cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef)); // FIXME: unused write } drawPlantlike(tile, true); cur_node.p.Y--; @@ -1742,10 +1744,12 @@ void MapblockMeshGenerator::drawNode() break; } cur_node.origin = intToFloat(cur_node.p, BS); - if (data->m_smooth_lighting) + if (data->m_smooth_lighting) { getSmoothLightFrame(); - else + } else { cur_node.light = LightPair(getInteriorLight(cur_node.n, 0, nodedef)); + cur_node.color = encode_light(cur_node.light, cur_node.f->light_source); + } switch (cur_node.f->drawtype) { case NDT_FLOWINGLIQUID: drawLiquidNode(); break; case NDT_GLASSLIKE: drawGlasslikeNode(); break; From c4bfa652017bc24c4eb6c0d47bae44aa5329c61f Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 7 Jan 2025 14:53:41 +0100 Subject: [PATCH 28/44] Fix black plantlike_rooted without smoothlighting There was code to take the light of the node above, but the color was not updated. To reproduce, don't set paramtype="light", (i.e. not what all the devtest nodes do). --- src/client/content_mapblock.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index ad15fcb2e..a33ad93c7 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -1267,7 +1267,8 @@ void MapblockMeshGenerator::drawPlantlikeRootedNode() getSmoothLightFrame(); } else { MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p); - cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef)); // FIXME: unused write + cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef)); + cur_node.color = encode_light(cur_node.light, cur_node.f->light_source); } drawPlantlike(tile, true); cur_node.p.Y--; From 7ba59731085858ca7af9a9ad5acad73e15d980af Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 7 Jan 2025 15:08:22 +0100 Subject: [PATCH 29/44] Get rid of MapblockMeshGenerator::cur_node.light --- src/client/content_mapblock.cpp | 19 ++++++++++--------- src/client/content_mapblock.h | 1 - 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index a33ad93c7..db172e097 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -542,19 +542,20 @@ void MapblockMeshGenerator::prepareLiquidNodeDrawing() if (data->m_smooth_lighting) return; // don't need to pre-compute anything in this case + auto light = LightPair(getInteriorLight(cur_node.n, 0, nodedef)); if (cur_node.f->light_source != 0) { // If this liquid emits light and doesn't contain light, draw // it at what it emits, for an increased effect u8 e = decode_light(cur_node.f->light_source); - cur_node.light = LightPair(std::max(e, cur_node.light.lightDay), - std::max(e, cur_node.light.lightNight)); + light = LightPair(std::max(e, light.lightDay), + std::max(e, light.lightNight)); } else if (nodedef->getLightingFlags(ntop).has_light) { // Otherwise, use the light of the node on top if possible - cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef)); + light = LightPair(getInteriorLight(ntop, 0, nodedef)); } - cur_liquid.color_top = encode_light(cur_node.light, cur_node.f->light_source); - cur_node.color = encode_light(cur_node.light, cur_node.f->light_source); + cur_liquid.color_top = encode_light(light, cur_node.f->light_source); + cur_node.color = encode_light(light, cur_node.f->light_source); } void MapblockMeshGenerator::getLiquidNeighborhood() @@ -1267,8 +1268,8 @@ void MapblockMeshGenerator::drawPlantlikeRootedNode() getSmoothLightFrame(); } else { MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p); - cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef)); - cur_node.color = encode_light(cur_node.light, cur_node.f->light_source); + auto light = LightPair(getInteriorLight(ntop, 0, nodedef)); + cur_node.color = encode_light(light, cur_node.f->light_source); } drawPlantlike(tile, true); cur_node.p.Y--; @@ -1748,8 +1749,8 @@ void MapblockMeshGenerator::drawNode() if (data->m_smooth_lighting) { getSmoothLightFrame(); } else { - cur_node.light = LightPair(getInteriorLight(cur_node.n, 0, nodedef)); - cur_node.color = encode_light(cur_node.light, cur_node.f->light_source); + auto light = LightPair(getInteriorLight(cur_node.n, 0, nodedef)); + cur_node.color = encode_light(light, cur_node.f->light_source); } switch (cur_node.f->drawtype) { case NDT_FLOWINGLIQUID: drawLiquidNode(); break; diff --git a/src/client/content_mapblock.h b/src/client/content_mapblock.h index 400577a08..bc9e86e8a 100644 --- a/src/client/content_mapblock.h +++ b/src/client/content_mapblock.h @@ -63,7 +63,6 @@ private: v3f origin; MapNode n; const ContentFeatures *f; - LightPair light; LightFrame frame; video::SColor color; } cur_node; From 9a60b83061f389df674a41a1a400acc6413f905b Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 7 Jan 2025 15:32:59 +0100 Subject: [PATCH 30/44] Rename meshgen lighting variables --- src/client/content_mapblock.cpp | 30 +++++++++++++++--------------- src/client/content_mapblock.h | 8 ++++---- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index db172e097..f1e268866 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -127,7 +127,7 @@ void MapblockMeshGenerator::drawQuad(const TileSpec &tile, v3f *coords, const v3 if (data->m_smooth_lighting) vertices[j].Color = blendLightColor(coords[j]); else - vertices[j].Color = cur_node.color; + vertices[j].Color = cur_node.lcolor; if (shade_face) applyFacesShading(vertices[j].Color, normal2); vertices[j].TCoords = tcoords[j]; @@ -239,16 +239,16 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box, void MapblockMeshGenerator::getSmoothLightFrame() { for (int k = 0; k < 8; ++k) - cur_node.frame.sunlight[k] = false; + cur_node.lframe.sunlight[k] = false; for (int k = 0; k < 8; ++k) { LightPair light(getSmoothLightTransparent(blockpos_nodes + cur_node.p, light_dirs[k], data)); - cur_node.frame.lightsDay[k] = light.lightDay; - cur_node.frame.lightsNight[k] = light.lightNight; + cur_node.lframe.lightsDay[k] = light.lightDay; + cur_node.lframe.lightsNight[k] = light.lightNight; // If there is direct sunlight and no ambient occlusion at some corner, // mark the vertical edge (top and bottom corners) containing it. if (light.lightDay == 255) { - cur_node.frame.sunlight[k] = true; - cur_node.frame.sunlight[k ^ 2] = true; + cur_node.lframe.sunlight[k] = true; + cur_node.lframe.sunlight[k ^ 2] = true; } } } @@ -271,9 +271,9 @@ LightInfo MapblockMeshGenerator::blendLight(const v3f &vertex_pos) f32 dy = (k & 2) ? y : 1 - y; f32 dz = (k & 1) ? z : 1 - z; // Use direct sunlight (255), if any; use daylight otherwise. - f32 light_boosted = cur_node.frame.sunlight[k] ? 255 : cur_node.frame.lightsDay[k]; - lightDay += dx * dy * dz * cur_node.frame.lightsDay[k]; - lightNight += dx * dy * dz * cur_node.frame.lightsNight[k]; + f32 light_boosted = cur_node.lframe.sunlight[k] ? 255 : cur_node.lframe.lightsDay[k]; + lightDay += dx * dy * dz * cur_node.lframe.lightsDay[k]; + lightNight += dx * dy * dz * cur_node.lframe.lightsNight[k]; lightBoosted += dx * dy * dz * light_boosted; } return LightInfo{lightDay, lightNight, lightBoosted}; @@ -379,7 +379,7 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, }); } else { drawCuboid(box, tiles, tile_count, txc, mask, [&] (int face, video::S3DVertex vertices[4]) { - video::SColor color = cur_node.color; + video::SColor color = cur_node.lcolor; if (!cur_node.f->light_source) applyFacesShading(color, vertices[0].Normal); for (int j = 0; j < 4; j++) { @@ -555,7 +555,7 @@ void MapblockMeshGenerator::prepareLiquidNodeDrawing() } cur_liquid.color_top = encode_light(light, cur_node.f->light_source); - cur_node.color = encode_light(light, cur_node.f->light_source); + cur_node.lcolor = encode_light(light, cur_node.f->light_source); } void MapblockMeshGenerator::getLiquidNeighborhood() @@ -702,7 +702,7 @@ void MapblockMeshGenerator::drawLiquidSides() if (data->m_smooth_lighting) color = blendLightColor(pos); else - color = cur_node.color; + color = cur_node.lcolor; pos += cur_node.origin; @@ -1269,7 +1269,7 @@ void MapblockMeshGenerator::drawPlantlikeRootedNode() } else { MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p); auto light = LightPair(getInteriorLight(ntop, 0, nodedef)); - cur_node.color = encode_light(light, cur_node.f->light_source); + cur_node.lcolor = encode_light(light, cur_node.f->light_source); } drawPlantlike(tile, true); cur_node.p.Y--; @@ -1713,7 +1713,7 @@ void MapblockMeshGenerator::drawMeshNode() bool is_light_source = cur_node.f->light_source != 0; for (u32 k = 0; k < vertex_count; k++) { video::S3DVertex &vertex = vertices[k]; - video::SColor color = cur_node.color; + video::SColor color = cur_node.lcolor; if (!is_light_source) applyFacesShading(color, vertex.Normal); vertex.Color = color; @@ -1750,7 +1750,7 @@ void MapblockMeshGenerator::drawNode() getSmoothLightFrame(); } else { auto light = LightPair(getInteriorLight(cur_node.n, 0, nodedef)); - cur_node.color = encode_light(light, cur_node.f->light_source); + cur_node.lcolor = encode_light(light, cur_node.f->light_source); } switch (cur_node.f->drawtype) { case NDT_FLOWINGLIQUID: drawLiquidNode(); break; diff --git a/src/client/content_mapblock.h b/src/client/content_mapblock.h index bc9e86e8a..8302cd2a7 100644 --- a/src/client/content_mapblock.h +++ b/src/client/content_mapblock.h @@ -59,12 +59,12 @@ private: // current node struct { - v3s16 p; - v3f origin; + v3s16 p; // relative to blockpos_nodes + v3f origin; // p in BS space MapNode n; const ContentFeatures *f; - LightFrame frame; - video::SColor color; + LightFrame lframe; // smooth lighting + video::SColor lcolor; // unsmooth lighting } cur_node; // lighting From c0ce918d77ed7e23c5e8da480d4ca99f213beb3c Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 7 Jan 2025 15:36:45 +0100 Subject: [PATCH 31/44] Meshgen: Handle enable_water_reflections like smooth_lighting --- src/client/content_mapblock.cpp | 7 +++---- src/client/content_mapblock.h | 1 - src/client/mapblock_mesh.cpp | 5 ----- src/client/mapblock_mesh.h | 6 +----- src/client/mesh_generator_thread.cpp | 4 +++- src/client/mesh_generator_thread.h | 3 ++- src/client/wieldmesh.cpp | 3 ++- src/unittest/test_content_mapblock.cpp | 3 ++- 8 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index f1e268866..56d0bd498 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -63,8 +63,7 @@ MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector data(input), collector(output), nodedef(data->nodedef), - blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE), - smooth_liquids(g_settings->getBool("enable_water_reflections")) + blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE) { } @@ -733,7 +732,7 @@ void MapblockMeshGenerator::drawLiquidTop() int u = corner_resolve[i][0]; int w = corner_resolve[i][1]; - if (smooth_liquids) { + if (data->m_enable_water_reflections) { int x = vertices[i].Pos.X > 0; int z = vertices[i].Pos.Z > 0; @@ -785,7 +784,7 @@ void MapblockMeshGenerator::drawLiquidTop() vertex.TCoords += tcoord_translate; - if (!smooth_liquids) { + if (!data->m_enable_water_reflections) { vertex.Normal = v3f(dx, 1., dz).normalize(); } } diff --git a/src/client/content_mapblock.h b/src/client/content_mapblock.h index 8302cd2a7..2bfbbdc61 100644 --- a/src/client/content_mapblock.h +++ b/src/client/content_mapblock.h @@ -112,7 +112,6 @@ private: f32 corner_levels[2][2]; }; LiquidData cur_liquid; - bool smooth_liquids = false; void prepareLiquidNodeDrawing(); void getLiquidNeighborhood(); diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index d26457996..b879de047 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -58,11 +58,6 @@ void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos) m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE; } -void MeshMakeData::setSmoothLighting(bool smooth_lighting) -{ - m_smooth_lighting = smooth_lighting; -} - /* Light and vertex color functions */ diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h index 0b9b437db..c4380432f 100644 --- a/src/client/mapblock_mesh.h +++ b/src/client/mapblock_mesh.h @@ -39,6 +39,7 @@ struct MeshMakeData v3s16 m_blockpos = v3s16(-1337,-1337,-1337); v3s16 m_crack_pos_relative = v3s16(-1337,-1337,-1337); bool m_smooth_lighting = false; + bool m_enable_water_reflections = false; u16 side_length; const NodeDefManager *nodedef; @@ -55,11 +56,6 @@ struct MeshMakeData Set the (node) position of a crack */ void setCrack(int crack_level, v3s16 crack_pos); - - /* - Enable or disable smooth lighting - */ - void setSmoothLighting(bool smooth_lighting); }; // represents a triangle as indexes into the vertex buffer in SMeshBuffer diff --git a/src/client/mesh_generator_thread.cpp b/src/client/mesh_generator_thread.cpp index 3d80f8e67..0b85a1bc9 100644 --- a/src/client/mesh_generator_thread.cpp +++ b/src/client/mesh_generator_thread.cpp @@ -40,6 +40,7 @@ MeshUpdateQueue::MeshUpdateQueue(Client *client): m_client(client) { m_cache_smooth_lighting = g_settings->getBool("smooth_lighting"); + m_cache_enable_water_reflections = g_settings->getBool("enable_water_reflections"); } MeshUpdateQueue::~MeshUpdateQueue() @@ -191,7 +192,8 @@ void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q) } data->setCrack(q->crack_level, q->crack_pos); - data->setSmoothLighting(m_cache_smooth_lighting); + data->m_smooth_lighting = m_cache_smooth_lighting; + data->m_enable_water_reflections = m_cache_enable_water_reflections; } /* diff --git a/src/client/mesh_generator_thread.h b/src/client/mesh_generator_thread.h index fb9b5ae9e..72e4c7bed 100644 --- a/src/client/mesh_generator_thread.h +++ b/src/client/mesh_generator_thread.h @@ -69,8 +69,9 @@ private: std::unordered_set m_inflight_blocks; std::mutex m_mutex; - // TODO: Add callback to update these when g_settings changes + // TODO: Add callback to update these when g_settings changes, and update all meshes bool m_cache_smooth_lighting; + bool m_cache_enable_water_reflections; void fillDataFromMapBlocks(QueuedMeshUpdate *q); }; diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index 3ba18711e..a557fc2a2 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -311,7 +311,8 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n, { MeshMakeData mesh_make_data(client->ndef(), 1); MeshCollector collector(v3f(0.0f * BS), v3f()); - mesh_make_data.setSmoothLighting(false); + mesh_make_data.m_smooth_lighting = false; + mesh_make_data.m_enable_water_reflections = false; MapblockMeshGenerator gen(&mesh_make_data, &collector); if (n.getParam2()) { diff --git a/src/unittest/test_content_mapblock.cpp b/src/unittest/test_content_mapblock.cpp index c357c5ea7..e7148a69f 100644 --- a/src/unittest/test_content_mapblock.cpp +++ b/src/unittest/test_content_mapblock.cpp @@ -39,7 +39,8 @@ public: MeshMakeData makeSingleNodeMMD(bool smooth_lighting = true) { MeshMakeData data{ndef(), 1}; - data.setSmoothLighting(smooth_lighting); + data.m_smooth_lighting = smooth_lighting; + data.m_enable_water_reflections = false; data.m_blockpos = {0, 0, 0}; for (s16 x = -1; x <= 1; x++) for (s16 y = -1; y <= 1; y++) From d044c27b5f3db867e04700ef3229af003162c983 Mon Sep 17 00:00:00 2001 From: Desour Date: Wed, 8 Jan 2025 10:01:13 +0100 Subject: [PATCH 32/44] MeshMakeData: Explain members, and add grid size and minimap flag --- src/client/content_mapblock.cpp | 8 ++--- src/client/mapblock_mesh.cpp | 50 +++++++++++++------------- src/client/mapblock_mesh.h | 16 +++++++-- src/client/mesh_generator_thread.cpp | 4 ++- src/client/wieldmesh.cpp | 3 +- src/unittest/test_content_mapblock.cpp | 3 +- 6 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 56d0bd498..5b69b4a5d 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -62,7 +62,7 @@ const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_railli MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output): data(input), collector(output), - nodedef(data->nodedef), + nodedef(data->m_nodedef), blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE) { } @@ -1773,9 +1773,9 @@ void MapblockMeshGenerator::generate() { ZoneScoped; - for (cur_node.p.Z = 0; cur_node.p.Z < data->side_length; cur_node.p.Z++) - for (cur_node.p.Y = 0; cur_node.p.Y < data->side_length; cur_node.p.Y++) - for (cur_node.p.X = 0; cur_node.p.X < data->side_length; cur_node.p.X++) { + for (cur_node.p.Z = 0; cur_node.p.Z < data->m_side_length; cur_node.p.Z++) + for (cur_node.p.Y = 0; cur_node.p.Y < data->m_side_length; cur_node.p.Y++) + for (cur_node.p.X = 0; cur_node.p.X < data->m_side_length; cur_node.p.X++) { cur_node.n = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p); cur_node.f = &nodedef->get(cur_node.n); drawNode(); diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index b879de047..05f9e73cc 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -26,9 +26,11 @@ MeshMakeData */ -MeshMakeData::MeshMakeData(const NodeDefManager *ndef, u16 side_length): - side_length(side_length), - nodedef(ndef) +MeshMakeData::MeshMakeData(const NodeDefManager *ndef, + u16 side_length, MeshGrid mesh_grid) : + m_side_length(side_length), + m_mesh_grid(mesh_grid), + m_nodedef(ndef) {} void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos) @@ -38,8 +40,9 @@ void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos) v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE; m_vmanip.clear(); + // extra 1 block thick layer around the mesh VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE, - blockpos_nodes + v3s16(1,1,1) * (side_length + MAP_BLOCKSIZE /* extra layer of blocks around the mesh */) - v3s16(1,1,1)); + blockpos_nodes + v3s16(1,1,1) * (m_side_length + MAP_BLOCKSIZE) - v3s16(1,1,1)); m_vmanip.addArea(voxel_area); } @@ -128,7 +131,7 @@ u16 getFaceLight(MapNode n, MapNode n2, const NodeDefManager *ndef) static u16 getSmoothLightCombined(const v3s16 &p, const std::array &dirs, MeshMakeData *data) { - const NodeDefManager *ndef = data->nodedef; + const NodeDefManager *ndef = data->m_nodedef; u16 ambient_occlusion = 0; u16 light_count = 0; @@ -316,7 +319,7 @@ void final_color_blend(video::SColor *result, */ void getNodeTileN(MapNode mn, const v3s16 &p, u8 tileindex, MeshMakeData *data, TileSpec &tile) { - const NodeDefManager *ndef = data->nodedef; + const NodeDefManager *ndef = data->m_nodedef; const ContentFeatures &f = ndef->get(mn); tile = f.tiles[tileindex]; bool has_crack = p == data->m_crack_pos_relative; @@ -336,7 +339,7 @@ void getNodeTileN(MapNode mn, const v3s16 &p, u8 tileindex, MeshMakeData *data, */ void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *data, TileSpec &tile) { - const NodeDefManager *ndef = data->nodedef; + const NodeDefManager *ndef = data->m_nodedef; // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0), // (0,0,1), (0,0,-1) or (0,0,0) @@ -588,7 +591,7 @@ void PartialMeshBuffer::draw(video::IVideoDriver *driver) const MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offset): m_tsrc(client->getTextureSource()), m_shdrsrc(client->getShaderSource()), - m_bounding_sphere_center((data->side_length * 0.5f - 0.5f) * BS), + m_bounding_sphere_center((data->m_side_length * 0.5f - 0.5f) * BS), m_animation_force_timer(0), // force initial animation m_last_crack(-1) { @@ -597,10 +600,12 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs for (auto &m : m_mesh) m = make_irr(); - auto mesh_grid = client->getMeshGrid(); + auto mesh_grid = data->m_mesh_grid; v3s16 bp = data->m_blockpos; - // Only generate minimap mapblocks at even coordinates. - if (mesh_grid.isMeshPos(bp) && client->getMinimap()) { + // Only generate minimap mapblocks at grid aligned coordinates. + // FIXME: ^ doesn't really make sense. and in practice, bp is always aligned + if (mesh_grid.isMeshPos(bp) && data->m_generate_minimap) { + // meshgen area always fits into a grid cell m_minimap_mapblocks.resize(mesh_grid.getCellVolume(), nullptr); v3s16 ofs; @@ -617,15 +622,10 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs } } + // algin vertices to mesh grid, not meshgen area v3f offset = intToFloat((data->m_blockpos - mesh_grid.getMeshPos(data->m_blockpos)) * MAP_BLOCKSIZE, BS); + MeshCollector collector(m_bounding_sphere_center, offset); - /* - Add special graphics: - - torches - - flowing water - - fences - - whatever - */ { MapblockMeshGenerator(data, &collector).generate(); @@ -731,7 +731,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs } } - m_bsp_tree.buildTree(&m_transparent_triangles, data->side_length); + m_bsp_tree.buildTree(&m_transparent_triangles, data->m_side_length); // Check if animation is required for this mesh m_has_animation = @@ -942,19 +942,19 @@ u8 get_solid_sides(MeshMakeData *data) { std::unordered_map results; v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE; - const NodeDefManager *ndef = data->nodedef; + const NodeDefManager *ndef = data->m_nodedef; u8 result = 0x3F; // all sides solid; - for (s16 i = 0; i < data->side_length && result != 0; i++) - for (s16 j = 0; j < data->side_length && result != 0; j++) { + for (s16 i = 0; i < data->m_side_length && result != 0; i++) + for (s16 j = 0; j < data->m_side_length && result != 0; j++) { v3s16 positions[6] = { v3s16(0, i, j), - v3s16(data->side_length - 1, i, j), + v3s16(data->m_side_length - 1, i, j), v3s16(i, 0, j), - v3s16(i, data->side_length - 1, j), + v3s16(i, data->m_side_length - 1, j), v3s16(i, j, 0), - v3s16(i, j, data->side_length - 1) + v3s16(i, j, data->m_side_length - 1) }; for (u8 k = 0; k < 6; k++) { diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h index c4380432f..47941386e 100644 --- a/src/client/mapblock_mesh.h +++ b/src/client/mapblock_mesh.h @@ -36,15 +36,25 @@ struct MinimapMapblock; struct MeshMakeData { VoxelManipulator m_vmanip; + + // base pos of meshgen area, in blocks v3s16 m_blockpos = v3s16(-1337,-1337,-1337); + // size of meshgen area, in nodes. + // vmanip will have at least an extra 1 node onion layer. + // area is expected to fit into mesh grid cell. + u16 m_side_length; + // vertex positions will be relative to this grid + MeshGrid m_mesh_grid; + + // relative to blockpos v3s16 m_crack_pos_relative = v3s16(-1337,-1337,-1337); + bool m_generate_minimap = false; bool m_smooth_lighting = false; bool m_enable_water_reflections = false; - u16 side_length; - const NodeDefManager *nodedef; + const NodeDefManager *m_nodedef; - MeshMakeData(const NodeDefManager *ndef, u16 side_length); + MeshMakeData(const NodeDefManager *ndef, u16 side_lingth, MeshGrid mesh_grid); /* Copy block data manually (to allow optimizations by the caller) diff --git a/src/client/mesh_generator_thread.cpp b/src/client/mesh_generator_thread.cpp index 0b85a1bc9..70f4287ab 100644 --- a/src/client/mesh_generator_thread.cpp +++ b/src/client/mesh_generator_thread.cpp @@ -177,7 +177,8 @@ void MeshUpdateQueue::done(v3s16 pos) void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q) { auto mesh_grid = m_client->getMeshGrid(); - MeshMakeData *data = new MeshMakeData(m_client->ndef(), MAP_BLOCKSIZE * mesh_grid.cell_size); + MeshMakeData *data = new MeshMakeData(m_client->ndef(), + MAP_BLOCKSIZE * mesh_grid.cell_size, mesh_grid); q->data = data; data->fillBlockDataBegin(q->p); @@ -192,6 +193,7 @@ void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q) } data->setCrack(q->crack_level, q->crack_pos); + data->m_generate_minimap = !!m_client->getMinimap(); data->m_smooth_lighting = m_cache_smooth_lighting; data->m_enable_water_reflections = m_cache_enable_water_reflections; } diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index a557fc2a2..4c4042ad4 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -309,8 +309,9 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n, std::vector *colors, const ContentFeatures &f) { - MeshMakeData mesh_make_data(client->ndef(), 1); + MeshMakeData mesh_make_data(client->ndef(), 1, client->getMeshGrid()); MeshCollector collector(v3f(0.0f * BS), v3f()); + mesh_make_data.m_generate_minimap = false; mesh_make_data.m_smooth_lighting = false; mesh_make_data.m_enable_water_reflections = false; MapblockMeshGenerator gen(&mesh_make_data, &collector); diff --git a/src/unittest/test_content_mapblock.cpp b/src/unittest/test_content_mapblock.cpp index e7148a69f..68f66eabf 100644 --- a/src/unittest/test_content_mapblock.cpp +++ b/src/unittest/test_content_mapblock.cpp @@ -38,7 +38,8 @@ public: MeshMakeData makeSingleNodeMMD(bool smooth_lighting = true) { - MeshMakeData data{ndef(), 1}; + MeshMakeData data{ndef(), 1, MeshGrid{1}}; + data.m_generate_minimap = false; data.m_smooth_lighting = smooth_lighting; data.m_enable_water_reflections = false; data.m_blockpos = {0, 0, 0}; From d15214af522387c118010c24c391d785a3985c3f Mon Sep 17 00:00:00 2001 From: lhofhansl Date: Sat, 11 Jan 2025 16:41:50 -0800 Subject: [PATCH 33/44] Remove shadow direction quantization, increase shadow update frames instead (#15665) * This removes shadow direction quantization and defaults shadow_update_frames to 16 instead. --- builtin/settingtypes.txt | 2 +- src/client/shadows/dynamicshadows.cpp | 14 +------------- src/defaultsettings.cpp | 2 +- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index a2d37df5f..c6b84fde7 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -1899,7 +1899,7 @@ shadow_poisson_filter (Poisson filtering) bool true # Minimum value: 1; maximum value: 16 # # Requires: enable_dynamic_shadows, opengl -shadow_update_frames (Map shadows update frames) int 8 1 16 +shadow_update_frames (Map shadows update frames) int 16 1 32 # Set to true to render debugging breakdown of the bloom effect. # In debug mode, the screen is split into 4 quadrants: diff --git a/src/client/shadows/dynamicshadows.cpp b/src/client/shadows/dynamicshadows.cpp index a5eea8f38..a186fc41b 100644 --- a/src/client/shadows/dynamicshadows.cpp +++ b/src/client/shadows/dynamicshadows.cpp @@ -13,18 +13,6 @@ using m4f = core::matrix4; -static v3f quantizeDirection(v3f direction, float step) -{ - - float yaw = std::atan2(direction.Z, direction.X); - float pitch = std::asin(direction.Y); // assume look is normalized - - yaw = std::floor(yaw / step) * step; - pitch = std::floor(pitch / step) * step; - - return v3f(std::cos(yaw)*std::cos(pitch), std::sin(pitch), std::sin(yaw)*std::cos(pitch)); -} - void DirectionalLight::createSplitMatrices(const Camera *cam) { static const float COS_15_DEG = 0.965926f; @@ -74,7 +62,7 @@ void DirectionalLight::createSplitMatrices(const Camera *cam) v3f boundVec = (cam_pos_scene + farCorner * sfFar) - center_scene; float radius = boundVec.getLength(); float length = radius * 3.0f; - v3f eye_displacement = quantizeDirection(direction, M_PI / 2880 /*15 seconds*/) * length; + v3f eye_displacement = direction * length; // we must compute the viewmat with the position - the camera offset // but the future_frustum position must be the actual world position diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index f2bcea1b5..ad36456f5 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -341,7 +341,7 @@ void set_default_settings() settings->setDefault("shadow_map_color", "false"); settings->setDefault("shadow_filters", "1"); settings->setDefault("shadow_poisson_filter", "true"); - settings->setDefault("shadow_update_frames", "8"); + settings->setDefault("shadow_update_frames", "16"); settings->setDefault("shadow_soft_radius", "5.0"); settings->setDefault("shadow_sky_body_orbit_tilt", "0.0"); From d4a6df3389233c4ba53b18bcf8fae92b8ca480c0 Mon Sep 17 00:00:00 2001 From: chmodsayshello Date: Sun, 12 Jan 2025 14:49:01 +0100 Subject: [PATCH 34/44] Add chat console scrollbar (#15104) --- src/chat.h | 3 +- src/client/game.cpp | 4 ++- src/gui/guiChatConsole.cpp | 66 +++++++++++++++++++++++++++++++------- src/gui/guiChatConsole.h | 8 +++-- 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/chat.h b/src/chat.h index d328732c3..97b391ccb 100644 --- a/src/chat.h +++ b/src/chat.h @@ -112,7 +112,8 @@ public: void resize(u32 scrollback); -protected: + // Get the current scroll position + s32 getScrollPosition() const { return m_scroll; } s32 getTopScrollPos() const; s32 getBottomScrollPos() const; diff --git a/src/client/game.cpp b/src/client/game.cpp index 6886abb45..a4a4c9909 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1799,7 +1799,9 @@ void Game::processUserInput(f32 dtime) m_game_focused = true; } - if (!guienv->hasFocus(gui_chat_console.get()) && gui_chat_console->isOpen()) { + if (!guienv->hasFocus(gui_chat_console.get()) && gui_chat_console->isOpen() + && !gui_chat_console->isMyChild(guienv->getFocus())) + { gui_chat_console->closeConsoleAtOnce(); } diff --git a/src/gui/guiChatConsole.cpp b/src/gui/guiChatConsole.cpp index 689ad22e0..31df2a944 100644 --- a/src/gui/guiChatConsole.cpp +++ b/src/gui/guiChatConsole.cpp @@ -16,6 +16,7 @@ #include "gettext.h" #include "irrlicht_changes/CGUITTFont.h" #include "util/string.h" +#include "guiScrollBar.h" #include inline u32 clamp_u8(s32 value) @@ -28,6 +29,11 @@ inline bool isInCtrlKeys(const irr::EKEY_CODE& kc) return kc == KEY_LCONTROL || kc == KEY_RCONTROL || kc == KEY_CONTROL; } +inline u32 getScrollbarSize(IGUIEnvironment* env) +{ + return env->getSkin()->getSize(gui::EGDS_SCROLLBAR_SIZE); +} + GUIChatConsole::GUIChatConsole( gui::IGUIEnvironment* env, gui::IGUIElement* parent, @@ -62,15 +68,14 @@ GUIChatConsole::GUIChatConsole( } const u16 chat_font_size = g_settings->getU16("chat_font_size"); - m_font = g_fontengine->getFont(chat_font_size != 0 ? - rangelim(chat_font_size, 5, 72) : FONT_SIZE_UNSPECIFIED, FM_Mono); + m_font.grab(g_fontengine->getFont(chat_font_size != 0 ? + rangelim(chat_font_size, 5, 72) : FONT_SIZE_UNSPECIFIED, FM_Mono)); if (!m_font) { errorstream << "GUIChatConsole: Unable to load mono font" << std::endl; } else { core::dimension2d dim = m_font->getDimension(L"M"); m_fontsize = v2u32(dim.Width, dim.Height); - m_font->grab(); } m_fontsize.X = MYMAX(m_fontsize.X, 1); m_fontsize.Y = MYMAX(m_fontsize.Y, 1); @@ -81,12 +86,11 @@ GUIChatConsole::GUIChatConsole( // track ctrl keys for mouse event m_is_ctrl_down = false; m_cache_clickable_chat_weblinks = g_settings->getBool("clickable_chat_weblinks"); -} -GUIChatConsole::~GUIChatConsole() -{ - if (m_font) - m_font->drop(); + m_scrollbar.reset(new GUIScrollBar(env, this, -1, core::rect(0, 0, 30, m_height), false, true, tsrc)); + m_scrollbar->setSubElement(true); + m_scrollbar->setLargeStep(1); + m_scrollbar->setSmallStep(1); } void GUIChatConsole::openConsole(f32 scale) @@ -121,6 +125,7 @@ void GUIChatConsole::closeConsole() m_open = false; Environment->removeFocus(this); m_menumgr->deletingMenu(this); + m_scrollbar->setVisible(false); } void GUIChatConsole::closeConsoleAtOnce() @@ -180,6 +185,10 @@ void GUIChatConsole::draw() m_screensize = screensize; m_desired_height = m_desired_height_fraction * m_screensize.Y; reformatConsole(); + } else if (!m_scrollbar->getAbsolutePosition().isPointInside(core::vector2di(screensize.X, m_height))) { + // the height of the chat window is no longer the height of the scrollbar + // happens while opening/closing the window + updateScrollbar(true); } // Animation @@ -204,6 +213,9 @@ void GUIChatConsole::reformatConsole() s32 rows = m_desired_height / m_fontsize.Y - 1; // make room for the input prompt if (cols <= 0 || rows <= 0) cols = rows = 0; + + updateScrollbar(true); + recalculateConsolePosition(); m_chat_backend->reformat(cols, rows); } @@ -293,10 +305,17 @@ void GUIChatConsole::drawBackground() void GUIChatConsole::drawText() { - if (m_font == NULL) + if (!m_font) return; ChatBuffer& buf = m_chat_backend->getConsoleBuffer(); + + core::recti rect; + if (m_scrollbar->isVisible()) + rect = core::rect (0, 0, m_screensize.X - getScrollbarSize(Environment), m_height); + else + rect = AbsoluteClippingRect; + for (u32 row = 0; row < buf.getRows(); ++row) { const ChatFormattedLine& line = buf.getFormattedLine(row); @@ -315,13 +334,13 @@ void GUIChatConsole::drawText() if (m_font->getType() == irr::gui::EGFT_CUSTOM) { // Draw colored text if possible - gui::CGUITTFont *tmp = static_cast(m_font); + auto *tmp = static_cast(m_font.get()); tmp->draw( fragment.text, destrect, false, false, - &AbsoluteClippingRect); + &rect); } else { // Otherwise use standard text m_font->draw( @@ -330,10 +349,12 @@ void GUIChatConsole::drawText() video::SColor(255, 255, 255, 255), false, false, - &AbsoluteClippingRect); + &rect); } } } + + updateScrollbar(); } void GUIChatConsole::drawPrompt() @@ -680,6 +701,11 @@ bool GUIChatConsole::OnEvent(const SEvent& event) prompt.input(std::wstring(event.StringInput.Str->c_str())); return true; } + else if (event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_SCROLL_BAR_CHANGED && + (void*) event.GUIEvent.Caller == (void*) m_scrollbar.get()) + { + m_chat_backend->getConsoleBuffer().scrollAbsolute(m_scrollbar->getPos()); + } return Parent ? Parent->OnEvent(event) : false; } @@ -692,6 +718,7 @@ void GUIChatConsole::setVisible(bool visible) m_height = 0; recalculateConsolePosition(); } + m_scrollbar->setVisible(visible); } bool GUIChatConsole::weblinkClick(s32 col, s32 row) @@ -763,3 +790,18 @@ void GUIChatConsole::updatePrimarySelection() std::string selected = wide_to_utf8(wselected); Environment->getOSOperator()->copyToPrimarySelection(selected.c_str()); } + +void GUIChatConsole::updateScrollbar(bool update_size) +{ + ChatBuffer &buf = m_chat_backend->getConsoleBuffer(); + m_scrollbar->setMin(buf.getTopScrollPos()); + m_scrollbar->setMax(buf.getBottomScrollPos()); + m_scrollbar->setPos(buf.getScrollPosition()); + m_scrollbar->setPageSize(m_fontsize.Y * buf.getLineCount()); + m_scrollbar->setVisible(m_scrollbar->getMin() != m_scrollbar->getMax()); + + if (update_size) { + const core::rect rect (m_screensize.X - getScrollbarSize(Environment), 0, m_screensize.X, m_height); + m_scrollbar->setRelativePosition(rect); + } +} diff --git a/src/gui/guiChatConsole.h b/src/gui/guiChatConsole.h index 8e6c32fcd..9b1309a6e 100644 --- a/src/gui/guiChatConsole.h +++ b/src/gui/guiChatConsole.h @@ -8,8 +8,10 @@ #include "modalMenu.h" #include "chat.h" #include "config.h" +#include "irr_ptr.h" class Client; +class GUIScrollBar; class GUIChatConsole : public gui::IGUIElement { @@ -20,7 +22,6 @@ public: ChatBackend* backend, Client* client, IMenuManager* menumgr); - virtual ~GUIChatConsole(); // Open the console (height = desired fraction of screen size) // This doesn't open immediately but initiates an animation. @@ -76,10 +77,13 @@ private: // If the selected text changed, we need to update the (X11) primary selection. void updatePrimarySelection(); + void updateScrollbar(bool update_size = false); + private: ChatBackend* m_chat_backend; Client* m_client; IMenuManager* m_menumgr; + irr_ptr m_scrollbar; // current screen size v2u32 m_screensize; @@ -116,7 +120,7 @@ private: video::SColor m_background_color = video::SColor(255, 0, 0, 0); // font - gui::IGUIFont *m_font = nullptr; + irr_ptr m_font; v2u32 m_fontsize; // Enable clickable chat weblinks From be75e42d7769ce5e3b08cf85607c896ba3808597 Mon Sep 17 00:00:00 2001 From: Hanicef <33922955+Hanicef@users.noreply.github.com> Date: Sun, 12 Jan 2025 14:49:13 +0100 Subject: [PATCH 35/44] Improve sleep accuracy on FPS limiter (#15648) --- src/client/renderingengine.cpp | 3 +-- src/porting.h | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index fe3c17936..807c5816a 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -50,8 +50,7 @@ void FpsControl::limit(IrrlichtDevice *device, f32 *dtime, bool assume_paused) if (busy_time < frametime_min) { sleep_time = frametime_min - busy_time; - if (sleep_time > 0) - sleep_us(sleep_time); + porting::preciseSleepUs(sleep_time); } else { sleep_time = 0; } diff --git a/src/porting.h b/src/porting.h index d6cec6c1a..8b753f518 100644 --- a/src/porting.h +++ b/src/porting.h @@ -32,12 +32,16 @@ #define sleep_ms(x) Sleep(x) #define sleep_us(x) Sleep((x)/1000) + #define SLEEP_ACCURACY_US 2000 + #define setenv(n,v,o) _putenv_s(n,v) #define unsetenv(n) _putenv_s(n,"") #else #include #include // setenv + #define SLEEP_ACCURACY_US 200 + #define sleep_ms(x) usleep((x)*1000) #define sleep_us(x) usleep(x) #endif @@ -220,6 +224,21 @@ inline u64 getDeltaMs(u64 old_time_ms, u64 new_time_ms) return (old_time_ms - new_time_ms); } +inline void preciseSleepUs(u64 sleep_time) +{ + if (sleep_time > 0) + { + u64 target_time = porting::getTimeUs() + sleep_time; + if (sleep_time > SLEEP_ACCURACY_US) + sleep_us(sleep_time - SLEEP_ACCURACY_US); + + // Busy-wait the remaining time to adjust for sleep inaccuracies + // The target - now > 0 construct will handle overflow gracefully (even though it should + // never happen) + while ((s64)(target_time - porting::getTimeUs()) > 0) {} + } +} + inline const char *getPlatformName() { return From 2cdf3af1b844fb048145dc47bcb28a4c69c5dc18 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 8 Jan 2025 18:29:40 +0100 Subject: [PATCH 36/44] Reduce size of SMaterial struct --- irr/include/SMaterial.h | 65 ++++++++++++++---------------- irr/include/SMaterialLayer.h | 4 +- irr/src/CAnimatedMeshSceneNode.cpp | 2 +- irr/src/CMeshSceneNode.cpp | 2 +- irr/src/CNullDriver.cpp | 2 +- src/client/render/anaglyph.cpp | 2 +- src/client/render/secondstage.cpp | 2 +- src/client/sky.cpp | 2 +- 8 files changed, 39 insertions(+), 42 deletions(-) diff --git a/irr/include/SMaterial.h b/irr/include/SMaterial.h index 2329e2761..3bbc6e946 100644 --- a/irr/include/SMaterial.h +++ b/irr/include/SMaterial.h @@ -20,7 +20,7 @@ class ITexture; //! Flag for MaterialTypeParam (in combination with EMT_ONETEXTURE_BLEND) or for BlendFactor //! BlendFunc = source * sourceFactor + dest * destFactor -enum E_BLEND_FACTOR +enum E_BLEND_FACTOR : u8 { EBF_ZERO = 0, //!< src & dest (0, 0, 0, 0) EBF_ONE, //!< src & dest (1, 1, 1, 1) @@ -36,7 +36,7 @@ enum E_BLEND_FACTOR }; //! Values defining the blend operation -enum E_BLEND_OPERATION +enum E_BLEND_OPERATION : u8 { EBO_NONE = 0, //!< No blending happens EBO_ADD, //!< Default blending adds the color values @@ -51,7 +51,7 @@ enum E_BLEND_OPERATION }; //! MaterialTypeParam: e.g. DirectX: D3DTOP_MODULATE, D3DTOP_MODULATE2X, D3DTOP_MODULATE4X -enum E_MODULATE_FUNC +enum E_MODULATE_FUNC : u8 { EMFN_MODULATE_1X = 1, EMFN_MODULATE_2X = 2, @@ -59,7 +59,7 @@ enum E_MODULATE_FUNC }; //! Comparison function, e.g. for depth buffer test -enum E_COMPARISON_FUNC +enum E_COMPARISON_FUNC : u8 { //! Depth test disabled (disable also write to depth buffer) ECFN_DISABLED = 0, @@ -82,7 +82,7 @@ enum E_COMPARISON_FUNC }; //! Enum values for enabling/disabling color planes for rendering -enum E_COLOR_PLANE +enum E_COLOR_PLANE : u8 { //! No color enabled ECP_NONE = 0, @@ -103,7 +103,7 @@ enum E_COLOR_PLANE //! Source of the alpha value to take /** This is currently only supported in EMT_ONETEXTURE_BLEND. You can use an or'ed combination of values. Alpha values are modulated (multiplied). */ -enum E_ALPHA_SOURCE +enum E_ALPHA_SOURCE : u8 { //! Use no alpha, somewhat redundant with other settings EAS_NONE = 0, @@ -181,7 +181,7 @@ Some drivers don't support a per-material setting of the anti-aliasing modes. In those cases, FSAA/multisampling is defined by the device mode chosen upon creation via irr::SIrrCreationParameters. */ -enum E_ANTI_ALIASING_MODE +enum E_ANTI_ALIASING_MODE : u8 { //! Use to turn off anti-aliasing for this material EAAM_OFF = 0, @@ -202,7 +202,7 @@ const c8 *const PolygonOffsetDirectionNames[] = { }; //! For SMaterial.ZWriteEnable -enum E_ZWRITE +enum E_ZWRITE : u8 { //! zwrite always disabled for this material EZW_OFF = 0, @@ -240,10 +240,10 @@ public: //! Default constructor. Creates a solid material SMaterial() : MaterialType(EMT_SOLID), ColorParam(0, 0, 0, 0), - MaterialTypeParam(0.0f), Thickness(1.0f), ZBuffer(ECFN_LESSEQUAL), - AntiAliasing(EAAM_SIMPLE), ColorMask(ECP_ALL), - BlendOperation(EBO_NONE), BlendFactor(0.0f), PolygonOffsetDepthBias(0.f), - PolygonOffsetSlopeScale(0.f), Wireframe(false), PointCloud(false), + MaterialTypeParam(0.0f), Thickness(1.0f), BlendFactor(0.0f), + PolygonOffsetDepthBias(0.f), PolygonOffsetSlopeScale(0.f), + ZBuffer(ECFN_LESSEQUAL), AntiAliasing(EAAM_SIMPLE), ColorMask(ECP_ALL), + BlendOperation(EBO_NONE), Wireframe(false), PointCloud(false), ZWriteEnable(EZW_AUTO), BackfaceCulling(true), FrontfaceCulling(false), FogEnable(false), UseMipMaps(true) @@ -268,28 +268,6 @@ public: //! Thickness of non-3dimensional elements such as lines and points. f32 Thickness; - //! Is the ZBuffer enabled? Default: ECFN_LESSEQUAL - /** If you want to disable depth test for this material - just set this parameter to ECFN_DISABLED. - Values are from E_COMPARISON_FUNC. */ - u8 ZBuffer; - - //! Sets the antialiasing mode - /** Values are chosen from E_ANTI_ALIASING_MODE. Default is - EAAM_SIMPLE, i.e. simple multi-sample anti-aliasing. */ - u8 AntiAliasing; - - //! Defines the enabled color planes - /** Values are defined as or'ed values of the E_COLOR_PLANE enum. - Only enabled color planes will be rendered to the current render - target. Typical use is to disable all colors when rendering only to - depth or stencil buffer, or using Red and Green for Stereo rendering. */ - u8 ColorMask : 4; - - //! Store the blend operation of choice - /** Values to be chosen from E_BLEND_OPERATION. */ - E_BLEND_OPERATION BlendOperation : 4; - //! Store the blend factors /** textureBlendFunc/textureBlendFuncSeparate functions should be used to write properly blending factors to this parameter. @@ -316,6 +294,25 @@ public: and -1.f to pull them towards the camera. */ f32 PolygonOffsetSlopeScale; + //! Is the ZBuffer enabled? Default: ECFN_LESSEQUAL + /** If you want to disable depth test for this material + just set this parameter to ECFN_DISABLED. */ + E_COMPARISON_FUNC ZBuffer : 4; + + //! Sets the antialiasing mode + /** Default is EAAM_SIMPLE, i.e. simple multi-sample anti-aliasing. */ + E_ANTI_ALIASING_MODE AntiAliasing : 4; + + //! Defines the enabled color planes + /** Values are defined as or'ed values of the E_COLOR_PLANE enum. + Only enabled color planes will be rendered to the current render + target. Typical use is to disable all colors when rendering only to + depth or stencil buffer, or using Red and Green for Stereo rendering. */ + E_COLOR_PLANE ColorMask : 4; + + //! Store the blend operation of choice + E_BLEND_OPERATION BlendOperation : 4; + //! Draw as wireframe or filled triangles? Default: false bool Wireframe : 1; diff --git a/irr/include/SMaterialLayer.h b/irr/include/SMaterialLayer.h index 419a8f1e9..4d43bd820 100644 --- a/irr/include/SMaterialLayer.h +++ b/irr/include/SMaterialLayer.h @@ -45,7 +45,7 @@ static const char *const aTextureClampNames[] = { //! Texture minification filter. /** Used when scaling textures down. See the documentation on OpenGL's `GL_TEXTURE_MIN_FILTER` for more information. */ -enum E_TEXTURE_MIN_FILTER +enum E_TEXTURE_MIN_FILTER : u8 { //! Aka nearest-neighbor. ETMINF_NEAREST_MIPMAP_NEAREST = 0, @@ -61,7 +61,7 @@ enum E_TEXTURE_MIN_FILTER /** Used when scaling textures up. See the documentation on OpenGL's `GL_TEXTURE_MAG_FILTER` for more information. Note that mipmaps are only used for minification, not for magnification. */ -enum E_TEXTURE_MAG_FILTER +enum E_TEXTURE_MAG_FILTER : u8 { //! Aka nearest-neighbor. ETMAGF_NEAREST = 0, diff --git a/irr/src/CAnimatedMeshSceneNode.cpp b/irr/src/CAnimatedMeshSceneNode.cpp index dffc867de..6facfcd06 100644 --- a/irr/src/CAnimatedMeshSceneNode.cpp +++ b/irr/src/CAnimatedMeshSceneNode.cpp @@ -253,7 +253,7 @@ void CAnimatedMeshSceneNode::render() // for debug purposes only: if (DebugDataVisible && PassCount == 1) { video::SMaterial debug_mat; - debug_mat.AntiAliasing = 0; + debug_mat.AntiAliasing = video::EAAM_OFF; driver->setMaterial(debug_mat); // show normals if (DebugDataVisible & scene::EDS_NORMALS) { diff --git a/irr/src/CMeshSceneNode.cpp b/irr/src/CMeshSceneNode.cpp index cffdbf855..89220cdc7 100644 --- a/irr/src/CMeshSceneNode.cpp +++ b/irr/src/CMeshSceneNode.cpp @@ -109,7 +109,7 @@ void CMeshSceneNode::render() // for debug purposes only: if (DebugDataVisible && PassCount == 1) { video::SMaterial m; - m.AntiAliasing = 0; + m.AntiAliasing = video::EAAM_OFF; m.ZBuffer = video::ECFN_DISABLED; driver->setMaterial(m); diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index 7a0e006c9..c87d5ae93 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -1311,7 +1311,7 @@ void CNullDriver::runOcclusionQuery(scene::ISceneNode *node, bool visible) OcclusionQueries[index].Run = 0; if (!visible) { SMaterial mat; - mat.AntiAliasing = 0; + mat.AntiAliasing = video::EAAM_OFF; mat.ColorMask = ECP_NONE; mat.ZWriteEnable = EZW_OFF; setMaterial(mat); diff --git a/src/client/render/anaglyph.cpp b/src/client/render/anaglyph.cpp index 7baf40322..833ad0114 100644 --- a/src/client/render/anaglyph.cpp +++ b/src/client/render/anaglyph.cpp @@ -18,7 +18,7 @@ void SetColorMaskStep::run(PipelineContext &context) { video::SOverrideMaterial &mat = context.device->getVideoDriver()->getOverrideMaterial(); mat.reset(); - mat.Material.ColorMask = color_mask; + mat.Material.ColorMask = static_cast(color_mask); mat.EnableProps = video::EMP_COLOR_MASK; mat.EnablePasses = scene::ESNRP_SKY_BOX | scene::ESNRP_SOLID | scene::ESNRP_TRANSPARENT | scene::ESNRP_TRANSPARENT_EFFECT; diff --git a/src/client/render/secondstage.cpp b/src/client/render/secondstage.cpp index 616077942..b8744f694 100644 --- a/src/client/render/secondstage.cpp +++ b/src/client/render/secondstage.cpp @@ -21,7 +21,7 @@ PostProcessingStep::PostProcessingStep(u32 _shader_id, const std::vector &_t void PostProcessingStep::configureMaterial() { material.UseMipMaps = false; - material.ZBuffer = true; + material.ZBuffer = video::ECFN_LESSEQUAL; material.ZWriteEnable = video::EZW_ON; for (u32 k = 0; k < texture_map.size(); ++k) { material.TextureLayers[k].AnisotropicFilter = 0; diff --git a/src/client/sky.cpp b/src/client/sky.cpp index 2c9e4234d..958ffa953 100644 --- a/src/client/sky.cpp +++ b/src/client/sky.cpp @@ -27,7 +27,7 @@ static video::SMaterial baseMaterial() video::SMaterial mat; mat.ZBuffer = video::ECFN_DISABLED; mat.ZWriteEnable = video::EZW_OFF; - mat.AntiAliasing = 0; + mat.AntiAliasing = video::EAAM_OFF; mat.TextureLayers[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE; mat.TextureLayers[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; mat.BackfaceCulling = false; From 9dd09d1056617d535c50c80c27897231b082a0ba Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 8 Jan 2025 19:30:48 +0100 Subject: [PATCH 37/44] Prevent VoxelManipulator size overflow --- doc/lua_api.md | 10 ++++++---- src/map.cpp | 17 +++++------------ src/map.h | 7 ++++--- src/voxel.cpp | 30 ++++++++++++++++++------------ 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index af57c5442..b0103d120 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5044,7 +5044,7 @@ inside the VoxelManip. can use `core.emerge_area` to make sure that the area you want to read/write is already generated. -* Other mods, or the core itself, could possibly modify the area of the map +* Other mods, or the engine itself, could possibly modify the area of the map currently loaded into a VoxelManip object. With the exception of Mapgen VoxelManips (see above section), the internal buffers are not updated. For this reason, it is strongly encouraged to complete the usage of a particular @@ -5059,9 +5059,11 @@ inside the VoxelManip. Methods ------- -* `read_from_map(p1, p2)`: Loads a chunk of map into the VoxelManip object +* `read_from_map(p1, p2)`: Loads a chunk of map into the VoxelManip object containing the region formed by `p1` and `p2`. * returns actual emerged `pmin`, actual emerged `pmax` + * Note that calling this multiple times will *add* to the area loaded in the + VoxelManip, and not reset it. * `write_to_map([light])`: Writes the data loaded from the `VoxelManip` back to the map. * **important**: data must be set using `VoxelManip:set_data()` before @@ -5120,8 +5122,8 @@ Methods generated mapchunk above are propagated down into the mapchunk, defaults to `true` if left out. * `update_liquids()`: Update liquid flow -* `was_modified()`: Returns `true` if the data in the voxel manipulator has been modified - since it was last read from the map. This means you have to call `get_data` again. +* `was_modified()`: Returns `true` if the data in the VoxelManip has been modified + since it was last read from the map. This means you have to call `get_data()` again. This only applies to a `VoxelManip` object from `core.get_mapgen_object`, where the engine will keep the map and the VM in sync automatically. * Note: this doesn't do what you think it does and is subject to removal. Don't use it! diff --git a/src/map.cpp b/src/map.cpp index 240788944..e8ccac0cc 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -752,17 +752,12 @@ MMVManip::MMVManip(Map *map): assert(map); } -void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max, - bool load_if_inexistent) +void MMVManip::initialEmerge(v3s16 p_min, v3s16 p_max, bool load_if_inexistent) { TimeTaker timer1("initialEmerge", &emerge_time); assert(m_map); - // Units of these are MapBlocks - v3s16 p_min = blockpos_min; - v3s16 p_max = blockpos_max; - VoxelArea block_area_nodes (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1)); @@ -775,6 +770,7 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max, infostream<getNode(0, 0, 0).getContent() == CONTENT_IGNORE) - { - // Mark that block was loaded as blank - flags |= VMANIP_BLOCK_CONTAINS_CIGNORE; - }*/ m_loaded_blocks[p] = flags; } - m_is_dirty = false; + if (all_new) + m_is_dirty = false; } void MMVManip::blitBackAll(std::map *modified_blocks, @@ -834,6 +826,7 @@ void MMVManip::blitBackAll(std::map *modified_blocks, /* Copy data of all blocks */ + assert(!m_loaded_blocks.empty()); for (auto &loaded_block : m_loaded_blocks) { v3s16 p = loaded_block.first; MapBlock *block = m_map->getBlockNoCreateNoEx(p); diff --git a/src/map.h b/src/map.h index 37d1a713d..a4f0e4524 100644 --- a/src/map.h +++ b/src/map.h @@ -298,9 +298,6 @@ protected: u32 needed_count); }; -#define VMANIP_BLOCK_DATA_INEXIST 1 -#define VMANIP_BLOCK_CONTAINS_CIGNORE 2 - class MMVManip : public VoxelManipulator { public: @@ -344,4 +341,8 @@ protected: value = flags describing the block */ std::map m_loaded_blocks; + + enum : u8 { + VMANIP_BLOCK_DATA_INEXIST = 1 << 0, + }; }; diff --git a/src/voxel.cpp b/src/voxel.cpp index 8f3858a1f..f74129260 100644 --- a/src/voxel.cpp +++ b/src/voxel.cpp @@ -113,6 +113,20 @@ void VoxelManipulator::print(std::ostream &o, const NodeDefManager *ndef, } } +static inline void checkArea(const VoxelArea &a) +{ + // won't overflow since cbrt(2^64) > 2^16 + u64 real_volume = static_cast(a.getExtent().X) * a.getExtent().Y * a.getExtent().Z; + + // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000 + // Note: the hard limit is somewhere around 2^31 due to s32 type + constexpr u64 MAX_ALLOWED = 4096000; + if (real_volume > MAX_ALLOWED) { + throw BaseException("VoxelManipulator: " + "Area volume exceeds allowed value of " + std::to_string(MAX_ALLOWED)); + } +} + void VoxelManipulator::addArea(const VoxelArea &area) { // Cancel if requested area has zero volume @@ -124,18 +138,10 @@ void VoxelManipulator::addArea(const VoxelArea &area) return; // Calculate new area - VoxelArea new_area; - // New area is the requested area if m_area has zero volume - if(m_area.hasEmptyExtent()) - { - new_area = area; - } - // Else add requested area to m_area - else - { - new_area = m_area; - new_area.addArea(area); - } + VoxelArea new_area = m_area; + new_area.addArea(area); + + checkArea(new_area); u32 new_size = new_area.getVolume(); From d0d7c11fe12cdfce6dd234c04dc3724fda3a8c6d Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 8 Jan 2025 19:31:23 +0100 Subject: [PATCH 38/44] Stop ServerThread immediately on errors --- src/server.cpp | 13 +++++++++++++ src/server.h | 3 +-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/server.cpp b/src/server.cpp index 092528d7a..25fc46605 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -625,6 +625,11 @@ void Server::AsyncRunStep(float dtime, bool initial_step) ZoneScoped; auto framemarker = FrameMarker("Server::AsyncRunStep()-frame").started(); + if (!m_async_fatal_error.get().empty()) { + infostream << "Refusing server step in error state" << std::endl; + return; + } + { // Send blocks to clients SendBlocks(dtime); @@ -3854,6 +3859,14 @@ std::string Server::getBuiltinLuaPath() return porting::path_share + DIR_DELIM + "builtin"; } +void Server::setAsyncFatalError(const std::string &error) +{ + m_async_fatal_error.set(error); + // make sure server steps stop happening immediately + if (m_thread) + m_thread->stop(); +} + // Not thread-safe. void Server::addShutdownError(const ModError &e) { diff --git a/src/server.h b/src/server.h index 560a3452d..407d43d1b 100644 --- a/src/server.h +++ b/src/server.h @@ -344,8 +344,7 @@ public: void setStepSettings(StepSettings spdata) { m_step_settings.store(spdata); } StepSettings getStepSettings() { return m_step_settings.load(); } - inline void setAsyncFatalError(const std::string &error) - { m_async_fatal_error.set(error); } + void setAsyncFatalError(const std::string &error); inline void setAsyncFatalError(const LuaError &e) { setAsyncFatalError(std::string("Lua: ") + e.what()); From 903d13ffff719f63f8f7b322ef8d81db72303f87 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 9 Jan 2025 13:15:36 +0100 Subject: [PATCH 39/44] Make sure mod paths are always absolute --- src/content/mod_configuration.cpp | 7 +++++-- src/content/mods.cpp | 3 ++- src/content/mods.h | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/content/mod_configuration.cpp b/src/content/mod_configuration.cpp index 37d2eadd4..810ea7626 100644 --- a/src/content/mod_configuration.cpp +++ b/src/content/mod_configuration.cpp @@ -47,7 +47,7 @@ void ModConfiguration::addMods(const std::vector &new_mods) } // Add new mods - for (int want_from_modpack = 1; want_from_modpack >= 0; --want_from_modpack) { + for (bool want_from_modpack : {true, false}) { // First iteration: // Add all the mods that come from modpacks // Second iteration: @@ -56,9 +56,12 @@ void ModConfiguration::addMods(const std::vector &new_mods) std::set seen_this_iteration; for (const ModSpec &mod : new_mods) { - if (mod.part_of_modpack != (bool)want_from_modpack) + if (mod.part_of_modpack != want_from_modpack) continue; + // unrelated to this code, but we want to assert it somewhere + assert(fs::IsPathAbsolute(mod.path)); + if (existing_mods.count(mod.name) == 0) { // GOOD CASE: completely new mod. m_unsatisfied_mods.push_back(mod); diff --git a/src/content/mods.cpp b/src/content/mods.cpp index a95ea0227..1c100f5a1 100644 --- a/src/content/mods.cpp +++ b/src/content/mods.cpp @@ -167,6 +167,7 @@ std::map getModsInPath( mod_path.clear(); mod_path.append(path).append(DIR_DELIM).append(modname); + mod_path = fs::AbsolutePath(mod_path); mod_virtual_path.clear(); // Intentionally uses / to keep paths same on different platforms @@ -174,7 +175,7 @@ std::map getModsInPath( ModSpec spec(modname, mod_path, part_of_modpack, mod_virtual_path); parseModContents(spec); - result.insert(std::make_pair(modname, spec)); + result[modname] = std::move(spec); } return result; } diff --git a/src/content/mods.h b/src/content/mods.h index b6083fe19..a7e1e5041 100644 --- a/src/content/mods.h +++ b/src/content/mods.h @@ -25,7 +25,7 @@ struct ModSpec { std::string name; std::string author; - std::string path; + std::string path; // absolute path on disk std::string desc; int release = 0; From 1427a98c5996639ee010c7eb331fc7583d327a03 Mon Sep 17 00:00:00 2001 From: cx384 Date: Tue, 31 Dec 2024 16:26:09 +0100 Subject: [PATCH 40/44] Optimize png files --- .../testabms/textures/testabms_after_node.png | Bin 179 -> 134 bytes .../testabms/textures/testabms_wait_node.png | Bin 183 -> 134 bytes .../textures/testnodes_attachedwr_bottom.png | Bin 265 -> 144 bytes .../textures/testnodes_attachedwr_side.png | Bin 173 -> 132 bytes .../textures/testnodes_attachedwr_top.png | Bin 153 -> 121 bytes .../testnodes/textures/testnodes_sign3d.png | Bin 214 -> 115 bytes .../textures/testtools_particle_clip.png | Bin 179 -> 124 bytes textures/base/pack/cdb_update_cropped.png | Bin 4383 -> 165 bytes textures/base/pack/checkbox_16.png | Bin 151 -> 137 bytes textures/base/pack/checkbox_32.png | Bin 224 -> 192 bytes textures/base/pack/server_view_clients.png | Bin 218 -> 146 bytes 11 files changed, 0 insertions(+), 0 deletions(-) diff --git a/games/devtest/mods/testabms/textures/testabms_after_node.png b/games/devtest/mods/testabms/textures/testabms_after_node.png index dab87594b998dde660a623a10cb6e8fe9a1a8b74..2a1efd53ec2242ac9bfe036a6aae90a60472bd27 100644 GIT binary patch delta 105 zcmV-v0G9u=0fqsPBw|fTL_t(IjbmU?`~ROJ3}^gT{Ex!M#YdMz(M&3h*8p@EAUhkY z0qD-eWg~4|K$Tb+JO<$MKdu19892no2vG*$ixHAtK-(}Fh-d@=5K|)pa>T9a00000 LNkvXXu0mjf8NMll delta 151 zcmV;I0BHY)0kZ*+B!2{RLP=Bz2nYy#2xN!=003%9L_t(Ijbmg``~RPT0>A`k-Be;g zVdLVX$uYqN)$gHd!o^p=hrM7GFb+Y z6$TW?!oV7U&%fvaiV_yYL?6Cr#c2S(sKaUiws^;CBTZZ|pwS2b#YP*cu_3DB00000 LNkvXXu0mjf2R16Z delta 155 zcmV;M0A&A$0k;8=B!2{RLP=Bz2nYy#2xN!=003@DL_t(Ijm47D4FDksLyN<(|2!_! z`{JTlOw3(k|0?DQMT3+0pf(zI1G`PWs!0Fb diff --git a/games/devtest/mods/testnodes/textures/testnodes_attachedwr_bottom.png b/games/devtest/mods/testnodes/textures/testnodes_attachedwr_bottom.png index 1a2e1e90e75acadfbac896969fd0b47789e90e37..9318c94546b35ef9542c8b967f7a652296cdc9a5 100644 GIT binary patch delta 115 zcmV-(0F3{M0+0caBy3knL_t(2kz<(9f8WV5jd+rQB-KEYfqWYZ3)bU7SZu(r0gDYu zNi#9k!3D9{fL{Z4KR~2`B%DFO4_GxoxHv-zZYmlBXDH#)K#h2SxD^)~khDZ32>_Ej Vc(|gY+GhX&002ovPDHLkV1jFqEIa@J delta 237 zcmVTB!AFJL_t(2&tsm@fB)C7@A>&_h$I=D9MdNB-zT1AAW5~8V;ZBA zW162|<)%&T`ud&>xPiR9!KO{^etwmV6Z-E%SPvgwz@y>f#qAJtnScHI4qdUI0;pVuQTA0mQtIpI-g^`DPWu;O7&AXduCckDp$B z{PYTo4H6Qna8r?u|M~MPKc5&i{2(Er%D}(?4=6MS+y+EET)Mmqj|~s*pM{vq1h-31 n*X_amv$#lv%Sla3B&SvYNAMiA19jSy00000NkvXXu0mjf_il97 diff --git a/games/devtest/mods/testnodes/textures/testnodes_attachedwr_side.png b/games/devtest/mods/testnodes/textures/testnodes_attachedwr_side.png index 382e2dafa72bbea3478b4a8f6962d2fe7ad72917..7701dc9e2095f56e73243e8fc2b00532e1502b54 100644 GIT binary patch delta 103 zcmV-t0GR)+0fYgNBw$NPL_t(2kz-i40f-9=))R>ayN0BsnV2fj1S!)1mj;q> z1_3`{)d1&W_cUA%lR+g7qy;M;M1c(x`tLhArV&pvkfa(&0svaEq~K0*Fs}dr002ov JPDHLkV1lJfB)? zr7;C5uz{aX3}W8LPp{w%em*ghZGh`X!~>co5L1zjN4AIJV8t{Q%^NKEgB8;t7EB=m zPI~qF!NrT)<>d{CA?M6ZXK->%o6vuscoG1-7gcR7enZm$015yANkvXXu0mjfnj}3u diff --git a/games/devtest/mods/testnodes/textures/testnodes_attachedwr_top.png b/games/devtest/mods/testnodes/textures/testnodes_attachedwr_top.png index 39ea67b8b3fd32226a6e7d8381dc8ed8654e492a..70976ca15473c32e3d6e9828a88d164205be03b0 100644 GIT binary patch delta 91 zcmV-h0Hpt!0eO%lRX|BZK~yM_V_3H2KS_uIhzkqW6Nv`9hNPsKm@3c&DboO#29j_F x0Y6~X0Ow-&G+YjoK_v~O1uGsz=a?o50RW6_wQ{fipLqZP002ovPDHLkV1f`DAt3+& delta 123 zcmb=N$v8o!G{MuwF+}5ha?G|T_RN|Mt&NQjzs%%yS!HI*nUJI)cp>=kasTxOOAT2y zH#E-o=SjK;1Z1R&ov#48pjVbv>xH?FqdA=%fj$6EqP<3hQpql o8fFt1fMQw9Clg$5Ijmx15I@LrD0{-e=L|sL>FVdQ&MBb@04-4-&Hw-a delta 185 zcmXTE#yCNxp0mIsvY3HEPZ@+6E0)@qF)%Q&mw5WRvOi@OV38F16jB=m6p}1)jVN)> z&&^HED`9XhN=+v&1m4V@>^xpWBTT|~d0D-5gpUXO@geCw4IUlG1 delta 150 zcmV;H0BQexvjLDKe*tq+M?wIu&K&6g003=CL_t(IPh(`D5HN!DzYG`t4>L!6oUF+o()$A5*L4)$_O_Aq!Fe8p8+6EU`vH({~tAg%rHQX zb&3KJW)RuYIBEbQE^uZhm=aK?Le5OEynqsjl;mgth#&M35VY2(vH$=807*qoM6N<$ Ef{HFXJpcdz diff --git a/textures/base/pack/cdb_update_cropped.png b/textures/base/pack/cdb_update_cropped.png index 8161dd7e4358334dd969eab9ca44bfb40639420b..2285c8ffc6ffb6e3138cd058067af00164330e85 100644 GIT binary patch delta 137 zcmV;40CxYMBBcS4B!6s4L_t(I%VS``0lHp){LerR0BIyzGfXi$#;Zx=%>Dl$Op->J zCJ?r)SOLZ`O&~TwjmV0~(gXr{HR01pNIilKyXVGr*Y%6mWdrZBFW;Y9dov>Bd~U|K zX~&Pf_Sx=-$lUC-qmL{YlJ2^CeoBtx%cb(s}{_V1gvqP;n?O*jgKyOHV({Eup|~1 zr8=ZzeiTqcF8s!^<2a_uF8pDKkMf1xs8%i66hRf6N-L#JbrLV*OA0dzVge8ZkuGAf zV0|bm#9X+^D}ZeblQ?EV^g0(_4SD3&A_!w`tc@ayV`>wF7iM4u5m^yddzL3C;K_y8 z>Uvlp$>!!}TeID!MFJ$v^E^p0B*PGZAfhcHU5pW-=t6@c&f!5(DWZmTRSRJTr|8!j zbr+7qJT?+vFzoXs=|j8JqsU;89P1I)i<^KX5zr5ML@Qguh+K`LT4O{) z#Z4%rFC0rDOG*E5W2D~Pjx3R=9t8m!g;nW0mNaf$(!-D-pa#RH7l?faQdgBxvF?b? zm@&6AHV|-6^4@_S*}Dk_l+P!4G^x=D&+BpF#`=P+NvbTECMzp`2hBSOiRWm7Rb+|a zIWC{zk&|W-%W@2IjG^*|qPiH8kU<6HHWheenWAWgR|tiY{RGP^i10h}9Rx4RtYVi~ zhI6uGD9R!#WTjX?HY$Tk1}aA39Wu?a1jRe^3D&8w1gEfwu(Nh2kh6$#$|jX83Cp!e zP=w=DgJJ-Y;ZVSwFa#Hh%Dpa}u~DNV<@KVjfP)KPrG^?~qZ5^C5LM`+p(gF*StrLi z^PTy21~eH3RiQ`}GST2PYo|G59E$*(0bxZWPl3Q3hrI~y2oiNIQmJY6E<9OvlhZ!9 zPO_+r9#Ka?nykZ>BX#(GiWaDN_y(O%lU1eV$I!;*!3qEmM_!^vVf_|!D1M_VP(%DF z{#dV?R|&(+OCg9-d<#*r3B?r#uK1KxD~19Hsz)MSN5<73NCiq^Bq!rQge=l_f@Ktn z5E;KnP;@@e@VrBk>3Aw6*`u1GH;WNe6aXDTD@afCKNPmuJg8h#vn0B?78$1if2!75_;w*m7B`|Dak#Xre zA=iXl<5FN;;EC*-kZW8Dj0-%GT|b#z8KbXLCQCn!4J6T@Nj>}jqGhxR#85x^~-_3&-?IZD6n+!a!O9% z`tUiJKaNgqA3pou^1<0JcDA;*S`RNuO-;SKChN?Dcy`0u_AIV%&aSyTW6$UH4c@ml zXI}b?3$C2)xLp?hllMYtaar-%hRyv8+q$+syC{49-h&%AEEK}Ku58UtIoI9ZQCPKP zUDcsm_f-F#@$dcr2po9Vt-$zn>9}8cBRKL1#kivkXGRvXg~$h5rHLTNw1ZM`iEf8*(m&QHZ(S1K$(h*lUsDx&2BqQ>e8uB cp4hhM>P#;d73ci}jsO4v07*qoM6N<$f~6BRXaE2J diff --git a/textures/base/pack/checkbox_32.png b/textures/base/pack/checkbox_32.png index 00208a0f1f5206c51ecef366db963ec07fdeab6c..bc6b2721b409001bcdcbc2260585df9d1e53c88a 100644 GIT binary patch delta 164 zcmV;V09*gy0l)!}B!7oVL_t(o!|jwy3V<*S1#|Y|rrM2o-)IF_N=(#zK=L5F!VGQt z05Tb;AY$vYM8U^C>oIdA+*g8t`$#bGeQLrJo^Y*ty@O9?ooxjdb+*a1OFP>WevvR+ zIKg{1$(gSkJum>>g(D=&3wYK3+a(PCP{OX^1QNDzM#2Y9NFDgXPd(8f^T%vwx|U7o SJ@jk<0000dH1;z=XX3pGx0t yTMhoF3BH8OFu@B?n2>=7Ovu8&a^LCirb!)t$2gkz6>ix80000Rj%+VIbB~17fVq>ENoCXjJa2kN@6@1>pFkt!iOE?u{lf#G>10B8pjAc_9 zB0cpmH2?3)#)wJ`17L=rI~zUp@wxz)pRpN&5(Y5m;{uFjQ#UbEDaFwUcMiJk*a8s- skOLDVFJRMv4^Zp{6c_yO$|l(W092MpD4HARQ2+n{07*qoM6N<$f~oON#Q*>R From 5aeaf20849f62609680763480998fb3219c18341 Mon Sep 17 00:00:00 2001 From: cx384 Date: Tue, 31 Dec 2024 16:27:10 +0100 Subject: [PATCH 41/44] CI png optimized check --- .github/workflows/png_file_checks.yml | 26 ++++++++++++++++++++++ util/ci/check_png_optimized.sh | 31 +++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 .github/workflows/png_file_checks.yml create mode 100755 util/ci/check_png_optimized.sh diff --git a/.github/workflows/png_file_checks.yml b/.github/workflows/png_file_checks.yml new file mode 100644 index 000000000..86cd93527 --- /dev/null +++ b/.github/workflows/png_file_checks.yml @@ -0,0 +1,26 @@ +name: png_file_checks + +# Check whether all png files are in a valid format +on: + push: + paths: + - '**.png' + - '.github/workflows/**.yml' + pull_request: + paths: + - '**.png' + - '.github/workflows/**.yml' + +jobs: + png_optimized: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install deps + run: | + sudo apt-get update + sudo apt install -y optipng + + - name: Check whether all png files are optimized + run: | + ./util/ci/check_png_optimized.sh diff --git a/util/ci/check_png_optimized.sh b/util/ci/check_png_optimized.sh new file mode 100755 index 000000000..856262797 --- /dev/null +++ b/util/ci/check_png_optimized.sh @@ -0,0 +1,31 @@ +#!/bin/bash -e + +# Only warn if decrease is more than 3% +optimization_requirement=3 + +git ls-files "*.png" | sort -u | ( + optimized=1 + temp_file=$(mktemp) + echo "Optimizing png files:" + while read file; do + # Does only run a fuzzy check without -o7 -zm1-9 since it would be too slow otherwise + decrease=($(optipng -nc -strip all -out "$temp_file" -clobber "$file" |& \ + sed -n 's/.*(\([0-9]\{1,\}\) bytes\? = \([0-9]\{1,\}\)\.[0-9]\{2\}% decrease).*/\1 \2/p')) + if [[ -n "${decrease[*]}" ]]; then + if [ "${decrease[1]}" -ge "$optimization_requirement" ]; then + echo -en "\033[31m" + optimized=0 + else + echo -en "\033[32m" + fi + echo -e "Decrease: ${decrease[0]}B ${decrease[1]}%\033[0m $file" + fi + done + rm "$temp_file" + + if [ "$optimized" -eq 0 ]; then + echo -e "\033[1;31mWarning: Could optimized png file(s) by more than $optimization_requirement%.\033[0m" \ + "Apply 'optipng -o7 -zm1-9 -nc -strip all -clobber '" + exit 1 + fi +) From 464cc925211cb2c5c90f951137328862e0d7f377 Mon Sep 17 00:00:00 2001 From: cx384 Date: Sun, 12 Jan 2025 16:20:05 +0100 Subject: [PATCH 42/44] Main menu server tab mods button (#15561) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lars Müller --- LICENSE.txt | 9 ++ builtin/mainmenu/dlg_server_list_mods.lua | 105 ++++++++++++++++++ builtin/mainmenu/init.lua | 1 + builtin/mainmenu/tab_online.lua | 38 ++++++- textures/base/pack/server_url_unavailable.png | Bin 0 -> 297 bytes .../pack/server_view_clients_unavailable.png | Bin 0 -> 145 bytes textures/base/pack/server_view_mods.png | Bin 0 -> 210 bytes .../pack/server_view_mods_unavailable.png | Bin 0 -> 198 bytes 8 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 builtin/mainmenu/dlg_server_list_mods.lua create mode 100644 textures/base/pack/server_url_unavailable.png create mode 100644 textures/base/pack/server_view_clients_unavailable.png create mode 100644 textures/base/pack/server_view_mods.png create mode 100644 textures/base/pack/server_view_mods_unavailable.png diff --git a/LICENSE.txt b/LICENSE.txt index f7930f528..503dd62d2 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -14,6 +14,9 @@ https://www.apache.org/licenses/LICENSE-2.0.html Textures by Zughy are under CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0/ +Textures by cx384 are under CC BY-SA 4.0 +https://creativecommons.org/licenses/by-sa/4.0/ + Media files by DS are under CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0/ @@ -64,7 +67,13 @@ Zughy: textures/base/pack/settings_info.png textures/base/pack/settings_reset.png textures/base/pack/server_url.png + textures/base/pack/server_url_unavailable.png textures/base/pack/server_view_clients.png + textures/base/pack/server_view_clients_unavailable.png + +cx384: + textures/base/pack/server_view_mods.png + textures/base/pack/server_view_mods_unavailable.png appgurueu: textures/base/pack/server_incompatible.png diff --git a/builtin/mainmenu/dlg_server_list_mods.lua b/builtin/mainmenu/dlg_server_list_mods.lua new file mode 100644 index 000000000..ad44ac37f --- /dev/null +++ b/builtin/mainmenu/dlg_server_list_mods.lua @@ -0,0 +1,105 @@ +-- Luanti +-- Copyright (C) 2024 cx384 +-- SPDX-License-Identifier: LGPL-2.1-or-later + +local function get_formspec(dialogdata) + local TOUCH_GUI = core.settings:get_bool("touch_gui") + local server = dialogdata.server + local group_by_prefix = dialogdata.group_by_prefix + local expand_all = dialogdata.expand_all + + -- A wrongly behaving server may send ill formed mod names + table.sort(server.mods) + + local cells = {} + if group_by_prefix then + local function get_prefix(mod) + return mod:match("[^_]*") + end + local count = {} + for _, mod in ipairs(server.mods) do + local prefix = get_prefix(mod) + count[prefix] = (count[prefix] or 0) + 1 + end + local last_prefix + local function add_row(depth, mod) + table.insert(cells, ("%d"):format(depth)) + table.insert(cells, mod) + end + for i, mod in ipairs(server.mods) do + local prefix = get_prefix(mod) + if last_prefix == prefix then + add_row(1, mod) + elseif count[prefix] > 1 then + add_row(0, prefix) + add_row(1, mod) + else + add_row(0, mod) + end + last_prefix = prefix + end + else + cells = table.copy(server.mods) + end + + for i, cell in ipairs(cells) do + cells[i] = core.formspec_escape(cell) + end + cells = table.concat(cells, ",") + + local heading + if server.gameid then + heading = fgettext("The $1 server uses a game called $2 and the following mods:", + "" .. core.hypertext_escape(server.name) .. "", + "") + else + heading = fgettext("The $1 server uses the following mods:", + "" .. core.hypertext_escape(server.name) .. "") + end + + local formspec = { + "formspec_version[8]", + "size[8,9.5]", + TOUCH_GUI and "padding[0.01,0.01]" or "", + "hypertext[0,0;8,1.5;;", heading, "]", + "tablecolumns[", group_by_prefix and + (expand_all and "indent;text" or "tree;text") or "text", "]", + "table[0.5,1.5;7,6.8;mods;", cells, "]", + "checkbox[0.5,8.7;group_by_prefix;", fgettext("Group by prefix"), ";", + group_by_prefix and "true" or "false", "]", + group_by_prefix and ("checkbox[0.5,9.15;expand_all;" .. fgettext("Expand all") .. ";" .. + (expand_all and "true" or "false") .. "]") or "", + "button[5.5,8.5;2,0.8;quit;OK]" + } + return table.concat(formspec, "") +end + +local function buttonhandler(this, fields) + if fields.quit then + this:delete() + return true + end + + if fields.group_by_prefix then + this.data.group_by_prefix = core.is_yes(fields.group_by_prefix) + return true + end + + if fields.expand_all then + this.data.expand_all = core.is_yes(fields.expand_all) + return true + end + + return false +end + +function create_server_list_mods_dialog(server) + local retval = dialog_create("dlg_server_list_mods", + get_formspec, + buttonhandler, + nil) + retval.data.group_by_prefix = false + retval.data.expand_all = false + retval.data.server = server + return retval +end diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index 4e1c201cd..9eceb41a8 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -56,6 +56,7 @@ dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua") dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua") dofile(menupath .. DIR_DELIM .. "dlg_reinstall_mtg.lua") dofile(menupath .. DIR_DELIM .. "dlg_clients_list.lua") +dofile(menupath .. DIR_DELIM .. "dlg_server_list_mods.lua") local tabs = { content = dofile(menupath .. DIR_DELIM .. "tab_content.lua"), diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index 02c6a9c24..bd7f45342 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -161,6 +161,26 @@ local function get_formspec(tabview, name, tabdata) core.formspec_escape(gamedata.serverdescription) .. "]" end + -- Mods button + local mods = selected_server.mods + if mods and #mods > 0 then + local tooltip = "" + if selected_server.gameid then + tooltip = fgettext("Game: $1", selected_server.gameid) .. "\n" + end + tooltip = tooltip .. fgettext("Number of mods: $1", #mods) + + retval = retval .. + "tooltip[btn_view_mods;" .. tooltip .. "]" .. + "style[btn_view_mods;padding=6]" .. + "image_button[4,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir .. + "server_view_mods.png") .. ";btn_view_mods;]" + else + retval = retval .. "image[4.1,1.4;0.3,0.3;" .. core.formspec_escape(defaulttexturedir .. + "server_view_mods_unavailable.png") .. "]" + end + + -- Clients list button local clients_list = selected_server.clients_list local can_view_clients_list = clients_list and #clients_list > 0 if can_view_clients_list then @@ -178,15 +198,23 @@ local function get_formspec(tabview, name, tabdata) retval = retval .. "style[btn_view_clients;padding=6]" retval = retval .. "image_button[4.5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir .. "server_view_clients.png") .. ";btn_view_clients;]" + else + retval = retval .. "image[4.6,1.4;0.3,0.3;" .. core.formspec_escape(defaulttexturedir .. + "server_view_clients_unavailable.png") .. "]" end + -- URL button if selected_server.url then retval = retval .. "tooltip[btn_server_url;" .. fgettext("Open server website") .. "]" retval = retval .. "style[btn_server_url;padding=6]" - retval = retval .. "image_button[" .. (can_view_clients_list and "4" or "4.5") .. ",1.3;0.5,0.5;" .. + retval = retval .. "image_button[3.5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir .. "server_url.png") .. ";btn_server_url;]" + else + retval = retval .. "image[3.6,1.4;0.3,0.3;" .. core.formspec_escape(defaulttexturedir .. + "server_url_unavailable.png") .. "]" end + -- Favorites toggle button if is_selected_fav() then retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]" retval = retval .. "style[btn_delete_favorite;padding=6]" @@ -468,6 +496,14 @@ local function main_button_handler(tabview, fields, name, tabdata) return true end + if fields.btn_view_mods then + local dlg = create_server_list_mods_dialog(find_selected_server()) + dlg:set_parent(tabview) + tabview:hide() + dlg:show() + return true + end + if fields.btn_mp_clear then tabdata.search_for = "" menudata.search_result = nil diff --git a/textures/base/pack/server_url_unavailable.png b/textures/base/pack/server_url_unavailable.png new file mode 100644 index 0000000000000000000000000000000000000000..8010ad46941facce593dda42e92298c318757dad GIT binary patch literal 297 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8K8Aw(>tdav#iUB?$u0YyAM=v!#COjx0)X&ey z)eXo63f}+r_586N3nusRGPM7=%Iw#3*i;In|IfLj&@UXRI>qRWVo(_qM+VEWC&4L=Y%C?r%`3|%-8y9^psMiT zyhEyHK@=-caPrh$LA8t6mT+;rU~3bN*82N$#oFm{bt@Yh_9gV_G<{^@c)|D1MAHEb z_9ZYfPIoX}&%G+Mp0Kt>CY1T5d0aK49>4^>bP0l+XkKHk)Un literal 0 HcmV?d00001 diff --git a/textures/base/pack/server_view_clients_unavailable.png b/textures/base/pack/server_view_clients_unavailable.png new file mode 100644 index 0000000000000000000000000000000000000000..964efcde1ef8c96de5981bf1df059b117cbf1a76 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`5uPrNAr`%RCpmI4C~&a+oy~vi z{*Sv>oPx6>gAO{hr#X1G$b{zde4BPE&F!X}lBK95^TogZ52{!gyd@p-ChAO@v^enJ s-{wnvUX0Ua)vQg7*p=?F`W38amXb{W_c-SiC(sTCPgg&ebxsLQ0N5ffk^lez literal 0 HcmV?d00001 diff --git a/textures/base/pack/server_view_mods.png b/textures/base/pack/server_view_mods.png new file mode 100644 index 0000000000000000000000000000000000000000..a2611d92d261fea9b835f16a76f58b9033f8e5b6 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Gd*1#Lo9lGCmC`z7znU@7ONLr z^QNX@t^5XI?LZdq__Zz(H)4vWbH_}+Eh*;9acpMN_hlQ6)OMWvD8JpK>AdN`;=I4r zI?Z|?8*Yf_R&cIhTa~-yCbN++!_tGPt9d`od~mPWb1iR?XB#_agSRF>+rWLr#U|<-v)|0Vqy5!OR|6f%;OXk; Jvd$@?2>^wxPrCpB literal 0 HcmV?d00001 diff --git a/textures/base/pack/server_view_mods_unavailable.png b/textures/base/pack/server_view_mods_unavailable.png new file mode 100644 index 0000000000000000000000000000000000000000..4238bb786a3f288b2e9ff4dd164f57a82dca3ab7 GIT binary patch literal 198 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`y`C`rU| literal 0 HcmV?d00001 From 636a734d78b6c0b8392eabda350131690b800682 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Mon, 13 Jan 2025 09:39:06 +0100 Subject: [PATCH 43/44] Resolve some quirks with (wield) item meshes for nodes (#15654) --- src/client/content_mapblock.cpp | 8 -- src/client/content_mapblock.h | 1 - src/client/mapblock_mesh.cpp | 38 +++++-- src/client/mapblock_mesh.h | 5 + src/client/wieldmesh.cpp | 184 +++++++------------------------- src/client/wieldmesh.h | 1 - src/nodedef.h | 15 --- src/voxel.h | 4 +- 8 files changed, 78 insertions(+), 178 deletions(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 5b69b4a5d..d8f1ff3b6 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -1781,11 +1781,3 @@ void MapblockMeshGenerator::generate() drawNode(); } } - -void MapblockMeshGenerator::renderSingle(content_t node, u8 param2) -{ - cur_node.p = {0, 0, 0}; - cur_node.n = MapNode(node, 0xff, param2); - cur_node.f = &nodedef->get(cur_node.n); - drawNode(); -} diff --git a/src/client/content_mapblock.h b/src/client/content_mapblock.h index 2bfbbdc61..a4ed6a0fc 100644 --- a/src/client/content_mapblock.h +++ b/src/client/content_mapblock.h @@ -47,7 +47,6 @@ class MapblockMeshGenerator public: MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output); void generate(); - void renderSingle(content_t node, u8 param2 = 0x00); private: MeshMakeData *const data; diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 05f9e73cc..a47bf5ae9 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -31,7 +31,9 @@ MeshMakeData::MeshMakeData(const NodeDefManager *ndef, m_side_length(side_length), m_mesh_grid(mesh_grid), m_nodedef(ndef) -{} +{ + assert(m_side_length > 0); +} void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos) { @@ -55,6 +57,24 @@ void MeshMakeData::fillBlockData(const v3s16 &bp, MapNode *data) m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size); } +void MeshMakeData::fillSingleNode(MapNode data, MapNode padding) +{ + m_blockpos = {0, 0, 0}; + + m_vmanip.clear(); + // area around 0,0,0 so that this positon has neighbors + const s16 sz = 3; + m_vmanip.addArea({v3s16(-sz), v3s16(sz)}); + + u32 count = m_vmanip.m_area.getVolume(); + for (u32 i = 0; i < count; i++) { + m_vmanip.m_data[i] = padding; + m_vmanip.m_flags[i] &= ~VOXELFLAG_NO_DATA; + } + + m_vmanip.setNodeNoEmerge({0, 0, 0}, data); +} + void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos) { if (crack_level >= 0) @@ -628,6 +648,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs MeshCollector collector(m_bounding_sphere_center, offset); { + // Generate everything MapblockMeshGenerator(data, &collector).generate(); } @@ -940,21 +961,22 @@ video::SColor encode_light(u16 light, u8 emissive_light) u8 get_solid_sides(MeshMakeData *data) { - std::unordered_map results; v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE; const NodeDefManager *ndef = data->m_nodedef; - u8 result = 0x3F; // all sides solid; + const u16 side = data->m_side_length; + assert(data->m_vmanip.m_area.contains(blockpos_nodes + v3s16(side - 1))); - for (s16 i = 0; i < data->m_side_length && result != 0; i++) - for (s16 j = 0; j < data->m_side_length && result != 0; j++) { + u8 result = 0x3F; // all sides solid + for (s16 i = 0; i < side && result != 0; i++) + for (s16 j = 0; j < side && result != 0; j++) { v3s16 positions[6] = { v3s16(0, i, j), - v3s16(data->m_side_length - 1, i, j), + v3s16(side - 1, i, j), v3s16(i, 0, j), - v3s16(i, data->m_side_length - 1, j), + v3s16(i, side - 1, j), v3s16(i, j, 0), - v3s16(i, j, data->m_side_length - 1) + v3s16(i, j, side - 1) }; for (u8 k = 0; k < 6; k++) { diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h index 47941386e..55aa172bd 100644 --- a/src/client/mapblock_mesh.h +++ b/src/client/mapblock_mesh.h @@ -62,6 +62,11 @@ struct MeshMakeData void fillBlockDataBegin(const v3s16 &blockpos); void fillBlockData(const v3s16 &bp, MapNode *data); + /* + Prepare block data for rendering a single node located at (0,0,0). + */ + void fillSingleNode(MapNode data, MapNode padding = MapNode(CONTENT_AIR)); + /* Set the (node) position of a crack */ diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index 4c4042ad4..f03de2a5b 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -21,24 +21,12 @@ #include #include "client/renderingengine.h" -#define WIELD_SCALE_FACTOR 30.0 -#define WIELD_SCALE_FACTOR_EXTRUDED 40.0 +#define WIELD_SCALE_FACTOR 30.0f +#define WIELD_SCALE_FACTOR_EXTRUDED 40.0f #define MIN_EXTRUSION_MESH_RESOLUTION 16 #define MAX_EXTRUSION_MESH_RESOLUTION 512 -/*! - * Applies overlays, textures and optionally materials to the given mesh and - * extracts tile colors for colorization. - * \param mattype overrides the buffer's material type, but can also - * be NULL to leave the original material. - * \param colors returns the colors of the mesh buffers in the mesh. - */ -static void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, - bool set_material, const video::E_MATERIAL_TYPE *mattype, - std::vector *colors, bool apply_scale = false); - - static scene::IMesh *createExtrusionMesh(int resolution_x, int resolution_y) { const f32 r = 0.5; @@ -237,19 +225,6 @@ WieldMeshSceneNode::~WieldMeshSceneNode() g_extrusion_mesh_cache = nullptr; } -void WieldMeshSceneNode::setCube(const ContentFeatures &f, - v3f wield_scale) -{ - scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube(); - scene::SMesh *copy = cloneMesh(cubemesh); - cubemesh->drop(); - postProcessNodeMesh(copy, f, false, &m_material_type, &m_colors, true); - copy->recalculateBoundingBox(); - changeToMesh(copy); - copy->drop(); - m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR); -} - void WieldMeshSceneNode::setExtruded(const std::string &imagename, const std::string &overlay_name, v3f wield_scale, ITextureSource *tsrc, u8 num_frames) @@ -264,6 +239,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, core::dimension2d dim = texture->getSize(); // Detect animation texture and pull off top frame instead of using entire thing + // FIXME: this is quite unportable, we should be working with the original TileLayer if there's one if (num_frames > 1) { u32 frame_height = dim.Height / num_frames; dim = core::dimension2d(dim.Width, frame_height); @@ -275,6 +251,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, mesh->getMeshBuffer(0)->getMaterial().setTexture(0, tsrc->getTexture(imagename)); if (overlay_texture) { + // duplicate the extruded mesh for the overlay scene::IMeshBuffer *copy = cloneMeshBuffer(mesh->getMeshBuffer(0)); copy->getMaterial().setTexture(0, overlay_texture); mesh->addMeshBuffer(copy); @@ -306,16 +283,10 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, } } -static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n, +static scene::SMesh *createGenericNodeMesh(Client *client, MapNode n, std::vector *colors, const ContentFeatures &f) { - MeshMakeData mesh_make_data(client->ndef(), 1, client->getMeshGrid()); - MeshCollector collector(v3f(0.0f * BS), v3f()); - mesh_make_data.m_generate_minimap = false; - mesh_make_data.m_smooth_lighting = false; - mesh_make_data.m_enable_water_reflections = false; - MapblockMeshGenerator gen(&mesh_make_data, &collector); - + n.setParam1(0xff); if (n.getParam2()) { // keep it } else if (f.param_type_2 == CPT2_WALLMOUNTED || @@ -329,7 +300,13 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n, } else if (f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_TORCHLIKE) { n.setParam2(1); } - gen.renderSingle(n.getContent(), n.getParam2()); + + MeshCollector collector(v3f(0), v3f()); + { + MeshMakeData mmd(client->ndef(), 1, MeshGrid{1}); + mmd.fillSingleNode(n); + MapblockMeshGenerator(&mmd, &collector).generate(); + } colors->clear(); scene::SMesh *mesh = new scene::SMesh(); @@ -399,15 +376,12 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che } // Handle nodes - // See also CItemDefManager::createClientCached() if (def.type == ITEM_NODE) { - bool cull_backface = f.needsBackfaceCulling(); - // Select rendering method switch (f.drawtype) { case NDT_AIRLIKE: setExtruded("no_texture_airlike.png", "", - v3f(1.0, 1.0, 1.0), tsrc, 1); + v3f(1), tsrc, 1); break; case NDT_SIGNLIKE: case NDT_TORCHLIKE: @@ -417,38 +391,33 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che v3f wscale = wield_scale; if (f.drawtype == NDT_FLOWINGLIQUID) wscale.Z *= 0.1f; - setExtruded(tsrc->getTextureName(f.tiles[0].layers[0].texture_id), - tsrc->getTextureName(f.tiles[0].layers[1].texture_id), - wscale, tsrc, - f.tiles[0].layers[0].animation_frame_count); - // Add color const TileLayer &l0 = f.tiles[0].layers[0]; - m_colors.emplace_back(l0.has_color, l0.color); const TileLayer &l1 = f.tiles[0].layers[1]; + setExtruded(tsrc->getTextureName(l0.texture_id), + tsrc->getTextureName(l1.texture_id), + wscale, tsrc, + l0.animation_frame_count); + // Add color + m_colors.emplace_back(l0.has_color, l0.color); m_colors.emplace_back(l1.has_color, l1.color); break; } case NDT_PLANTLIKE_ROOTED: { - setExtruded(tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), - "", wield_scale, tsrc, - f.special_tiles[0].layers[0].animation_frame_count); - // Add color + // use the plant tile const TileLayer &l0 = f.special_tiles[0].layers[0]; + setExtruded(tsrc->getTextureName(l0.texture_id), + "", wield_scale, tsrc, + l0.animation_frame_count); m_colors.emplace_back(l0.has_color, l0.color); break; } - case NDT_NORMAL: - case NDT_ALLFACES: - case NDT_LIQUID: - setCube(f, wield_scale); - break; default: { - // Render non-trivial drawtypes like the actual node + // Render all other drawtypes like the actual node MapNode n(id); if (def.place_param2) n.setParam2(*def.place_param2); - mesh = createSpecialNodeMesh(client, n, &m_colors, f); + mesh = createGenericNodeMesh(client, n, &m_colors, f); changeToMesh(mesh); mesh->drop(); m_meshnode->setScale( @@ -461,9 +430,9 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che u32 material_count = m_meshnode->getMaterialCount(); for (u32 i = 0; i < material_count; ++i) { video::SMaterial &material = m_meshnode->getMaterial(i); + // FIXME: overriding this breaks different alpha modes the mesh may have material.MaterialType = m_material_type; material.MaterialTypeParam = 0.5f; - material.BackfaceCulling = cull_backface; material.forEachTexture([this] (auto &tex) { setMaterialFilters(tex, m_bilinear_filter, m_trilinear_filter, m_anisotropic_filter); @@ -574,8 +543,6 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) // Shading is on by default result->needs_shading = true; - bool cull_backface = f.needsBackfaceCulling(); - // If inventory_image is defined, it overrides everything else const std::string inventory_image = item.getInventoryImage(idef); const std::string inventory_overlay = item.getInventoryOverlay(idef); @@ -592,51 +559,32 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) result->needs_shading = false; } else if (def.type == ITEM_NODE) { switch (f.drawtype) { - case NDT_NORMAL: - case NDT_ALLFACES: - case NDT_LIQUID: - case NDT_FLOWINGLIQUID: { - scene::IMesh *cube = g_extrusion_mesh_cache->createCube(); - mesh = cloneMesh(cube); - cube->drop(); - if (f.drawtype == NDT_FLOWINGLIQUID) { - scaleMesh(mesh, v3f(1.2, 0.03, 1.2)); - translateMesh(mesh, v3f(0, -0.57, 0)); - } else - scaleMesh(mesh, v3f(1.2, 1.2, 1.2)); - // add overlays - postProcessNodeMesh(mesh, f, false, nullptr, - &result->buffer_colors, true); - if (f.drawtype == NDT_ALLFACES) - scaleMesh(mesh, v3f(f.visual_scale)); - break; - } case NDT_PLANTLIKE: { - mesh = getExtrudedMesh(tsrc, - tsrc->getTextureName(f.tiles[0].layers[0].texture_id), - tsrc->getTextureName(f.tiles[0].layers[1].texture_id)); - // Add color const TileLayer &l0 = f.tiles[0].layers[0]; - result->buffer_colors.emplace_back(l0.has_color, l0.color); const TileLayer &l1 = f.tiles[0].layers[1]; + mesh = getExtrudedMesh(tsrc, + tsrc->getTextureName(l0.texture_id), + tsrc->getTextureName(l1.texture_id)); + // Add color + result->buffer_colors.emplace_back(l0.has_color, l0.color); result->buffer_colors.emplace_back(l1.has_color, l1.color); break; } case NDT_PLANTLIKE_ROOTED: { - mesh = getExtrudedMesh(tsrc, - tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), ""); - // Add color + // Use the plant tile const TileLayer &l0 = f.special_tiles[0].layers[0]; + mesh = getExtrudedMesh(tsrc, + tsrc->getTextureName(l0.texture_id), ""); result->buffer_colors.emplace_back(l0.has_color, l0.color); break; } default: { - // Render non-trivial drawtypes like the actual node + // Render all other drawtypes like the actual node MapNode n(id); if (def.place_param2) n.setParam2(*def.place_param2); - mesh = createSpecialNodeMesh(client, n, &result->buffer_colors, f); + mesh = createGenericNodeMesh(client, n, &result->buffer_colors, f); scaleMesh(mesh, v3f(0.12, 0.12, 0.12)); break; } @@ -645,13 +593,13 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) { scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); video::SMaterial &material = buf->getMaterial(); + // FIXME: overriding this breaks different alpha modes the mesh may have material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.MaterialTypeParam = 0.5f; material.forEachTexture([] (auto &tex) { tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; tex.MagFilter = video::ETMAGF_NEAREST; }); - material.BackfaceCulling = cull_backface; } rotateMeshXZby(mesh, -45); @@ -672,7 +620,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename, const std::string &overlay_name) { // check textures - video::ITexture *texture = tsrc->getTextureForMesh(imagename); + video::ITexture *texture = tsrc->getTexture(imagename); if (!texture) { return NULL; } @@ -707,59 +655,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.MaterialTypeParam = 0.5f; } - scaleMesh(mesh, v3f(2.0, 2.0, 2.0)); + scaleMesh(mesh, v3f(2)); return mesh; } - -static void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, - bool set_material, const video::E_MATERIAL_TYPE *mattype, - std::vector *colors, bool apply_scale) -{ - // FIXME: this function is weirdly inconsistent with what MapBlockMesh does. - // also set_material is never true - - const u32 mc = mesh->getMeshBufferCount(); - // Allocate colors for existing buffers - colors->resize(mc); - - for (u32 i = 0; i < mc; ++i) { - const TileSpec *tile = &(f.tiles[i]); - scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); - for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) { - const TileLayer *layer = &tile->layers[layernum]; - if (layer->texture_id == 0) - continue; - if (layernum != 0) { - // FIXME: why do this? - scene::IMeshBuffer *copy = cloneMeshBuffer(buf); - copy->getMaterial() = buf->getMaterial(); - mesh->addMeshBuffer(copy); - copy->drop(); - buf = copy; - colors->emplace_back(layer->has_color, layer->color); - } else { - (*colors)[i] = ItemPartColor(layer->has_color, layer->color); - } - - video::SMaterial &material = buf->getMaterial(); - if (set_material) - layer->applyMaterialOptions(material); - if (mattype) { - material.MaterialType = *mattype; - } - if (layer->animation_frame_count > 1) { - const FrameSpec &animation_frame = (*layer->frames)[0]; - material.setTexture(0, animation_frame.texture); - } else { - material.setTexture(0, layer->texture); - } - - if (apply_scale && tile->world_aligned) { - u32 n = buf->getVertexCount(); - for (u32 k = 0; k != n; ++k) - buf->getTCoords(k) /= layer->scale; - } - } - } -} diff --git a/src/client/wieldmesh.h b/src/client/wieldmesh.h index a3d8c3af1..0b65dfbd9 100644 --- a/src/client/wieldmesh.h +++ b/src/client/wieldmesh.h @@ -92,7 +92,6 @@ public: WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id = -1); virtual ~WieldMeshSceneNode(); - void setCube(const ContentFeatures &f, v3f wield_scale); void setExtruded(const std::string &imagename, const std::string &overlay_image, v3f wield_scale, ITextureSource *tsrc, u8 num_frames); void setItem(const ItemStack &item, Client *client, diff --git a/src/nodedef.h b/src/nodedef.h index d819be815..24bb0c460 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -474,21 +474,6 @@ struct ContentFeatures } } - bool needsBackfaceCulling() const - { - switch (drawtype) { - case NDT_TORCHLIKE: - case NDT_SIGNLIKE: - case NDT_FIRELIKE: - case NDT_RAILLIKE: - case NDT_PLANTLIKE: - case NDT_PLANTLIKE_ROOTED: - case NDT_MESH: - return false; - default: - return true; - } - } bool isLiquid() const{ return (liquid_type != LIQUID_NONE); diff --git a/src/voxel.h b/src/voxel.h index 63775040d..c47f97a30 100644 --- a/src/voxel.h +++ b/src/voxel.h @@ -459,7 +459,9 @@ public: { if(!m_area.contains(p)) return false; - m_data[m_area.index(p)] = n; + const s32 index = m_area.index(p); + m_data[index] = n; + m_flags[index] &= ~VOXELFLAG_NO_DATA; return true; } From 2bfcd45b35d9e64cbbe54827c4d58d3b5082299a Mon Sep 17 00:00:00 2001 From: DS Date: Mon, 13 Jan 2025 09:39:20 +0100 Subject: [PATCH 44/44] Fix always waving semitransparent liquid regression --- client/shaders/nodes_shader/opengl_fragment.glsl | 6 +++--- src/client/shader.cpp | 12 +++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/client/shaders/nodes_shader/opengl_fragment.glsl b/client/shaders/nodes_shader/opengl_fragment.glsl index 537f8b4a7..ed0404cea 100644 --- a/client/shaders/nodes_shader/opengl_fragment.glsl +++ b/client/shaders/nodes_shader/opengl_fragment.glsl @@ -51,7 +51,7 @@ centroid varying float nightRatio; varying highp vec3 eyeVec; #ifdef ENABLE_DYNAMIC_SHADOWS -#if (defined(ENABLE_WATER_REFLECTIONS) && MATERIAL_WAVING_LIQUID && ENABLE_WAVING_WATER) +#if (defined(ENABLE_WATER_REFLECTIONS) && MATERIAL_WATER_REFLECTIONS && ENABLE_WAVING_WATER) vec4 perm(vec4 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); @@ -502,7 +502,7 @@ void main(void) vec3 viewVec = normalize(worldPosition + cameraOffset - cameraPosition); // Water reflections -#if (defined(ENABLE_WATER_REFLECTIONS) && MATERIAL_WAVING_LIQUID && ENABLE_WAVING_WATER) +#if (defined(ENABLE_WATER_REFLECTIONS) && MATERIAL_WATER_REFLECTIONS && ENABLE_WAVING_WATER) vec3 wavePos = worldPosition * vec3(2.0, 0.0, 2.0); float off = animationTimer * WATER_WAVE_SPEED * 10.0; wavePos.x /= WATER_WAVE_LENGTH * 3.0; @@ -530,7 +530,7 @@ void main(void) col.rgb += water_reflect_color * f_adj_shadow_strength * brightness_factor; #endif -#if (defined(ENABLE_NODE_SPECULAR) && !MATERIAL_WAVING_LIQUID) +#if (defined(ENABLE_NODE_SPECULAR) && !MATERIAL_WATER_REFLECTIONS) // Apply specular to blocks. if (dot(v_LightDirection, vNormal) < 0.0) { float intensity = 2.0 * (1.0 - (base.r * varColor.r)); diff --git a/src/client/shader.cpp b/src/client/shader.cpp index f953a2148..290e3a572 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -687,13 +687,23 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: case TILE_MATERIAL_WAVING_LIQUID_BASIC: - case TILE_MATERIAL_LIQUID_TRANSPARENT: shaders_header << "#define MATERIAL_WAVING_LIQUID 1\n"; break; default: shaders_header << "#define MATERIAL_WAVING_LIQUID 0\n"; break; } + switch (material_type) { + case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: + case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: + case TILE_MATERIAL_WAVING_LIQUID_BASIC: + case TILE_MATERIAL_LIQUID_TRANSPARENT: + shaders_header << "#define MATERIAL_WATER_REFLECTIONS 1\n"; + break; + default: + shaders_header << "#define MATERIAL_WATER_REFLECTIONS 0\n"; + break; + } shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n"; shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n";