From 9d504e0592479db4ef906e1329dd94cebf52b4a2 Mon Sep 17 00:00:00 2001 From: lzwdgc Date: Mon, 22 Apr 2024 02:21:49 +0300 Subject: [PATCH] [tm_converter2] Initial commit. It uses external dxt5 decompressor which one-off of previous version. Probably rounding error in our v1. --- src/tm_converter2/tm_converter2.cpp | 192 ++++++++++++++++++++++++++++ sw.cpp | 4 + 2 files changed, 196 insertions(+) create mode 100644 src/tm_converter2/tm_converter2.cpp diff --git a/src/tm_converter2/tm_converter2.cpp b/src/tm_converter2/tm_converter2.cpp new file mode 100644 index 0000000..9a77a2c --- /dev/null +++ b/src/tm_converter2/tm_converter2.cpp @@ -0,0 +1,192 @@ +/* + * AIM tm_converter + * Copyright (C) 2015 lzwdgc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +/* +aim icons +TEX_KT_ICONS.TM +64 x 32 +16 icon in a column +*/ + +// TODO: add dxt5 compressor from stb libs (stb_dxt5) +// see org.sw.demo.stb.all + +using namespace std; + +#pragma pack(push, 1) +struct tm_file { + int32_t width; + int32_t height; + // https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dformat +#ifdef _WIN32 + D3DFORMAT d3dformat; +#else + uint32_t d3dformat; +#endif + // see for some infos https://learn.microsoft.com/en-us/previous-versions/ms889290(v=msdn.10) + // IDirect3DDevice8::CreateTexture + // or not? or number of helper images or total imgs + uint32_t levels; + // or not only dxt5? maybe enum? + uint32_t dxt5_compression; + // TEX_NIGHT13.TM has 1 here + // TEX_kt_icons.TM has 8 here + // maybe levels? + // number of anims? icon variants? + uint32_t unk0; + uint8_t unkX[0x4C-0x18]; +}; +#pragma pack(pop) + +void convert(const path &fn) +{ + primitives::templates2::mmap_file f{fn}; + stream s{f}; + tm_file tm = s; + + // format check + switch (tm.d3dformat) { + case D3DFMT_A8R8G8B8: + break; + case D3DFMT_X8R8G8B8: + break; + default: + SW_UNIMPLEMENTED; + } + + // compression check + switch (tm.dxt5_compression) { + case 0: + break; + case 1: + break; + default: + SW_UNIMPLEMENTED; + } + + auto save = [&](auto &&sub) { + cv::Mat m(tm.width, tm.height, CV_8UC4); + if (tm.dxt5_compression) { + // this have some one off results + // probaby we did different rounding in current (v1) impl + BlockDecompressImageDXT5(tm.width, tm.height, s.p, (unsigned long *)m.data); + s.skip(tm.width * tm.height); + // only for dxt5 + m.forEach([](auto &v, auto *pos) { + // ARGB -> BGRA (big endian) + // but in bytes (little endian) + // 0xBGRA -> 0xABGR + auto &val = *(uint32_t *)&v; + val = std::rotr(val, 8); + }); + if (tm.d3dformat == D3DFMT_X8R8G8B8) { + // and shrink if possible + cv::cvtColor(m, m, cv::COLOR_BGRA2BGR); + } + } + else + { + // 'simple' files consists of: + // 1. 'normal' image (bitmap) + // 2. some kind of mask? + // 3. rest? levels? + // but every tm has multiple levels or so + + int size = tm.width * tm.height * 2; + auto dst = m.data; + for (int i = 0; i < size; ++i) { + uint8_t c = s; + uint8_t lo = c & 0x0F; + uint8_t hi = (c & 0xF0) >> 4; + *dst++ = (lo << 4) | lo; + *dst++ = (hi << 4) | hi; + } + } + // opencv can't save to tga directly + cv::imwrite((path(fn) += sub + ".bmp"s).string(), m); + }; + save(""); + // not sure how to parse rest, probably dx8 generated texture levels + // and we dont need them + return; + + if (!tm.dxt5_compression) { + save("_mask"); // what is it? + } + for (int i = 0; i < tm.unk0; ++i) { + // obviosly small + tm.width /= 2; + tm.height /= 2; + save(std::format("_small{}", i + 1)); + if (!tm.dxt5_compression) { + save(std::format("_small{}_mask", i + 1)); + } + } + + if (s.p - f.p != f.sz) { + int a = 5; + a++; + SW_UNIMPLEMENTED; + } +} + +int main(int argc, char *argv[]) +{ + cl::list list(cl::Positional, cl::desc(""), cl::Required, cl::OneOrMore); + + cl::ParseCommandLineOptions(argc, argv); + + for (auto &&p : list) { + if (fs::is_regular_file(p)) { + convert(p); + } else if (fs::is_directory(p)) { + auto files = enumerate_files_like(p, ".*\\.TM", false); + for (auto &f : files) { + std::cout << "processing: " << to_printable_string(f) << "\n"; + convert(f); + } + } else { + throw std::runtime_error("Bad fs object"); + } + } + return 0; +} diff --git a/sw.cpp b/sw.cpp index 3a621ed..4e71a46 100644 --- a/sw.cpp +++ b/sw.cpp @@ -57,6 +57,10 @@ void build(Solution &s) add_exe_with_common("script2txt"); add_exe_with_common("txt2script"); add_exe_with_common("tm_converter"); + add_exe_with_common("tm_converter2") += + "org.sw.demo.BenjaminDobell.s3tc_dxt_decompression-master"_dep, + "org.sw.demo.intel.opencv.highgui"_dep + ; add_exe("name_generator"); add_exe_with_common("save_loader"); add_exe_with_common("bms_converter");