Add more scripts.

This commit is contained in:
lzwdgc 2015-07-05 02:18:44 +03:00
parent d76c25bd7a
commit a5989276a7
14 changed files with 277 additions and 111 deletions

@ -1 +1 @@
Subproject commit 2d884b843a057c25159833226a4e2c73443d91eb Subproject commit a2768a05d85958cb52de967a1ef2ea20d9bba309

View file

@ -40,7 +40,10 @@ std::vector<uint8_t> readFile(const std::string &fn)
{ {
FILE *f = fopen(fn.c_str(), "rb"); FILE *f = fopen(fn.c_str(), "rb");
if (!f) if (!f)
{
printf("Cannot open file %s\n", fn.c_str());
throw std::runtime_error("Cannot open file " + fn); throw std::runtime_error("Cannot open file " + fn);
}
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
auto sz = ftell(f); auto sz = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
@ -64,121 +67,141 @@ buffer::buffer()
} }
buffer::buffer(size_t size) buffer::buffer(size_t size)
: buf(new std::vector<uint8_t>(size)) : buf_(new std::vector<uint8_t>(size))
{ {
this->size = buf->size(); size_ = buf_->size();
skip(0); skip(0);
} }
buffer::buffer(const std::vector<uint8_t> &buf, uint32_t data_offset) buffer::buffer(const std::vector<uint8_t> &buf, uint32_t data_offset)
: buf(new std::vector<uint8_t>(buf)), data_offset(data_offset) : buf_(new std::vector<uint8_t>(buf)), data_offset(data_offset)
{ {
skip(0); skip(0);
size = this->buf->size(); size_ = buf_->size();
} }
buffer::buffer(buffer &rhs, uint32_t size) buffer::buffer(buffer &rhs, uint32_t size)
: buf(rhs.buf) : buf_(rhs.buf_)
{ {
index = rhs.index; index_ = rhs.index_;
data_offset = rhs.data_offset; data_offset = rhs.data_offset;
ptr = rhs.ptr; ptr = rhs.ptr;
this->size = index + size; size_ = index_ + size;
rhs.skip(size); rhs.skip(size);
} }
buffer::buffer(buffer &rhs, uint32_t size, uint32_t offset) buffer::buffer(buffer &rhs, uint32_t size, uint32_t offset)
: buf(rhs.buf) : buf_(rhs.buf_)
{ {
index = offset; index_ = offset;
data_offset = offset; data_offset = offset;
ptr = (uint8_t *)buf->data() + index; ptr = (uint8_t *)buf_->data() + index_;
this->size = index + size; size_ = index_ + size;
} }
uint32_t buffer::read(void *dst, uint32_t size, bool nothrow) const uint32_t buffer::read(void *dst, uint32_t size, bool nothrow) const
{ {
if (!buf) if (!buf_)
throw std::logic_error("buffer: not initialized"); throw std::logic_error("buffer: not initialized");
if (index >= this->size) if (index_ >= size_)
{ {
if (nothrow) if (nothrow)
return 0; return 0;
throw std::logic_error("buffer: out of range"); throw std::logic_error("buffer: out of range");
} }
if (index + size > this->size) if (index_ + size > size_)
{ {
if (!nothrow) if (!nothrow)
throw std::logic_error("buffer: too much data"); throw std::logic_error("buffer: too much data");
size = this->size - index; size = size_ - index_;
} }
memcpy(dst, buf->data() + index, size); memcpy(dst, buf_->data() + index_, size);
skip(size); skip(size);
return size; return size;
} }
uint32_t buffer::readfrom(void *dst, uint32_t size, uint32_t offset, bool nothrow) const
{
if (!buf_)
throw std::logic_error("buffer: not initialized");
if (offset + size > size_)
{
if (!nothrow)
throw std::logic_error("buffer: too much data");
size = size_ - offset;
}
memcpy(dst, buf_->data() + offset, size);
return size;
}
uint32_t buffer::write(const void *src, uint32_t size, bool nothrow) uint32_t buffer::write(const void *src, uint32_t size, bool nothrow)
{ {
if (!buf) if (!buf_)
{ {
buf = std::make_shared<std::vector<uint8_t>>(size); buf_ = std::make_shared<std::vector<uint8_t>>(size);
this->size = buf->size(); size_ = buf_->size();
} }
if (index > this->size) if (index_ > size_)
{ {
if (nothrow) if (nothrow)
return 0; return 0;
throw std::logic_error("buffer: out of range"); throw std::logic_error("buffer: out of range");
} }
if (index + size > this->size) if (index_ + size > size_)
{ {
buf->resize(index + size); buf_->resize(index_ + size);
this->size = buf->size(); size_ = buf_->size();
} }
memcpy((uint8_t *)buf->data() + index, src, size); memcpy((uint8_t *)buf_->data() + index_, src, size);
skip(size); skip(size);
return size; return size;
} }
void buffer::skip(int n) const void buffer::skip(int n) const
{ {
if (!buf) if (!buf_)
throw std::logic_error("buffer: not initialized"); throw std::logic_error("buffer: not initialized");
index += n; index_ += n;
data_offset += n; data_offset += n;
ptr = (uint8_t *)buf->data() + index; ptr = (uint8_t *)buf_->data() + index_;
} }
void buffer::reset() const void buffer::reset() const
{ {
index = 0; index_ = 0;
data_offset = 0; data_offset = 0;
ptr = (uint8_t *)buf->data(); ptr = (uint8_t *)buf_->data();
}
void buffer::seek(uint32_t size) const
{
reset();
skip(size);
} }
bool buffer::check(int index) const bool buffer::check(int index) const
{ {
return this->index == index; return index_ == index;
} }
bool buffer::eof() const bool buffer::eof() const
{ {
return check(this->size); return check(size_);
} }
uint32_t buffer::getIndex() const uint32_t buffer::index() const
{ {
return index; return index_;
} }
uint32_t buffer::getSize() const uint32_t buffer::size() const
{ {
return this->size; return size_;
} }
const std::vector<uint8_t> &buffer::getBuf() const const std::vector<uint8_t> &buffer::buf() const
{ {
if (!buf) if (!buf_)
throw std::logic_error("buffer: not initialized"); throw std::logic_error("buffer: not initialized");
return *buf; return *buf_;
} }

