polyimport.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. #include "polyimport.h"
  2. #include "OSBasics.h"
  3. #include "PolyObject.h"
  4. #include "physfs.h"
  5. #ifdef WIN32
  6. #include "getopt.h"
  7. #define getopt getopt_a
  8. #else
  9. #include <unistd.h>
  10. #endif
  11. using namespace Polycode;
  12. const struct aiScene* scene = NULL;
  13. bool hasWeights = false;
  14. vector<aiBone*> bones;
  15. unsigned int numBones = 0;
  16. std::vector<String> materialsInFile;
  17. bool writeNormals = false;
  18. bool writeTangents = false;
  19. bool writeColors = false;
  20. bool writeBoneWeights = false;
  21. bool writeUVs = false;
  22. bool writeSecondaryUVs = false;
  23. bool hasMaterial(String materialName) {
  24. for(int i=0; i < materialsInFile.size(); i++) {
  25. if(materialsInFile[i] == materialName) {
  26. return true;
  27. }
  28. }
  29. return false;
  30. }
  31. unsigned int addBone(aiBone *bone) {
  32. for(int i=0; i < bones.size(); i++) {
  33. if(bones[i]->mName == bone->mName)
  34. return i;
  35. }
  36. bones.push_back(bone);
  37. return bones.size()-1;
  38. }
  39. void addToMesh(String prefix, Polycode::Mesh *tmesh, const struct aiScene *sc, const struct aiNode* nd, bool swapZY, bool addSubmeshes, bool listOnly, ObjectEntry *parentSceneObject, String overrideMaterial, ObjectEntry *materialsParent, String assetPrefixPath) {
  40. int i, nIgnoredPolygons = 0;
  41. unsigned int n = 0, t;
  42. // draw all meshes assigned to this node
  43. for (; n < nd->mNumMeshes; ++n) {
  44. if(!addSubmeshes) {
  45. tmesh = new Polycode::Mesh(Mesh::TRI_MESH);
  46. tmesh->indexedMesh = true;
  47. }
  48. const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
  49. Vector3 bBox;
  50. if(listOnly) {
  51. if(!addSubmeshes) {
  52. printf("%s%s.mesh\n", prefix.c_str(), nd->mName.data);
  53. }
  54. } else {
  55. printf("Importing mesh:%s (%d vertices) (%d faces) \n", mesh->mName.data, mesh->mNumVertices, mesh->mNumFaces);
  56. }
  57. //apply_material(sc->mMaterials[mesh->mMaterialIndex]);
  58. for (t = 0; t < mesh->mNumVertices; ++t) {
  59. Vertex *vertex = new Vertex();
  60. int index = t;
  61. if(mesh->mColors[0] != NULL) {
  62. vertex->vertexColor.setColorRGBA(mesh->mColors[0][index].r, mesh->mColors[0][index].g, mesh->mColors[0][index].b, mesh->mColors[0][index].a);
  63. }
  64. if(mesh->mTangents != NULL) {
  65. if(swapZY)
  66. vertex->tangent = Vector3(mesh->mTangents[index].x, mesh->mTangents[index].z, -mesh->mTangents[index].y);
  67. else
  68. vertex->tangent = Vector3(mesh->mTangents[index].x, mesh->mTangents[index].y, mesh->mTangents[index].z);
  69. }
  70. if(mesh->mNormals != NULL) {
  71. if(swapZY)
  72. vertex->setNormal(mesh->mNormals[index].x, mesh->mNormals[index].z, -mesh->mNormals[index].y);
  73. else
  74. vertex->setNormal(mesh->mNormals[index].x, mesh->mNormals[index].y, mesh->mNormals[index].z);
  75. }
  76. if(mesh->HasTextureCoords(0))
  77. {
  78. vertex->setTexCoord(mesh->mTextureCoords[0][index].x, mesh->mTextureCoords[0][index].y);
  79. }
  80. if(mesh->HasTextureCoords(1))
  81. {
  82. vertex->setSecondaryTexCoord(mesh->mTextureCoords[1][index].x, mesh->mTextureCoords[1][index].y);
  83. }
  84. for( unsigned int a = 0; a < mesh->mNumBones; a++) {
  85. aiBone* bone = mesh->mBones[a];
  86. unsigned int boneIndex = addBone(bone);
  87. for( unsigned int b = 0; b < bone->mNumWeights; b++) {
  88. if(bone->mWeights[b].mVertexId == index) {
  89. vertex->addBoneAssignment(boneIndex, bone->mWeights[b].mWeight);
  90. hasWeights = true;
  91. }
  92. }
  93. }
  94. if(swapZY) {
  95. vertex->set(mesh->mVertices[index].x, mesh->mVertices[index].z, -mesh->mVertices[index].y);
  96. } else {
  97. vertex->set(mesh->mVertices[index].x, mesh->mVertices[index].y, mesh->mVertices[index].z);
  98. }
  99. if(fabs(vertex->x) > bBox.x) {
  100. bBox.x = fabs(vertex->x);
  101. }
  102. if(fabs(vertex->y) > bBox.y) {
  103. bBox.y = fabs(vertex->y);
  104. }
  105. if(fabs(vertex->z) > bBox.z) {
  106. bBox.z = fabs(vertex->z);
  107. }
  108. tmesh->addVertex(vertex);
  109. }
  110. for (t = 0; t < mesh->mNumFaces; ++t) {
  111. const struct aiFace* face = &mesh->mFaces[t];
  112. if (face->mNumIndices != 3) {
  113. nIgnoredPolygons++;
  114. continue;
  115. }
  116. for(i = 0; i < face->mNumIndices; i++) {
  117. int index = face->mIndices[i];
  118. tmesh->addIndex(index);
  119. }
  120. }
  121. if(!addSubmeshes && !listOnly) {
  122. String fileNameMesh = prefix+String(nd->mName.data)+".mesh";
  123. OSFILE *outFile = OSBasics::open(fileNameMesh.c_str(), "wb");
  124. tmesh->saveToFile(outFile, writeNormals, writeTangents, writeColors, writeBoneWeights, writeUVs, writeSecondaryUVs);
  125. OSBasics::close(outFile);
  126. delete tmesh;
  127. ObjectEntry *meshEntry = parentSceneObject->addChild("child");
  128. meshEntry->addChild("id", String(nd->mName.data));
  129. meshEntry->addChild("tags", "");
  130. meshEntry->addChild("type", "SceneMesh");
  131. meshEntry->addChild("cR", "1");
  132. meshEntry->addChild("cG", "1");
  133. meshEntry->addChild("cB", "1");
  134. meshEntry->addChild("cA", "1");
  135. meshEntry->addChild("blendMode", "0");
  136. aiVector3D p;
  137. aiVector3D s;
  138. aiQuaternion r;
  139. nd->mTransformation.Decompose(s, r, p);
  140. meshEntry->addChild("sX", s.x);
  141. if(swapZY) {
  142. meshEntry->addChild("sY", s.z);
  143. meshEntry->addChild("sZ", s.y);
  144. } else {
  145. meshEntry->addChild("sY", s.y);
  146. meshEntry->addChild("sZ", s.z);
  147. }
  148. meshEntry->addChild("rX", r.x);
  149. if(swapZY) {
  150. meshEntry->addChild("rY", r.z);
  151. meshEntry->addChild("rZ", -r.y);
  152. } else {
  153. meshEntry->addChild("rY", r.y);
  154. meshEntry->addChild("rZ", r.z);
  155. }
  156. meshEntry->addChild("rW", r.w);
  157. meshEntry->addChild("pX", p.x);
  158. if(swapZY) {
  159. meshEntry->addChild("pY", p.z);
  160. meshEntry->addChild("pZ", -p.y);
  161. } else{
  162. meshEntry->addChild("pY", p.y);
  163. meshEntry->addChild("pZ", p.z);
  164. }
  165. bBox = bBox * 2.0;
  166. if(bBox.x == 0.0) {
  167. bBox.x = 0.001;
  168. }
  169. if(bBox.y == 0.0) {
  170. bBox.y = 0.001;
  171. }
  172. if(bBox.z == 0.0) {
  173. bBox.z = 0.001;
  174. }
  175. meshEntry->addChild("bbX", bBox.x);
  176. meshEntry->addChild("bbY", bBox.y);
  177. meshEntry->addChild("bbZ", bBox.z);
  178. ObjectEntry *sceneMeshEntry = meshEntry->addChild("SceneMesh");
  179. sceneMeshEntry->addChild("file", assetPrefixPath+fileNameMesh);
  180. String materialName = "Default";
  181. int materialIndex = mesh->mMaterialIndex;
  182. if(materialIndex < scene->mNumMaterials) {
  183. aiString name;
  184. scene->mMaterials[materialIndex]->Get(AI_MATKEY_NAME,name);
  185. if(name.length > 0) {
  186. materialName = String(name.data);
  187. }
  188. }
  189. if(materialsParent && materialName != "Default") {
  190. if(!hasMaterial(materialName)) {
  191. ObjectEntry *materialEntry = materialsParent->addChild("material");
  192. materialEntry->addChild("name", materialName);
  193. materialEntry->addChild("blendingMode", 0);
  194. materialEntry->addChild("blendingMode", 0);
  195. ObjectEntry *shaderEntry = materialEntry->addChild("shader");
  196. shaderEntry->addChild("name", "DefaultShaderNoTexture");
  197. materialsInFile.push_back(materialName);
  198. }
  199. }
  200. if(overrideMaterial != "") {
  201. sceneMeshEntry->addChild("material", overrideMaterial);
  202. } else {
  203. sceneMeshEntry->addChild("material", materialName);
  204. }
  205. }
  206. if (nIgnoredPolygons) {
  207. printf("Ignored %d non-triangular polygons\n", nIgnoredPolygons);
  208. }
  209. }
  210. // draw all children
  211. for (n = 0; n < nd->mNumChildren; ++n) {
  212. addToMesh(prefix, tmesh, sc, nd->mChildren[n], swapZY, addSubmeshes, listOnly, parentSceneObject, overrideMaterial, materialsParent, assetPrefixPath);
  213. }
  214. }
  215. int getBoneID(aiString name) {
  216. for(int i=0; i < bones.size(); i++) {
  217. if(bones[i]->mName == name) {
  218. return i;
  219. }
  220. }
  221. return 666;
  222. }
  223. void addToISkeleton(ISkeleton *skel, IBone *parent, const struct aiScene *sc, const struct aiNode* nd) {
  224. IBone *bone = new IBone();
  225. bone->parent = parent;
  226. bone->name = nd->mName;
  227. bone->t = nd->mTransformation;
  228. for(int i=0; i < bones.size(); i++) {
  229. if(bones[i]->mName == bone->name) {
  230. bone->bindMatrix = bones[i]->mOffsetMatrix;
  231. }
  232. }
  233. for (int n = 0; n < nd->mNumChildren; ++n) {
  234. addToISkeleton(skel, bone, sc, nd->mChildren[n]);
  235. }
  236. skel->addIBone(bone, getBoneID(bone->name));
  237. }
  238. int exportToFile(String prefix, bool swapZY, bool addSubmeshes, bool listOnly, bool exportEntity, bool generateMaterialFile, String overrideMaterial, String assetPrefixPath, String baseFileName) {
  239. Object materialObject;
  240. ObjectEntry *materialsParent = NULL;;
  241. if(generateMaterialFile) {
  242. materialObject.root.name = "polycode";
  243. materialsParent = materialObject.root.addChild("materials");
  244. }
  245. Object sceneObject;
  246. sceneObject.root.name = "entity";
  247. sceneObject.root.addChild("version", 2);
  248. ObjectEntry *parentEntry = sceneObject.root.addChild("root");
  249. parentEntry->addChild("id", "");
  250. parentEntry->addChild("tags", "");
  251. parentEntry->addChild("type", "Entity");
  252. parentEntry->addChild("cR", "1");
  253. parentEntry->addChild("cG", "1");
  254. parentEntry->addChild("cB", "1");
  255. parentEntry->addChild("cA", "1");
  256. parentEntry->addChild("blendMode", "0");
  257. parentEntry->addChild("sX", 1.0);
  258. parentEntry->addChild("sY", 1.0);
  259. parentEntry->addChild("sZ", 1.0);
  260. parentEntry->addChild("rX", 0.0);
  261. parentEntry->addChild("rY", 0.0);
  262. parentEntry->addChild("rZ", 0.0);
  263. parentEntry->addChild("rW", 1.0);
  264. parentEntry->addChild("pX", 0.0);
  265. parentEntry->addChild("pY", 0.0);
  266. parentEntry->addChild("pZ", 0.0);
  267. parentEntry->addChild("bbX", 0.0);
  268. parentEntry->addChild("bbY", 0.0);
  269. parentEntry->addChild("bbZ", 0.0);
  270. ObjectEntry *children = parentEntry->addChild("children");
  271. Polycode::Mesh *mesh = new Polycode::Mesh(Mesh::TRI_MESH);
  272. mesh->indexedMesh = true;
  273. addToMesh(prefix, mesh, scene, scene->mRootNode, swapZY, addSubmeshes, listOnly, children, overrideMaterial, materialsParent, assetPrefixPath);
  274. if(addSubmeshes) {
  275. String fileNameMesh;
  276. if(prefix != "") {
  277. fileNameMesh = prefix+".mesh";
  278. } else {
  279. fileNameMesh = "out.mesh";
  280. }
  281. if(listOnly) {
  282. printf("%s\n", fileNameMesh.c_str());
  283. } else {
  284. OSFILE *outFile = OSBasics::open(fileNameMesh.c_str(), "wb");
  285. mesh->saveToFile(outFile, writeNormals, writeTangents, writeColors, writeBoneWeights, writeUVs, writeSecondaryUVs);
  286. OSBasics::close(outFile);
  287. }
  288. }
  289. if(hasWeights) {
  290. if(listOnly) {
  291. printf("%s.skeleton\n", prefix.c_str());
  292. } else {
  293. printf("Mesh has weights, exporting skeleton...\n");
  294. }
  295. String fileNameSkel;
  296. if(prefix != "") {
  297. fileNameSkel = prefix+".skeleton";
  298. } else {
  299. fileNameSkel = "out.skeleton";
  300. }
  301. ISkeleton *skeleton = new ISkeleton();
  302. for (int n = 0; n < scene->mRootNode->mNumChildren; ++n) {
  303. if(scene->mRootNode->mChildren[n]->mNumChildren > 0) {
  304. addToISkeleton(skeleton, NULL, scene, scene->mRootNode->mChildren[n]);
  305. }
  306. }
  307. if(scene->HasAnimations()) {
  308. printf("Importing animations...\n");
  309. for(int i=0; i < scene->mNumAnimations;i++) {
  310. aiAnimation *a = scene->mAnimations[i];
  311. if(listOnly) {
  312. printf("%s%s.anim\n", prefix.c_str(), a->mName.data);
  313. } else {
  314. printf("Importing '%s' (%d tracks)\n", a->mName.data, a->mNumChannels);
  315. }
  316. IAnimation *anim = new IAnimation();
  317. anim->tps = a->mTicksPerSecond;
  318. anim->name = a->mName.data;
  319. anim->numTracks = a->mNumChannels;
  320. anim->length = a->mDuration/a->mTicksPerSecond;
  321. for(int c=0; c < a->mNumChannels; c++) {
  322. aiNodeAnim *nodeAnim = a->mChannels[c];
  323. ITrack *track = new ITrack();
  324. track->nodeAnim = nodeAnim;
  325. anim->tracks.push_back(track);
  326. }
  327. skeleton->addAnimation(anim);
  328. }
  329. } else {
  330. printf("No animations in file...\n");
  331. }
  332. if(!listOnly) {
  333. skeleton->saveToFile(fileNameSkel.c_str(), swapZY);
  334. }
  335. } else {
  336. if(!listOnly) {
  337. printf("No weight data, skipping skeleton export...\n");
  338. }
  339. }
  340. String matFileName = baseFileName+".mat";
  341. if(!listOnly && materialsParent) {
  342. materialObject.saveToXML(matFileName);
  343. }
  344. if(!listOnly && exportEntity) {
  345. if(materialsParent) {
  346. ObjectEntry *settings = sceneObject.root.addChild("settings");
  347. ObjectEntry *matFiles = settings->addChild("matFiles");
  348. ObjectEntry *matFile = matFiles->addChild("matFile");
  349. matFile->addChild("path", assetPrefixPath+matFileName);
  350. }
  351. String entityFileName = baseFileName+".entity";
  352. sceneObject.saveToXML(entityFileName);
  353. }
  354. if(mesh) {
  355. delete mesh;
  356. }
  357. return 1;
  358. }
  359. int main(int argc, char **argv) {
  360. bool argsValid = true;
  361. bool showHelp = false;
  362. bool swapZYAxis = false;
  363. bool generateTangents = false;
  364. bool addSubmeshes = false;
  365. bool listOnly = false;
  366. bool showAssimpDebug = false;
  367. bool generateNormals = false;
  368. bool exportEntity = false;
  369. bool generateMaterialFile = false;
  370. String overrideMaterial;
  371. String prefix;
  372. String assetPrefixPath;
  373. int opt;
  374. while ((opt = getopt(argc, argv, "engcwuvadlhp:stmfo:x:")) != -1) {
  375. switch ((char)opt) {
  376. case 'e':
  377. exportEntity = true;
  378. break;
  379. case 'n':
  380. writeNormals = true;
  381. break;
  382. case 'g':
  383. writeTangents = true;
  384. break;
  385. case 'c':
  386. writeColors = true;
  387. break;
  388. case 'w':
  389. writeBoneWeights = true;
  390. break;
  391. case 'u':
  392. writeUVs = true;
  393. break;
  394. case 'v':
  395. writeSecondaryUVs = true;
  396. break;
  397. case 's':
  398. swapZYAxis = true;
  399. break;
  400. case 't':
  401. generateTangents = true;
  402. break;
  403. case 'm':
  404. generateNormals = true;
  405. break;
  406. case 'a':
  407. addSubmeshes = true;
  408. break;
  409. case 'd':
  410. showAssimpDebug = true;
  411. break;
  412. case 'l':
  413. listOnly = true;
  414. break;
  415. case 'p':
  416. prefix = String(optarg);
  417. break;
  418. case 'h':
  419. showHelp = true;
  420. break;
  421. case 'f':
  422. generateMaterialFile = true;
  423. break;
  424. case 'o':
  425. overrideMaterial = String(optarg);
  426. break;
  427. case 'x':
  428. assetPrefixPath = String(optarg)+"/";
  429. break;
  430. default:
  431. argsValid = false;
  432. break;
  433. }
  434. }
  435. if(listOnly && argc < 3) {
  436. argsValid = false;
  437. }
  438. if(!listOnly) {
  439. printf("Polycode import tool v"POLYCODE_VERSION_STRING"\n");
  440. }
  441. if(!argsValid) {
  442. printf("Invalid arguments! Run with -h to see available options.\n\n");
  443. return 0;
  444. }
  445. if(showHelp || argc < 2) {
  446. printf("usage: polyimport [-adhlstngcwuvmef] [-o override_material] [-p output_prefix] [-x asset_path] source_file\n\n");
  447. printf("Misc options:\n");
  448. printf("d: Show Assimp debug info.\n");
  449. printf("h: Show this help.\n");
  450. printf("l: List output files, but do not convert.\n");
  451. printf("p: Specify a file prefix for exported files.\n");
  452. printf("\nMesh import options:\n");
  453. printf("a: Add all meshes to a single mesh.\n");
  454. printf("s: Swap Z/Y axis (e.g. import from Blender)\n");
  455. printf("m: Generate normals.\n");
  456. printf("t: Generate tangents.\n");
  457. printf("\nMesh export options:\n");
  458. printf("n: Export normals\n");
  459. printf("g: Export tangents\n");
  460. printf("c: Export colors\n");
  461. printf("w: Export bone weights\n");
  462. printf("u: Export UV coordinates\n");
  463. printf("v: Export secondary UV coordinates\n");
  464. printf("\nEntity export options:\n");
  465. printf("e: Export entity scene\n");
  466. printf("f: Generate material file\n");
  467. printf("o: Specify override material.\n");
  468. printf("x: Specify asset prefix path.\n");
  469. printf("\n");
  470. return 0;
  471. }
  472. PHYSFS_init(argv[0]);
  473. if(showAssimpDebug) {
  474. struct aiLogStream stream;
  475. stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL);
  476. aiAttachLogStream(&stream);
  477. }
  478. int inputArg = argc-1;
  479. if(!listOnly) {
  480. printf("Loading %s...\n", argv[inputArg]);
  481. }
  482. String baseFileName = String(argv[inputArg]);
  483. std::vector<String> parts = baseFileName.split("/");
  484. if(parts.size() > 1) {
  485. baseFileName = parts[parts.size()-1];
  486. }
  487. baseFileName = baseFileName.substr(0, baseFileName.find_last_of("."));
  488. scene = aiImportFile(argv[inputArg], aiProcess_JoinIdenticalVertices|
  489. aiProcess_Triangulate);
  490. if(scene) {
  491. if(generateTangents && !listOnly) {
  492. aiApplyPostProcessing(scene, aiProcess_CalcTangentSpace);
  493. }
  494. if(generateNormals && !listOnly) {
  495. aiApplyPostProcessing(scene, aiProcess_GenSmoothNormals);
  496. }
  497. exportToFile(prefix, swapZYAxis, addSubmeshes, listOnly, exportEntity, generateMaterialFile, overrideMaterial, assetPrefixPath, baseFileName);
  498. } else {
  499. printf("Error opening scene (%s)\n", aiGetErrorString());
  500. }
  501. aiReleaseImport(scene);
  502. return 1;
  503. }