Main.cpp 21 KB

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