mirror of
https://github.com/aimrebirth/tools.git
synced 2026-04-14 17:33:25 +00:00
Initial fbx model converter.
This commit is contained in:
parent
98d993fa55
commit
6ce917f5e8
6 changed files with 454 additions and 101 deletions
|
|
@ -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"
|
||||
|
|
|
|||
391
src/mod_converter/fbx.cpp
Normal file
391
src/mod_converter/fbx.cpp
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
#include "fbx.h"
|
||||
|
||||
#include "model.h"
|
||||
|
||||
#include <fbxsdk.h>
|
||||
|
||||
#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<FbxSurfacePhong>(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;
|
||||
}
|
||||
1
src/mod_converter/fbx.h
Normal file
1
src/mod_converter/fbx.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
#pragma once
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
const float scale_mult = 30.0f;
|
||||
|
||||
const map<char, string> 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();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
extern const float scale_mult;
|
||||
|
||||
class buffer;
|
||||
|
||||
enum
|
||||
|
|
@ -102,7 +104,7 @@ struct vertex
|
|||
std::string printTex() const;
|
||||
};
|
||||
|
||||
using triangle = aim_vector3<uint16_t>;
|
||||
using face = aim_vector3<uint16_t>;
|
||||
|
||||
struct animation
|
||||
{
|
||||
|
|
@ -135,14 +137,11 @@ struct animation
|
|||
|
||||
struct damage_model
|
||||
{
|
||||
uint32_t n_polygons;
|
||||
std::string name;
|
||||
std::vector<uint16_t> model_polygons;
|
||||
uint32_t flags;
|
||||
uint32_t n_vertex;
|
||||
uint32_t n_triangles;
|
||||
std::vector<vertex> vertices;
|
||||
std::vector<triangle> damage_triangles;
|
||||
std::vector<face> 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<vertex> vertices;
|
||||
std::vector<triangle> faces;
|
||||
std::vector<face> faces;
|
||||
|
||||
// animations
|
||||
std::vector<animation> animations;
|
||||
|
|
@ -243,8 +238,6 @@ struct block
|
|||
|
||||
struct model
|
||||
{
|
||||
int n_blocks;
|
||||
char header[0x40];
|
||||
std::vector<block> blocks;
|
||||
|
||||
void load(const buffer &b);
|
||||
|
|
|
|||
Loading…
Reference in a new issue