From a30525d7c9b3ddc2189cd18eead8f5c085c7ffef Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 18 Feb 2026 22:41:05 -0800 Subject: [PATCH] Fix WMO visibility culling and renderer initialization guards --- include/rendering/m2_renderer.hpp | 2 ++ include/rendering/wmo_renderer.hpp | 3 +++ src/core/logger.cpp | 1 + src/rendering/m2_renderer.cpp | 2 ++ src/rendering/wmo_renderer.cpp | 19 +++++++++---------- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/include/rendering/m2_renderer.hpp b/include/rendering/m2_renderer.hpp index ef9b5e86..0e6069dd 100644 --- a/include/rendering/m2_renderer.hpp +++ b/include/rendering/m2_renderer.hpp @@ -322,6 +322,7 @@ public: uint32_t getQueryCallCount() const { return queryCallCount; } // Stats + bool isInitialized() const { return initialized_; } uint32_t getModelCount() const { return static_cast(models.size()); } uint32_t getInstanceCount() const { return static_cast(instances.size()); } uint32_t getTotalTriangleCount() const; @@ -347,6 +348,7 @@ public: void setOnTaxi(bool onTaxi) { onTaxi_ = onTaxi; } private: + bool initialized_ = false; bool insideInterior = false; bool onTaxi_ = false; pipeline::AssetManager* assetManager = nullptr; diff --git a/include/rendering/wmo_renderer.hpp b/include/rendering/wmo_renderer.hpp index e6fffa3c..82295ca1 100644 --- a/include/rendering/wmo_renderer.hpp +++ b/include/rendering/wmo_renderer.hpp @@ -142,6 +142,7 @@ public: /** * Get number of loaded models */ + bool isInitialized() const { return initialized_; } uint32_t getModelCount() const { return loadedModels.size(); } /** @@ -573,6 +574,8 @@ private: std::vector instances; uint32_t nextInstanceId = 1; + bool initialized_ = false; + // Rendering state bool wireframeMode = false; bool frustumCulling = true; diff --git a/src/core/logger.cpp b/src/core/logger.cpp index 10e52b6f..ddeed740 100644 --- a/src/core/logger.cpp +++ b/src/core/logger.cpp @@ -61,6 +61,7 @@ void Logger::log(LogLevel level, const std::string& message) { std::cout << line.str() << '\n'; if (fileStream.is_open()) { fileStream << line.str() << '\n'; + fileStream.flush(); } } diff --git a/src/rendering/m2_renderer.cpp b/src/rendering/m2_renderer.cpp index 28cca90a..7730c607 100644 --- a/src/rendering/m2_renderer.cpp +++ b/src/rendering/m2_renderer.cpp @@ -261,6 +261,7 @@ M2Renderer::~M2Renderer() { } bool M2Renderer::initialize(pipeline::AssetManager* assets) { + if (initialized_) { assetManager = assets; return true; } assetManager = assets; numAnimThreads_ = std::min(4u, std::max(1u, std::thread::hardware_concurrency() - 1)); @@ -635,6 +636,7 @@ bool M2Renderer::initialize(pipeline::AssetManager* assets) { } LOG_INFO("M2 renderer initialized"); + initialized_ = true; return true; } diff --git a/src/rendering/wmo_renderer.cpp b/src/rendering/wmo_renderer.cpp index f32affc8..9031d711 100644 --- a/src/rendering/wmo_renderer.cpp +++ b/src/rendering/wmo_renderer.cpp @@ -37,6 +37,7 @@ WMORenderer::~WMORenderer() { } bool WMORenderer::initialize(pipeline::AssetManager* assets) { + if (initialized_) { assetManager = assets; return true; } core::Logger::getInstance().info("Initializing WMO renderer..."); assetManager = assets; @@ -204,6 +205,7 @@ bool WMORenderer::initialize(pipeline::AssetManager* assets) { initOcclusionResources(); core::Logger::getInstance().info("WMO renderer initialized"); + initialized_ = true; return true; } @@ -1205,19 +1207,16 @@ void WMORenderer::render(const Camera& camera, const glm::mat4& view, const glm: for (uint32_t gi : dl.visibleGroups) { const auto& group = model.groups[gi]; - // Skip non-renderable groups: - // 0x20000 = SHOW_SKYBOX (transparent sky windows) - // 0x4000000 = ANTIPORTAL (occlusion planes, not visible geometry) - // 0x8000000 = disables batch rendering - if (group.groupFlags & (0x20000 | 0x4000000 | 0x8000000)) { + // Skip truly non-visible groups: + // 0x20000 = SHOW_SKYBOX (window/skybox planes) + // 0x4000000 = ANTIPORTAL (occlusion planes, not render geometry) + // Note: 0x8000000 is *not* a safe global skip; some valid world WMOs use it. + if (group.groupFlags & (0x20000 | 0x4000000)) { continue; } - // Skip groups where ALL batches use the fallback white texture — - // these are collision/placeholder/LOD shell groups with no visual data - if (group.allUntextured) { - continue; - } + // Do not globally cull untextured groups: some valid world WMOs can + // temporarily resolve to fallback textures. Render geometry anyway. // STORMWIND.WMO specific fix: LOD shell visibility control