Fix a lot of bugs. Add animations reading.

This commit is contained in:
lzwdgc 2015-06-30 21:02:40 +03:00
parent fb6aa75845
commit e511c01359
5 changed files with 291 additions and 206 deletions

View file

@ -0,0 +1,6 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
print(sorted(set(open(sys.argv[1]).readlines())))

View file

@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fstream>
#include <sstream>
#include <stdio.h>
#include <stdint.h>
@ -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;
}

View file

@ -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__':

View file

@ -19,6 +19,7 @@
#include "model.h"
#include <fstream>
#include <set>
#include <string>
#include <common.h>
@ -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)
{
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);
}
// animations
for (auto &a : animations)
a.load(data);
for (auto &dm : damage_models)
dm.load(data);
if (!data.eof())
throw std::logic_error("extraction error: fragment #" + std::string(name0));
}
void segment1::load(buffer &b)
if (!data.eof() && triangles_mult_7)
{
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, unk8);
READ(b, unk3);
// 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: 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);
@ -183,42 +163,64 @@ 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);
READ(b, unk0);
triangles.resize(unk0[0][0]);
for (int i = 0; i < 1; i++)
for (auto &s : segments)
s.loadHeader(b);
if (segments[0].n)
for (auto &s : segments)
s.loadData(b);
}
void animation::segment::loadHeader(buffer &b)
{
for (auto &t : triangles)
READ(b, t);
char unk1[0x30]; // some 6 floats
for (int i = 0; i < unk0[0][0]; i++)
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_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);
for (auto &f : blocks)
{
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";
if (fragments.empty())
return;
const auto &f = fragments[0];
for (auto &v : f.vertices)
o << v.printVertex() << "\n";
o << "\n";
@ -229,6 +231,7 @@ void model::writeObj(std::string fn)
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);
@ -239,4 +242,8 @@ void model::writeObj(std::string fn)
z += "/" + z;
o << "f " << x << " " << y << " " << z << "\n";
}
o << "\n";
o << "\n";
}
}

View file

@ -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,41 +84,40 @@ struct vertex
typedef uint16_t triangle;
struct unk_float3x4
struct animation
{
// +1 +0.5 -0.5 +1
struct segment
{
float unk[4][3];
};
struct unk_float6
{
float unk[6];
};
struct segment
{
uint32_t type;
uint32_t n;
uint32_t unk0;
uint32_t unk1;
virtual void load(buffer &b) = 0;
std::vector<triangle> triangles;
std::vector<unk_float6> unk2;
void loadHeader(buffer &b);
void loadData(buffer &b);
};
struct segment1 : public segment
{
uint32_t type;
char name[0xC];
uint32_t unk0[4][3];
std::vector<triangle> triangles;
std::vector<unk_float3x4> unk1;
segment segments[4];
virtual void load(buffer &b);
};
struct segment2 : public segment
struct damage_model
{
struct repeater
{
uint32_t unk2;
uint32_t n_polygons;
float unk8[3];
char unk3[0x3C];
std::vector<uint16_t> triangles2;
char name[0x3C];
std::vector<uint16_t> polygons;
uint8_t unk6;
uint32_t flags;
uint32_t n_vertex;
@ -98,31 +128,52 @@ struct segment2 : public segment
virtual void load(buffer &b);
};
char name[0xC];
uint32_t unk0[4][3];
std::vector<triangle> triangles;
std::vector<unk_float6> unk1;
std::vector<unk_float6> unk1_1;
std::vector<repeater> unk2;
virtual void load(buffer &b);
};
struct segment6 : public segment1
struct material
{
virtual void load(buffer &b);
Vector4 ambient;
Vector4 diffuse;
Vector4 specular;
Vector4 emissive;
float power;
};
struct fragment
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<vertex> vertices;
std::vector<uint16_t> triangles;
// segments
std::vector<segment *> segments;
// animations
std::vector<animation> animations;
std::vector<damage_model> damage_models;
void load(buffer &b);
};
struct model
{
int n_fragments;
int n_blocks;
char header[0x40];
std::vector<fragment> fragments;
std::vector<block> blocks;
void load(buffer &b);
void writeObj(std::string fn);