Main.cpp 21 KB

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