View file

@ -42,26 +42,28 @@ public:
buffer(buffer &rhs, uint32_t size, uint32_t offset); buffer(buffer &rhs, uint32_t size, uint32_t offset);
uint32_t read(void *dst, uint32_t size, bool nothrow = false) const; uint32_t read(void *dst, uint32_t size, bool nothrow = false) const;
uint32_t readfrom(void *dst, uint32_t size, uint32_t offset, bool nothrow = false) const;
uint32_t write(const void *src, uint32_t size, bool nothrow = false); uint32_t write(const void *src, uint32_t size, bool nothrow = false);
template <typename T> template <typename T>
uint32_t write(const T &src, bool nothrow = false) uint32_t write(const T &src)
{ {
return write(&src, sizeof(src), nothrow); return write(&src, sizeof(src));
} }
void seek(uint32_t size) const;
void skip(int n) const; void skip(int n) const;
bool eof() const; bool eof() const;
bool check(int index) const; bool check(int index) const;
void reset() const; void reset() const;
uint32_t getIndex() const; uint32_t index() const;
uint32_t getSize() const; uint32_t size() const;
const std::vector<uint8_t> &getBuf() const; const std::vector<uint8_t> &buf() const;
private: private:
std::shared_ptr<std::vector<uint8_t>> buf; std::shared_ptr<std::vector<uint8_t>> buf_;
mutable uint32_t index = 0; mutable uint32_t index_ = 0;
mutable uint8_t *ptr = 0; mutable uint8_t *ptr = 0;
mutable uint32_t data_offset = 0; mutable uint32_t data_offset = 0;
mutable uint32_t size = 0; mutable uint32_t size_ = 0;
}; };

View file

@ -0,0 +1 @@
python mod_converter.py --dir "h:\\Games\\Epic Games\\Projects\\AIM\\models1\\"

View file

