From f1d332825ea3552cf04386582891c6348aa7e655 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 01:40:05 -0700 Subject: [PATCH] feat(editor): export WMO textures with the zone Placed WMO buildings reference textures (walls, floors, decorations) that were not being exported alongside the WOB files. Added collectWMOTextures() which loads the root WMO + all group files and gathers every texture path, then folds these into the same PNG export pass that handles terrain and M2 textures. Exported zones now have every texture they need across all model types. --- tools/editor/editor_app.cpp | 10 +++++++++- tools/editor/texture_exporter.cpp | 33 +++++++++++++++++++++++++++++++ tools/editor/texture_exporter.hpp | 5 +++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/tools/editor/editor_app.cpp b/tools/editor/editor_app.cpp index 896767ac..ab4ba7d1 100644 --- a/tools/editor/editor_app.cpp +++ b/tools/editor/editor_app.cpp @@ -1152,13 +1152,20 @@ void EditorApp::exportZone(const std::string& outputDir) { std::unordered_set uniq; for (auto& t : TextureExporter::collectUsedTextures(terrain_)) uniq.insert(std::move(t)); std::unordered_set visitedM2; + std::unordered_set visitedWMO; auto addM2Tex = [&](const std::string& m2Path) { if (m2Path.empty() || !visitedM2.insert(m2Path).second) return; for (auto& t : TextureExporter::collectM2Textures(assetManager_.get(), m2Path)) uniq.insert(std::move(t)); }; + auto addWMOTex = [&](const std::string& wmoPath) { + if (wmoPath.empty() || !visitedWMO.insert(wmoPath).second) return; + for (auto& t : TextureExporter::collectWMOTextures(assetManager_.get(), wmoPath)) + uniq.insert(std::move(t)); + }; for (const auto& obj : objectPlacer_.getObjects()) { if (obj.type == PlaceableType::M2) addM2Tex(obj.path); + else if (obj.type == PlaceableType::WMO) addWMOTex(obj.path); } for (const auto& npc : npcSpawner_.getSpawns()) addM2Tex(npc.modelPath); @@ -1167,7 +1174,8 @@ void EditorApp::exportZone(const std::string& outputDir) { if (!usedTextures.empty()) { int exported = TextureExporter::exportTexturesAsPng( assetManager_.get(), usedTextures, base + "/textures"); - LOG_INFO("Exported ", exported, " textures as PNG (terrain + ", visitedM2.size(), " M2s)"); + LOG_INFO("Exported ", exported, " textures as PNG (terrain + ", + visitedM2.size(), " M2s + ", visitedWMO.size(), " WMOs)"); } } diff --git a/tools/editor/texture_exporter.cpp b/tools/editor/texture_exporter.cpp index d4fa6a2a..45470241 100644 --- a/tools/editor/texture_exporter.cpp +++ b/tools/editor/texture_exporter.cpp @@ -2,6 +2,7 @@ #include "pipeline/asset_manager.hpp" #include "pipeline/blp_loader.hpp" #include "pipeline/m2_loader.hpp" +#include "pipeline/wmo_loader.hpp" #include "core/logger.hpp" #include #include @@ -45,6 +46,38 @@ std::vector TextureExporter::collectM2Textures(pipeline::AssetManag return out; } +std::vector TextureExporter::collectWMOTextures(pipeline::AssetManager* am, + const std::string& wmoPath) { + std::vector out; + if (!am || wmoPath.empty()) return out; + + auto rootData = am->readFile(wmoPath); + if (rootData.empty()) return out; + auto wmo = pipeline::WMOLoader::load(rootData); + + // Load group files so any group-only texture references are populated too. + std::string base = wmoPath; + if (base.size() > 4) base = base.substr(0, base.size() - 4); + for (uint32_t gi = 0; gi < wmo.nGroups; gi++) { + char suffix[16]; + std::snprintf(suffix, sizeof(suffix), "_%03u.wmo", gi); + auto gd = am->readFile(base + suffix); + if (!gd.empty()) pipeline::WMOLoader::loadGroup(gd, wmo, gi); + } + + std::unordered_set unique; + for (const auto& tex : wmo.textures) { + if (tex.empty()) continue; + std::string p = tex; + std::transform(p.begin(), p.end(), p.begin(), + [](unsigned char c) { return std::tolower(c); }); + unique.insert(p); + } + out.assign(unique.begin(), unique.end()); + std::sort(out.begin(), out.end()); + return out; +} + int TextureExporter::exportTexturesAsPng(pipeline::AssetManager* am, const std::vector& texturePaths, const std::string& outputDir) { diff --git a/tools/editor/texture_exporter.hpp b/tools/editor/texture_exporter.hpp index d8e44cc8..bac55148 100644 --- a/tools/editor/texture_exporter.hpp +++ b/tools/editor/texture_exporter.hpp @@ -20,6 +20,11 @@ public: static std::vector collectM2Textures(pipeline::AssetManager* am, const std::string& m2Path); + // Collect all texture paths referenced by a WMO root file. + // Includes textures used by every group (loads root + group files via `am`). + static std::vector collectWMOTextures(pipeline::AssetManager* am, + const std::string& wmoPath); + // Export all used textures as PNG to an output directory // Returns count of successfully exported textures static int exportTexturesAsPng(pipeline::AssetManager* am,