From 665a73e75f6bfc0fcbe1f7e8733d0bda14c879b9 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 3 Feb 2026 11:46:12 -0800 Subject: [PATCH] Fix WMO MOHD chunk parsing by adding missing nTextures field The MOHD header structure was missing the nTextures field at the start, causing all subsequent field reads to be offset by 4 bytes. This corrupted bounding box values and caused floor geometry to be incorrectly culled. --- include/pipeline/wmo_loader.hpp | 3 ++- src/pipeline/wmo_loader.cpp | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/pipeline/wmo_loader.hpp b/include/pipeline/wmo_loader.hpp index d7af1167..5cf14820 100644 --- a/include/pipeline/wmo_loader.hpp +++ b/include/pipeline/wmo_loader.hpp @@ -149,8 +149,9 @@ struct WMOGroup { // Complete WMO Model struct WMOModel { - // Root WMO data + // Root WMO data (from MOHD chunk) uint32_t version; + uint32_t nTextures; // Added - was missing, caused offset issues uint32_t nGroups; uint32_t nPortals; uint32_t nLights; diff --git a/src/pipeline/wmo_loader.cpp b/src/pipeline/wmo_loader.cpp index 200017be..19186848 100644 --- a/src/pipeline/wmo_loader.cpp +++ b/src/pipeline/wmo_loader.cpp @@ -99,7 +99,8 @@ WMOModel WMOLoader::load(const std::vector& wmoData) { } case MOHD: { - // Header + // Header - SMOHeader structure (WotLK 3.3.5a) + model.nTextures = read(wmoData, offset); // Was missing! model.nGroups = read(wmoData, offset); model.nPortals = read(wmoData, offset); model.nLights = read(wmoData, offset); @@ -107,7 +108,7 @@ WMOModel WMOLoader::load(const std::vector& wmoData) { model.nDoodadDefs = read(wmoData, offset); model.nDoodadSets = read(wmoData, offset); - [[maybe_unused]] uint32_t ambColor = read(wmoData, offset); // Ambient color + [[maybe_unused]] uint32_t ambColor = read(wmoData, offset); // Ambient color (BGRA) [[maybe_unused]] uint32_t wmoID = read(wmoData, offset); model.boundingBoxMin.x = read(wmoData, offset); @@ -118,7 +119,10 @@ WMOModel WMOLoader::load(const std::vector& wmoData) { model.boundingBoxMax.y = read(wmoData, offset); model.boundingBoxMax.z = read(wmoData, offset); - core::Logger::getInstance().info("WMO groups: ", model.nGroups); + // flags and numLod (uint16 each) - skip for now + offset += 4; + + core::Logger::getInstance().info("WMO header: nTextures=", model.nTextures, " nGroups=", model.nGroups); break; } @@ -452,6 +456,7 @@ bool WMOLoader::loadGroup(const std::vector& groupData, uint32_t vertexCount = subChunkSize / 12; // 3 floats per vertex for (uint32_t i = 0; i < vertexCount; i++) { WMOVertex vertex; + // Keep vertices in WoW model-local coords - coordinate swap done in model matrix vertex.position.x = read(groupData, mogpOffset); vertex.position.y = read(groupData, mogpOffset); vertex.position.z = read(groupData, mogpOffset);