diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b20433..7a9cabd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,3 +13,6 @@ add_executable(script2txt ${script2txt_src}) file(GLOB mmp_extractor_src "mmp_extractor/*") add_executable(mmp_extractor ${mmp_extractor_src}) + +file(GLOB mod_converter_src "mod_converter/*") +add_executable(mod_converter ${mod_converter_src}) diff --git a/src/mod_converter/mod_converter.cpp b/src/mod_converter/mod_converter.cpp new file mode 100644 index 0000000..370e5cd --- /dev/null +++ b/src/mod_converter/mod_converter.cpp @@ -0,0 +1,72 @@ +/* + * AIM mod_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 + +using namespace std; + +#include "model.h" + +model read_model(string fn) +{ + model m; + FILE *f = fopen(fn.c_str(), "rb"); + if (!f) + return m; + try + { + m.load(f); + } + catch (std::exception &e) + { + printf("error: %s\n", fn.c_str()); + printf("%s\n", e.what()); + return m; + } + auto p = ftell(f); + fseek(f, 0, SEEK_END); + auto end = ftell(f); + if (p != ftell(f)) + { + printf("error: %s\n", fn.c_str()); + printf(" : %x != %x\n", p, end); + } + fclose(f); + return m; +} + +int main(int argc, char *argv[]) +{ +#ifdef NDEBUG + if (argc != 2) + { + cout << "Usage:\n" << argv[0] << " model_file" << "\n"; + return 1; + } + read_model(argv[1]); +#else +#endif + return 0; +} diff --git a/src/mod_converter/mod_converter.py b/src/mod_converter/mod_converter.py new file mode 100644 index 0000000..07f4699 --- /dev/null +++ b/src/mod_converter/mod_converter.py @@ -0,0 +1,24 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +import argparse +import os +import subprocess + +def main(): + parser = argparse.ArgumentParser(description='Batch models converter') + parser.add_argument('--dir', dest='dir', help='path to directory with models') + pargs = parser.parse_args() + + if pargs.dir: + run(pargs.dir) + +def run(dir): + for file in os.listdir(dir): + if os.path.isdir(file): + continue + p = subprocess.Popen(['mod_converter.exe', file]) + p.communicate() + +if __name__ == '__main__': + main() diff --git a/src/mod_converter/model.cpp b/src/mod_converter/model.cpp new file mode 100644 index 0000000..10431c5 --- /dev/null +++ b/src/mod_converter/model.cpp @@ -0,0 +1,191 @@ +/* + * AIM mod_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 "model.h" + +#include + +#define FREAD(var) fread(&var, 1, sizeof(var), f) +#define SREAD(var) s.read(&var, sizeof(var)) +#define SREAD_N(var, sz) s.read(&var, sz) + +void vertex::load(s_file &s, uint32_t flags) +{ + SREAD(vX); + SREAD(vZ); + SREAD(vY); + + if (flags & F_WIND) + SREAD(wind); + + SREAD(nX); + SREAD(nZ); + SREAD(nY); + + SREAD(t1); + SREAD(t2); +} + +void fragment::load(FILE *f) +{ + FREAD(type); + FREAD(name0); + FREAD(name1); + FREAD(name2); + FREAD(name3); + FREAD(name4); + FREAD(unk0); + FREAD(unk1); + FREAD(unk2); + FREAD(unk3); + FREAD(size); + FREAD(unk4); + data.resize(size); + data_offset = ftell(f); + fread(data.data(), 1, size, f); +} + +bool fragment::extract() +{ + s_file s(data, data_offset); + + SREAD(n_segments); + segments.resize(n_segments); + SREAD(header); + SREAD(triangles_mult_7); + SREAD(unk10); + SREAD(flags); + SREAD(n_vertex); + vertices.resize(n_vertex); + SREAD(n_triangles); + if (triangles_mult_7) + n_triangles *= 7; + triangles.resize(n_triangles); + for (auto &v : vertices) + v.load(s, flags); + for (auto &t : triangles) + SREAD(t); + + for (auto &seg : segments) + { + uint32_t type; + SREAD(type); + switch (type) + { + case 1: + seg = new segment1; + break; + case 2: + seg = new segment2; + break; + case 6: + seg = new segment6; + break; + default: + throw std::logic_error("unknown segment type " + std::to_string(type)); + } + seg->type = type; + seg->extract(s); + } + + return s.eof(); +} + +void segment1::extract(s_file &s) +{ + SREAD(name); + SREAD(unk0); + triangles.resize(unk0[0][0]); + unk1.resize(unk0[0][0]); + for (int i = 0; i < 2; i++) + { + for (auto &t : triangles) + SREAD(t); + for (auto &unk: unk1) + SREAD(unk); + } +} + +void segment2::extract(s_file &s) +{ + SREAD(name); + SREAD(unk0); + triangles.resize(unk0[0][0]); + unk1.resize(unk0[0][0]); + unk1_1.resize(unk0[0][0]); + for (auto &t : triangles) + SREAD(t); + for (auto &unk : unk1) + SREAD(unk); + for (auto &unk : unk1_1) + SREAD(unk); + while (!s.eof()) + { + repeater r; + r.extract(s); + unk2.push_back(r); + } +} + +void segment2::repeater::extract(s_file &s) +{ + SREAD(unk2); + triangles2.resize(unk2); + SREAD(unk8); + SREAD(unk3); + for (auto &t : triangles2) + SREAD(t); + SREAD(unk6); + SREAD(flags); + SREAD(n_vertex); + vertices.resize(n_vertex); + SREAD(n_triangles); + triangles.resize(n_triangles); + for (auto &v : vertices) + v.load(s, flags); + for (auto &t : triangles) + SREAD(t); +} + +void segment6::extract(s_file &s) +{ + SREAD(name); + SREAD(unk0); + triangles.resize(unk0[0][0]); + for (int i = 0; i < 1; i++) + { + for (auto &t : triangles) + SREAD(t); + char unk1[0x30]; // some 6 floats + for (int i = 0; i < unk0[0][0]; i++) + SREAD(unk1); + } +} + +void model::load(FILE *f) +{ + FREAD(n_fragments); + FREAD(header); + fragments.resize(n_fragments); + for (int i = 0; i < fragments.size(); i++) + { + fragments[i].load(f); + if (!fragments[i].extract()) + throw std::logic_error("extraction error: fragment #" + std::to_string(i)); + } +} diff --git a/src/mod_converter/model.h b/src/mod_converter/model.h new file mode 100644 index 0000000..48c736b --- /dev/null +++ b/src/mod_converter/model.h @@ -0,0 +1,188 @@ +/* + * AIM mod_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 . + */ + +#pragma once + +#include +#include + +struct s_file +{ + uint32_t index = 0; + const std::vector &buf; + uint8_t *ptr; + uint32_t data_offset; + + s_file(const std::vector &buf, uint32_t data_offset) + : buf(buf), data_offset(data_offset) + {} + uint32_t read(void *dst, uint32_t size) + { + if (index >= buf.size()) + throw std::logic_error("s_file: out of range"); + if (index + size > buf.size()) + size = buf.size() - index; + memcpy(dst, buf.data() + index, size); + skip(size); + return size; + } + void skip(int n) + { + index += n; + data_offset += n; + ptr = (uint8_t *)buf.data() + index; + } + bool eof() const + { + return index == buf.size(); + } +}; + +enum +{ + F_WIND = 0x4, +}; + +struct vertex +{ + float vX; + float vZ; + float vY; + + float wind; + + float nX; + float nZ; + float nY; + + float t1; + float t2; + + void load(s_file &s, uint32_t flags); +}; + +typedef uint16_t triangle; + +struct unk_float3x4 +{ + float unk[4][3]; +}; + +struct unk_float6 +{ + float unk[6]; +}; + +struct segment +{ + uint32_t type; + + virtual void extract(s_file &s) = 0; +}; + +struct segment1 : public segment +{ + char name[0xC]; + uint32_t unk0[4][3]; + std::vector triangles; + std::vector unk1; + + virtual void extract(s_file &s); +}; + +struct segment2 : public segment +{ + struct repeater + { + uint32_t unk2; + float unk8[3]; + char unk3[0x3C]; + std::vector triangles2; + uint8_t unk6; + uint32_t flags; + uint32_t n_vertex; + uint32_t n_triangles; + std::vector vertices; + std::vector triangles; + + virtual void extract(s_file &s); + }; + + char name[0xC]; + uint32_t unk0[4][3]; + std::vector triangles; + std::vector unk1; + std::vector unk1_1; + std::vector unk2; + + virtual void extract(s_file &s); +}; + +struct segment6 : public segment1 +{ + virtual void extract(s_file &s); +}; + +struct fragment +{ + // main header + uint32_t type; + char name0[0x20]; + char name1[0x20]; + char name2[0x20]; + char name3[0x20]; + char name4[0x20]; + uint32_t unk0; + uint32_t unk1; + uint32_t unk2[2]; + uint32_t unk3; + uint32_t size; + uint32_t unk4[10]; + + // data buffer + std::vector data; + + // main data + uint32_t n_segments; + char header[0x68]; + uint32_t triangles_mult_7; + char unk10[0x20]; + uint32_t flags; + uint32_t n_vertex; + uint32_t n_triangles; + std::vector vertices; + std::vector triangles; + + // segments + std::vector segments; + + // internal vars + uint32_t data_offset; + + void load(FILE *f); + bool extract(); +}; + +struct model +{ + int n_fragments; + char header[0x40]; + std::vector fragments; + + void load(FILE *f); +};