Main.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. #include <assimp/Importer.hpp>
  2. #include <assimp/scene.h>
  3. #include <assimp/postprocess.h>
  4. #include <iostream>
  5. #include <stdexcept>
  6. #include <cstdarg>
  7. #include <fstream>
  8. #include <cstdint>
  9. #include <sstream>
  10. #include <cassert>
  11. //==============================================================================
  12. /// Load the scene
  13. static const void load(
  14. const std::string& filename,
  15. Exporter& exporter)
  16. {
  17. LOGI("Loading file %s\n", filename.c_str());
  18. const aiScene* scene = exporter.importer.ReadFile(filename, 0
  19. //| aiProcess_FindInstances
  20. | aiProcess_Triangulate
  21. | aiProcess_JoinIdenticalVertices
  22. //| aiProcess_SortByPType
  23. | aiProcess_ImproveCacheLocality
  24. | aiProcess_OptimizeMeshes
  25. | aiProcess_RemoveRedundantMaterials
  26. );
  27. if(!scene)
  28. {
  29. ERROR("%s\n", importer.GetErrorString());
  30. }
  31. exporter.scene = scene;
  32. LOGI("File loaded successfully!\n");
  33. return *scene;
  34. }
  35. //==============================================================================
  36. static void parseCommandLineArgs(int argc, char** argv, Exporter& exporter)
  37. {
  38. static const char* usage = R"(Usage: %s in_file out_dir [options]
  39. Options:
  40. -rpath <string> : Append a string to the meshes and materials
  41. -texrpath <string> : Append a string to the textures paths
  42. -flipyz : Flip y with z (For blender exports)
  43. )";
  44. // Parse config
  45. if(argc < 3)
  46. {
  47. goto error;
  48. }
  49. exporter.inputFname = argv[1];
  50. exporter.outDir = argv[2] + std::string("/");
  51. for(int i = 3; i < argc; i++)
  52. {
  53. if(strcmp(argv[i], "-texrpath") == 0)
  54. {
  55. ++i;
  56. if(i < argc)
  57. {
  58. exporter.texrpath = argv[i] + std::string("/");
  59. }
  60. else
  61. {
  62. goto error;
  63. }
  64. }
  65. else if(strcmp(argv[i], "-rpath") == 0)
  66. {
  67. ++i;
  68. if(i < argc)
  69. {
  70. exporter.rpath = argv[i] + std::string("/");
  71. }
  72. else
  73. {
  74. goto error;
  75. }
  76. }
  77. else if(strcmp(argv[i], "-flipyz") == 0)
  78. {
  79. exporter.flipyz = true;
  80. }
  81. else
  82. {
  83. goto error;
  84. }
  85. }
  86. if(exporter.rpath.empty())
  87. {
  88. exporter.rpath = exporter.outDir;
  89. }
  90. if(exporter.texrpath.empty())
  91. {
  92. exporter.texrpath = exporter.outDir;
  93. }
  94. return;
  95. error:
  96. printf(usage, argv[0]);
  97. exit(1);
  98. }
  99. //==============================================================================
  100. static void exportModel(
  101. const aiScene& scene,
  102. const aiNode& node)
  103. {
  104. if(node.mNumMeshes == 0)
  105. {
  106. return;
  107. }
  108. std::string name = node.mName.C_Str();
  109. LOGI("Exporting model %s\n", name.c_str());
  110. std::fstream file;
  111. file.open(config.outDir + name + ".ankimdl", std::ios::out);
  112. file << xmlHeader << '\n';
  113. file << "<model>\n";
  114. file << "\t<modelPatches>\n";
  115. for(uint32_t i = 0; i < node.mNumMeshes; i++)
  116. {
  117. uint32_t meshIndex = node.mMeshes[i];
  118. const aiMesh& mesh = *scene.mMeshes[meshIndex];
  119. // start
  120. file << "\t\t<modelPatch>\n";
  121. // Write mesh
  122. file << "\t\t\t<mesh>" << config.rpath
  123. << mesh.mName.C_Str() << ".ankimesh</mesh>\n";
  124. // Write material
  125. const aiMaterial& mtl = *scene.mMaterials[mesh.mMaterialIndex];
  126. aiString mtlname;
  127. mtl.Get(AI_MATKEY_NAME, mtlname);
  128. file << "\t\t\t<material>" << config.rpath
  129. << mtlname.C_Str() << ".ankimtl</material>\n";
  130. // end
  131. file << "\t\t</modelPatch>\n";
  132. }
  133. file << "\t</modelPatches>\n";
  134. file << "</model>\n";
  135. }
  136. //==============================================================================
  137. static void visitNode(const aiNode* node, const aiScene& scene)
  138. {
  139. if(node == nullptr)
  140. {
  141. return;
  142. }
  143. // For every mesh of this node
  144. for(uint32_t i = 0; i < node->mNumMeshes; i++)
  145. {
  146. uint32_t meshIndex = node->mMeshes[i];
  147. const aiMesh& mesh = *scene.mMeshes[meshIndex];
  148. // Is material set?
  149. if(config.meshes[meshIndex].mtlIndex == 0xFFFFFFFF)
  150. {
  151. // Connect mesh with material
  152. config.meshes[meshIndex].mtlIndex = mesh.mMaterialIndex;
  153. // Connect material with mesh
  154. config.materials[mesh.mMaterialIndex].meshIndices.push_back(
  155. meshIndex);
  156. }
  157. else if(config.meshes[meshIndex].mtlIndex != mesh.mMaterialIndex)
  158. {
  159. ERROR("Previous material index conflict\n");
  160. }
  161. config.meshes[meshIndex].transforms.push_back(node->mTransformation);
  162. }
  163. // Go to children
  164. for(uint32_t i = 0; i < node->mNumChildren; i++)
  165. {
  166. visitNode(node->mChildren[i], scene);
  167. }
  168. }
  169. //==============================================================================
  170. static void exportScene(const aiScene& scene)
  171. {
  172. LOGI("Exporting scene to %s\n", config.outDir.c_str());
  173. //
  174. // Open scene file
  175. //
  176. std::ofstream file;
  177. file.open(config.outDir + "master.ankiscene");
  178. file << xmlHeader << "\n"
  179. << "<scene>\n";
  180. //
  181. // Get all the data
  182. //
  183. config.meshes.resize(scene.mNumMeshes);
  184. config.materials.resize(scene.mNumMaterials);
  185. int i = 0;
  186. for(Mesh& mesh : config.meshes)
  187. {
  188. mesh.index = i++;
  189. }
  190. i = 0;
  191. for(Material& mtl : config.materials)
  192. {
  193. mtl.index = i++;
  194. }
  195. const aiNode* node = scene.mRootNode;
  196. visitNode(node, scene);
  197. #if 0
  198. //
  199. // Export non instanced static meshes
  200. //
  201. for(uint32_t i = 0; i < config.meshes.size(); i++)
  202. {
  203. // Check if instance is one
  204. if(config.meshes[i].transforms.size() == 1)
  205. {
  206. continue;
  207. }
  208. // Export the material
  209. aiMaterial& aimtl = *scene.mMaterials[mesh.mtlIndex];
  210. std::string mtlName = getMaterialName(aimtl);
  211. exportMaterial(scene, aimtl, false, &mtlName);
  212. // Export mesh
  213. std::string meshName = std::string(scene.mMeshes[i]->mName.C_Str())
  214. + "_static_" + std::to_string(i);
  215. exportMesh(*scene.mMeshes[i], &meshName, nullptr);
  216. for(uint32_t t = 0; t < config.meshes[i].transforms.size(); t++)
  217. {
  218. std::string nname = name + "_" + std::to_string(t);
  219. exportMesh(*scene.mMeshes[i], &nname,
  220. &config.meshes[i].transforms[t], config);
  221. }
  222. }
  223. #endif
  224. //
  225. // Write the instanced meshes
  226. //
  227. for(uint32_t i = 0; i < config.meshes.size(); i++)
  228. {
  229. const Mesh& mesh = config.meshes[i];
  230. // Skip meshes that are not instance candidates
  231. if(mesh.transforms.size() == 0)
  232. {
  233. continue;
  234. }
  235. // Export the material
  236. aiMaterial& aimtl = *scene.mMaterials[mesh.mtlIndex];
  237. std::string mtlName = getMaterialName(aimtl) + "_instanced";
  238. exportMaterial(scene, aimtl, true, &mtlName);
  239. // Export mesh
  240. std::string meshName = std::string(scene.mMeshes[i]->mName.C_Str())
  241. + "_instanced_" + std::to_string(i);
  242. exportMesh(*scene.mMeshes[i], &meshName, nullptr);
  243. // Write model file
  244. std::string modelName = mtlName + "_" + std::to_string(i);
  245. {
  246. std::ofstream file;
  247. file.open(
  248. config.outDir + modelName + ".ankimdl");
  249. file << xmlHeader << "\n"
  250. << "<model>\n"
  251. << "\t<modelPatches>\n"
  252. << "\t\t<modelPatch>\n"
  253. << "\t\t\t<mesh>" << config.rpath << meshName
  254. << ".ankimesh</mesh>\n"
  255. << "\t\t\t<material>" << config.rpath << mtlName
  256. << ".ankimtl</material>\n"
  257. << "\t\t</modelPatch>\n"
  258. << "\t</modelPatches>\n"
  259. << "</model>\n";
  260. }
  261. // Node name
  262. std::string nodeName = getMaterialName(aimtl) + "_instanced_"
  263. + std::to_string(i);
  264. // Write the scene file
  265. file << "\t<modelNode>\n"
  266. << "\t\t<name>" << nodeName << "</name>\n"
  267. << "\t\t<model>" << config.rpath << modelName
  268. << ".ankimdl</model>\n"
  269. << "\t\t<instancesCount>"
  270. << mesh.transforms.size() << "</instancesCount>\n";
  271. for(uint32_t j = 0; j < mesh.transforms.size(); j++)
  272. {
  273. file << "\t\t<transform>";
  274. aiMatrix4x4 trf = toAnkiMatrix(mesh.transforms[j]);
  275. for(uint32_t a = 0; a < 4; a++)
  276. {
  277. for(uint32_t b = 0; b < 4; b++)
  278. {
  279. file << trf[a][b] << " ";
  280. }
  281. }
  282. file << "</transform>\n";
  283. }
  284. file << "\t</modelNode>\n";
  285. }
  286. #if 0
  287. // Write bmeshes
  288. for(uint32_t mtlId = 0; mtlId < config.materials.size(); mtlId++)
  289. {
  290. const Material& mtl = config.materials[mtlId];
  291. // Check if used
  292. if(mtl.meshIndices.size() < 1)
  293. {
  294. continue;
  295. }
  296. std::string name = getMaterialName(*scene.mMaterials[mtlId]) + ".bmesh";
  297. std::fstream file;
  298. file.open(config.outDir + name, std::ios::out);
  299. file << xmlHeader << "\n";
  300. file << "<bucketMesh>\n";
  301. file << "\t<meshes>\n";
  302. for(uint32_t j = 0; j < mtl.meshIndices.size(); j++)
  303. {
  304. uint32_t meshId = mtl.meshIndices[j];
  305. const Mesh& mesh = config.meshes[meshId];
  306. for(uint32_t k = 0; k < mesh.transforms.size(); k++)
  307. {
  308. file << "\t\t<mesh>" << config.rpath
  309. << "mesh_" + std::to_string(meshId) << "_"
  310. << std::to_string(k)
  311. << ".mesh</mesh>\n";
  312. }
  313. }
  314. file << "\t</meshes>\n";
  315. file << "</bucketMesh>\n";
  316. }
  317. // Create the master model
  318. std::fstream file;
  319. file.open(config.outDir + "static_geometry.mdl", std::ios::out);
  320. file << xmlHeader << "\n";
  321. file << "<model>\n";
  322. file << "\t<modelPatches>\n";
  323. for(uint32_t i = 0; i < config.materials.size(); i++)
  324. {
  325. // Check if used
  326. if(config.materials[i].meshIndices.size() < 1)
  327. {
  328. continue;
  329. }
  330. file << "\t\t<modelPatch>\n";
  331. file << "\t\t\t<bucketMesh>" << config.rpath
  332. << getMaterialName(*scene.mMaterials[i]) << ".bmesh</bucketMesh>\n";
  333. file << "\t\t\t<material>" << config.rpath
  334. << getMaterialName(*scene.mMaterials[i])
  335. << ".mtl</material>\n";
  336. file << "\t\t</modelPatch>\n";
  337. }
  338. file << "\t</modelPatches>\n";
  339. file << "</model>\n";
  340. #endif
  341. //
  342. // Animations
  343. //
  344. for(unsigned i = 0; i < scene.mNumAnimations; i++)
  345. {
  346. exportAnimation(*scene.mAnimations[i], i, scene);
  347. }
  348. file << "</scene>\n";
  349. LOGI("Done exporting scene!\n");
  350. }
  351. //==============================================================================
  352. int main(int argc, char** argv)
  353. {
  354. try
  355. {
  356. Exporter exporter;
  357. parseCommandLineArgs(argc, argv, exporter);
  358. // Load file
  359. load(exporter.inputFname, exporter);
  360. // Export
  361. exportScene(exporter);
  362. }
  363. catch(std::exception& e)
  364. {
  365. std::cerr << "Exception: " << e.what() << std::endl;
  366. }
  367. }