Kelsidavis-WoWee/tools/editor/texture_exporter.cpp

90 lines
3.2 KiB
C++
Raw Normal View History

#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>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
namespace wowee {
namespace editor {
std::vector<std::string> TextureExporter::collectUsedTextures(const pipeline::ADTTerrain& terrain) {
std::unordered_set<std::string> unique;
for (const auto& tex : terrain.textures)
unique.insert(tex);
std::vector<std::string> result(unique.begin(), unique.end());
std::sort(result.begin(), result.end());
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) {
namespace fs = std::filesystem;
int exported = 0;
for (const auto& texPath : texturePaths) {
auto blpImage = am->loadTexture(texPath);
if (!blpImage.isValid()) {
LOG_WARNING("Texture not found or invalid: ", texPath);
continue;
}
// Build output path: replace backslashes, change .blp to .png
std::string outPath = texPath;
std::replace(outPath.begin(), outPath.end(), '\\', '/');
// Lowercase
std::transform(outPath.begin(), outPath.end(), outPath.begin(),
[](unsigned char c) { return std::tolower(c); });
// Change extension
auto dotPos = outPath.rfind('.');
if (dotPos != std::string::npos)
outPath = outPath.substr(0, dotPos) + ".png";
std::string fullPath = outputDir + "/" + outPath;
fs::create_directories(fs::path(fullPath).parent_path());
// Write RGBA data as PNG
if (stbi_write_png(fullPath.c_str(), blpImage.width, blpImage.height, 4,
blpImage.data.data(), blpImage.width * 4)) {
exported++;
} else {
LOG_WARNING("Failed to write PNG: ", fullPath);
}
}
LOG_INFO("Exported ", exported, "/", texturePaths.size(), " textures as PNG to ", outputDir);
return exported;
}
} // namespace editor
} // namespace wowee