@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <algorithm>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <stdio.h> #include <stdio.h>
@ -27,6 +28,48 @@
using namespace std; using namespace std;
// options
bool silent = false;
bool printMaxPolygonBlock = false;
string filename;
bool parse_cmd(int argc, char *argv[]);
void print(const block &b, const std::string &fn)
{
if (b.type == BlockType::ParticleEmitter)
return;
auto obj_fn = fn;
if (!printMaxPolygonBlock)
obj_fn += string(".") + b.name;
obj_fn += ".obj";
ofstream o(obj_fn);
o << "#" << "\n";
o << "# A.I.M. Model Converter (ver. " << version() << ")\n";
o << "#" << "\n";
o << "\n";
int p1 = fn.rfind("\\");
int p2 = fn.rfind("/");
auto mtl = fn.substr(std::max(p1, p2) + 1);
if (!printMaxPolygonBlock)
mtl += string(".") + b.name;
o << "mtllib " << mtl << ".mtl\n";
o << "\n";
o << b.printObj(mtl);
auto mtl_fn = fn;
if (!printMaxPolygonBlock)
mtl_fn += string(".") + b.name;
mtl_fn += ".mtl";
ofstream m(mtl_fn);
m << "#" << "\n";
m << "# A.I.M. Model Converter (ver. " << version() << ")\n";
m << "#" << "\n";
m << "\n";
m << b.printMtl(mtl);
}
void convert_model(string fn) void convert_model(string fn)
{ {
buffer b(readFile(fn)); buffer b(readFile(fn));
@ -36,26 +79,47 @@ void convert_model(string fn)
if (!b.eof()) if (!b.eof())
{ {
stringstream ss; stringstream ss;
ss << hex << b.getIndex() << " != " << hex << b.getSize(); ss << hex << b.index() << " != " << hex << b.size();
throw std::logic_error(ss.str()); throw std::logic_error(ss.str());
} }
m.writeObj(fn); // write obj and mtl
if (printMaxPolygonBlock)
{
int max = 0;
int maxBlock = -1;
for (int i = 0; i < m.blocks.size(); i++)
{
if (m.blocks[i].n_vertex > max)
{
max = m.blocks[i].n_vertex;
maxBlock = i;
}
}
print(m.blocks[maxBlock], filename);
}
else
{
for (auto &f : m.blocks)
print(f, filename);
}
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
try try
{ {
if (argc != 2) if (argc < 2 || !parse_cmd(argc, argv))
{ {
printf("Usage: %s model_file\n", argv[0]); printf("Usage: %s [OPTIONS] model_file\n", argv[0]);
return 1; return 1;
} }
convert_model(argv[1]); convert_model(filename);
return 0; return 0;
} }
catch (std::runtime_error &e) catch (std::runtime_error &e)
{ {
if (silent)
return 1;
string error; string error;
if (argv[1]) if (argv[1])
error += argv[1]; error += argv[1];
@ -72,13 +136,42 @@ catch (std::runtime_error &e)
} }
catch (std::exception &e) catch (std::exception &e)
{ {
if (silent)
return 1;
printf("%s\n", argv[1]); printf("%s\n", argv[1]);
printf("error: %s\n", e.what()); printf("error: %s\n", e.what());
return 1; return 1;
} }
catch (...) catch (...)
{ {
if (silent)
return 1;
printf("%s\n", argv[1]); printf("%s\n", argv[1]);
printf("error: unknown exception\n"); printf("error: unknown exception\n");
return 1; return 1;
} }
bool parse_cmd(int argc, char *argv[])
{
for (int i = 1; i < argc; i++)
{
auto arg = argv[i];
if (*arg != '-')
{
if (i != argc - 1)
return false;
filename = arg;
continue;
}
switch (arg[1])
{
case 's':
silent = true;
break;
case 'm':
printMaxPolygonBlock = true;
break;
}
}
return true;
}

View file

@ -139,22 +139,28 @@ std::string block::printMtl(const std::string &mtl_name) const
// d 1.0 // d 1.0
// illum // illum
s += "\n"; s += "\n";
s += "map_Ka " + string(tex_mask) + ".tga\n"; if (string(tex_mask) != "_DEFAULT_")
s += "map_Kd " + string(tex_mask) + ".tga\n"; s += "map_Ka " + string(tex_mask) + ".tga" + "\n";
s += "map_Ks " + string(tex_spec) + ".tga\n"; if (string(tex_mask) != "_DEFAULT_")
s += "map_Ns " + string(tex_spec) + ".tga\n"; s += "map_Kd " + string(tex_mask) + ".tga" + "\n";
if (string(tex_spec) != "_DEFAULT_")
s += "map_Ks " + string(tex_spec) + ".tga" + "\n";
if (string(tex_spec) != "_DEFAULT_")
s += "map_Ns " + string(tex_spec) + ".tga" + "\n";
s += "\n"; s += "\n";
return s; return s;
} }
std::string block::printObj() const std::string block::printObj(const std::string &mtl_name) const
{ {
string s; string s;
s += string("o ") + name + "\n"; // UE does not recognize russian strings in .obj
s += string("g ") + name + "\n"; //s += string("o ") + name + "\n";
//s += string("g ") + name + "\n";
s += "g group1\n";
s += "s off\n"; s += "s off\n";
s += "\n"; s += "\n";
s += "usemtl main\n"; s += "usemtl " + mtl_name + "\n";
s += "\n"; s += "\n";
for (auto &v : vertices) for (auto &v : vertices)
@ -201,12 +207,12 @@ void block::load(buffer &b)
READ(b, unk4); READ(b, unk4);
if (size == 0) // critical error!!! cannot survive if (size == 0) // critical error!!! cannot survive
throw std::runtime_error("model file has bad block size field"); throw std::runtime_error("model file has bad block size field (size == 0)");
// data // data
buffer data = buffer(b, size); buffer data = buffer(b, size);
// we cannot process this type at the moment // we cannot process this type at the moment
if (type == BlockType::ParticleEmitter) if (type == BlockType::ParticleEmitter)
return; return;
@ -253,7 +259,7 @@ void block::load(buffer &b)
{ {
// unknown end of block // unknown end of block
auto triangles2 = triangles; auto triangles2 = triangles;
triangles2.resize((data.getSize() - data.getIndex()) / sizeof(triangle)); triangles2.resize((data.size() - data.index()) / sizeof(triangle));
for (auto &t : triangles2) for (auto &t : triangles2)
READ(data, t); READ(data, t);
} }
@ -271,29 +277,3 @@ void model::load(buffer &b)
for (auto &f : blocks) for (auto &f : blocks)
f.load(b); f.load(b);
} }
void model::writeObj(std::string 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";
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();
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);
}
}

