From f9f9cedef8d518ad4d30a70951d5ea2460dbb55e Mon Sep 17 00:00:00 2001 From: lzwdgc Date: Sat, 29 Jul 2017 00:46:41 +0300 Subject: [PATCH] Add simple mod reader. --- src/CMakeLists.txt | 4 + src/mod_converter/fbx.cpp | 81 ++++++++++---------- src/mod_converter/model.cpp | 67 +++++++++++------ src/mod_converter/model.h | 71 ++++++++++------- src/mod_reader/mod_reader.cpp | 138 ++++++++++++++++++++++++++++++++++ 5 files changed, 268 insertions(+), 93 deletions(-) create mode 100644 src/mod_reader/mod_reader.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4b887ce..415ba5e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,6 +50,10 @@ else() message(STATUS "provide fbx sdk path to build mod converter") endif() +file(GLOB mod_reader_src "mod_reader/*") +add_executable(mod_reader ${mod_reader_src} mod_converter/model.cpp) +target_link_libraries(mod_reader common) + file(GLOB mpj_loader_src "mpj_loader/*") add_executable(mpj_loader ${mpj_loader_src}) target_link_libraries(mpj_loader common) diff --git a/src/mod_converter/fbx.cpp b/src/mod_converter/fbx.cpp index 868780c..075bffe 100644 --- a/src/mod_converter/fbx.cpp +++ b/src/mod_converter/fbx.cpp @@ -231,7 +231,7 @@ bool CreateScene(model &model, const std::string &name, FbxManager* pSdkManager, if (!b.canPrint()) continue; - auto block_name = name + "/" + b.name; + auto block_name = name + "/" + b.h.name; // mesh auto m = FbxMesh::Create(pSdkManager, block_name.c_str()); @@ -296,10 +296,10 @@ bool CreateScene(model &model, const std::string &name, FbxManager* pSdkManager, { FbxString lMaterialName = block_name.c_str(); FbxString lShadingName = "Phong"; - FbxDouble3 lAmbientColor(b.mat.ambient.x, b.mat.ambient.y, b.mat.ambient.z); - FbxDouble3 lSpecularColor(b.mat.specular.x, b.mat.specular.y, b.mat.specular.z); - FbxDouble3 lDiffuseColor(b.mat.diffuse.x, b.mat.diffuse.y, b.mat.diffuse.z); - FbxDouble3 lEmissiveColor(b.mat.emissive.x, b.mat.emissive.y, b.mat.emissive.z); + FbxDouble3 lAmbientColor(b.mat.ambient.r, b.mat.ambient.g, b.mat.ambient.b); + FbxDouble3 lSpecularColor(b.mat.specular.r, b.mat.specular.g, b.mat.specular.b); + FbxDouble3 lDiffuseColor(b.mat.diffuse.r, b.mat.diffuse.g, b.mat.diffuse.b); + FbxDouble3 lEmissiveColor(b.mat.emissive.r, b.mat.emissive.g, b.mat.emissive.b); FbxLayer* lLayer = m->GetLayer(0); @@ -322,14 +322,14 @@ bool CreateScene(model &model, const std::string &name, FbxManager* pSdkManager, // Generate primary and secondary colors. lMaterial->Emissive.Set(lEmissiveColor); - //lMaterial->EmissiveFactor.Set(b.material.emissive.x); + lMaterial->EmissiveFactor.Set(b.mat.emissive.r); lMaterial->Ambient.Set(lAmbientColor); - //lMaterial->AmbientFactor.Set(b.mat.ambient.x); + lMaterial->AmbientFactor.Set(b.mat.ambient.r); // Add texture for diffuse channel lMaterial->Diffuse.Set(lDiffuseColor); - //lMaterial->DiffuseFactor.Set(b.mat.diffuse.x); + lMaterial->DiffuseFactor.Set(b.mat.diffuse.r); //lMaterial->TransparencyFactor.Set(0.4); //lMaterial->ShadingModel.Set(lShadingName); @@ -340,42 +340,40 @@ bool CreateScene(model &model, const std::string &name, FbxManager* pSdkManager, node->AddMaterial(lMaterial); } - FbxFileTexture* lTexture; - - // Set texture properties. - lTexture = FbxFileTexture::Create(pScene, "Diffuse Texture"); - lTexture->SetFileName((b.tex_mask + texture_extension).c_str()); // Resource file is in current directory. - lTexture->SetTextureUse(FbxTexture::eStandard); - lTexture->SetMappingType(FbxTexture::eUV); - lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial); - lTexture->UVSet.Set(gDiffuseElementName); - if (lMaterial) - lMaterial->Diffuse.ConnectSrcObject(lTexture); - - // Set texture properties. - lTexture = FbxFileTexture::Create(pScene, "Ambient Texture"); - lTexture->SetFileName((b.tex_mask + texture_extension).c_str()); // Resource file is in current directory. - lTexture->SetTextureUse(FbxTexture::eStandard); - lTexture->SetMappingType(FbxTexture::eUV); - lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial); - lTexture->UVSet.Set(gAmbientElementName); - if (lMaterial) - lMaterial->Ambient.ConnectSrcObject(lTexture); - - // Set texture properties. - lTexture = FbxFileTexture::Create(pScene, "Specular Texture"); - lTexture->SetFileName((b.tex_spec + texture_extension).c_str()); // Resource file is in current directory. - lTexture->SetTextureUse(FbxTexture::eStandard); - lTexture->SetMappingType(FbxTexture::eUV); - lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial); - lTexture->UVSet.Set(gSpecularElementName); - if (lMaterial) - lMaterial->Specular.ConnectSrcObject(lTexture); - - + if (b.mat_type != MaterialType::MaterialOnly) + { + FbxFileTexture* lTexture; + // Set texture properties. + lTexture = FbxFileTexture::Create(pScene, "Diffuse Texture"); + lTexture->SetFileName((b.h.tex_mask + texture_extension).c_str()); // Resource file is in current directory. + lTexture->SetTextureUse(FbxTexture::eStandard); + lTexture->SetMappingType(FbxTexture::eUV); + lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial); + lTexture->UVSet.Set(gDiffuseElementName); + if (lMaterial) + lMaterial->Diffuse.ConnectSrcObject(lTexture); + // Set texture properties. + lTexture = FbxFileTexture::Create(pScene, "Ambient Texture"); + lTexture->SetFileName((b.h.tex_mask + texture_extension).c_str()); // Resource file is in current directory. + lTexture->SetTextureUse(FbxTexture::eStandard); + lTexture->SetMappingType(FbxTexture::eUV); + lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial); + lTexture->UVSet.Set(gAmbientElementName); + if (lMaterial) + lMaterial->Ambient.ConnectSrcObject(lTexture); + // Set texture properties. + lTexture = FbxFileTexture::Create(pScene, "Specular Texture"); + lTexture->SetFileName((b.h.tex_spec + texture_extension).c_str()); // Resource file is in current directory. + lTexture->SetTextureUse(FbxTexture::eStandard); + lTexture->SetMappingType(FbxTexture::eUV); + lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial); + lTexture->UVSet.Set(gSpecularElementName); + if (lMaterial) + lMaterial->Specular.ConnectSrcObject(lTexture); + } // add smoothing groups FbxGeometryConverter lGeometryConverter(pSdkManager); @@ -383,7 +381,6 @@ bool CreateScene(model &model, const std::string &name, FbxManager* pSdkManager, //convert soft/hard edge info to smoothing group info lGeometryConverter.ComputePolygonSmoothingFromEdgeSmoothing(m); - // pScene->GetRootNode()->AddChild(node); } diff --git a/src/mod_converter/model.cpp b/src/mod_converter/model.cpp index 832bed8..1c8caab 100644 --- a/src/mod_converter/model.cpp +++ b/src/mod_converter/model.cpp @@ -27,8 +27,6 @@ #include -#include - //#include //#include @@ -235,6 +233,13 @@ void damage_model::load(const buffer &b) READ(b, t); } +std::string mat_color::print() const +{ + string s; + s += to_string(r) + " " + to_string(g) + " " + to_string(b); + return s; +} + void material::load(const buffer &b) { READ(b, diffuse); @@ -245,9 +250,12 @@ void material::load(const buffer &b) auto delim_by_3 = [](auto &v) { - v.x /= 3.0f; - v.y /= 3.0f; - v.z /= 3.0f; + //if (v.r > 1) + //v.r /= 3.0f; + //if (v.g > 1) + //v.g /= 3.0f; + //if (v.b > 1) + //v.b /= 3.0f; }; // in aim - those values lie in interval [0,3] instead of [0,1] @@ -292,7 +300,7 @@ void animation::segment::loadData(const buffer &b) std::string block::printMtl() const { string s; - s += "newmtl " + name + "\n"; + s += "newmtl " + h.name + "\n"; s += "\n"; s += "Ka " + mat.ambient.print() + "\n"; s += "Kd " + mat.diffuse.print() + "\n"; @@ -301,14 +309,14 @@ std::string block::printMtl() const // d 1.0 // illum s += "\n"; - if (string(tex_mask) != "_DEFAULT_") - s += "map_Ka " + string(tex_mask) + texture_extension + "\n"; - if (string(tex_mask) != "_DEFAULT_") - s += "map_Kd " + string(tex_mask) + texture_extension + "\n"; - if (string(tex_spec) != "_DEFAULT_") - s += "map_Ks " + string(tex_spec) + texture_extension + "\n"; - if (string(tex_spec) != "_DEFAULT_") - s += "map_Ns " + string(tex_spec) + texture_extension + "\n"; + if (h.tex_mask != "_DEFAULT_") + s += "map_Ka " + h.tex_mask + texture_extension + "\n"; + if (h.tex_mask != "_DEFAULT_") + s += "map_Kd " + h.tex_mask + texture_extension + "\n"; + if (h.tex_spec != "_DEFAULT_") + s += "map_Ks " + h.tex_spec + texture_extension + "\n"; + if (h.tex_spec != "_DEFAULT_") + s += "map_Ns " + h.tex_spec + texture_extension + "\n"; s += "\n"; return s; } @@ -316,9 +324,9 @@ std::string block::printMtl() const std::string block::printObj(int group_offset, bool rotate_x_90) const { string s; - s += "usemtl " + name + "\n"; + s += "usemtl " + h.name + "\n"; s += "\n"; - s += "g " + name + "\n"; + s += "g " + h.name + "\n"; s += "s 1\n"; // still unk how to use s += "\n"; @@ -348,9 +356,8 @@ std::string block::printObj(int group_offset, bool rotate_x_90) const return s; } -void block::load(const buffer &b) +void block::header::load(const buffer &b) { - // header READ(b, type); READ_STRING(b, name); name = translate(name); @@ -363,17 +370,27 @@ void block::load(const buffer &b) READ(b, unk3); READ(b, size); READ(b, unk4); +} - if (size == 0) // critical error!!! cannot survive +void block::load(const buffer &b) +{ + h.load(b); + + if (h.size == 0) // critical error!!! cannot survive throw std::runtime_error("model file has bad block size field (size == 0)"); // data - buffer data = buffer(b, size); + buffer data = buffer(b, h.size); // we cannot process this type at the moment - if (type == BlockType::ParticleEmitter) + if (h.type == BlockType::ParticleEmitter) return; + loadPayload(data); +} + +void block::loadPayload(const buffer &data) +{ // anims uint32_t n_animations; READ(data, n_animations); @@ -420,7 +437,7 @@ void block::load(const buffer &b) for (auto &dm : damage_models) dm.load(data); - string s = "extraction error: block #" + std::string(name); + string s = "extraction error: block #" + std::string(h.name); if (!data.eof()) { cerr << s << "\n"; @@ -442,11 +459,11 @@ void block::load(const buffer &b) bool block::canPrint() const { - if (type == BlockType::ParticleEmitter) + if (h.type == BlockType::ParticleEmitter) return false; - if (type != BlockType::VisibleObject) + if (h.type != BlockType::VisibleObject) return false; - if (!(all_lods == 15 || LODs.lod1)) + if (!(h.all_lods == 15 || h.LODs.lod1)) return false; return true; } diff --git a/src/mod_converter/model.h b/src/mod_converter/model.h index 1ff5dd8..590622e 100644 --- a/src/mod_converter/model.h +++ b/src/mod_converter/model.h @@ -150,12 +150,22 @@ struct damage_model virtual void load(const buffer &b); }; +struct mat_color +{ + float r; + float g; + float b; + float alpha; + + std::string print() const; +}; + struct material { - aim_vector4 ambient; - aim_vector4 diffuse; - aim_vector4 specular; - aim_vector4 emissive; + mat_color ambient; + mat_color diffuse; + mat_color specular; + mat_color emissive; float power; void load(const buffer &b); @@ -176,26 +186,40 @@ struct additional_parameters struct block { - // header - BlockType type; - std::string name; - std::string tex_mask; - std::string tex_spec; - std::string tex3; - std::string tex4; - union // LODs + struct header { - struct + BlockType type; + std::string name; + std::string tex_mask; + std::string tex_spec; + std::string tex3; + std::string tex4; + union // LODs { - uint8_t lod1 : 1; - uint8_t lod2 : 1; - uint8_t lod3 : 1; - uint8_t lod4 : 1; - uint8_t : 4; - } LODs; - uint32_t all_lods; + struct + { + uint8_t lod1 : 1; + uint8_t lod2 : 1; + uint8_t lod3 : 1; + uint8_t lod4 : 1; + uint8_t : 4; + } LODs; + uint32_t all_lods; + }; + + // stuff + uint32_t size; + + // unk + uint32_t unk2[3]; + uint32_t unk3; + uint32_t unk4[10]; + + void load(const buffer &b); }; + header h; + // data material mat; MaterialType mat_type; @@ -216,13 +240,7 @@ struct block std::vector animations; std::vector damage_models; - // stuff - uint32_t size; - // unk - uint32_t unk2[3]; - uint16_t unk3[2]; - uint32_t unk4[10]; uint32_t unk7; float unk9; uint32_t unk10; @@ -231,6 +249,7 @@ struct block uint32_t unk12; void load(const buffer &b); + void loadPayload(const buffer &b); std::string printMtl() const; std::string printObj(int group_offset, bool rotate_x_90 = false) const; diff --git a/src/mod_reader/mod_reader.cpp b/src/mod_reader/mod_reader.cpp new file mode 100644 index 0000000..68194b6 --- /dev/null +++ b/src/mod_reader/mod_reader.cpp @@ -0,0 +1,138 @@ +/* + * 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 +#include "../mod_converter/model.h" + +#include + +using namespace std; + +// options +bool all_formats = false; +bool silent = false; +bool printMaxPolygonBlock = false; +path p; + +bool parse_cmd(int argc, char *argv[]); + +void convert_model(const path &fn) +{ + buffer b(read_file(fn)); + block bl; + bl.loadPayload(b); + + if (!b.eof()) + { + stringstream ss; + ss << hex << b.index() << " != " << hex << b.size(); + throw std::logic_error(ss.str()); + } +} + +int main(int argc, char *argv[]) +try +{ + if (argc < 2 || !parse_cmd(argc, argv)) + { + printf("Usage: %s [OPTIONS] {model_file,model_dir}\n", argv[0]); + return 1; + } + if (fs::is_regular_file(p)) + convert_model(p); + else if (fs::is_directory(p)) + { + auto files = enumerate_files(p, false); + for (auto &f : files) + { + if (f.has_extension()) + continue; + std::cout << "processing: " << f << "\n"; + convert_model(f); + } + } + else + throw std::runtime_error("Bad fs object"); + return 0; +} +catch (std::runtime_error &e) +{ + if (silent) + return 1; + string error; + error += p.string(); + error += "\n"; + error += "fatal error: "; + error += e.what(); + error += "\n"; + ofstream ofile(p.string() + ".error.txt"); + ofile << error; + return 1; +} +catch (std::exception &e) +{ + if (silent) + return 1; + printf("%s\n", p.string().c_str()); + printf("error: %s\n", e.what()); + return 1; +} +catch (...) +{ + if (silent) + return 1; + printf("%s\n", p.string().c_str()); + printf("error: unknown exception\n"); + 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; + p = arg; + continue; + } + switch (arg[1]) + { + case 'a': + all_formats = true; + break; + case 's': + silent = true; + break; + case 'm': + printMaxPolygonBlock = true; + break; + } + } + return true; +}