From 6ce917f5e8387d94bb295ce9c062bad546054d68 Mon Sep 17 00:00:00 2001 From: lzwdgc Date: Fri, 28 Jul 2017 03:06:37 +0300 Subject: [PATCH] Initial fbx model converter. --- src/CMakeLists.txt | 4 +- src/mod_converter/fbx.cpp | 391 ++++++++++++++++++++++++++++ src/mod_converter/fbx.h | 1 + src/mod_converter/mod_converter.cpp | 64 +---- src/mod_converter/model.cpp | 76 ++++-- src/mod_converter/model.h | 19 +- 6 files changed, 454 insertions(+), 101 deletions(-) create mode 100644 src/mod_converter/fbx.cpp create mode 100644 src/mod_converter/fbx.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b69879e..b26cc8a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,8 +27,8 @@ if (DEFINED FBX_SDK_ROOT) target_link_libraries(mod_converter common #pvt.cppan.demo.eigen - debug "${FBX_SDK_ROOT}/lib/vs2015/x86/debug/libfbxsdk.lib" - optimized "${FBX_SDK_ROOT}/lib/vs2015/x86/release/libfbxsdk.lib" + debug "${FBX_SDK_ROOT}/lib/vs2015/x86/debug/libfbxsdk-md.lib" + optimized "${FBX_SDK_ROOT}/lib/vs2015/x86/release/libfbxsdk-md.lib" ) target_include_directories(mod_converter PUBLIC "${FBX_SDK_ROOT}/include" diff --git a/src/mod_converter/fbx.cpp b/src/mod_converter/fbx.cpp new file mode 100644 index 0000000..4520608 --- /dev/null +++ b/src/mod_converter/fbx.cpp @@ -0,0 +1,391 @@ +#include "fbx.h" + +#include "model.h" + +#include + +#ifdef IOS_REF +#undef IOS_REF +#define IOS_REF (*(pManager->GetIOSettings())) +#endif + +extern bool all_formats; + +void InitializeSdkObjects(FbxManager*& pManager, FbxScene*& pScene) +{ + //The first thing to do is to create the FBX Manager which is the object allocator for almost all the classes in the SDK + pManager = FbxManager::Create(); + if (!pManager) + { + FBXSDK_printf("Error: Unable to create FBX Manager!\n"); + exit(1); + } + + //Create an IOSettings object. This object holds all import/export settings. + FbxIOSettings* ios = FbxIOSettings::Create(pManager, IOSROOT); + pManager->SetIOSettings(ios); + + //Load plugins from the executable directory (optional) + FbxString lPath = FbxGetApplicationDirectory(); + pManager->LoadPluginsDirectory(lPath.Buffer()); + + //Create an FBX scene. This object holds most objects imported/exported from/to files. + pScene = FbxScene::Create(pManager, "My Scene"); + if (!pScene) + { + FBXSDK_printf("Error: Unable to create FBX scene!\n"); + exit(1); + } +} + +void DestroySdkObjects(FbxManager* pManager, bool pExitStatus) +{ + //Delete the FBX Manager. All the objects that have been allocated using the FBX Manager and that haven't been explicitly destroyed are also automatically destroyed. + if (pManager) pManager->Destroy(); + if (!pExitStatus) + FBXSDK_printf("Error: Unable to destroy FBX Manager!\n"); +} + +bool SaveScene(FbxManager* pManager, FbxDocument* pScene, const char* pFilename, bool pEmbedMedia, bool blender = false) +{ + int lMajor, lMinor, lRevision; + bool lStatus = true; + + // Create an exporter. + FbxExporter* lExporter = FbxExporter::Create(pManager, ""); + + auto pFileFormat = pManager->GetIOPluginRegistry()->GetNativeWriterFormat(); + FbxString lDesc = pManager->GetIOPluginRegistry()->GetWriterFormatDescription(pFileFormat); + + // Set the export states. By default, the export states are always set to + // true except for the option eEXPORT_TEXTURE_AS_EMBEDDED. The code below + // shows how to change these states. + IOS_REF.SetBoolProp(EXP_FBX_MATERIAL, true); + IOS_REF.SetBoolProp(EXP_FBX_TEXTURE, true); + IOS_REF.SetBoolProp(EXP_FBX_EMBEDDED, pEmbedMedia); + IOS_REF.SetBoolProp(EXP_FBX_SHAPE, true); + IOS_REF.SetBoolProp(EXP_FBX_GOBO, true); + IOS_REF.SetBoolProp(EXP_FBX_ANIMATION, true); + IOS_REF.SetBoolProp(EXP_FBX_GLOBAL_SETTINGS, true); + + // Initialize the exporter by providing a filename. + if (lExporter->Initialize(pFilename, pFileFormat, pManager->GetIOSettings()) == false) + { + FBXSDK_printf("Call to FbxExporter::Initialize() failed.\n"); + FBXSDK_printf("Error returned: %s\n\n", lExporter->GetStatus().GetErrorString()); + return false; + } + + // Export the scene. + // this one for blender + if (blender) + lExporter->SetFileExportVersion(FbxString("FBX201400"), FbxSceneRenamer::eNone); + lStatus = lExporter->Export(pScene); + + // Destroy the exporter. + lExporter->Destroy(); + return lStatus; +} + +bool LoadScene(FbxManager* pManager, FbxDocument* pScene, const char* pFilename) +{ + int lFileMajor, lFileMinor, lFileRevision; + int lSDKMajor, lSDKMinor, lSDKRevision; + //int lFileFormat = -1; + int i, lAnimStackCount; + bool lStatus; + char lPassword[1024]; + + // Get the file version number generate by the FBX SDK. + FbxManager::GetFileFormatVersion(lSDKMajor, lSDKMinor, lSDKRevision); + + // Create an importer. + FbxImporter* lImporter = FbxImporter::Create(pManager, ""); + + // Initialize the importer by providing a filename. + const bool lImportStatus = lImporter->Initialize(pFilename, -1, pManager->GetIOSettings()); + lImporter->GetFileVersion(lFileMajor, lFileMinor, lFileRevision); + + if (!lImportStatus) + { + FbxString error = lImporter->GetStatus().GetErrorString(); + FBXSDK_printf("Call to FbxImporter::Initialize() failed.\n"); + FBXSDK_printf("Error returned: %s\n\n", error.Buffer()); + + if (lImporter->GetStatus().GetCode() == FbxStatus::eInvalidFileVersion) + { + FBXSDK_printf("FBX file format version for this FBX SDK is %d.%d.%d\n", lSDKMajor, lSDKMinor, lSDKRevision); + FBXSDK_printf("FBX file format version for file '%s' is %d.%d.%d\n\n", pFilename, lFileMajor, lFileMinor, lFileRevision); + } + + return false; + } + + FBXSDK_printf("FBX file format version for this FBX SDK is %d.%d.%d\n", lSDKMajor, lSDKMinor, lSDKRevision); + + if (lImporter->IsFBX()) + { + FBXSDK_printf("FBX file format version for file '%s' is %d.%d.%d\n\n", pFilename, lFileMajor, lFileMinor, lFileRevision); + + // From this point, it is possible to access animation stack information without + // the expense of loading the entire file. + + FBXSDK_printf("Animation Stack Information\n"); + + lAnimStackCount = lImporter->GetAnimStackCount(); + + FBXSDK_printf(" Number of Animation Stacks: %d\n", lAnimStackCount); + FBXSDK_printf(" Current Animation Stack: \"%s\"\n", lImporter->GetActiveAnimStackName().Buffer()); + FBXSDK_printf("\n"); + + for (i = 0; i < lAnimStackCount; i++) + { + FbxTakeInfo* lTakeInfo = lImporter->GetTakeInfo(i); + + FBXSDK_printf(" Animation Stack %d\n", i); + FBXSDK_printf(" Name: \"%s\"\n", lTakeInfo->mName.Buffer()); + FBXSDK_printf(" Description: \"%s\"\n", lTakeInfo->mDescription.Buffer()); + + // Change the value of the import name if the animation stack should be imported + // under a different name. + FBXSDK_printf(" Import Name: \"%s\"\n", lTakeInfo->mImportName.Buffer()); + + // Set the value of the import state to false if the animation stack should be not + // be imported. + FBXSDK_printf(" Import State: %s\n", lTakeInfo->mSelect ? "true" : "false"); + FBXSDK_printf("\n"); + } + + // Set the import states. By default, the import states are always set to + // true. The code below shows how to change these states. + IOS_REF.SetBoolProp(IMP_FBX_MATERIAL, true); + IOS_REF.SetBoolProp(IMP_FBX_TEXTURE, true); + IOS_REF.SetBoolProp(IMP_FBX_LINK, true); + IOS_REF.SetBoolProp(IMP_FBX_SHAPE, true); + IOS_REF.SetBoolProp(IMP_FBX_GOBO, true); + IOS_REF.SetBoolProp(IMP_FBX_ANIMATION, true); + IOS_REF.SetBoolProp(IMP_FBX_GLOBAL_SETTINGS, true); + } + + // Import the scene. + lStatus = lImporter->Import(pScene); + + if (lStatus == false && lImporter->GetStatus().GetCode() == FbxStatus::ePasswordError) + { + FBXSDK_printf("Please enter password: "); + + lPassword[0] = '\0'; + + FBXSDK_CRT_SECURE_NO_WARNING_BEGIN + scanf("%s", lPassword); + FBXSDK_CRT_SECURE_NO_WARNING_END + + FbxString lString(lPassword); + + IOS_REF.SetStringProp(IMP_FBX_PASSWORD, lString); + IOS_REF.SetBoolProp(IMP_FBX_PASSWORD_ENABLE, true); + + lStatus = lImporter->Import(pScene); + + if (lStatus == false && lImporter->GetStatus().GetCode() == FbxStatus::ePasswordError) + { + FBXSDK_printf("\nPassword is wrong, import aborted.\n"); + } + } + + // Destroy the importer. + lImporter->Destroy(); + + return lStatus; +} + +bool CreateScene(model &m, const std::string &name, FbxManager* pSdkManager, FbxScene* pScene); + +void model::printFbx(const std::string &fn) +{ + FbxManager* lSdkManager = NULL; + FbxScene* lScene = NULL; + + // Prepare the FBX SDK. + InitializeSdkObjects(lSdkManager, lScene); + + // Create the scene. + CreateScene(*this, fn, lSdkManager, lScene); + + SaveScene(lSdkManager, lScene, (fn + "_ue4.fbx").c_str(), true); + if (all_formats) + SaveScene(lSdkManager, lScene, (fn + "_blender.fbx").c_str(), true, true); + + // Destroy all objects created by the FBX SDK. + DestroySdkObjects(lSdkManager, true); +} + +bool CreateScene(model &model, const std::string &name, FbxManager* pSdkManager, FbxScene* pScene) +{ + static const char* gDiffuseElementName = "DiffuseUV"; + static const char* gAmbientElementName = "AmbientUV"; + static const char* gSpecularElementName = "SpecularUV"; + + for (auto &b : model.blocks) + { + if (!b.canPrint()) + continue; + + auto block_name = name + "/" + b.name; + + // mesh + auto m = FbxMesh::Create(pSdkManager, block_name.c_str()); + + // node + FbxNode *node = FbxNode::Create(pScene, block_name.c_str()); + node->SetNodeAttribute(m); + node->SetShadingMode(FbxNode::eTextureShading); // change?! was texture sh + + // vertices + m->InitControlPoints(b.vertices.size()); + + // normals + auto normal = m->CreateElementNormal(); + normal->SetMappingMode(FbxGeometryElement::eByControlPoint); + normal->SetReferenceMode(FbxGeometryElement::eDirect); + + // uv + auto create_uv = [&m](auto &name) + { + auto uv1 = m->CreateElementUV(name); + uv1->SetMappingMode(FbxGeometryElement::eByControlPoint); + uv1->SetReferenceMode(FbxGeometryElement::eDirect); + return uv1; + }; + + auto d_uv = create_uv(gDiffuseElementName); + auto a_uv = create_uv(gAmbientElementName); + auto s_uv = create_uv(gSpecularElementName); + + // add vertices, normals, uvs + int i = 0; + for (auto &v : b.vertices) + { + FbxVector4 x; + x.Set(-v.coordinates.x * scale_mult, v.coordinates.z * scale_mult, v.coordinates.y * scale_mult, v.coordinates.w); + m->SetControlPointAt(x, i++); + normal->GetDirectArray().Add(FbxVector4(-v.normal.x, -v.normal.z, v.normal.y)); + + float f; + auto uc = modf(fabs(v.texture_coordinates.u), &f); + auto vc = modf(fabs(v.texture_coordinates.v), &f); + d_uv->GetDirectArray().Add(FbxVector2(uc, 1 - vc)); + a_uv->GetDirectArray().Add(FbxVector2(uc, 1 - vc)); + s_uv->GetDirectArray().Add(FbxVector2(uc, 1 - vc)); + } + + // faces + for (auto &v : b.faces) + { + // Set the control point indices of the bottom side of the pyramid + m->BeginPolygon(); + m->AddPolygon(v.x); + m->AddPolygon(v.z); + m->AddPolygon(v.y); + m->EndPolygon(); + } + + // mats + auto lMaterial = node->GetSrcObject(0); + if (lMaterial == NULL) + { + 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); + + FbxLayer* lLayer = m->GetLayer(0); + + // Create a layer element material to handle proper mapping. + FbxLayerElementMaterial* lLayerElementMaterial = FbxLayerElementMaterial::Create(m, lMaterialName.Buffer()); + + // This allows us to control where the materials are mapped. Using eAllSame + // means that all faces/polygons of the mesh will be assigned the same material. + lLayerElementMaterial->SetMappingMode(FbxLayerElement::eAllSame); + lLayerElementMaterial->SetReferenceMode(FbxLayerElement::eDirect); + + // Save the material on the layer + lLayer->SetMaterials(lLayerElementMaterial); + + // Add an index to the lLayerElementMaterial. Since we have only one, and are using eAllSame mapping mode, + // we only need to add one. + lLayerElementMaterial->GetIndexArray().Add(0); + + lMaterial = FbxSurfacePhong::Create(pScene, lMaterialName.Buffer()); + + // Generate primary and secondary colors. + lMaterial->Emissive.Set(lEmissiveColor); + //lMaterial->EmissiveFactor.Set(b.material.emissive.x); + + lMaterial->Ambient.Set(lAmbientColor); + //lMaterial->AmbientFactor.Set(b.mat.ambient.x); + + // Add texture for diffuse channel + lMaterial->Diffuse.Set(lDiffuseColor); + //lMaterial->DiffuseFactor.Set(b.mat.diffuse.x); + + //lMaterial->TransparencyFactor.Set(0.4); + //lMaterial->ShadingModel.Set(lShadingName); + //lMaterial->Shininess.Set(0.5); + + lMaterial->Specular.Set(lSpecularColor); + lMaterial->SpecularFactor.Set(b.mat.power); + node->AddMaterial(lMaterial); + } + + FbxFileTexture* lTexture; + + // Set texture properties. + lTexture = FbxFileTexture::Create(pScene, "Diffuse Texture"); + lTexture->SetFileName((b.tex_mask + ".TM.tga").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 + ".TM.tga").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 + ".TM.tga").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); + lGeometryConverter.ComputeEdgeSmoothingFromNormals(m); + //convert soft/hard edge info to smoothing group info + lGeometryConverter.ComputePolygonSmoothingFromEdgeSmoothing(m); + + + // + pScene->GetRootNode()->AddChild(node); + } + return true; +} diff --git a/src/mod_converter/fbx.h b/src/mod_converter/fbx.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/src/mod_converter/fbx.h @@ -0,0 +1 @@ +#pragma once diff --git a/src/mod_converter/mod_converter.cpp b/src/mod_converter/mod_converter.cpp index 3f088b6..30e83fc 100644 --- a/src/mod_converter/mod_converter.cpp +++ b/src/mod_converter/mod_converter.cpp @@ -29,47 +29,13 @@ using namespace std; // options +bool all_formats = false; 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) { buffer b(readFile(fn)); @@ -84,30 +50,9 @@ void convert_model(string fn) } // write all - m.print(filename); + if (all_formats) + m.print(filename); m.printFbx(filename); - return; - - // 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[]) @@ -166,6 +111,9 @@ bool parse_cmd(int argc, char *argv[]) } switch (arg[1]) { + case 'a': + all_formats = true; + break; case 's': silent = true; break; diff --git a/src/mod_converter/model.cpp b/src/mod_converter/model.cpp index 734c090..5c4c61f 100644 --- a/src/mod_converter/model.cpp +++ b/src/mod_converter/model.cpp @@ -36,6 +36,8 @@ using namespace std; +const float scale_mult = 30.0f; + const map transliteration = { { 'à',"a" }, @@ -171,18 +173,18 @@ std::string vertex::printVertex(bool rotate_x_90) const { // that rotation is really equivalent to exchanging y and z and z sign s = "v " + - to_string(-coordinates.x) + " " + - to_string(coordinates.z) + " " + - to_string(coordinates.y) + " " + + to_string(-coordinates.x * scale_mult) + " " + + to_string(coordinates.z * scale_mult) + " " + + to_string(coordinates.y * scale_mult) + " " + to_string(coordinates.w) ; } else { s = "v " + - to_string(-coordinates.x) + " " + - to_string(coordinates.y) + " " + - to_string(-coordinates.z) + " " + + to_string(-coordinates.x * scale_mult) + " " + + to_string(coordinates.y * scale_mult) + " " + + to_string(-coordinates.z * scale_mult) + " " + to_string(coordinates.w) ; } @@ -211,6 +213,7 @@ std::string vertex::printTex() const void damage_model::load(const buffer &b) { + uint32_t n_polygons; READ(b, n_polygons); model_polygons.resize(n_polygons); READ(b, unk8); @@ -219,13 +222,15 @@ void damage_model::load(const buffer &b) READ(b, t); READ(b, unk6); READ(b, flags); + uint32_t n_vertex; + uint32_t n_faces; READ(b, n_vertex); vertices.resize(n_vertex); - READ(b, n_triangles); - damage_triangles.resize(n_triangles / 3); + READ(b, n_faces); + faces.resize(n_faces / 3); for (auto &v : vertices) v.load(b, flags); - for (auto &t : damage_triangles) + for (auto &t : faces) READ(b, t); } @@ -236,6 +241,18 @@ void material::load(const buffer &b) READ(b, specular); READ(b, emissive); READ(b, power); + + auto delim_by_3 = [](auto &v) + { + v.x /= 3.0f; + v.y /= 3.0f; + v.z /= 3.0f; + }; + + // in aim - those values lie in interval [0,3] instead of [0,1] + delim_by_3(diffuse); + delim_by_3(ambient); + delim_by_3(specular); } void animation::load(const buffer &b) @@ -273,15 +290,15 @@ void animation::segment::loadData(const buffer &b) std::string block::printMtl() const { - static const string ext = ".TM.bmp"; + static const string ext = ".TM.tga"; string s; s += "newmtl " + name + "\n"; s += "\n"; - s += "Ka " + material.ambient.print() + "\n"; - s += "Kd " + material.diffuse.print() + "\n"; - s += "Ks " + material.specular.print() + "\n"; - s += " Ns " + to_string(material.power) + "\n"; + s += "Ka " + mat.ambient.print() + "\n"; + s += "Kd " + mat.diffuse.print() + "\n"; + s += "Ks " + mat.specular.print() + "\n"; + s += " Ns " + to_string(mat.power) + "\n"; // d 1.0 // illum s += "\n"; @@ -316,18 +333,15 @@ std::string block::printObj(int group_offset, bool rotate_x_90) const s += v.printTex() + "\n"; s += "\n"; - if (n_faces) + for (auto &t : faces) { - for (auto &t : faces) - { - auto x = to_string(t.x + 1 + group_offset); - auto y = to_string(t.y + 1 + group_offset); - auto z = to_string(t.z + 1 + group_offset); - x += "/" + x + "/" + x; - y += "/" + y + "/" + y; - z += "/" + z + "/" + z; - s += "f " + x + " " + z + " " + y + "\n"; - } + auto x = to_string(t.x + 1 + group_offset); + auto y = to_string(t.y + 1 + group_offset); + auto z = to_string(t.z + 1 + group_offset); + x += "/" + x + "/" + x; + y += "/" + y + "/" + y; + z += "/" + z + "/" + z; + s += "f " + x + " " + z + " " + y + "\n"; } s += "\n"; @@ -361,9 +375,10 @@ void block::load(const buffer &b) if (type == BlockType::ParticleEmitter) return; + uint32_t n_animations; READ(data, n_animations); animations.resize(n_animations); - material.load(data); + mat.load(data); // unk READ(data, effect); @@ -379,10 +394,13 @@ void block::load(const buffer &b) // READ(data, additional_params); + uint32_t n_damage_models; READ(data, n_damage_models); damage_models.resize(n_damage_models); READ(data, rot); READ(data, flags); + uint32_t n_vertex; + uint32_t n_faces; READ(data, n_vertex); vertices.resize(n_vertex); READ(data, n_faces); @@ -412,7 +430,7 @@ void block::load(const buffer &b) { // unknown end of block auto triangles2 = faces; - triangles2.resize((data.size() - data.index()) / sizeof(triangle)); + triangles2.resize((data.size() - data.index()) / sizeof(face)); for (auto &t : triangles2) READ(data, t); } @@ -433,9 +451,11 @@ bool block::canPrint() const void model::load(const buffer &b) { + int n_blocks; 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."); + char header[0x40]; READ(b, header); blocks.resize(n_blocks); for (auto &f : blocks) @@ -465,7 +485,7 @@ void model::print(const std::string &fn) continue; o << b.printObj(n_vert, rotate_x_90) << "\n"; - n_vert += b.n_vertex; + n_vert += b.vertices.size(); } }; diff --git a/src/mod_converter/model.h b/src/mod_converter/model.h index 922649b..b456ce3 100644 --- a/src/mod_converter/model.h +++ b/src/mod_converter/model.h @@ -22,6 +22,8 @@ #include #include +extern const float scale_mult; + class buffer; enum @@ -102,7 +104,7 @@ struct vertex std::string printTex() const; }; -using triangle = aim_vector3; +using face = aim_vector3; struct animation { @@ -135,14 +137,11 @@ struct animation struct damage_model { - uint32_t n_polygons; std::string name; std::vector model_polygons; uint32_t flags; - uint32_t n_vertex; - uint32_t n_triangles; std::vector vertices; - std::vector damage_triangles; + std::vector faces; uint8_t unk6; float unk8[3]; @@ -197,8 +196,7 @@ struct block }; // data - uint32_t n_animations; - material material; + material mat; //unk (anim + transform settings?) EffectType effect; @@ -208,13 +206,10 @@ struct block // additional_parameters additional_params; - uint32_t n_damage_models; rotation rot; uint32_t flags; - uint32_t n_vertex; - uint32_t n_faces; std::vector vertices; - std::vector faces; + std::vector faces; // animations std::vector animations; @@ -243,8 +238,6 @@ struct block struct model { - int n_blocks; - char header[0x40]; std::vector blocks; void load(const buffer &b);