View file

@ -214,7 +214,7 @@ struct block
void load(buffer &b); void load(buffer &b);
std::string printMtl(const std::string &mtl_name) const; std::string printMtl(const std::string &mtl_name) const;
std::string printObj() const; std::string printObj(const std::string &mtl_name) const;
}; };
struct model struct model
@ -224,5 +224,4 @@ struct model
std::vector<block> blocks; std::vector<block> blocks;
void load(buffer &b); void load(buffer &b);
void writeObj(std::string fn);
}; };

View file

@ -0,0 +1 @@
python obj_extractor.py --db "h:\Games\Epic Games\Projects\Polygon4\Mods\db.sqlite" --dir "h:\Games\AIM\data\maps.pak.dir"

View file

@ -55,7 +55,7 @@ struct storage
if (!b.eof()) if (!b.eof())
{ {
stringstream ss; stringstream ss;
ss << hex << b.getIndex() << " != " << hex << b.getSize(); ss << hex << b.index() << " != " << hex << b.size();
throw std::logic_error(ss.str()); throw std::logic_error(ss.str());
} }
} }
@ -99,7 +99,10 @@ void write_mmo(string db, const storage &s)
} }
if (map_id == 0) if (map_id == 0)
{
printf("error: this map is not found in the database\n");
return; return;
}
auto this_map = storage->maps[map_id]; auto this_map = storage->maps[map_id];
@ -122,10 +125,10 @@ void write_mmo(string db, const storage &s)
{ {
auto bld = storage->addBuilding(); auto bld = storage->addBuilding();
bld->text_id = o; bld->text_id = o;
bld_ids[o] = bld->id; bld_ids[o] = bld->getId();
} }
else else
bld_ids[o] = iter->second->id; bld_ids[o] = iter->second->getId();
} }
for (auto &object : segment->objects) for (auto &object : segment->objects)
{ {
@ -146,7 +149,7 @@ void write_mmo(string db, const storage &s)
if (i == storage->mapBuildings.end()) if (i == storage->mapBuildings.end())
{ {
auto mb2 = storage->addMapBuilding(storage->maps[map_id].get()); auto mb2 = storage->addMapBuilding(storage->maps[map_id].get());
mb.id = mb2->id; mb.setId(mb2->getId());
*mb2.get() = mb; *mb2.get() = mb;
} }
} }
@ -170,10 +173,10 @@ void write_mmo(string db, const storage &s)
{ {
auto bld = storage->addObject(); auto bld = storage->addObject();
bld->text_id = o; bld->text_id = o;
bld_ids[o] = bld->id; bld_ids[o] = bld->getId();
} }
else else
bld_ids[o] = iter->second->id; bld_ids[o] = iter->second->getId();
} }
for (auto &object : segment->objects) for (auto &object : segment->objects)
{ {
@ -194,7 +197,7 @@ void write_mmo(string db, const storage &s)
if (i == storage->mapObjects.end()) if (i == storage->mapObjects.end())
{ {
auto mb2 = storage->addMapObject(storage->maps[map_id].get()); auto mb2 = storage->addMapObject(storage->maps[map_id].get());
mb.id = mb2->id; mb.setId(mb2->getId());
*mb2.get() = mb; *mb2.get() = mb;
} }
} }

