polyimport.cpp 14 KB

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