diff --git a/src/mod_converter/fragment_names.py b/src/mod_converter/fragment_names.py
new file mode 100644
index 0000000..494f635
--- /dev/null
+++ b/src/mod_converter/fragment_names.py
@@ -0,0 +1,6 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+import sys
+
+print(sorted(set(open(sys.argv[1]).readlines())))
\ No newline at end of file
diff --git a/src/mod_converter/mod_converter.cpp b/src/mod_converter/mod_converter.cpp
index a48ff1b..dee3973 100644
--- a/src/mod_converter/mod_converter.cpp
+++ b/src/mod_converter/mod_converter.cpp
@@ -16,6 +16,7 @@
* along with this program. If not, see .
*/
+#include
#include
#include
#include
@@ -28,8 +29,6 @@ using namespace std;
void convert_model(string fn)
{
- printf("%s\n", fn.c_str());
-
buffer b(readFile(fn));
model m;
m.load(b);
@@ -41,44 +40,45 @@ void convert_model(string fn)
throw std::logic_error(ss.str());
}
- m.writeObj(fn + ".obj");
+ m.writeObj(fn);
}
int main(int argc, char *argv[])
try
{
-#ifdef NDEBUG
if (argc != 2)
{
- cout << "Usage:\n" << argv[0] << " model_file" << "\n";
+ printf("Usage: %s model_file \n", argv[0]);
return 1;
}
- read_model(argv[1]);
-#else
- convert_model("h:\\Games\\AIM\\data\\res0.pak.dir\\Data\\Models\\MOD_GL_M1_A_ATTACKER");
- convert_model("h:\\Games\\AIM\\data\\res0.pak.dir\\Data\\Models\\MOD_GL_M1_B_BASE");
-
- convert_model("h:\\Games\\AIM\\data\\res0.pak.dir\\Data\\Models\\MOD_BLD_BASE1");
- convert_model("h:\\Games\\AIM\\data\\res0.pak.dir\\Data\\Models\\MOD_GL_S4_SINIGR");
-
- convert_model("h:\\Games\\AIM\\data\\res0.pak.dir\\Data\\Models\\MOD_GL_FIRE");
- convert_model("h:\\Games\\AIM\\data\\res0.pak.dir\\Data\\Models\\MOD_GL_FARA");
-
- convert_model("h:\\Games\\AIM\\data\\res0.pak.dir\\Data\\Models\\MOD_FX_ANTI_MATER_GUN");
- convert_model("h:\\Games\\AIM\\data\\res0.pak.dir\\Data\\Models\\MOD_UNFL_STONE01");
- convert_model("h:\\Games\\AIM\\data\\res0.pak.dir\\Data\\Models\\MOD_L1_KUST");
- convert_model("h:\\Games\\AIM\\data\\res0.pak.dir\\Data\\Models\\MOD_L6_KUST_12");
- convert_model("h:\\Games\\AIM\\data\\res0.pak.dir\\Data\\Models\\MOD_GL_M1_A_ATTACKER_DAMAGED");
-#endif
+ convert_model(argv[1]);
return 0;
}
+catch (std::runtime_error &e)
+{
+ string error;
+ if (argv[1])
+ error += argv[1];
+ error += "\n";
+ error += "fatal error: ";
+ error += e.what();
+ error += "\n";
+ if (argv[1])
+ {
+ ofstream ofile(string(argv[1]) + ".error.txt");
+ ofile << error;
+ }
+ return 1;
+}
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;
-}
\ No newline at end of file
+}
diff --git a/src/mod_converter/mod_converter.py b/src/mod_converter/mod_converter.py
index 07f4699..ede48bb 100644
--- a/src/mod_converter/mod_converter.py
+++ b/src/mod_converter/mod_converter.py
@@ -5,6 +5,11 @@ import argparse
import os
import subprocess
+banned_ext = [
+ '.obj',
+ '.txt'
+]
+
def main():
parser = argparse.ArgumentParser(description='Batch models converter')
parser.add_argument('--dir', dest='dir', help='path to directory with models')
@@ -14,10 +19,10 @@ def main():
run(pargs.dir)
def run(dir):
- for file in os.listdir(dir):
- if os.path.isdir(file):
+ for file in sorted(os.listdir(dir)):
+ if os.path.isdir(file) or os.path.splitext(file)[1] in banned_ext:
continue
- p = subprocess.Popen(['mod_converter.exe', file])
+ p = subprocess.Popen(['mod_converter.exe', dir + '/' + file])
p.communicate()
if __name__ == '__main__':
diff --git a/src/mod_converter/model.cpp b/src/mod_converter/model.cpp
index 2624100..5eebc20 100644
--- a/src/mod_converter/model.cpp
+++ b/src/mod_converter/model.cpp
@@ -19,6 +19,7 @@
#include "model.h"
#include
+#include
#include
#include
@@ -33,8 +34,8 @@ void vertex::load(buffer &b, uint32_t flags)
READ(b, vZ);
READ(b, vY);
- if (flags & F_WIND)
- READ(b, wind);
+ if (flags & F_UNK0)
+ READ(b, unk0);
READ(b, nX);
READ(b, nZ);
@@ -65,34 +66,58 @@ std::string vertex::printTex() const
return s;
}
-void fragment::load(buffer &b)
+void block::load(buffer &b)
{
// header
READ(b, type);
- READ(b, name0);
- READ(b, name1);
- READ(b, name2);
- READ(b, name3);
- READ(b, name4);
- READ(b, unk0);
+ READ(b, name);
+ READ(b, tex_mask);
+ READ(b, tex_spec);
+ READ(b, tex3);
+ READ(b, tex4);
+ READ(b, LODs);
READ(b, unk1);
READ(b, unk2);
READ(b, unk3);
READ(b, size);
READ(b, unk4);
+ if (size == 0) // critical error!!! cannot survive
+ throw std::runtime_error("model file has bad block size field");
+
// data
- buffer data(b, size);
- READ(data, n_segments);
- segments.resize(n_segments);
- READ(data, header);
- READ(data, triangles_mult_7);
+ buffer data = buffer(b, size);
+
+ // we cannot process this type at the moment
+ if (type == BlockType::ParticleEmitter)
+ return;
+
+ READ(data, n_animations);
+ animations.resize(n_animations);
+ READ(data, material);
+
+ // unk
+ READ(data, unk_flags0);
+ READ(data, unk7);
+ READ(data, unk9);
READ(data, unk10);
+ READ(data, auto_animation);
+ READ(data, animation_cycle);
+ READ(data, unk8);
+ READ(data, unk11);
+ READ(data, unk12);
+ READ(data, triangles_mult_7);
+ //
+
+ READ(data, additional_params);
+ READ(data, n_damage_models);
+ damage_models.resize(n_damage_models);
+ READ(data, rot);
READ(data, flags);
READ(data, n_vertex);
vertices.resize(n_vertex);
READ(data, n_triangles);
- if (triangles_mult_7)
+ if (triangles_mult_7 && (flags & F_UNK0) && !unk11)
n_triangles *= 7;
triangles.resize(n_triangles);
for (auto &v : vertices)
@@ -100,76 +125,31 @@ void fragment::load(buffer &b)
for (auto &t : triangles)
READ(data, t);
- // segments
- for (auto &seg : segments)
+ // animations
+ for (auto &a : animations)
+ a.load(data);
+ for (auto &dm : damage_models)
+ dm.load(data);
+
+ if (!data.eof() && triangles_mult_7)
{
- uint32_t type;
- READ(data, 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->load(data);
+ // unknown end of block
+ auto triangles2 = triangles;
+ triangles2.resize((data.getSize() - data.getIndex()) / sizeof(triangle));
+ for (auto &t : triangles2)
+ READ(data, t);
}
-
if (!data.eof())
- throw std::logic_error("extraction error: fragment #" + std::string(name0));
+ throw std::logic_error("extraction error: block #" + std::string(name));
}
-void segment1::load(buffer &b)
+void damage_model::load(buffer &b)
{
- READ(b, name);
- READ(b, unk0);
- triangles.resize(unk0[0][0]);
- unk1.resize(unk0[0][0]);
- for (int i = 0; i < 2; i++)
- {
- for (auto &t : triangles)
- READ(b, t);
- for (auto &unk: unk1)
- READ(b, unk);
- }
-}
-
-void segment2::load(buffer &b)
-{
- READ(b, name);
- READ(b, unk0);
- triangles.resize(unk0[0][0]);
- unk1.resize(unk0[0][0]);
- unk1_1.resize(unk0[0][0]);
- for (auto &t : triangles)
- READ(b, t);
- for (auto &unk : unk1)
- READ(b, unk);
- for (auto &unk : unk1_1)
- READ(b, unk);
- while (!b.eof())
- {
- repeater r;
- r.load(b);
- unk2.push_back(r);
- }
-}
-
-void segment2::repeater::load(buffer &b)
-{
- READ(b, unk2);
- triangles2.resize(unk2);
+ READ(b, n_polygons);
+ polygons.resize(n_polygons);
READ(b, unk8);
- READ(b, unk3);
- for (auto &t : triangles2)
+ READ(b, name);
+ for (auto &t : polygons)
READ(b, t);
READ(b, unk6);
READ(b, flags);
@@ -183,60 +163,87 @@ void segment2::repeater::load(buffer &b)
READ(b, t);
}
-void segment6::load(buffer &b)
+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);
- triangles.resize(unk0[0][0]);
- for (int i = 0; i < 1; i++)
+ 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);
- char unk1[0x30]; // some 6 floats
- for (int i = 0; i < unk0[0][0]; i++)
- READ(b, unk1);
}
+ unk2.resize(n);
+ for (auto &unk : unk2)
+ READ(b, unk);
}
void model::load(buffer &b)
{
- READ(b, n_fragments);
+ READ(b, n_blocks);
+ if (n_blocks > 1000) // probably bad file
+ throw std::runtime_error("Model file has bad block count (should be <= 1000). Probably not a model.");
READ(b, header);
- fragments.resize(n_fragments);
- for (auto &f : fragments)
+ blocks.resize(n_blocks);
+ for (auto &f : blocks)
f.load(b);
}
void model::writeObj(std::string fn)
{
- ofstream o(fn);
- o << "# " << "\n";
- o << "# A.I.M. Model Converter (ver. " << version() << ")\n";
- o << "# " << "\n";
- o << "\n";
-
- if (fragments.empty())
- return;
-
- const auto &f = fragments[0];
- 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";
-
- for (int i = 0; i <= f.n_triangles - 3; i += 3)
+ for (auto &f : blocks)
{
- 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";
+ ofstream o(fn + "." + f.name + ".obj");
+ o << "#" << "\n";
+ 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";
+ o << "\n";
+
+ 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";
}
}
diff --git a/src/mod_converter/model.h b/src/mod_converter/model.h
index 3937f2f..21128b0 100644
--- a/src/mod_converter/model.h
+++ b/src/mod_converter/model.h
@@ -26,7 +26,38 @@ class buffer;
enum
{
- F_WIND = 0x4,
+ F_UNK0 = 0x4,
+};
+
+enum class AdditionalParameter : uint32_t
+{
+ None,
+ DetalizationCoefficient
+};
+
+enum class ModelRotation : uint32_t
+{
+ None,
+ Vertical,
+ Horizontal,
+ Other
+};
+
+enum class BlockType : uint32_t
+{
+ VisibleObject,
+ HelperObject,
+ BitmapAlpha,
+ BitmapGrass,
+ ParticleEmitter
+};
+
+struct Vector4
+{
+ float x;
+ float y;
+ float z;
+ float w;
};
struct vertex
@@ -35,7 +66,7 @@ struct vertex
float vZ;
float vY;
- float wind;
+ float unk0;
float nX;
float nZ;
@@ -53,76 +84,96 @@ struct vertex
typedef uint16_t triangle;
-struct unk_float3x4
+struct animation
{
- float unk[4][3];
-};
-
-struct unk_float6
-{
- float unk[6];
-};
-
-struct segment
-{
- uint32_t type;
-
- virtual void load(buffer &b) = 0;
-};
-
-struct segment1 : public segment
-{
- char name[0xC];
- uint32_t unk0[4][3];
- std::vector triangles;
- std::vector unk1;
-
- virtual void load(buffer &b);
-};
-
-struct segment2 : public segment
-{
- struct repeater
+ // +1 +0.5 -0.5 +1
+ struct segment
{
- 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 load(buffer &b);
+ struct unk_float6
+ {
+ float unk[6];
+ };
+
+ uint32_t n;
+ uint32_t unk0;
+ uint32_t unk1;
+
+ std::vector triangles;
+ std::vector unk2;
+
+ void loadHeader(buffer &b);
+ void loadData(buffer &b);
};
+ uint32_t type;
char name[0xC];
- uint32_t unk0[4][3];
- std::vector triangles;
- std::vector unk1;
- std::vector unk1_1;
- std::vector unk2;
-
+ segment segments[4];
+
virtual void load(buffer &b);
};
-struct segment6 : public segment1
+struct damage_model
{
+ uint32_t n_polygons;
+ float unk8[3];
+ char name[0x3C];
+ std::vector polygons;
+ uint8_t unk6;
+ uint32_t flags;
+ uint32_t n_vertex;
+ uint32_t n_triangles;
+ std::vector vertices;
+ std::vector triangles;
+
virtual void load(buffer &b);
};
-struct fragment
+struct material
+{
+ Vector4 ambient;
+ Vector4 diffuse;
+ Vector4 specular;
+ Vector4 emissive;
+ float power;
+};
+
+struct rotation
+{
+ ModelRotation type;
+ float speed;
+ // center of rotating axis
+ float x;
+ float y;
+ float z;
+};
+
+struct additional_parameters
+{
+ AdditionalParameter params;
+ float detalization_koef;
+};
+
+struct block
{
// header
- uint32_t type;
- char name0[0x20];
- char name1[0x20];
- char name2[0x20];
- char name3[0x20];
- char name4[0x20];
- uint32_t unk0;
+ BlockType type;
+ char name[0x20];
+ char tex_mask[0x20];
+ char tex_spec[0x20];
+ char tex3[0x20];
+ char tex4[0x20];
+ union // LODs
+ {
+ struct
+ {
+ uint8_t lod1 : 1;
+ uint8_t lod2 : 1;
+ uint8_t lod3 : 1;
+ uint8_t lod4 : 1;
+ uint8_t : 4;
+ } _;
+ uint32_t LODs;
+ };
uint32_t unk1;
uint32_t unk2[2];
uint32_t unk3;
@@ -130,27 +181,43 @@ struct fragment
uint32_t unk4[10];
// data
- uint32_t n_segments;
- char header[0x68];
+ uint32_t n_animations;
+ material material;
+
+ //unk (anim + transform settings?)
+ uint32_t unk_flags0;
+ uint32_t unk7;
+ float unk9;
+ uint32_t unk10;
+ uint32_t auto_animation;
+ float animation_cycle;
+ float unk8;
+ uint32_t unk11;
+ uint32_t unk12;
uint32_t triangles_mult_7;
- char unk10[0x20];
+ //
+
+ additional_parameters additional_params;
+ uint32_t n_damage_models;
+ rotation rot;
uint32_t flags;
uint32_t n_vertex;
uint32_t n_triangles;
std::vector vertices;
std::vector triangles;
- // segments
- std::vector segments;
+ // animations
+ std::vector animations;
+ std::vector damage_models;
void load(buffer &b);
};
struct model
{
- int n_fragments;
+ int n_blocks;
char header[0x40];
- std::vector fragments;
+ std::vector blocks;
void load(buffer &b);
void writeObj(std::string fn);