aboutsummaryrefslogtreecommitdiff
path: root/NvBlast/tools/ApexImporter/src
diff options
context:
space:
mode:
authorBryan Galdrikian <[email protected]>2017-02-21 12:07:59 -0800
committerBryan Galdrikian <[email protected]>2017-02-21 12:07:59 -0800
commit446ce137c6823ba9eff273bdafdaf266287c7c98 (patch)
treed20aab3e2ed08d7b3ca71c2f40db6a93ea00c459 /NvBlast/tools/ApexImporter/src
downloadblast-1.0.0-beta.tar.xz
blast-1.0.0-beta.zip
first commitv1.0.0-beta
Diffstat (limited to 'NvBlast/tools/ApexImporter/src')
-rw-r--r--NvBlast/tools/ApexImporter/src/ApexDestructibleObjExporter.cpp314
-rw-r--r--NvBlast/tools/ApexImporter/src/ApexDestructibleObjExporter.h47
-rw-r--r--NvBlast/tools/ApexImporter/src/Main.cpp298
3 files changed, 659 insertions, 0 deletions
diff --git a/NvBlast/tools/ApexImporter/src/ApexDestructibleObjExporter.cpp b/NvBlast/tools/ApexImporter/src/ApexDestructibleObjExporter.cpp
new file mode 100644
index 0000000..0c90ac1
--- /dev/null
+++ b/NvBlast/tools/ApexImporter/src/ApexDestructibleObjExporter.cpp
@@ -0,0 +1,314 @@
+#include "ApexDestructibleObjExporter.h"
+
+#include "Log.h"
+
+#include "PsFastXml.h"
+#include "PsFileBuffer.h"
+#include "PxInputDataFromPxFileBuf.h"
+#include <PxVec2.h>
+#include <PxVec3.h>
+#include <map>
+#include <FbxFileWriter.h>
+#include <ObjFileWriter.h>
+
+
+using namespace nvidia;
+using namespace Nv::Blast;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Material Parser
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+const float VEC_EPS = 1e-4;
+
+class MaterialXmlParser : public physx::shdfnd::FastXml::Callback
+{
+public:
+ std::string textureFile;
+
+protected:
+ // encountered a comment in the XML
+ virtual bool processComment(const char* /*comment*/)
+ {
+ return true;
+ }
+
+ virtual bool processClose(const char* /*element*/, unsigned int /*depth*/, bool& /*isError*/)
+ {
+ return true;
+ }
+
+ // return true to continue processing the XML document, false to skip.
+ virtual bool processElement(const char* elementName, // name of the element
+ const char* elementData, // element data, null if none
+ const physx::shdfnd::FastXml::AttributePairs& attr,
+ int /*lineno*/) // line number in the source XML file
+ {
+ PX_UNUSED(attr);
+ if (::strcmp(elementName, "sampler2D") == 0)
+ {
+ int nameIndex = -1;
+ for (int i = 0; i < attr.getNbAttr(); i += 2)
+ {
+ if (::strcmp(attr.getKey(i), "name") == 0)
+ {
+ nameIndex = i;
+ break;
+ }
+ }
+
+ if (::strcmp(attr.getValue(nameIndex), "diffuseTexture") == 0)
+ {
+ textureFile = elementData;
+ }
+ }
+
+ return true;
+ }
+};
+
+std::string getTextureFromMaterial(const char* materialPath)
+{
+ PsFileBuffer fileBuffer(materialPath, general_PxIOStream2::PxFileBuf::OPEN_READ_ONLY);
+ PxInputDataFromPxFileBuf inputData(fileBuffer);
+ MaterialXmlParser parser;
+ physx::shdfnd::FastXml* xml = physx::shdfnd::createFastXml(&parser);
+ xml->processXml(inputData, false);
+
+ xml->release();
+
+ // trim folders
+ std::string textureFile = parser.textureFile.substr(parser.textureFile.find_last_of("/\\") + 1);
+
+ return textureFile;
+}
+
+
+bool ApexDestructibleGeometryExporter::exportToFile(NvBlastAsset* asset, const DestructibleAsset& apexAsset, const std::string& name, const std::vector<uint32_t>& chunkReorderInvMap, bool toFbx, bool toObj, bool fbxascii, bool toUe4)
+{
+ const RenderMeshAsset* rAsset = apexAsset.getRenderMeshAsset();
+ uint32_t submeshCount = rAsset->getSubmeshCount();
+ std::vector<std::string> materialPathes;
+ // gather materials
+ {
+ for (uint32_t submeshIndex = 0; submeshIndex < submeshCount; ++submeshIndex)
+ {
+ const char* materialName = rAsset->getMaterialName(submeshIndex);
+ std::ostringstream materialPath;
+ materialPath << m_materialsDir << "\\" << materialName;
+ std::string texturePath = getTextureFromMaterial(materialPath.str().c_str());
+ materialPathes.push_back(texturePath);
+ }
+ }
+ struct vc3Comp
+ {
+ bool operator()(const PxVec3& a, const PxVec3& b) const
+ {
+ if (a.x + VEC_EPS < b.x) return true;
+ if (a.x - VEC_EPS > b.x) return false;
+ if (a.y + VEC_EPS < b.y) return true;
+ if (a.y - VEC_EPS > b.y) return false;
+ if (a.z + VEC_EPS < b.z) return true;
+ return false;
+ }
+ };
+ struct vc2Comp
+ {
+ bool operator()(const PxVec2& a, const PxVec2& b) const
+ {
+ if (a.x + VEC_EPS < b.x) return true;
+ if (a.x - VEC_EPS > b.x) return false;
+ if (a.y + VEC_EPS < b.y) return true;
+ return false;
+ }
+ };
+
+ std::vector<PxVec3> compressedPositions;
+ std::vector<PxVec3> compressedNormals;
+ std::vector<PxVec2> compressedTextures;
+
+ std::vector<uint32_t> positionsMapping;
+ std::vector<uint32_t> normalsMapping;
+ std::vector<uint32_t> texturesMapping;
+
+ std::map<PxVec3, uint32_t, vc3Comp> posMap;
+ std::map<PxVec3, uint32_t, vc3Comp> normMap;
+ std::map<PxVec2, uint32_t, vc2Comp> texMap;
+
+
+ // gather data for export
+ {
+ for (uint32_t submeshIndex = 0; submeshIndex < submeshCount; ++submeshIndex)
+ {
+ const RenderSubmesh& currentSubmesh = rAsset->getSubmesh(submeshIndex);
+ uint32_t indexCount = currentSubmesh.getVertexBuffer().getVertexCount();
+ const VertexFormat& fmt = currentSubmesh.getVertexBuffer().getFormat();
+ // Find position buffer index
+ uint32_t bufferId = 0;
+ {
+ for (; bufferId < fmt.getBufferCount(); ++bufferId)
+ {
+ if (fmt.getBufferSemantic(bufferId) != RenderVertexSemantic::POSITION)
+ continue;
+ else
+ break;
+ }
+ if (bufferId == fmt.getBufferCount())
+ {
+ lout() << "Can't find positions buffer" << std::endl;
+ return false;
+ }
+ }
+ const PxVec3* posistions = reinterpret_cast<const PxVec3*>(currentSubmesh.getVertexBuffer().getBuffer(bufferId));
+ uint32_t oldSize = (uint32_t)positionsMapping.size();
+ positionsMapping.resize(oldSize + indexCount);
+ for (uint32_t i = 0; i < indexCount; ++i)
+ {
+ auto it = posMap.find(posistions[i]);
+ if (it == posMap.end())
+ {
+ posMap[posistions[i]] = (uint32_t)compressedPositions.size();
+ positionsMapping[oldSize + i] = (uint32_t)compressedPositions.size();
+ compressedPositions.push_back(posistions[i]);
+ }
+ else
+ {
+ positionsMapping[oldSize + i] = it->second;
+ }
+ }
+ }
+
+ for (uint32_t submeshIndex = 0; submeshIndex < submeshCount; ++submeshIndex)
+ {
+ const RenderSubmesh& currentSubmesh = rAsset->getSubmesh(submeshIndex);
+ uint32_t indexCount = currentSubmesh.getVertexBuffer().getVertexCount();
+ const VertexFormat& fmt = currentSubmesh.getVertexBuffer().getFormat();
+ // Find normal buffer index
+ uint32_t bufferId = 0;
+ {
+ for (; bufferId < fmt.getBufferCount(); ++bufferId)
+ {
+ if (fmt.getBufferSemantic(bufferId) != RenderVertexSemantic::NORMAL)
+ continue;
+ else
+ break;
+ }
+ if (bufferId == fmt.getBufferCount())
+ {
+ lout() << "Can't find positions buffer" << std::endl;
+ return false;
+ }
+ }
+ const PxVec3* normals = reinterpret_cast<const PxVec3*>(currentSubmesh.getVertexBuffer().getBuffer(bufferId));
+ uint32_t oldSize = (uint32_t)normalsMapping.size();
+ normalsMapping.resize(oldSize + indexCount);
+ for (uint32_t i = 0; i < indexCount; ++i)
+ {
+ auto it = normMap.find(normals[i]);
+ if (it == normMap.end())
+ {
+ normMap[normals[i]] = (uint32_t)compressedNormals.size();
+ normalsMapping[oldSize + i] = (uint32_t)compressedNormals.size();
+ compressedNormals.push_back(normals[i]);
+ }
+ else
+ {
+ normalsMapping[oldSize + i] = it->second;
+ }
+ }
+
+ }
+ for (uint32_t submeshIndex = 0; submeshIndex < submeshCount; ++submeshIndex)
+ {
+ const RenderSubmesh& currentSubmesh = rAsset->getSubmesh(submeshIndex);
+ uint32_t indexCount = currentSubmesh.getVertexBuffer().getVertexCount();
+ const VertexFormat& fmt = currentSubmesh.getVertexBuffer().getFormat();
+
+ // Find texture coords buffer index
+ uint32_t bufferId = 0;
+ {
+ for (; bufferId < fmt.getBufferCount(); ++bufferId)
+ {
+ if (fmt.getBufferSemantic(bufferId) != RenderVertexSemantic::TEXCOORD0)
+ continue;
+ else
+ break;
+ }
+ if (bufferId == fmt.getBufferCount())
+ {
+ lout() << "Can't find positions buffer" << std::endl;
+ return false;
+ }
+ }
+ const PxVec2* texCoord = reinterpret_cast<const PxVec2*>(currentSubmesh.getVertexBuffer().getBuffer(bufferId));
+ uint32_t oldSize = (uint32_t)texturesMapping.size();
+ texturesMapping.resize(oldSize + indexCount);
+ for (uint32_t i = 0; i < indexCount; ++i)
+ {
+ auto it = texMap.find(texCoord[i]);
+ if (it == texMap.end())
+ {
+ texMap[texCoord[i]] = (uint32_t)compressedTextures.size();
+ texturesMapping[oldSize + i] = (uint32_t)compressedTextures.size();
+ compressedTextures.push_back(texCoord[i]);
+ }
+ else
+ {
+ texturesMapping[oldSize + i] = it->second;
+ }
+ }
+
+ }
+
+ uint32_t apexChunkCount = apexAsset.getChunkCount();
+ uint32_t chunkCount = static_cast<uint32_t>(chunkReorderInvMap.size());
+
+ std::vector<std::vector<std::vector<int32_t> > > pInd(chunkCount);
+ std::vector<std::vector<std::vector<int32_t> > > tInd(chunkCount);
+ std::vector<std::vector<std::vector<int32_t> > > nInd(chunkCount);
+
+
+ for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex)
+ {
+ uint32_t apexChunkIndex = chunkReorderInvMap[chunkIndex];
+ if (apexChunkIndex >= apexChunkCount)
+ {
+ continue;
+ }
+ uint32_t part = apexAsset.getPartIndex(apexChunkIndex);
+ uint32_t offset = 0;
+ for (uint32_t submeshIndex = 0; submeshIndex < submeshCount; ++submeshIndex)
+ {
+ const RenderSubmesh& currentSubmesh = rAsset->getSubmesh(submeshIndex);
+ const uint32_t* indexArray = currentSubmesh.getIndexBuffer(part);
+ uint32_t indexCount = currentSubmesh.getIndexCount(part);
+ pInd[chunkIndex].push_back(std::vector<int32_t>());
+ tInd[chunkIndex].push_back(std::vector<int32_t>());
+ nInd[chunkIndex].push_back(std::vector<int32_t>());
+
+ for (uint32_t i = 0; i < indexCount;++i)
+ {
+ pInd[chunkIndex].back().push_back(positionsMapping[indexArray[i] + offset]);
+ tInd[chunkIndex].back().push_back(texturesMapping[indexArray[i] + offset]);
+ nInd[chunkIndex].back().push_back(normalsMapping[indexArray[i] + offset]);
+ }
+ offset += currentSubmesh.getVertexBuffer().getVertexCount();
+ }
+ }
+
+ if (toObj)
+ {
+ ObjFileWriter writer;
+ writer.saveToFile(asset, name, m_exportDir, compressedPositions, compressedNormals, compressedTextures, pInd, nInd, tInd, materialPathes, submeshCount);
+ }
+ if (toFbx)
+ {
+ FbxFileWriter writer;
+ writer.bOutputFBXAscii = fbxascii;
+ writer.setConvertToUE4(toUe4);
+ writer.saveToFile(asset, name, m_exportDir, compressedPositions, compressedNormals, compressedTextures, pInd, nInd, tInd, materialPathes, submeshCount);
+ }
+ }
+
+ return true;
+}
diff --git a/NvBlast/tools/ApexImporter/src/ApexDestructibleObjExporter.h b/NvBlast/tools/ApexImporter/src/ApexDestructibleObjExporter.h
new file mode 100644
index 0000000..cd6f238
--- /dev/null
+++ b/NvBlast/tools/ApexImporter/src/ApexDestructibleObjExporter.h
@@ -0,0 +1,47 @@
+#ifndef OBJ_APEX_EXPORTER_H
+#define OBJ_APEX_EXPORTER_H
+
+#include <string>
+#include <vector>
+#include "DestructibleAsset.h"
+
+
+
+
+namespace physx
+{
+ class PxVec3;
+ class PxVec2;
+}
+
+struct NvBlastAsset;
+
+namespace Nv
+{
+namespace Blast
+{
+
+class ApexDestructibleGeometryExporter
+{
+public:
+ ApexDestructibleGeometryExporter(std::string materialsDir, std::string exportDir) : m_materialsDir(materialsDir), m_exportDir(exportDir)
+ {}
+
+ bool exportToFile(NvBlastAsset* asset, const nvidia::apex::DestructibleAsset& apexAsset, const std::string& name, const std::vector<uint32_t>& chunkReorderInvMap, bool toFbx, bool toObj, bool fbxascii, bool toUe4);
+
+private:
+ ApexDestructibleGeometryExporter& operator=(const ApexDestructibleGeometryExporter&)
+ {
+ return *this;
+ }
+ const std::string m_materialsDir;
+ const std::string m_exportDir;
+
+};
+
+
+} // namespace Blast
+} // namespace Nv
+
+
+#endif //OBJ_EXPORTER_H
diff --git a/NvBlast/tools/ApexImporter/src/Main.cpp b/NvBlast/tools/ApexImporter/src/Main.cpp
new file mode 100644
index 0000000..157e923
--- /dev/null
+++ b/NvBlast/tools/ApexImporter/src/Main.cpp
@@ -0,0 +1,298 @@
+
+#if NV_VC
+#pragma warning(push)
+#pragma warning(disable: 4996) // 'fopen' unsafe warning, from NxFileBuffer.h
+#endif
+
+#include "PxPhysicsAPI.h"
+#include "Apex.h"
+#include <ModuleDestructible.h>
+#include <DestructibleAsset.h>
+#include "NullRenderer.h"
+#include "NvBlastExtApexImportTool.h"
+#include "Log.h"
+#include <string>
+#include <iostream>
+#include "tclap/CmdLine.h"
+#include "ApexDestructibleObjExporter.h"
+#include "NvBlastTkFramework.h"
+#include "NvBlastExtPxAsset.h"
+#include "NvBlastExtPxManager.h"
+#include <BlastDataExporter.h>
+#include "windows.h"
+#include <NvBlastTkAsset.h>
+#define DEFAULT_INPUT_FILE "../../../tools/ApexImporter/resources/assets/table.apb"
+#define DEFAULT_OUTPUT_DIR "C:/TestFracturer/"
+#define DEFAULT_ASSET_NAME "table"
+
+using namespace Nv::Blast;
+using namespace Nv::Blast::ApexImporter;
+
+void loggingCallback(int type, const char* msg, const char* file, int line)
+{
+ if (type == NvBlastMessage::Info)
+ lout() << Log::TYPE_INFO << msg << " FILE:" << file << " Line: " << line << "\n";
+ else
+ lout() << Log::TYPE_ERROR << msg << " FILE:" << file << " Line: " << line << "\n";
+}
+
+bool isDirectoryExist(std::string path)
+{
+ DWORD attributes = GetFileAttributesA(path.c_str());
+ if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ return true;
+ }
+ return false;
+}
+
+bool mkDirRecursively(std::string path)
+{
+ if (isDirectoryExist(path))
+ {
+ return true;
+ }
+ auto indx = path.find_first_of("\\/");
+ while (indx != std::string::npos)
+ {
+ std::string subfolder = path.substr(0, indx);
+ CreateDirectory(subfolder.c_str(), NULL);
+ indx = path.find_first_of("\\/", indx + 1);
+ }
+ return isDirectoryExist(path);
+}
+
+// Create an Asset from the APEX destructible asset
+void run(const std::string& inFilepath, const std::string& outDir, const std::string& assetName, uint32_t mode, bool llFlag, bool tkFlag, bool extPxFlag, bool obj, bool fbx, bool fbxascii, bool ue4)
+{
+ std::string inputDir = inFilepath.substr(0, inFilepath.find_last_of("/\\"));
+
+ // load APEX
+ ApexImportTool blast(loggingCallback);
+
+ lout() << Log::TYPE_INFO << "ApexImportTool initialization" << std::endl;
+ blast.initialize();
+ if (!blast.isValid())
+ {
+ lout() << Log::TYPE_ERROR << "Failed to create BlastSDK" << std::endl;
+ return;
+ }
+
+ // load asset
+ lout() << Log::TYPE_INFO << "Loading asset: " << inFilepath << std::endl;
+ physx::PxFileBuf* apexAssetStream = nvidia::apex::GetApexSDK()->createStream(inFilepath.c_str(), physx::PxFileBuf::OPEN_READ_ONLY);
+ nvidia::apex::DestructibleAsset* apexAsset = blast.loadAssetFromFile(apexAssetStream);
+ if (!apexAsset)
+ {
+ return;
+ }
+ apexAssetStream->release();
+
+ ApexImporterConfig config;
+ config.infSearchMode = static_cast<ApexImporterConfig::InterfaceSearchMode>(mode);
+
+ std::vector<uint32_t> chunkReorderInvMap;
+ TkFrameworkDesc frameworkDesc =
+ {
+ nvidia::apex::GetApexSDK()->getErrorCallback(),
+ nvidia::apex::GetApexSDK()->getAllocator()
+ };
+ TkFramework* framework = NvBlastTkFrameworkCreate(frameworkDesc);
+ if (framework == nullptr)
+ {
+ lout() << Log::TYPE_ERROR << "Failed to create TkFramework" << std::endl;
+ return;
+ }
+
+ std::vector<NvBlastChunkDesc> chunkDesc;
+ std::vector<NvBlastBondDesc> bondDescs;
+ std::vector<uint32_t> flags;
+
+ std::vector<ExtPxAssetDesc::ChunkDesc> physicsChunks;
+ std::vector<ExtPxAssetDesc::SubchunkDesc> physicsSubchunks;
+
+ bool result = blast.importApexAsset(chunkReorderInvMap, apexAsset, chunkDesc, bondDescs, flags, config);
+ if (!result)
+ {
+ lout() << Log::TYPE_ERROR << "Failed to build Blast asset data" << std::endl;
+ return;
+ };
+
+ result = blast.getCollisionGeometry(apexAsset, static_cast<uint32_t>(chunkDesc.size()), chunkReorderInvMap, flags, physicsChunks, physicsSubchunks);
+ if (!result)
+ {
+ lout() << Log::TYPE_ERROR << "Failed to build physics data" << std::endl;
+ return;
+ };
+
+
+ // save asset
+ lout() << Log::TYPE_INFO << "Saving blast asset: " << outDir << std::endl;
+ BlastDataExporter blExpr(framework, nvidia::apex::GetApexSDK()->getCookingInterface(), loggingCallback);
+ NvBlastAsset* llAsset = blExpr.createLlBlastAsset(bondDescs, chunkDesc);
+
+ std::cout <<"Chunk count: " << NvBlastAssetGetChunkCount(llAsset, NULL) << std::endl;
+
+ if (llAsset == nullptr && (llFlag || fbx))
+ {
+ lout() << Log::TYPE_ERROR << "Failed to build low-level asset" << std::endl;
+ return;
+ }
+
+ if (llFlag)
+ {
+ std::ostringstream outBlastFilePathStream;
+ outBlastFilePathStream << outDir << "/" << assetName << ".llasset";
+ std::string outBlastFilePath = outBlastFilePathStream.str();
+ blExpr.saveBlastLLAsset(outBlastFilePath, llAsset);
+ std::cout << "Wrote NvBlastAsset to " << outBlastFilePath << std::endl;
+ }
+ if (tkFlag)
+ {
+ TkAsset* tkAsset = blExpr.createTkBlastAsset(bondDescs, chunkDesc);
+ std::ostringstream outBlastFilePathStream;
+ outBlastFilePathStream << outDir << "/" << assetName << ".tkasset";
+ std::string outBlastFilePath = outBlastFilePathStream.str();
+ blExpr.saveBlastTkAsset(outBlastFilePath, tkAsset);
+ std::cout << "Wrote TkAsset to " << outBlastFilePath << std::endl;
+ tkAsset->release();
+ }
+ if (extPxFlag)
+ {
+ ExtPxAsset* pxAsset = blExpr.createExtBlastAsset(bondDescs, chunkDesc, physicsChunks);
+ std::ostringstream outBlastFilePathStream;
+ outBlastFilePathStream << outDir << "/" << assetName << ".bpxa";
+ std::string outBlastFilePath = outBlastFilePathStream.str();
+ blExpr.saveBlastExtAsset(outBlastFilePath, pxAsset);
+ std::cout << "Wrote ExtPxAsset to " << outBlastFilePath << std::endl;
+ pxAsset->release();
+ }
+
+ lout() << Log::TYPE_INFO << "Saving model file: " << outDir << std::endl;
+ ApexDestructibleGeometryExporter objSaver(inputDir, outDir);
+ objSaver.exportToFile(llAsset, *apexAsset, assetName, chunkReorderInvMap, fbx, obj, fbxascii, ue4);
+ _aligned_free(llAsset);
+}
+
+
+int main(int argc, const char* const* argv)
+{
+ try
+ {
+ // setup cmd line
+ TCLAP::CmdLine cmd("Blast SDK: APEX Importer", ' ', "0.1");
+
+ TCLAP::ValueArg<std::string> infileArg("f", "file", "File to load", true, DEFAULT_INPUT_FILE, "infile");
+ cmd.add(infileArg);
+
+ TCLAP::ValueArg<std::string> outDirArg("o", "outputDir", "Output directory", false, DEFAULT_OUTPUT_DIR, "output directory");
+ cmd.add(outDirArg);
+
+ TCLAP::ValueArg<std::string> outAssetName("n", "outAssetName", "Output asset name", true, DEFAULT_ASSET_NAME, "output asset name");
+ cmd.add(outAssetName);
+
+
+ TCLAP::ValueArg<uint32_t> interfaceSearchMode("m", "mode", "Interface search mode", false, 0, "0 - EXACT, 1 - FORCED, for detailed description see docs.");
+ cmd.add(interfaceSearchMode);
+
+ TCLAP::SwitchArg debugSwitch("d", "debug", "Print debug output", cmd, false);
+
+ TCLAP::SwitchArg bpxaOutputArg("", "bpxa", "Output ExtPxAsset to the output directory (ext: bpxa)", false);
+ cmd.add(bpxaOutputArg);
+
+ TCLAP::SwitchArg tkOutputArg("", "tk", "Output TkAsset to the output directory (ext: tkasset)", false);
+ cmd.add(tkOutputArg);
+
+ TCLAP::SwitchArg llOutputArg("", "ll", "Output LL Blast asset to the output directory (ext: llasset)", false);
+ cmd.add(llOutputArg);
+
+ TCLAP::SwitchArg ue4OutputArg("", "ue4", "Output FBX with UE4 coordinate system", false);
+ cmd.add(ue4OutputArg);
+
+ TCLAP::SwitchArg fbxAsciiArg("", "fbxascii", "Output FBX as an ascii file (defaults to binary output)", false);
+ cmd.add(fbxAsciiArg);
+
+ TCLAP::SwitchArg objOutputArg("", "obj", "Output a OBJ mesh to the output directory", false);
+ cmd.add(objOutputArg);
+
+ TCLAP::SwitchArg fbxOutputArg("", "fbx", "Output a FBX mesh to the output directory", false);
+ cmd.add(fbxOutputArg);
+
+
+ // parse cmd input
+ cmd.parse(argc, argv);
+
+ bool bOutputBPXA = bpxaOutputArg.getValue();
+ bool bOutputTK = tkOutputArg.getValue();
+ bool bOutputLL = llOutputArg.getValue();
+
+ bool bUE4CoordSystem = ue4OutputArg.isSet();
+ bool bOutputFBXAscii = fbxAsciiArg.isSet();
+
+ bool bOutputObjFile = objOutputArg.isSet();
+ bool bOutputFbxFile = fbxOutputArg.isSet();
+
+
+ // Did we specify no output formats?
+ if (!bpxaOutputArg.isSet() && !tkOutputArg.isSet() && !llOutputArg.isSet())
+ {
+ std::cout << "Didn't specify an output format on the command line, so defaulting to outputting BPXA" << std::endl;
+ bOutputBPXA = true;
+ }
+ // Did we specify no geometry output formats?
+ if (!bOutputObjFile && !bOutputFbxFile)
+ {
+ std::cout << "Didn't specify an output geometry format on the command line, so defaulting to outputting .OBJ" << std::endl;
+ bOutputObjFile = true;
+ }
+
+ // get cmd parse results
+ std::string infile = infileArg.getValue();
+ std::string outDir;
+ std::string assetName = outAssetName.getValue();
+
+ /**
+ Set output dir, make sure that it exist.
+ */
+ if (outDirArg.isSet())
+ {
+ outDir = outDirArg.getValue();
+ std::string temp = outDir + '/';
+ if (!isDirectoryExist(outDir.data()))
+ {
+ std::cout << "Output directory doesn't exist. It will be created." << std::endl;
+ if (!mkDirRecursively(temp.data()))
+ {
+ std::cout << "Directory creation failed!" << std::endl;
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ auto idx = infile.find_last_of("/\\");
+ if (idx == 0 || idx == std::string::npos)
+ {
+ outDir = ".";
+ }
+ else
+ {
+ outDir = infile.substr(0, idx);
+ }
+ }
+
+ bool debug = debugSwitch.getValue();
+ int mode = interfaceSearchMode.getValue();
+ // do stuff
+ if (debug)
+ lout().setMinVerbosity(Log::MOST_VERBOSE);
+
+ run(infile, outDir, assetName, mode, bOutputLL, bOutputTK, bOutputBPXA, bOutputObjFile, bOutputFbxFile, bOutputFBXAscii, bUE4CoordSystem);
+ }
+ catch (TCLAP::ArgException &e) // catch any exceptions
+ {
+ lout() << Log::TYPE_ERROR << "error: " << e.error() << " for arg " << e.argId() << std::endl;
+ }
+
+ return 0;
+}