feat(editor): export NPC/M2 model textures as PNG with the zone

TextureExporter::collectUsedTextures only picked up terrain textures, so
exported zones were missing every texture referenced by NPC creature models
and placed M2 doodads. Added collectM2Textures() and unified the export
collection to include terrain + all referenced M2 paths, so the rendered
zone is fully self-contained in the PNG/WOM open formats.
This commit is contained in:
Kelsi 2026-05-06 01:11:47 -07:00
parent 732e58355a
commit 4b3375ac44
3 changed files with 55 additions and 6 deletions

View file

@ -1,6 +1,7 @@
#include "texture_exporter.hpp"
#include "pipeline/asset_manager.hpp"
#include "pipeline/blp_loader.hpp"
#include "pipeline/m2_loader.hpp"
#include "core/logger.hpp"
#include <filesystem>
#include <algorithm>
@ -20,6 +21,30 @@ std::vector<std::string> TextureExporter::collectUsedTextures(const pipeline::AD
return result;
}
std::vector<std::string> TextureExporter::collectM2Textures(pipeline::AssetManager* am,
const std::string& m2Path) {
std::vector<std::string> out;
if (!am || m2Path.empty()) return out;
auto data = am->readFile(m2Path);
if (data.empty()) return out;
auto m2 = pipeline::M2Loader::load(data);
// Skin file holds geometry but textures live in the M2 header itself.
// Even if isValid() is false (no skin loaded), the texture list is populated.
std::unordered_set<std::string> unique;
for (const auto& tex : m2.textures) {
if (tex.filename.empty()) continue;
std::string p = tex.filename;
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<std::string>& texturePaths,
const std::string& outputDir) {