From 75a4f2b0d7a849a3d4ed7026441fea53421073e9 Mon Sep 17 00:00:00 2001 From: lzwdgc Date: Wed, 1 Jul 2015 02:03:38 +0300 Subject: [PATCH] Add tm converter (into tga). --- src/CMakeLists.txt | 4 + src/common/common.cpp | 63 ++++++++- src/common/common.h | 26 +++- src/mod_converter/mod_converter.cpp | 2 +- src/mod_converter/model.cpp | 210 +++++++++++++++++----------- src/mod_converter/model.h | 4 + src/tm_converter/tm_converter.cpp | 96 +++++++++++++ 7 files changed, 314 insertions(+), 91 deletions(-) create mode 100644 src/tm_converter/tm_converter.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7dbf224..344dd2f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,4 +21,8 @@ file(GLOB mod_converter_src "mod_converter/*") add_executable(mod_converter ${mod_converter_src}) target_link_libraries(mod_converter common) +file(GLOB tm_converter_src "tm_converter/*") +add_executable(tm_converter ${tm_converter_src}) +target_link_libraries(tm_converter common) + add_subdirectory(common) \ No newline at end of file diff --git a/src/common/common.cpp b/src/common/common.cpp index 9cbeb9a..82be229 100644 --- a/src/common/common.cpp +++ b/src/common/common.cpp @@ -50,15 +50,31 @@ std::vector readFile(const std::string &fn) return buf; } +void writeFile(const std::string &fn, const std::vector &data) +{ + FILE *f = fopen(fn.c_str(), "wb"); + if (!f) + throw std::runtime_error("Cannot open file " + fn); + fwrite(data.data(), 1, data.size(), f); + fclose(f); +} + buffer::buffer() { } +buffer::buffer(size_t size) + : buf(new std::vector(size)) +{ + this->size = buf->size(); + skip(0); +} + buffer::buffer(const std::vector &buf, uint32_t data_offset) : buf(new std::vector(buf)), data_offset(data_offset) { skip(0); - size = buf.size(); + size = this->buf->size(); } buffer::buffer(buffer &rhs, uint32_t size) @@ -80,7 +96,7 @@ buffer::buffer(buffer &rhs, uint32_t size, uint32_t offset) this->size = index + size; } -uint32_t buffer::read(void *dst, uint32_t size, bool nothrow) +uint32_t buffer::read(void *dst, uint32_t size, bool nothrow) const { if (!buf) throw std::logic_error("buffer: not initialized"); @@ -91,13 +107,40 @@ uint32_t buffer::read(void *dst, uint32_t size, bool nothrow) throw std::logic_error("buffer: out of range"); } if (index + size > this->size) + { + if (!nothrow) + throw std::logic_error("buffer: too much data"); size = this->size - index; + } memcpy(dst, buf->data() + index, size); skip(size); return size; } -void buffer::skip(int n) +uint32_t buffer::write(const void *src, uint32_t size, bool nothrow) +{ + if (!buf) + { + buf = std::make_shared>(size); + this->size = buf->size(); + } + if (index > this->size) + { + if (nothrow) + return 0; + throw std::logic_error("buffer: out of range"); + } + if (index + size > this->size) + { + buf->resize(index + size); + this->size = buf->size(); + } + memcpy((uint8_t *)buf->data() + index, src, size); + skip(size); + return size; +} + +void buffer::skip(int n) const { if (!buf) throw std::logic_error("buffer: not initialized"); @@ -106,6 +149,13 @@ void buffer::skip(int n) ptr = (uint8_t *)buf->data() + index; } +void buffer::reset() const +{ + index = 0; + data_offset = 0; + ptr = (uint8_t *)buf->data(); +} + bool buffer::check(int index) const { return this->index == index; @@ -125,3 +175,10 @@ uint32_t buffer::getSize() const { return this->size; } + +const std::vector &buffer::getBuf() const +{ + if (!buf) + throw std::logic_error("buffer: not initialized"); + return *buf; +} diff --git a/src/common/common.h b/src/common/common.h index 4545639..1a8f4de 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -26,30 +26,42 @@ #define READ(b, var) b.read(&var, sizeof(var)) #define READ_NOTHROW(b, var) b.read(&var, sizeof(var), true) #define READ_N(b, var, sz) b.read(&var, sz) +#define WRITE(b, var) b.write(&var, sizeof(var)) std::string version(); std::vector readFile(const std::string &fn); +void writeFile(const std::string &fn, const std::vector &data); class buffer { public: buffer(); + buffer(size_t size); buffer(const std::vector &buf, uint32_t data_offset = 0); buffer(buffer &rhs, uint32_t size); buffer(buffer &rhs, uint32_t size, uint32_t offset); - uint32_t read(void *dst, uint32_t size, bool nothrow = false); - void skip(int n); + uint32_t read(void *dst, uint32_t size, bool nothrow = false) const; + uint32_t write(const void *src, uint32_t size, bool nothrow = false); + template + uint32_t write(const T &src, bool nothrow = false) + { + return write(&src, sizeof(src), nothrow); + } + + void skip(int n) const; bool eof() const; bool check(int index) const; + void reset() const; uint32_t getIndex() const; uint32_t getSize() const; + const std::vector &getBuf() const; private: - std::shared_ptr> buf; - uint32_t index = 0; - uint8_t *ptr = 0; - uint32_t data_offset = 0; - uint32_t size = 0; + std::shared_ptr> buf; + mutable uint32_t index = 0; + mutable uint8_t *ptr = 0; + mutable uint32_t data_offset = 0; + mutable uint32_t size = 0; }; diff --git a/src/mod_converter/mod_converter.cpp b/src/mod_converter/mod_converter.cpp index dee3973..2458cbd 100644 --- a/src/mod_converter/mod_converter.cpp +++ b/src/mod_converter/mod_converter.cpp @@ -48,7 +48,7 @@ try { if (argc != 2) { - printf("Usage: %s model_file \n", argv[0]); + printf("Usage: %s model_file\n", argv[0]); return 1; } convert_model(argv[1]); diff --git a/src/mod_converter/model.cpp b/src/mod_converter/model.cpp index 5eebc20..ac8cbbb 100644 --- a/src/mod_converter/model.cpp +++ b/src/mod_converter/model.cpp @@ -18,6 +18,7 @@ #include "model.h" +#include #include #include #include @@ -28,6 +29,13 @@ using namespace std; std::string version(); +std::string Vector4::print() const +{ + string s; + s += to_string(x) + " " + to_string(y) + " " + to_string(z); + return s; +} + void vertex::load(buffer &b, uint32_t flags) { READ(b, vX); @@ -66,6 +74,116 @@ std::string vertex::printTex() const return s; } +void damage_model::load(buffer &b) +{ + READ(b, n_polygons); + polygons.resize(n_polygons); + READ(b, unk8); + READ(b, name); + for (auto &t : polygons) + READ(b, t); + READ(b, unk6); + READ(b, flags); + READ(b, n_vertex); + vertices.resize(n_vertex); + READ(b, n_triangles); + triangles.resize(n_triangles); + for (auto &v : vertices) + v.load(b, flags); + for (auto &t : triangles) + READ(b, t); +} + +void animation::load(buffer &b) +{ + READ(b, type); + READ(b, name); + for (auto &s : segments) + s.loadHeader(b); + if (segments[0].n) + for (auto &s : segments) + s.loadData(b); +} + +void animation::segment::loadHeader(buffer &b) +{ + READ(b, n); + READ(b, unk0); + READ(b, unk1); +} + +void animation::segment::loadData(buffer &b) +{ + if (n == 0) + return; + if (unk0) + { + triangles.resize(n); + for (auto &t : triangles) + READ(b, t); + } + unk2.resize(n); + for (auto &unk : unk2) + READ(b, unk); +} + +std::string block::printMtl(const std::string &mtl_name) const +{ + string s; + s += "newmtl " + mtl_name + "\n"; + s += "\n"; + s += "Ka " + material.ambient.print() + "\n"; + s += "Kd " + material.diffuse.print() + "\n"; + s += "Ks " + material.specular.print() + "\n"; + s += " Ns " + to_string(material.power) + "\n"; + // d 1.0 + // illum + s += "\n"; + s += "map_Ka " + string(tex_mask) + ".tga\n"; + s += "map_Kd " + string(tex_mask) + ".tga\n"; + s += "map_Ks " + string(tex_spec) + ".tga\n"; + s += "map_Ns " + string(tex_spec) + ".tga\n"; + s += "\n"; + return s; +} + +std::string block::printObj() const +{ + string s; + s += string("o ") + name + "\n"; + s += string("g ") + name + "\n"; + s += "s off\n"; + s += "\n"; + s += "usemtl main\n"; + s += "\n"; + + for (auto &v : vertices) + s += v.printVertex() + "\n"; + s += "\n"; + for (auto &v : vertices) + s += v.printNormal() + "\n"; + s += "\n"; + for (auto &v : vertices) + s += v.printTex() + "\n"; + s += "\n"; + + if (n_triangles) + for (int i = 0; i <= n_triangles - 3; i += 3) + { + auto x = to_string(triangles[i] + 1); + auto y = to_string(triangles[i + 2] + 1); + auto z = to_string(triangles[i + 1] + 1); + x += "/" + x; + y += "/" + y; + z += "/" + z; + s += "f " + x + " " + y + " " + z + "\n"; + } + + s += "\n"; + s += "\n"; + return s; +} + void block::load(buffer &b) { // header @@ -143,59 +261,6 @@ void block::load(buffer &b) throw std::logic_error("extraction error: block #" + std::string(name)); } -void damage_model::load(buffer &b) -{ - READ(b, n_polygons); - polygons.resize(n_polygons); - READ(b, unk8); - READ(b, name); - for (auto &t : polygons) - READ(b, t); - READ(b, unk6); - READ(b, flags); - READ(b, n_vertex); - vertices.resize(n_vertex); - READ(b, n_triangles); - triangles.resize(n_triangles); - for (auto &v : vertices) - v.load(b, flags); - for (auto &t : triangles) - READ(b, t); -} - -void animation::load(buffer &b) -{ - READ(b, type); - READ(b, name); - for (auto &s : segments) - s.loadHeader(b); - if (segments[0].n) - for (auto &s : segments) - s.loadData(b); -} - -void animation::segment::loadHeader(buffer &b) -{ - READ(b, n); - READ(b, unk0); - READ(b, unk1); -} - -void animation::segment::loadData(buffer &b) -{ - if (n == 0) - return; - if (unk0) - { - triangles.resize(n); - for (auto &t : triangles) - READ(b, t); - } - unk2.resize(n); - for (auto &unk : unk2) - READ(b, unk); -} - void model::load(buffer &b) { READ(b, n_blocks); @@ -216,34 +281,19 @@ void model::writeObj(std::string fn) o << "# A.I.M. Model Converter (ver. " << version() << ")\n"; o << "#" << "\n"; o << "\n"; - o << "o " << f.name << "\n"; - o << "g " << f.name << "\n"; - o << "s off\n"; + int p1 = fn.rfind("\\"); + int p2 = fn.rfind("/"); + auto mtl = fn.substr(std::max(p1, p2) + 1); + mtl += string(".") + f.name; + o << "mtllib " << mtl << ".mtl\n"; o << "\n"; + o << f.printObj(); - for (auto &v : f.vertices) - o << v.printVertex() << "\n"; - o << "\n"; - for (auto &v : f.vertices) - o << v.printNormal() << "\n"; - o << "\n"; - for (auto &v : f.vertices) - o << v.printTex() << "\n"; - o << "\n"; - - if (f.n_triangles) - for (int i = 0; i <= f.n_triangles - 3; i += 3) - { - auto x = to_string(f.triangles[i] + 1); - auto y = to_string(f.triangles[i + 2] + 1); - auto z = to_string(f.triangles[i + 1] + 1); - x += "/" + x; - y += "/" + y; - z += "/" + z; - o << "f " << x << " " << y << " " << z << "\n"; - } - - o << "\n"; - o << "\n"; + ofstream m(fn + "." + f.name + ".mtl"); + m << "#" << "\n"; + m << "# A.I.M. Model Converter (ver. " << version() << ")\n"; + m << "#" << "\n"; + m << "\n"; + m << f.printMtl(mtl); } } diff --git a/src/mod_converter/model.h b/src/mod_converter/model.h index 21128b0..e629176 100644 --- a/src/mod_converter/model.h +++ b/src/mod_converter/model.h @@ -58,6 +58,8 @@ struct Vector4 float y; float z; float w; + + std::string print() const; }; struct vertex @@ -211,6 +213,8 @@ struct block std::vector damage_models; void load(buffer &b); + std::string printMtl(const std::string &mtl_name) const; + std::string printObj() const; }; struct model diff --git a/src/tm_converter/tm_converter.cpp b/src/tm_converter/tm_converter.cpp new file mode 100644 index 0000000..5788065 --- /dev/null +++ b/src/tm_converter/tm_converter.cpp @@ -0,0 +1,96 @@ +/* + * 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 + +using namespace std; + +void tm2tga(string fn) +{ + int width, height; + + buffer src(readFile(fn)); + READ(src, width); + READ(src, height); + src.reset(); + src.skip(0x4C); + + // http://paulbourke.net/dataformats/tga/ + buffer dst; + dst.write(uint8_t(0xE)); // idlength (comment length) + dst.write(uint8_t(0)); // colourmaptype + dst.write(uint8_t(2)); // datatypecode + dst.write(uint16_t(0)); // colourmaporigin + dst.write(uint16_t(0)); // colourmaplength + dst.write(uint8_t(0)); // colourmapdepth + dst.write(uint16_t(0)); // x_origin + dst.write(uint16_t(0)); // y_origin + dst.write(uint16_t(width)); // width + dst.write(uint16_t(height)); // height + dst.write(uint8_t(32)); // bitsperpixel + dst.write(uint8_t(0x28)); // imagedescriptor + + const char *label = "AIMTMConverter"; + dst.write(label, strlen(label), false); + + int size = width * height * 2; + for (int i = 0; i < size; i++) + { + uint8_t c; + READ(src, c); + uint8_t lo = c & 0x0F; + uint8_t hi = (c & 0xF0) >> 4; + dst.write(uint8_t((lo << 4) | lo)); + dst.write(uint8_t((hi << 4) | hi)); + } + + transform(fn.begin(), fn.end(), fn.begin(), tolower); + fn = fn.substr(0, fn.rfind(".tm")) + ".tga"; + writeFile(fn, dst.getBuf()); +} + +int main(int argc, char *argv[]) +try +{ + if (argc != 2) + { + printf("Usage: %s file.tm\n", argv[0]); + return 1; + } + tm2tga(argv[1]); + return 0; +} +catch (std::exception &e) +{ + printf("%s\n", argv[1]); + printf("error: %s\n", e.what()); + return 1; +} +catch (...) +{ + printf("%s\n", argv[1]); + printf("error: unknown exception\n"); + return 1; +}