Main.cpp 21 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  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. static const char* xmlHeader = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
  12. struct Mesh
  13. {
  14. uint32_t index = 0xFFFFFFFF; ///< Mesh index in the scene
  15. std::vector<aiMatrix4x4> transforms;
  16. uint32_t mtlIndex = 0xFFFFFFFF;
  17. };
  18. struct Material
  19. {
  20. uint32_t index = 0xFFFFFFFF;
  21. std::vector<uint32_t> meshIndices;
  22. };
  23. struct Config
  24. {
  25. std::string inputFname;
  26. std::string outDir;
  27. std::string rpath;
  28. std::string texpath;
  29. bool flipyz = false;
  30. std::vector<Mesh> meshes;
  31. std::vector<Material> materials;
  32. };
  33. Config config;
  34. //==============================================================================
  35. // Log and errors
  36. #define STR(s) #s
  37. #define XSTR(s) STR(s)
  38. #define LOGI(...) \
  39. printf("[I] (" __FILE__ ":" XSTR(__LINE__) ") " __VA_ARGS__)
  40. #define ERROR(...) \
  41. do { \
  42. fprintf(stderr, "[E] (" __FILE__ ":" XSTR(__LINE__) ") " __VA_ARGS__); \
  43. exit(0); \
  44. } while(0)
  45. #define LOGW(...) \
  46. fprintf(stderr, "[W] (" __FILE__ ":" XSTR(__LINE__) ") " __VA_ARGS__)
  47. //==============================================================================
  48. static std::string replaceAllString(
  49. const std::string& str,
  50. const std::string& from,
  51. const std::string& to)
  52. {
  53. if(from.empty())
  54. {
  55. return str;
  56. }
  57. std::string out = str;
  58. size_t start_pos = 0;
  59. while((start_pos = out.find(from, start_pos)) != std::string::npos)
  60. {
  61. out.replace(start_pos, from.length(), to);
  62. start_pos += to.length();
  63. }
  64. return out;
  65. }
  66. //==============================================================================
  67. static std::string getFilename(const std::string& path)
  68. {
  69. std::string out;
  70. const size_t last = path.find_last_of("/");
  71. if(std::string::npos != last)
  72. {
  73. out.insert(out.end(), path.begin() + last + 1, path.end());
  74. }
  75. return out;
  76. }
  77. //==============================================================================
  78. static aiMatrix4x4 toAnkiMatrix(const aiMatrix4x4& in)
  79. {
  80. static const aiMatrix4x4 toLeftHanded(
  81. 1, 0, 0, 0,
  82. 0, 0, 1, 0,
  83. 0, -1, 0, 0,
  84. 0, 0, 0, 1);
  85. static const aiMatrix4x4 toLeftHandedInv(
  86. 1, 0, 0, 0,
  87. 0, 0, -1, 0,
  88. 0, 1, 0, 0,
  89. 0, 0, 0, 1);
  90. if(config.flipyz)
  91. {
  92. return toLeftHanded * in * toLeftHandedInv;
  93. }
  94. else
  95. {
  96. return in;
  97. }
  98. }
  99. //==============================================================================
  100. static void parseConfig(int argc, char** argv)
  101. {
  102. static const char* usage = R"(Usage: %s in_file out_dir [options]
  103. Options:
  104. -rpath <string> : Append a string to the meshes and materials
  105. -texrpath <string> : Append a string to the textures paths
  106. -flipyz : Flip y with z (For blender exports)
  107. )";
  108. // Parse config
  109. if(argc < 3)
  110. {
  111. goto error;
  112. }
  113. config.inputFname = argv[1];
  114. config.outDir = argv[2] + std::string("/");
  115. for(int i = 3; i < argc; i++)
  116. {
  117. if(strcmp(argv[i], "-texrpath") == 0)
  118. {
  119. ++i;
  120. if(i < argc)
  121. {
  122. config.texpath = argv[i] + std::string("/");
  123. }
  124. else
  125. {
  126. goto error;
  127. }
  128. }
  129. else if(strcmp(argv[i], "-rpath") == 0)
  130. {
  131. ++i;
  132. if(i < argc)
  133. {
  134. config.rpath = argv[i] + std::string("/");
  135. }
  136. else
  137. {
  138. goto error;
  139. }
  140. }
  141. else if(strcmp(argv[i], "-flipyz") == 0)
  142. {
  143. config.flipyz = true;
  144. }
  145. else
  146. {
  147. goto error;
  148. }
  149. }
  150. if(config.rpath.empty())
  151. {
  152. config.rpath = config.outDir;
  153. }
  154. if(config.texpath.empty())
  155. {
  156. config.texpath = config.outDir;
  157. }
  158. return;
  159. error:
  160. printf(usage, argv[0]);
  161. exit(0);
  162. }
  163. //==============================================================================
  164. /// Load the scene
  165. static const aiScene& load(
  166. const std::string& filename,
  167. Assimp::Importer& importer)
  168. {
  169. LOGI("Loading file %s\n", filename.c_str());
  170. const aiScene* scene = importer.ReadFile(filename, 0
  171. //| aiProcess_FindInstances
  172. | aiProcess_Triangulate
  173. | aiProcess_JoinIdenticalVertices
  174. //| aiProcess_SortByPType
  175. | aiProcess_ImproveCacheLocality
  176. | aiProcess_OptimizeMeshes
  177. | aiProcess_RemoveRedundantMaterials
  178. );
  179. if(!scene)
  180. {
  181. ERROR("%s\n", importer.GetErrorString());
  182. }
  183. LOGI("File loaded successfully!\n");
  184. return *scene;
  185. }
  186. //==============================================================================
  187. static const uint32_t MAX_BONES_PER_VERTEX = 4;
  188. /// Bone/weight info per vertex
  189. struct Vw
  190. {
  191. uint32_t boneIds[MAX_BONES_PER_VERTEX];
  192. float weigths[MAX_BONES_PER_VERTEX];
  193. uint32_t bonesCount;
  194. };
  195. //==============================================================================
  196. static void exportMesh(
  197. const aiMesh& mesh,
  198. const std::string* name_,
  199. const aiMatrix4x4* transform)
  200. {
  201. std::string name = (name_) ? *name_ : mesh.mName.C_Str();
  202. std::fstream file;
  203. LOGI("Exporting mesh %s\n", name.c_str());
  204. uint32_t vertsCount = mesh.mNumVertices;
  205. // Open file
  206. file.open(config.outDir + name + ".ankimesh",
  207. std::ios::out | std::ios::binary);
  208. // Write magic word
  209. file.write("ANKIMESH", 8);
  210. // Write the name
  211. uint32_t size = name.size();
  212. file.write((char*)&size, sizeof(uint32_t));
  213. file.write(&name[0], size);
  214. // Write positions
  215. file.write((char*)&vertsCount, sizeof(uint32_t));
  216. for(uint32_t i = 0; i < mesh.mNumVertices; i++)
  217. {
  218. aiVector3D pos = mesh.mVertices[i];
  219. // Transform
  220. if(transform)
  221. {
  222. pos = (*transform) * pos;
  223. }
  224. // flip
  225. if(config.flipyz)
  226. {
  227. static const aiMatrix4x4 toLefthanded(
  228. 1, 0, 0, 0,
  229. 0, 0, 1, 0,
  230. 0, -1, 0, 0,
  231. 0, 0, 0, 1);
  232. pos = toLefthanded * pos;
  233. }
  234. for(uint32_t j = 0; j < 3; j++)
  235. {
  236. file.write((char*)&pos[j], sizeof(float));
  237. }
  238. }
  239. // Write the indices
  240. file.write((char*)&mesh.mNumFaces, sizeof(uint32_t));
  241. for(uint32_t i = 0; i < mesh.mNumFaces; i++)
  242. {
  243. const aiFace& face = mesh.mFaces[i];
  244. if(face.mNumIndices != 3)
  245. {
  246. ERROR("For some reason the assimp didn't triangulate\n");
  247. }
  248. for(uint32_t j = 0; j < 3; j++)
  249. {
  250. uint32_t index = face.mIndices[j];
  251. file.write((char*)&index, sizeof(uint32_t));
  252. }
  253. }
  254. // Write the tex coords
  255. file.write((char*)&vertsCount, sizeof(uint32_t));
  256. // For all channels
  257. for(uint32_t ch = 0; ch < mesh.GetNumUVChannels(); ch++)
  258. {
  259. if(mesh.mNumUVComponents[ch] != 2)
  260. {
  261. ERROR("Incorrect number of UV components\n");
  262. }
  263. // For all tex coords of this channel
  264. for(uint32_t i = 0; i < vertsCount; i++)
  265. {
  266. aiVector3D texCoord = mesh.mTextureCoords[ch][i];
  267. for(uint32_t j = 0; j < 2; j++)
  268. {
  269. file.write((char*)&texCoord[j], sizeof(float));
  270. }
  271. }
  272. }
  273. // Write bone weigths count
  274. if(mesh.HasBones())
  275. {
  276. #if 0
  277. // Write file
  278. file.write((char*)&vertsCount, sizeof(uint32_t));
  279. // Gather info for each vertex
  280. std::vector<Vw> vw;
  281. vw.resize(vertsCount);
  282. memset(&vw[0], 0, sizeof(Vw) * vertsCount);
  283. // For all bones
  284. for(uint32_t i = 0; i < mesh.mNumBones; i++)
  285. {
  286. const aiBone& bone = *mesh.mBones[i];
  287. // for every weights of the bone
  288. for(uint32_t j = 0; j < bone.mWeightsCount; j++)
  289. {
  290. const aiVertexWeight& weigth = bone.mWeights[j];
  291. // Sanity check
  292. if(weight.mVertexId >= vertCount)
  293. {
  294. ERROR("Out of bounds vert ID");
  295. }
  296. Vm& a = vm[weight.mVertexId];
  297. // Check out of bounds
  298. if(a.bonesCount >= MAX_BONES_PER_VERTEX)
  299. {
  300. LOGW("Too many bones for vertex %d\n", weigth.mVertexId);
  301. continue;
  302. }
  303. // Write to vertex
  304. a.boneIds[a.bonesCount] = i;
  305. a.weigths[a.bonesCount] = weigth.mWeigth;
  306. ++a.bonesCount;
  307. }
  308. // Now write the file
  309. }
  310. #endif
  311. }
  312. else
  313. {
  314. uint32_t num = 0;
  315. file.write((char*)&num, sizeof(uint32_t));
  316. }
  317. }
  318. //==============================================================================
  319. static void exportSkeleton(const aiMesh& mesh)
  320. {
  321. assert(mesh.HasBones());
  322. std::string name = mesh.mName.C_Str();
  323. std::fstream file;
  324. LOGI("Exporting skeleton %s\n", name.c_str());
  325. // Open file
  326. file.open(config.outDir + name + ".skel", std::ios::out);
  327. file << xmlHeader << "\n";
  328. file << "<skeleton>\n";
  329. file << "\t<bones>\n";
  330. bool rootBoneFound = false;
  331. for(uint32_t i = 0; i < mesh.mNumBones; i++)
  332. {
  333. const aiBone& bone = *mesh.mBones[i];
  334. file << "\t\t<bone>\n";
  335. // <name>
  336. file << "\t\t\t<name>" << bone.mName.C_Str() << "</name>\n";
  337. if(strcmp(bone.mName.C_Str(), "root") == 0)
  338. {
  339. rootBoneFound = true;
  340. }
  341. // <transform>
  342. file << "\t\t\t<transform>";
  343. for(uint32_t j = 0; j < 16; j++)
  344. {
  345. file << bone.mOffsetMatrix[j] << " ";
  346. }
  347. file << "</transform>\n";
  348. file << "\t\t</bone>\n";
  349. }
  350. if(!rootBoneFound)
  351. {
  352. ERROR("There should be one bone named \"root\"\n");
  353. }
  354. file << "\t</bones>\n";
  355. file << "</skeleton>\n";
  356. }
  357. //==============================================================================
  358. static std::string getMaterialName(const aiMaterial& mtl)
  359. {
  360. aiString ainame;
  361. std::string name;
  362. if(mtl.Get(AI_MATKEY_NAME, ainame) == AI_SUCCESS)
  363. {
  364. name = ainame.C_Str();
  365. }
  366. else
  367. {
  368. ERROR("Material's name is missing\n");
  369. }
  370. return name;
  371. }
  372. //==============================================================================
  373. static void exportMaterial(
  374. const aiScene& scene,
  375. const aiMaterial& mtl,
  376. bool instanced,
  377. const std::string* name_)
  378. {
  379. std::string diffTex;
  380. std::string normTex;
  381. std::string name;
  382. if(name_)
  383. {
  384. name = *name_;
  385. }
  386. else
  387. {
  388. name = getMaterialName(mtl);
  389. }
  390. LOGI("Exporting material %s\n", name.c_str());
  391. // Diffuse texture
  392. if(mtl.GetTextureCount(aiTextureType_DIFFUSE) < 1)
  393. {
  394. ERROR("Material has no diffuse textures\n");
  395. }
  396. aiString path;
  397. if(mtl.GetTexture(aiTextureType_DIFFUSE, 0, &path) == AI_SUCCESS)
  398. {
  399. diffTex = getFilename(path.C_Str());
  400. }
  401. else
  402. {
  403. ERROR("Failed to retrieve texture\n");
  404. }
  405. // Normal texture
  406. if(mtl.GetTextureCount(aiTextureType_NORMALS) > 0)
  407. {
  408. if(mtl.GetTexture(aiTextureType_NORMALS, 0, &path) == AI_SUCCESS)
  409. {
  410. normTex = getFilename(path.C_Str());
  411. }
  412. else
  413. {
  414. ERROR("Failed to retrieve texture\n");
  415. }
  416. }
  417. // Write file
  418. static const char* diffMtlStr =
  419. #include "diffTemplateMtl.h"
  420. ;
  421. static const char* diffNormMtlStr =
  422. #include "diffNormTemplateMtl.h"
  423. ;
  424. std::fstream file;
  425. file.open(config.outDir + name + ".ankimtl", std::ios::out);
  426. // Chose the correct template
  427. std::string str;
  428. if(normTex.size() == 0)
  429. {
  430. str = diffMtlStr;
  431. }
  432. else
  433. {
  434. str = replaceAllString(diffNormMtlStr, "%normalMap%",
  435. config.texpath + normTex);
  436. }
  437. str = replaceAllString(str, "%instanced%", (instanced) ? "1" : "0");
  438. str = replaceAllString(str, "%diffuseMap%", config.texpath + diffTex);
  439. file << str;
  440. }
  441. //==============================================================================
  442. static void exportLight(
  443. const aiLight& light,
  444. std::fstream& file)
  445. {
  446. if(light.mType != aiLightSource_POINT || light.mType != aiLightSource_SPOT)
  447. {
  448. LOGW("Skipping light %s. Unsupported type\n", light.mName.C_Str());
  449. return;
  450. }
  451. file << "\t<light>\n";
  452. file << "\t\t<name>" << light.mName.C_Str() << "</name>\n";
  453. file << "\t\t<diffuseColor>"
  454. << light.mColorDiffuse[0] << " "
  455. << light.mColorDiffuse[1] << " "
  456. << light.mColorDiffuse[2] << " "
  457. << light.mColorDiffuse[3]
  458. << "</diffuseColor>\n";
  459. file << "\t\t<specularColor>"
  460. << light.mColorSpecular[0] << " "
  461. << light.mColorSpecular[1] << " "
  462. << light.mColorSpecular[2] << " "
  463. << light.mColorSpecular[3]
  464. << "</specularColor>\n";
  465. aiMatrix4x4 trf;
  466. aiMatrix4x4::Translation(light.mPosition, trf);
  467. switch(light.mType)
  468. {
  469. case aiLightSource_POINT:
  470. {
  471. file << "\t\t<type>point</type>\n";
  472. // At this point I want the radius and have the attenuation factors
  473. // att = Ac + Al*d + Aq*d^2. When d = r then att = 0.0. Also if we
  474. // assume that Ac is 0 then:
  475. // 0 = Al*r + Aq*r^2. Solving by r is easy
  476. float r = -light.mAttenuationLinear / light.mAttenuationQuadratic;
  477. file << "\t\t<radius>" << r << "</radius>\n";
  478. break;
  479. }
  480. case aiLightSource_SPOT:
  481. file << "\t\t<type>spot</type>\n";
  482. break;
  483. default:
  484. assert(0);
  485. break;
  486. }
  487. // <transform>
  488. file << "\t\t<transform>";
  489. for(uint32_t i = 0; i < 16; i++)
  490. {
  491. file << trf[i] << " ";
  492. }
  493. file << "</transform>\n";
  494. file << "\t</light>\n";
  495. }
  496. //==============================================================================
  497. static void exportModel(
  498. const aiScene& scene,
  499. const aiNode& node)
  500. {
  501. if(node.mNumMeshes == 0)
  502. {
  503. return;
  504. }
  505. std::string name = node.mName.C_Str();
  506. LOGI("Exporting model %s\n", name.c_str());
  507. std::fstream file;
  508. file.open(config.outDir + name + ".ankimdl", std::ios::out);
  509. file << xmlHeader << '\n';
  510. file << "<model>\n";
  511. file << "\t<modelPatches>\n";
  512. for(uint32_t i = 0; i < node.mNumMeshes; i++)
  513. {
  514. uint32_t meshIndex = node.mMeshes[i];
  515. const aiMesh& mesh = *scene.mMeshes[meshIndex];
  516. // start
  517. file << "\t\t<modelPatch>\n";
  518. // Write mesh
  519. file << "\t\t\t<mesh>" << config.rpath
  520. << mesh.mName.C_Str() << ".ankimesh</mesh>\n";
  521. // Write material
  522. const aiMaterial& mtl = *scene.mMaterials[mesh.mMaterialIndex];
  523. aiString mtlname;
  524. mtl.Get(AI_MATKEY_NAME, mtlname);
  525. file << "\t\t\t<material>" << config.rpath
  526. << mtlname.C_Str() << ".ankimtl</material>\n";
  527. // end
  528. file << "\t\t</modelPatch>\n";
  529. }
  530. file << "\t</modelPatches>\n";
  531. file << "</model>\n";
  532. }
  533. //==============================================================================
  534. static void exportAnimation(
  535. const aiAnimation& anim,
  536. uint32_t index,
  537. const aiScene& scene)
  538. {
  539. // Get name
  540. std::string name = anim.mName.C_Str();
  541. if(name.size() == 0)
  542. {
  543. name = std::string("animation_") + std::to_string(index);
  544. }
  545. // Find if it's skeleton animation
  546. /*bool isSkeletalAnimation = false;
  547. for(uint32_t i = 0; i < scene.mNumMeshes; i++)
  548. {
  549. const aiMesh& mesh = *scene.mMeshes[i];
  550. if(mesh.HasBones())
  551. {
  552. }
  553. }*/
  554. std::fstream file;
  555. LOGI("Exporting animation %s\n", name.c_str());
  556. file.open(config.outDir + name + ".anim", std::ios::out);
  557. file << xmlHeader << "\n";
  558. file << "<animation>\n";
  559. file << "\t<duration>" << anim.mDuration << "</duration>\n";
  560. file << "\t<channels>\n";
  561. for(uint32_t i = 0; i < anim.mNumChannels; i++)
  562. {
  563. const aiNodeAnim& nAnim = *anim.mChannels[i];
  564. file << "\t\t<channel>\n";
  565. // Name
  566. file << "\t\t\t<name>" << nAnim.mNodeName.C_Str() << "</name>\n";
  567. // Positions
  568. file << "\t\t\t<positionKeys>\n";
  569. for(uint32_t j = 0; j < nAnim.mNumPositionKeys; j++)
  570. {
  571. const aiVectorKey& key = nAnim.mPositionKeys[j];
  572. file << "\t\t\t\t<key><time>" << key.mTime << "</time>"
  573. << "<value>" << key.mValue[0] << " "
  574. << key.mValue[1] << " " << key.mValue[2] << "</value></key>\n";
  575. }
  576. file << "</positionKeys>\n";
  577. // Rotations
  578. file << "\t\t\t<rotationKeys>";
  579. for(uint32_t j = 0; j < nAnim.mNumRotationKeys; j++)
  580. {
  581. const aiQuatKey& key = nAnim.mRotationKeys[j];
  582. file << "\t\t\t\t<key><time>" << key.mTime << "</time>"
  583. << "<value>" << key.mValue.y << " " << key.mValue.z << " "
  584. << key.mValue.w << "</value></key>\n";
  585. }
  586. file << "</rotationKeys>\n";
  587. // Scale
  588. file << "\t\t\t<scalingKeys>";
  589. for(uint32_t j = 0; j < nAnim.mNumScalingKeys; j++)
  590. {
  591. const aiVectorKey& key = nAnim.mScalingKeys[j];
  592. // Note: only uniform scale
  593. file << "\t\t\t\t<key><time>" << key.mTime << "</time>"
  594. << "<value>"
  595. << ((key.mValue[0] + key.mValue[1] + key.mValue[2]) / 3.0)
  596. << "</value></key>\n";
  597. }
  598. file << "</scalingKeys>\n";
  599. file << "\t\t</channel>\n";
  600. }
  601. file << "\t</channels>\n";
  602. file << "</animation>\n";
  603. }
  604. //==============================================================================
  605. static void visitNode(const aiNode* node, const aiScene& scene)
  606. {
  607. if(node == nullptr)
  608. {
  609. return;
  610. }
  611. // For every mesh of this node
  612. for(uint32_t i = 0; i < node->mNumMeshes; i++)
  613. {
  614. uint32_t meshIndex = node->mMeshes[i];
  615. const aiMesh& mesh = *scene.mMeshes[meshIndex];
  616. // Is material set?
  617. if(config.meshes[meshIndex].mtlIndex == 0xFFFFFFFF)
  618. {
  619. // Connect mesh with material
  620. config.meshes[meshIndex].mtlIndex = mesh.mMaterialIndex;
  621. // Connect material with mesh
  622. config.materials[mesh.mMaterialIndex].meshIndices.push_back(
  623. meshIndex);
  624. }
  625. else if(config.meshes[meshIndex].mtlIndex != mesh.mMaterialIndex)
  626. {
  627. ERROR("Previous material index conflict\n");
  628. }
  629. config.meshes[meshIndex].transforms.push_back(node->mTransformation);
  630. }
  631. // Go to children
  632. for(uint32_t i = 0; i < node->mNumChildren; i++)
  633. {
  634. visitNode(node->mChildren[i], scene);
  635. }
  636. }
  637. //==============================================================================
  638. static void exportScene(const aiScene& scene)
  639. {
  640. LOGI("Exporting scene to %s\n", config.outDir.c_str());
  641. //
  642. // Open scene file
  643. //
  644. std::ofstream file;
  645. file.open(config.outDir + "master.scene");
  646. file << xmlHeader << "\n"
  647. << "<scene>\n";
  648. //
  649. // Get all the data
  650. //
  651. config.meshes.resize(scene.mNumMeshes);
  652. config.materials.resize(scene.mNumMaterials);
  653. int i = 0;
  654. for(Mesh& mesh : config.meshes)
  655. {
  656. mesh.index = i++;
  657. }
  658. i = 0;
  659. for(Material& mtl : config.materials)
  660. {
  661. mtl.index = i++;
  662. }
  663. const aiNode* node = scene.mRootNode;
  664. visitNode(node, scene);
  665. #if 0
  666. //
  667. // Export non instanced static meshes
  668. //
  669. for(uint32_t i = 0; i < config.meshes.size(); i++)
  670. {
  671. // Check if instance is one
  672. if(config.meshes[i].transforms.size() == 1)
  673. {
  674. continue;
  675. }
  676. // Export the material
  677. aiMaterial& aimtl = *scene.mMaterials[mesh.mtlIndex];
  678. std::string mtlName = getMaterialName(aimtl);
  679. exportMaterial(scene, aimtl, false, &mtlName);
  680. // Export mesh
  681. std::string meshName = std::string(scene.mMeshes[i]->mName.C_Str())
  682. + "_static_" + std::to_string(i);
  683. exportMesh(*scene.mMeshes[i], &meshName, nullptr);
  684. for(uint32_t t = 0; t < config.meshes[i].transforms.size(); t++)
  685. {
  686. std::string nname = name + "_" + std::to_string(t);
  687. exportMesh(*scene.mMeshes[i], &nname,
  688. &config.meshes[i].transforms[t], config);
  689. }
  690. }
  691. #endif
  692. //
  693. // Write the instanced meshes
  694. //
  695. for(uint32_t i = 0; i < config.meshes.size(); i++)
  696. {
  697. const Mesh& mesh = config.meshes[i];
  698. // Skip meshes that are not instance candidates
  699. if(mesh.transforms.size() == 0)
  700. {
  701. continue;
  702. }
  703. // Export the material
  704. aiMaterial& aimtl = *scene.mMaterials[mesh.mtlIndex];
  705. std::string mtlName = getMaterialName(aimtl) + "_instanced";
  706. exportMaterial(scene, aimtl, true, &mtlName);
  707. // Export mesh
  708. std::string meshName = std::string(scene.mMeshes[i]->mName.C_Str())
  709. + "_instanced_" + std::to_string(i);
  710. exportMesh(*scene.mMeshes[i], &meshName, nullptr);
  711. // Write model file
  712. std::string modelName = mtlName + "_" + std::to_string(i);
  713. {
  714. std::ofstream file;
  715. file.open(
  716. config.outDir + modelName + ".ankimdl");
  717. file << xmlHeader << "\n"
  718. << "<model>\n"
  719. << "\t<modelPatches>\n"
  720. << "\t\t<modelPatch>\n"
  721. << "\t\t\t<mesh>" << config.rpath << meshName
  722. << ".ankimesh</mesh>\n"
  723. << "\t\t\t<material>" << config.rpath << mtlName
  724. << ".ankimtl</material>\n"
  725. << "\t\t</modelPatch>\n"
  726. << "\t</modelPatches>\n"
  727. << "</model>\n";
  728. }
  729. // Node name
  730. std::string nodeName = getMaterialName(aimtl) + "_instanced_"
  731. + std::to_string(i);
  732. // Write the scene file
  733. file << "\t<modelNode>\n"
  734. << "\t\t<name>" << nodeName << "</name>\n"
  735. << "\t\t<model>" << config.rpath << modelName
  736. << ".ankimdl</model>\n"
  737. << "\t\t<instancesCount>"
  738. << mesh.transforms.size() << "</instancesCount>\n";
  739. for(uint32_t j = 0; j < mesh.transforms.size(); j++)
  740. {
  741. file << "\t\t<transform>";
  742. aiMatrix4x4 trf = toAnkiMatrix(mesh.transforms[j]);
  743. for(uint32_t a = 0; a < 4; a++)
  744. {
  745. for(uint32_t b = 0; b < 4; b++)
  746. {
  747. file << trf[a][b] << " ";
  748. }
  749. }
  750. file << "</transform>\n";
  751. }
  752. file << "\t</modelNode>\n";
  753. }
  754. #if 0
  755. // Write bmeshes
  756. for(uint32_t mtlId = 0; mtlId < config.materials.size(); mtlId++)
  757. {
  758. const Material& mtl = config.materials[mtlId];
  759. // Check if used
  760. if(mtl.meshIndices.size() < 1)
  761. {
  762. continue;
  763. }
  764. std::string name = getMaterialName(*scene.mMaterials[mtlId]) + ".bmesh";
  765. std::fstream file;
  766. file.open(config.outDir + name, std::ios::out);
  767. file << xmlHeader << "\n";
  768. file << "<bucketMesh>\n";
  769. file << "\t<meshes>\n";
  770. for(uint32_t j = 0; j < mtl.meshIndices.size(); j++)
  771. {
  772. uint32_t meshId = mtl.meshIndices[j];
  773. const Mesh& mesh = config.meshes[meshId];
  774. for(uint32_t k = 0; k < mesh.transforms.size(); k++)
  775. {
  776. file << "\t\t<mesh>" << config.rpath
  777. << "mesh_" + std::to_string(meshId) << "_"
  778. << std::to_string(k)
  779. << ".mesh</mesh>\n";
  780. }
  781. }
  782. file << "\t</meshes>\n";
  783. file << "</bucketMesh>\n";
  784. }
  785. // Create the master model
  786. std::fstream file;
  787. file.open(config.outDir + "static_geometry.mdl", std::ios::out);
  788. file << xmlHeader << "\n";
  789. file << "<model>\n";
  790. file << "\t<modelPatches>\n";
  791. for(uint32_t i = 0; i < config.materials.size(); i++)
  792. {
  793. // Check if used
  794. if(config.materials[i].meshIndices.size() < 1)
  795. {
  796. continue;
  797. }
  798. file << "\t\t<modelPatch>\n";
  799. file << "\t\t\t<bucketMesh>" << config.rpath
  800. << getMaterialName(*scene.mMaterials[i]) << ".bmesh</bucketMesh>\n";
  801. file << "\t\t\t<material>" << config.rpath
  802. << getMaterialName(*scene.mMaterials[i])
  803. << ".mtl</material>\n";
  804. file << "\t\t</modelPatch>\n";
  805. }
  806. file << "\t</modelPatches>\n";
  807. file << "</model>\n";
  808. #endif
  809. file << "</scene>\n";
  810. LOGI("Done exporting scene!\n");
  811. }
  812. //==============================================================================
  813. int main(int argc, char** argv)
  814. {
  815. try
  816. {
  817. parseConfig(argc, argv);
  818. // Load
  819. Assimp::Importer importer;
  820. const aiScene& scene = load(config.inputFname, importer);
  821. // Export
  822. exportScene(scene);
  823. }
  824. catch(std::exception& e)
  825. {
  826. std::cerr << "Exception: " << e.what() << std::endl;
  827. }
  828. }