View file

@ -0,0 +1,26 @@
#!/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 maps')
parser.add_argument('--db', dest='db', help='path to db')
pargs = parser.parse_args()
if pargs.dir:
run(pargs.dir, pargs.db)
def run(dir, db):
for file in sorted(os.listdir(dir)):
if os.path.isdir(file) or os.path.splitext(file)[1] != ".mmo":
continue
print('loading: ' + file)
p = subprocess.Popen(['obj_extractor.exe', db, dir + '/' + file])
p.communicate()
if __name__ == '__main__':
main()

View file

@ -171,7 +171,7 @@ KNOWN_OBJECT(Anomaly);
KNOWN_OBJECT(Boundary); KNOWN_OBJECT(Boundary);
#define UNKNOWN_OBJECT(name) \ #define UNKNOWN_OBJECT(name) \
struct name : public MapObject { void load(buffer &b){ int pos = b.getIndex(); assert(false); } } struct name : public MapObject { void load(buffer &b){ int pos = b.index(); assert(false); } }
UNKNOWN_OBJECT(Building); UNKNOWN_OBJECT(Building);
UNKNOWN_OBJECT(Goods); UNKNOWN_OBJECT(Goods);

View file

@ -0,0 +1 @@
python tm_converter.py --dir "h:\\Games\\Epic Games\\Projects\\AIM\\models\\aim1\\"

View file

@ -27,15 +27,31 @@
using namespace std; using namespace std;
void convert_simple(buffer &dst, buffer &src, int width, int height)
{
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));
}
}
void tm2tga(string fn) void tm2tga(string fn)
{ {
int width, height; int width, height;
int dxt5 = 0;
buffer src(readFile(fn)); buffer src(readFile(fn));
READ(src, width); READ(src, width);
READ(src, height); READ(src, height);
src.reset(); src.seek(0x10);
src.skip(0x4C); src.read(&dxt5, 1);
src.seek(0x4C);
// http://paulbourke.net/dataformats/tga/ // http://paulbourke.net/dataformats/tga/
buffer dst; buffer dst;
@ -53,22 +69,19 @@ void tm2tga(string fn)
dst.write(uint8_t(0x28)); // imagedescriptor dst.write(uint8_t(0x28)); // imagedescriptor
const char *label = "AIMTMConverter"; const char *label = "AIMTMConverter";
dst.write(label, strlen(label), false); dst.write(label, strlen(label));
int size = width * height * 2; if (dxt5)
for (int i = 0; i < size; i++)
{ {
uint8_t c; //convert_dxt5(dst, src, width, height);
READ(src, c); throw std::logic_error("dxt5 converter is not implemented!");
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));
} }
else
convert_simple(dst, src, width, height);
transform(fn.begin(), fn.end(), fn.begin(), ::tolower); transform(fn.begin(), fn.end(), fn.begin(), ::tolower);
fn = fn.substr(0, fn.rfind(".tm")) + ".tga"; fn = fn.substr(0, fn.rfind(".tm")) + ".tga";
writeFile(fn, dst.getBuf()); writeFile(fn, dst.buf());
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])

View file

@ -0,0 +1,24 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import argparse
import os
import subprocess
def main():
parser = argparse.ArgumentParser(description='Batch textures converter')
parser.add_argument('--dir', dest='dir', help='path to directory with textures')
pargs = parser.parse_args()
if pargs.dir:
run(pargs.dir)
def run(dir):
for file in sorted(os.listdir(dir)):
if os.path.isdir(file) or os.path.splitext(file)[1].lower() != ".tm":
continue
p = subprocess.Popen(['tm_converter.exe', dir + '/' + file])
p.communicate()
if __name__ == '__main__':
main()