assimp.h 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109
  1. /*
  2. * m3dconv/assimp.h
  3. *
  4. * Copyright (C) 2019 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief simple 3D model to M3D converter Assimp-related code
  27. * https://gitlab.com/bztsrc/model3d
  28. *
  29. */
  30. #include <assimp/cimport.h>
  31. #include <assimp/scene.h>
  32. #include <assimp/postprocess.h>
  33. #ifdef EXPINLINE
  34. #include <png.h>
  35. #include <libimagequant.h>
  36. #endif
  37. unsigned char *readfile(char *fn, unsigned int *size);
  38. /*** Assimp specific code. BEWARE, DRAGONS LIVE HERE ***/
  39. const struct aiScene *scene = NULL;
  40. typedef struct {
  41. char *pKey;
  42. unsigned int type;
  43. unsigned int index;
  44. } aiMatProp;
  45. /* --- Scalar Properties --- !!!!! must match m3d_propertytypes !!!!! */
  46. static aiMatProp aiProps[] = {
  47. { AI_MATKEY_COLOR_DIFFUSE }, /* m3dp_Kd */
  48. { AI_MATKEY_COLOR_AMBIENT }, /* m3dp_Ka */
  49. { AI_MATKEY_COLOR_SPECULAR }, /* m3dp_Ks */
  50. { AI_MATKEY_SHININESS }, /* m3dp_Ns */
  51. { AI_MATKEY_COLOR_EMISSIVE }, /* m3dp_Ke */
  52. { AI_MATKEY_COLOR_REFLECTIVE }, /* m3dp_Tf */
  53. { AI_MATKEY_BUMPSCALING }, /* m3dp_Km */
  54. { AI_MATKEY_OPACITY }, /* m3dp_d */
  55. { AI_MATKEY_SHADING_MODEL }, /* m3dp_il */
  56. { NULL, 0, 0 }, /* m3dp_Pr */
  57. { AI_MATKEY_REFLECTIVITY }, /* m3dp_Pm */
  58. { NULL, 0, 0 }, /* m3dp_Ps */
  59. { AI_MATKEY_REFRACTI }, /* m3dp_Ni */
  60. { NULL, 0, 0 },
  61. { NULL, 0, 0 },
  62. { NULL, 0, 0 },
  63. { NULL, 0, 0 }
  64. };
  65. /* --- Texture Map Properties --- !!!!! must match m3d_propertytypes !!!!! */
  66. static aiMatProp aiTxProps[] = {
  67. { AI_MATKEY_TEXTURE_DIFFUSE(0) }, /* m3dp_map_Kd */
  68. { AI_MATKEY_TEXTURE_AMBIENT(0) }, /* m3dp_map_Ka */
  69. { AI_MATKEY_TEXTURE_SPECULAR(0) }, /* m3dp_map_Ks */
  70. { AI_MATKEY_TEXTURE_SHININESS(0) }, /* m3dp_map_Ns */
  71. { AI_MATKEY_TEXTURE_EMISSIVE(0) }, /* m3dp_map_Ke */
  72. { NULL, 0, 0 }, /* m3dp_map_Tf */
  73. { AI_MATKEY_TEXTURE_HEIGHT(0) }, /* m3dp_bump */
  74. { AI_MATKEY_TEXTURE_OPACITY(0) }, /* m3dp_map_d */
  75. { AI_MATKEY_TEXTURE_REFLECTION(0) }, /* m3dp_refl */
  76. { AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE_ROUGHNESS,0) },/* m3dp_map_Pr */
  77. { AI_MATKEY_TEXTURE(aiTextureType_METALNESS,0) }, /* m3dp_map_Pm */
  78. { NULL, 0, 0 }, /* m3dp_map_Ps */
  79. { AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION,0) },/* m3dp_map_Ni */
  80. { NULL, 0, 0 },
  81. { NULL, 0, 0 },
  82. { NULL, 0, 0 },
  83. { NULL, 0, 0 }
  84. };
  85. typedef struct {
  86. struct aiNode *node;
  87. struct aiMatrix4x4 mt;
  88. uint32_t parent;
  89. M3D_INDEX boneid;
  90. M3D_INDEX pos;
  91. M3D_INDEX ori;
  92. M3D_INDEX lpos;
  93. M3D_INDEX lori;
  94. int isbone;
  95. } node_t;
  96. node_t *nodes = NULL;
  97. unsigned int numnodes = 0;
  98. unsigned int numskeleton = 0;
  99. typedef struct {
  100. unsigned int length;
  101. unsigned char *data;
  102. } pngbuf_t;
  103. /* helpers for debugging */
  104. void _assimp_nodedump(struct aiNode *node, int l)
  105. {
  106. unsigned int i;
  107. if(!node) return;
  108. for(i=0;(int)i < l; i++) printf(" ");
  109. printf("node '%s'\n", node->mName.data);
  110. _assimp_prt(&node->mTransformation);
  111. for (i = 0; i < node->mNumChildren; i++)
  112. _assimp_nodedump(node->mChildren[i], l+1);
  113. }
  114. /**
  115. * Add a material property
  116. */
  117. void _assimp_addprop(m3dm_t *m, uint8_t type, uint32_t value)
  118. {
  119. unsigned int i;
  120. if(type < 128 && !value) return;
  121. i = m->numprop++;
  122. m->prop = (m3dp_t*)realloc(m->prop, m->numprop * sizeof(m3dp_t));
  123. if(!m->prop) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  124. m->prop[i].type = type;
  125. m->prop[i].value.num = value;
  126. }
  127. /**
  128. * Convert colors
  129. */
  130. static uint32_t _assimp_color(struct aiColor4D *c)
  131. {
  132. return ((uint8_t)(c->a*255) << 24L) |
  133. ((uint8_t)(c->b*255) << 16L) |
  134. ((uint8_t)(c->g*255) << 8L) |
  135. ((uint8_t)(c->r*255) << 0L);
  136. }
  137. /**
  138. * Transform bone relative matrix to world matrix
  139. */
  140. void _assimp_toworld(struct aiMatrix4x4 *result, struct aiNode *node)
  141. {
  142. if(node->mParent) {
  143. _assimp_toworld(result, node->mParent);
  144. aiMultiplyMatrix4(result, &node->mTransformation);
  145. } else {
  146. *result = node->mTransformation;
  147. }
  148. }
  149. /**
  150. * Convert node-tree
  151. */
  152. void _assimp_nodes(struct aiNode *node)
  153. {
  154. unsigned int i;
  155. if(!node) return;
  156. nodes = (node_t*)realloc(nodes, (numnodes+1) * sizeof(node_t));
  157. if(!nodes) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  158. memset(&nodes[numnodes], 0, sizeof(node_t));
  159. nodes[numnodes].node = node;
  160. memcpy(&nodes[numnodes].mt, &node->mTransformation, sizeof(struct aiMatrix4x4));
  161. _assimp_fixmat(&nodes[numnodes].mt);
  162. nodes[numnodes].parent = nodes[numnodes].boneid = -1U;
  163. numnodes++;
  164. for (i = 0; i < node->mNumChildren; i++)
  165. _assimp_nodes(node->mChildren[i]);
  166. }
  167. /**
  168. * Fix the node tree...
  169. */
  170. void _assimp_fixnodes()
  171. {
  172. struct aiMesh *mesh;
  173. struct aiNode *node;
  174. struct aiNode *bone;
  175. /*
  176. struct aiAnimation *an;
  177. struct aiNodeAnim *na;
  178. struct aiVector3D scaling, pos;
  179. struct aiQuaternion rot;
  180. int x, y, z, w;
  181. */
  182. unsigned int i, j, k, l, m;
  183. for(m = 0; m < numnodes; m++) {
  184. node = nodes[m].node;
  185. for(i = 0; i < node->mNumMeshes; i++) {
  186. mesh = scene->mMeshes[node->mMeshes[i]];
  187. /* mark nodes that are listed here as bones */
  188. for(j = 0; j < mesh->mNumBones; j++)
  189. for(k = 0; k < numnodes; k++)
  190. if(!strcmp(nodes[k].node->mName.data, mesh->mBones[j]->mName.data)) {
  191. for(bone = nodes[k].node; bone != NULL; bone = bone->mParent) {
  192. for(l = 0; l < numnodes; l++) if(nodes[l].node == bone) break;
  193. if(nodes[l].node != scene->mRootNode) {
  194. if(!nodes[l].isbone) numskeleton++;
  195. nodes[l].isbone = 1;
  196. }
  197. }
  198. break;
  199. }
  200. }
  201. }
  202. /*
  203. for(m = 0; m < scene->mNumAnimations; m++) {
  204. an = scene->mAnimations[m];
  205. if(an->mTicksPerSecond <= 0.0) an->mTicksPerSecond = 30.0;
  206. for(j = 0; j < an->mNumChannels; j++) {
  207. na = an->mChannels[j];
  208. for(l = 0; l < numnodes; l++)
  209. if(!strcmp(nodes[l].node->mName.data, na->mNodeName.data)) {
  210. if(!nodes[l].isbone) {
  211. node = nodes[l].node;
  212. aiDecomposeMatrix(&node->mTransformation, &scaling, &rot, &pos);
  213. if(na->mNumPositionKeys) {
  214. memcpy(&pos, &na->mPositionKeys[0].mValue, sizeof(struct aiVector3D));
  215. x = (int)(pos.x * 1000000);
  216. y = (int)(pos.y * 1000000);
  217. z = (int)(pos.z * 1000000);
  218. for(k = 0; k < na->mNumPositionKeys; k++) {
  219. if( (int)(na->mPositionKeys[k].mValue.x * 1000000) != x ||
  220. (int)(na->mPositionKeys[k].mValue.y * 1000000) != y ||
  221. (int)(na->mPositionKeys[k].mValue.z * 1000000) != z) {
  222. printf("ERROR: mesh '%s' position transform cannot be converted as a skeletal animation\n",
  223. na->mNodeName.data);
  224. break;
  225. }
  226. }
  227. }
  228. if(na->mNumRotationKeys) {
  229. memcpy(&rot, &na->mRotationKeys[0].mValue, sizeof(struct aiQuaternion));
  230. x = (int)(rot.x * 1000000);
  231. y = (int)(rot.y * 1000000);
  232. z = (int)(rot.z * 1000000);
  233. w = (int)(rot.w * 1000000);
  234. for(k = 0; k < na->mNumRotationKeys; k++)
  235. if( (int)(na->mRotationKeys[k].mValue.x * 1000000) != x ||
  236. (int)(na->mRotationKeys[k].mValue.y * 1000000) != y ||
  237. (int)(na->mRotationKeys[k].mValue.z * 1000000) != z ||
  238. (int)(na->mRotationKeys[k].mValue.w * 1000000) != w) {
  239. printf("ERROR: mesh '%s' rotation transform cannot be converted as a skeletal animation\n",
  240. na->mNodeName.data);
  241. break;
  242. }
  243. }
  244. if(na->mNumScalingKeys) {
  245. memcpy(&scaling, &na->mScalingKeys[0].mValue, sizeof(struct aiVector3D));
  246. x = (int)(scaling.x * 1000000);
  247. y = (int)(scaling.y * 1000000);
  248. z = (int)(scaling.z * 1000000);
  249. for(k = 0; k < na->mNumScalingKeys; k++)
  250. if( (int)(na->mScalingKeys[k].mValue.x * 1000000) != x ||
  251. (int)(na->mScalingKeys[k].mValue.y * 1000000) != y ||
  252. (int)(na->mScalingKeys[k].mValue.z * 1000000) != z) {
  253. printf("ERROR: mesh '%s' scaling transform cannot be converted as a skeletal animation\n",
  254. na->mNodeName.data);
  255. break;
  256. }
  257. }
  258. printf("fixing %s %g,%g,%g %g,%g,%g,%g\n",node->mName.data,pos.x,pos.y,pos.z,rot.x,rot.y,rot.z,rot.w);
  259. _assimp_prt(&node->mTransformation);
  260. _assimp_composematrix(&node->mTransformation, &pos, &rot, &scaling);
  261. }
  262. break;
  263. }
  264. }
  265. }
  266. */
  267. }
  268. #ifdef EXPINLINE
  269. /* png helpers */
  270. static void _assimp_pngerr(png_structp png_ptr, png_const_charp str)
  271. {
  272. pngbuf_t *pngbuf = (pngbuf_t*)png_get_io_ptr(png_ptr);
  273. fprintf(stderr, "m3dconv: png compression failed: %s\n", str);
  274. if(pngbuf && pngbuf->data) { free(pngbuf->data); pngbuf->data = NULL; }
  275. pngbuf->length = 0;
  276. }
  277. static void _assimp_pngwr(png_structp png_ptr, png_bytep data, png_size_t length)
  278. {
  279. unsigned int i;
  280. pngbuf_t *pngbuf = (pngbuf_t*)png_get_io_ptr(png_ptr);
  281. i = pngbuf->length; pngbuf->length += length;
  282. pngbuf->data = (unsigned char*)realloc(pngbuf->data, pngbuf->length);
  283. if(!pngbuf->data) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  284. memcpy(pngbuf->data + i, data, length);
  285. }
  286. /**
  287. * Get inlined textures
  288. */
  289. void _assimp_textures(m3d_t *m3d)
  290. {
  291. unsigned int i, j, k, l, o, ct;
  292. uint8_t *buff;
  293. char *bn;
  294. struct aiTexture *tx;
  295. png_structp png_ptr;
  296. png_infop info_ptr;
  297. png_color pal[256];
  298. png_byte trns[256];
  299. pngbuf_t pngbuf;
  300. liq_attr *handle;
  301. liq_image *input_image;
  302. liq_result *quantization_result;
  303. const liq_palette *liqpalette;
  304. for(i = 0; i < scene->mNumTextures; i++) {
  305. tx = scene->mTextures[i];
  306. if(!tx->mWidth || !tx->mHeight || !tx->pcData) continue;
  307. bn = strrchr((const char*)&tx->mFilename.data, '.');
  308. if(bn) *bn = 0;
  309. bn = strrchr((const char*)&tx->mFilename.data, '/');
  310. if(!bn) bn = strrchr((const char*)&tx->mFilename.data, '\\');
  311. if(!bn) bn = tx->mFilename.data; else bn++;
  312. bn = _m3d_safestr(bn, 0);
  313. for(l = 0, o = -1U; l < m3d->numtexture; l++)
  314. if(!strcmp(bn, m3d->texture[l].name)) { o = l; free(bn); break; }
  315. if(o != -1U) continue;
  316. o = m3d->numtexture++;
  317. m3d->texture = (m3dtx_t*)realloc(m3d->texture, m3d->numtexture * sizeof(m3dtx_t));
  318. if(!m3d->texture) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  319. m3d->texture[o].name = bn;
  320. m3d->texture[o].w = 0;
  321. m3d->texture[o].h = 0;
  322. m3d->texture[o].d = NULL;
  323. if(storeinline) {
  324. l = 1; ct = PNG_COLOR_TYPE_GRAY;
  325. if(!strcmp(tx->achFormatHint, "rgba8008")) { l = 2; ct = PNG_COLOR_TYPE_GRAY_ALPHA; } else
  326. if(!strcmp(tx->achFormatHint, "rgba0808")) { l = 2; ct = PNG_COLOR_TYPE_GRAY_ALPHA; } else
  327. if(!strcmp(tx->achFormatHint, "rgba0088")) { l = 2; ct = PNG_COLOR_TYPE_GRAY_ALPHA; } else
  328. if(!strcmp(tx->achFormatHint, "rgba8880")) { l = 3; ct = PNG_COLOR_TYPE_RGB_ALPHA; } else
  329. if(!strcmp(tx->achFormatHint, "rgba8888")) { l = 4; ct = PNG_COLOR_TYPE_RGB_ALPHA; }
  330. buff = (uint8_t*)malloc(tx->mWidth * tx->mHeight * l);
  331. if(!buff) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  332. for(j = k = 0; j < tx->mWidth * tx->mHeight; j++)
  333. switch(l) {
  334. case 1:
  335. buff[k++] = tx->achFormatHint[4] == '8' ? tx->pcData[j].r :
  336. (tx->achFormatHint[5] == '8' ? tx->pcData[j].g :tx->pcData[j].b);
  337. break;
  338. case 2:
  339. buff[k++] = tx->achFormatHint[4] == '8' ? tx->pcData[j].r :
  340. (tx->achFormatHint[5] == '8' ? tx->pcData[j].g :tx->pcData[j].b);
  341. buff[k++] = tx->pcData[j].a;
  342. break;
  343. case 3:
  344. buff[k++] = tx->pcData[j].r; buff[k++] = tx->pcData[j].g;
  345. buff[k++] = tx->pcData[j].b; buff[k++] = 255;
  346. break;
  347. case 4:
  348. buff[k++] = tx->pcData[j].r; buff[k++] = tx->pcData[j].g;
  349. buff[k++] = tx->pcData[j].b; buff[k++] = tx->pcData[j].a;
  350. break;
  351. }
  352. png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, _assimp_pngerr, NULL);
  353. if(!png_ptr) {
  354. _assimp_pngerr(NULL, "png_create_write_struct failed");
  355. free(buff);
  356. continue;
  357. }
  358. info_ptr = png_create_info_struct(png_ptr);
  359. if(!info_ptr) {
  360. _assimp_pngerr(NULL, "png_create_info_struct failed");
  361. png_destroy_write_struct(&png_ptr, NULL);
  362. free(buff);
  363. continue;
  364. }
  365. if(setjmp(png_jmpbuf(png_ptr))) {
  366. _assimp_pngerr(NULL, "unknown error happened");
  367. png_destroy_write_struct(&png_ptr, &info_ptr);
  368. free(buff);
  369. if(pngbuf.data) free(pngbuf.data);
  370. continue;
  371. }
  372. memset(&pngbuf, 0, sizeof(pngbuf_t));
  373. png_set_write_fn(png_ptr, &pngbuf, _assimp_pngwr, NULL);
  374. png_set_compression_level(png_ptr, 9);
  375. png_set_compression_mem_level(png_ptr, 5);
  376. png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_VALUE_NONE);
  377. if(l > 2) {
  378. /* why can't people design a simple and clean API? This liq is braindead too. */
  379. handle = liq_attr_create();
  380. input_image = liq_image_create_rgba(handle, buff, tx->mWidth, tx->mHeight, 0);
  381. if (liq_image_quantize(input_image, handle, &quantization_result) == LIQ_OK) {
  382. liq_set_dithering_level(quantization_result, 1.0);
  383. liqpalette = liq_get_palette(quantization_result);
  384. liq_write_remapped_image(quantization_result, input_image, buff, tx->mWidth * tx->mHeight);
  385. ct = PNG_COLOR_TYPE_PALETTE;
  386. for(j = k = 0; j < liqpalette->count; j++) {
  387. pal[j].red = liqpalette->entries[j].r;
  388. pal[j].green = liqpalette->entries[j].g;
  389. pal[j].blue = liqpalette->entries[j].b;
  390. trns[j] = liqpalette->entries[j].a;
  391. if(trns[j] < 255) k++;
  392. }
  393. png_set_PLTE(png_ptr, info_ptr, pal, liqpalette->count);
  394. if(k)
  395. png_set_tRNS(png_ptr, info_ptr, trns, k, NULL);
  396. }
  397. }
  398. png_set_IHDR(png_ptr, info_ptr, tx->mWidth, tx->mHeight, 8, ct, PNG_INTERLACE_NONE,
  399. PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE);
  400. png_write_info(png_ptr, info_ptr);
  401. png_set_packing(png_ptr);
  402. png_write_image(png_ptr, (png_bytepp)&buff);
  403. png_write_end(png_ptr, info_ptr);
  404. png_destroy_write_struct(&png_ptr, &info_ptr);
  405. free(buff);
  406. if(pngbuf.length && pngbuf.data) {
  407. inlined = (m3di_t*)realloc(inlined, (numinlined+1) * sizeof(m3di_t));
  408. if(!inlined) { fprintf(stderr, "m3dconv: memory allocation error\n"); exit(3); }
  409. inlined[numinlined].name = bn;
  410. inlined[numinlined].length = pngbuf.length;
  411. inlined[numinlined].data = pngbuf.data;
  412. numinlined++;
  413. if(verbose>1) printf(" Inlining '%s'\n", bn);
  414. }
  415. }
  416. }
  417. }
  418. #endif
  419. /**
  420. * This does the hard work of parsing most of the assimp structures
  421. */
  422. void _assimp_mesh(m3d_t *m3d, char *fn)
  423. {
  424. struct aiMatrix4x4 mt;
  425. struct aiMatrix3x3 mr;
  426. struct aiMaterial *mat = NULL;
  427. struct aiMesh *mesh;
  428. struct aiFace *face;
  429. struct aiNode *node;
  430. struct aiVector3D v;
  431. struct aiString name;
  432. struct aiColor4D c;
  433. char *tn, *path, *bn, *sn;
  434. unsigned int i, j, k, l, n, m, o, mi, idx, ti;
  435. float f;
  436. m3dv_t *vertex;
  437. for(m = 0; m < numnodes; m++) {
  438. node = nodes[m].node;
  439. _assimp_toworld(&mt, node);
  440. _assimp_fixmat(&mt);
  441. _assimp_extract3x3(&mr, &mt);
  442. for(i = 0; i < node->mNumMeshes; i++) {
  443. mesh = scene->mMeshes[node->mMeshes[i]];
  444. /* mesh->mMaterialIndex */
  445. mi = (M3D_INDEX)-1U;
  446. if(scene->mMaterials) {
  447. mat = scene->mMaterials[mesh->mMaterialIndex];
  448. if(mat && aiGetMaterialString(mat, AI_MATKEY_NAME, &name) == AI_SUCCESS && name.length &&
  449. strcmp(name.data, AI_DEFAULT_MATERIAL_NAME)) {
  450. for(j = 0; j < m3d->nummaterial; j++)
  451. if(!strcmp(name.data, m3d->material[j].name)) { mi = j; break; }
  452. if(mi == -1U) {
  453. mi = m3d->nummaterial++;
  454. m3d->material = (m3dm_t*)realloc(m3d->material, m3d->nummaterial * sizeof(m3dm_t));
  455. if(!m3d->material) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  456. m3d->material[mi].name = _m3d_safestr(name.data, 0);
  457. m3d->material[mi].numprop = 0;
  458. m3d->material[mi].prop = NULL;
  459. for(k = 0; k < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); k++) {
  460. if(m3d_propertytypes[k].format == m3dpf_map) continue;
  461. if(aiProps[k].pKey) {
  462. switch(m3d_propertytypes[k].format) {
  463. case m3dpf_color:
  464. if(aiGetMaterialColor(mat, aiProps[k].pKey,aiProps[k].type,aiProps[k].index, &c)
  465. == AI_SUCCESS) {
  466. l = _assimp_color(&c);
  467. if(l != 0)
  468. _assimp_addprop(&m3d->material[mi], m3d_propertytypes[k].id, l);
  469. }
  470. break;
  471. case m3dpf_float:
  472. if(aiGetMaterialFloatArray(mat, aiProps[k].pKey,aiProps[k].type,aiProps[k].index,&f,NULL)
  473. == AI_SUCCESS) {
  474. _assimp_addprop(&m3d->material[mi], m3d_propertytypes[k].id, *((uint32_t*)&f));
  475. }
  476. break;
  477. default:
  478. if(aiGetMaterialIntegerArray(mat, aiProps[k].pKey,aiProps[k].type,aiProps[k].index,
  479. (int*)&l, NULL) == AI_SUCCESS) {
  480. if(m3d_propertytypes[k].id == m3dp_il)
  481. switch(l) {
  482. case aiShadingMode_NoShading: l = 0; break;
  483. case aiShadingMode_Phong: l = 2; break;
  484. default: l = 1; break;
  485. }
  486. _assimp_addprop(&m3d->material[mi], m3d_propertytypes[k].id, l);
  487. }
  488. break;
  489. }
  490. }
  491. if(aiTxProps[k].pKey && aiGetMaterialTexture(mat, aiTxProps[k].type, aiTxProps[k].index,
  492. &name, NULL, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) {
  493. /* some designers are foolish enough to store ABSOLUTE paths in texture names... */
  494. sn = strrchr(name.data, '/');
  495. if(!sn) sn = strrchr(name.data, '\\');
  496. if(!sn) sn = name.data; else sn++;
  497. path = (char*)malloc(strlen(fn) + strlen(sn) + 5);
  498. if(!path) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  499. strcpy(path, fn);
  500. bn = strrchr(path, '/');
  501. if(!bn) bn = strrchr(path, '\\');
  502. if(!bn) bn = path; else bn++;
  503. strcpy(bn, sn);
  504. tn = _m3d_safestr(sn, 0);
  505. bn = strrchr(tn, '.');
  506. if(bn) *bn = 0;
  507. /* check if we already have this texture */
  508. for(l = 0, o = -1U; l < m3d->numtexture; l++)
  509. if(!strcmp(tn, m3d->texture[l].name)) { o = l; free(tn); break; }
  510. if(o == -1U) {
  511. /* only png textures can be inlined. Let's try to find the texture file... */
  512. if(storeinline) {
  513. for(l = 0, o = -1U; l < numinlined; l++)
  514. if(!strcmp(tn, inlined[l].name)) { o = l; break; }
  515. if(o == -1U) {
  516. bn = strrchr(path, '.');
  517. if(bn) strcpy(bn, ".png");
  518. if(!readfile(path, &o) && bn) {
  519. strcpy(bn, ".PNG");
  520. if(!readfile(path, &o)) {
  521. for(o = strlen(path)-1; o > 0 && path[o]!='/' && path[o]!='\\'; o--)
  522. if(path[o] >= 'A' && path[o] <= 'Z') path[o] += 'a'-'A';
  523. readfile(path, &o);
  524. }
  525. }
  526. if(o && verbose>1) printf(" Inlining '%s'\n", tn);
  527. }
  528. }
  529. o = m3d->numtexture++;
  530. m3d->texture = (m3dtx_t*)realloc(m3d->texture, m3d->numtexture * sizeof(m3dtx_t));
  531. if(!m3d->texture) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  532. m3d->texture[o].name = tn;
  533. m3d->texture[o].w = 0;
  534. m3d->texture[o].h = 0;
  535. m3d->texture[o].d = NULL;
  536. }
  537. free(path);
  538. _assimp_addprop(&m3d->material[mi], m3d_propertytypes[k].id + 128, o);
  539. }
  540. }
  541. }
  542. }
  543. }
  544. /* dirty hack, we need a place to store global m3d vertex ids for these local vertices */
  545. if(mesh->mBitangents) free(mesh->mBitangents);
  546. mesh->mBitangents = (struct aiVector3D*)malloc(mesh->mNumVertices * sizeof(uint32_t));
  547. if(!mesh->mBitangents) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  548. memset(mesh->mBitangents, 0, mesh->mNumVertices * sizeof(uint32_t));
  549. /* iterate on face polygons */
  550. for(l = j = 0; j < mesh->mNumFaces; j++) {
  551. if(mesh->mFaces[j].mNumIndices != 3) continue;
  552. l++;
  553. }
  554. m3d->face = (m3df_t*)realloc(m3d->face, (m3d->numface + l) * sizeof(m3df_t));
  555. if(!m3d->face) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  556. memset(&m3d->face[m3d->numface], 255, l * sizeof(m3df_t)); /* set all index to -1 by default */
  557. idx = m3d->numvertex;
  558. m3d->numvertex += (mesh->mNormals && !withoutnorm ? 6 : 3) * l;
  559. m3d->vertex = (m3dv_t*)realloc(m3d->vertex, m3d->numvertex * sizeof(m3dv_t));
  560. if(!m3d->vertex) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  561. memset(&m3d->vertex[idx], 0, (m3d->numvertex - idx) * sizeof(m3dv_t));
  562. ti = m3d->numtmap;
  563. m3d->numtmap += (mesh->mTextureCoords[0] && !withoutuv ? 3 : 0) * l;
  564. if(m3d->numtmap > ti) {
  565. m3d->tmap = (m3dti_t*)realloc(m3d->tmap, m3d->numtmap * sizeof(m3dti_t));
  566. if(!m3d->tmap) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  567. memset(&m3d->tmap[ti], 0, (m3d->numtmap - ti) * sizeof(m3dti_t));
  568. }
  569. for(j = 0; j < mesh->mNumFaces; j++) {
  570. face = &mesh->mFaces[j];
  571. if(face->mNumIndices != 3) continue;
  572. n = m3d->numface++;
  573. m3d->face[n].materialid = mi;
  574. for(k = 0; k < face->mNumIndices; k++) {
  575. l = face->mIndices[k];
  576. v = mesh->mVertices[l];
  577. aiTransformVecByMatrix4(&v, &mt);
  578. m3d->face[n].vertex[k] = (M3D_INDEX)idx;
  579. ((uint32_t*)(mesh->mBitangents))[l] = idx;
  580. vertex = &m3d->vertex[idx];
  581. vertex->x = v.x;
  582. vertex->y = v.y;
  583. vertex->z = v.z;
  584. vertex->w = 1.0;
  585. vertex->skinid = (M3D_INDEX)-1U;
  586. vertex->type = 0;
  587. if(mesh->mColors[0] != NULL)
  588. vertex->color = _assimp_color(&mesh->mColors[0][l]);
  589. idx++;
  590. if(mesh->mNormals != NULL && !withoutnorm) {
  591. v = mesh->mNormals[l];
  592. aiTransformVecByMatrix3(&v, &mr);
  593. m3d->face[n].normal[k] = (M3D_INDEX)idx;
  594. vertex = &m3d->vertex[idx];
  595. vertex->x = v.x;
  596. vertex->y = v.y;
  597. vertex->z = v.z;
  598. vertex->w = 1.0;
  599. vertex->skinid = (M3D_INDEX)-1U;
  600. vertex->type = 1;
  601. idx++;
  602. }
  603. if(mesh->mTextureCoords[0] != NULL && !withoutuv) {
  604. m3d->tmap[ti].u = mesh->mTextureCoords[0][l].x;
  605. m3d->tmap[ti].v = mesh->mTextureCoords[0][l].y;
  606. m3d->face[n].texcoord[k] = (M3D_INDEX)ti;
  607. ti++;
  608. }
  609. }
  610. }
  611. }
  612. }
  613. }
  614. /**
  615. * Get the skeleton from the node tree
  616. */
  617. int _assimp_skeleton(m3d_t *m3d)
  618. {
  619. unsigned int i, j, k, r = 0;
  620. struct aiMatrix4x4 m, inv;
  621. for(i = 0; i < numnodes; i++) {
  622. k = -1U;
  623. if(nodes[i].node->mParent && nodes[i].node->mParent != scene->mRootNode) {
  624. if(nodes[i].parent != -1U)
  625. k = nodes[i].parent;
  626. else {
  627. for(j = 0; j < i; j++)
  628. if(nodes[j].node == nodes[i].node->mParent) {
  629. k = nodes[i].parent = j;
  630. break;
  631. }
  632. if(k == -1U) {
  633. printf("ERROR: inconsistent bone structure, no such parent '%s' for node '%s'\n",
  634. nodes[i].node->mParent->mName.data, nodes[i].node->mName.data);
  635. exit(1);
  636. }
  637. }
  638. }
  639. /* corrigate for the mess we might have in assimp node structures... */
  640. if(doworld) {
  641. if(k != -1U)
  642. _assimp_toworld(&inv, nodes[k].node);
  643. else
  644. aiIdentityMatrix4(&inv);
  645. _assimp_inverse(&inv);
  646. _assimp_toworld(&m, nodes[i].node);
  647. aiMultiplyMatrix4(&m, &inv);
  648. } else
  649. memcpy(&m, &nodes[i].node->mTransformation, sizeof(struct aiMatrix4x4));
  650. /* now m is a parent bone relative transformation matrix */
  651. m3d->vertex = _assimp_addspace(m3d->vertex, &m3d->numvertex, &m, k == -1U ? VT_WORLD : VT_RELATIVE, &k);
  652. nodes[i].pos = (M3D_INDEX)k;
  653. nodes[i].ori = (M3D_INDEX)(k + 1);
  654. /* we don't need the scaling part */
  655. m3d->numvertex--;
  656. if(nodes[i].boneid != -1U && (nodes[i].pos != nodes[i].lpos || nodes[i].ori != nodes[i].lori)) r++;
  657. }
  658. return r;
  659. }
  660. /**
  661. * Export bone structure
  662. */
  663. void _assimp_bones(m3d_t *m3d)
  664. {
  665. unsigned int i, j;
  666. if(!numskeleton) return;
  667. m3d->numbone = numskeleton;
  668. m3d->bone = (m3db_t*)malloc(numskeleton * sizeof(m3db_t));
  669. if(!m3d->bone) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  670. memset(m3d->bone, 0, numskeleton * sizeof(m3db_t));
  671. _assimp_skeleton(m3d);
  672. for(i = j = 0; i < numnodes; i++) {
  673. if(nodes[i].isbone) {
  674. m3d->bone[j].name = _m3d_safestr(nodes[i].node->mName.data, 0);
  675. m3d->bone[j].parent = (nodes[i].parent != -1U ? nodes[nodes[i].parent].boneid : -1U);
  676. m3d->bone[j].pos = nodes[i].pos;
  677. m3d->bone[j].ori = nodes[i].ori;
  678. nodes[i].boneid = j++;
  679. }
  680. }
  681. }
  682. /**
  683. * Export skin into a temporary skintrans array
  684. */
  685. void _assimp_skin(m3d_t *m3d)
  686. {
  687. unsigned int i, j, k, l, m, boneid, idx;
  688. M3D_FLOAT w;
  689. struct aiNode *node;
  690. struct aiMesh *mesh;
  691. struct aiBone *bone;
  692. /* allocate separate skin group for each vertex. m3d_save will compress it */
  693. m3d->skin = (m3ds_t*)malloc(m3d->numvertex * sizeof(m3ds_t));
  694. if(!m3d->skin) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  695. m3d->numskin = m3d->numvertex;
  696. for(i = 0; i < m3d->numvertex; i++)
  697. for(j = 0; j < M3D_NUMBONE; j++) {
  698. m3d->skin[i].boneid[j] = (M3D_INDEX)-1U;
  699. m3d->skin[i].weight[j] = (M3D_FLOAT)0.0;
  700. }
  701. /* this is messed up, m3d_t stores boneid+weight pairs (skin records) per vertex, but Assimp
  702. * has mesh local list of bones and local vertex indices+weight pairs */
  703. for(m = 0; m < numnodes; m++) {
  704. node = nodes[m].node;
  705. for(i = 0; i < node->mNumMeshes; i++) {
  706. mesh = scene->mMeshes[node->mMeshes[i]];
  707. if(mesh->mBitangents) {
  708. for(j = 0; j < mesh->mNumBones; j++) {
  709. bone = mesh->mBones[j];
  710. if(bone) {
  711. boneid = -1U;
  712. for(k = 0; k < numnodes; k++)
  713. if(!strcmp(nodes[k].node->mName.data, bone->mName.data)) { boneid = nodes[k].boneid; break; }
  714. if(boneid != -1U) {
  715. for(k = 0; k < bone->mNumWeights; k++) {
  716. idx = ((uint32_t*)(mesh->mBitangents))[bone->mWeights[k].mVertexId];
  717. m3d->vertex[idx].skinid = (M3D_INDEX)idx;
  718. w = (M3D_FLOAT)bone->mWeights[k].mWeight;
  719. /* sort skin records by weight descending */
  720. for(l = 0; l < M3D_NUMBONE && m3d->skin[idx].weight[l] > w; l++);
  721. if(m3d->skin[idx].boneid[l] == boneid && m3d->skin[idx].weight[l] == w) continue;
  722. /* insert new boneid+weight pair if there's place */
  723. if(l < M3D_NUMBONE) {
  724. if(l + 1 < M3D_NUMBONE && m3d->skin[idx].weight[l] != (M3D_FLOAT)0.0) {
  725. memmove(&m3d->skin[idx].boneid[l+1], &m3d->skin[idx].boneid[l],
  726. (M3D_NUMBONE - l - 1) * sizeof(M3D_INDEX));
  727. memmove(&m3d->skin[idx].weight[l+1], &m3d->skin[idx].weight[l],
  728. (M3D_NUMBONE - l - 1) * sizeof(M3D_FLOAT));
  729. }
  730. m3d->skin[idx].boneid[l] = boneid;
  731. m3d->skin[idx].weight[l] = w;
  732. }
  733. }
  734. } else
  735. printf("ERROR: inconsistent skeleton, no bone aiNode for aiBone '%s'\n", bone->mName.data);
  736. }
  737. }
  738. }
  739. }
  740. }
  741. }
  742. /**
  743. * Import assimp animation data
  744. */
  745. void _assimp_anim(m3d_t *m3d)
  746. {
  747. unsigned int i, j, k, l, m, a, n;
  748. struct aiMesh *mesh;
  749. struct aiBone *bone;
  750. struct aiMatrix4x4 ma;
  751. struct aiAnimation *an;
  752. struct aiNodeAnim *na;
  753. struct aiNode *node;
  754. struct aiVector3D scaling, pos;
  755. struct aiQuaternion rot;
  756. double *t;
  757. m3da_t *anim;
  758. if(!m3d->numbone) return;
  759. /* Assimp has:
  760. * anim
  761. * \-channels (bones)
  762. * |-positionkeys (each with it's own timestamp)
  763. * |-rotationkeys (each with it's own timestamp)
  764. * \-scalingkeys (each with it's own timestamp)
  765. *
  766. * We need:
  767. * anim
  768. * \-frame (timestamp)
  769. * \-bone, position, rotation (only that changed compared to the previous frame, scaling in rotation)
  770. */
  771. if(arg_framedelay <= 0.0) arg_framedelay = 1.0;
  772. for(a = 0; a < scene->mNumAnimations; a++) {
  773. an = scene->mAnimations[a];
  774. if(an->mTicksPerSecond <= 0.0) an->mTicksPerSecond = 1.0;
  775. /* add a new action */
  776. j = m3d->numaction++;
  777. m3d->action = (m3da_t*)realloc(m3d->action, m3d->numaction * sizeof(m3da_t));
  778. if(!m3d->action) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  779. anim = &m3d->action[j];
  780. anim->name = _m3d_safestr(an->mName.data[0] ? an->mName.data : "Global", 0);
  781. /* don't trust Assimp, mDuration is often wrong! */
  782. /* anim->durationmsec = an->mDuration / an->mTicksPerSecond * 1000.0 * arg_framedelay; */
  783. anim->durationmsec = 0;
  784. anim->numframe = 0;
  785. anim->frame = NULL;
  786. /* at this point I'm absolutely certain that assimp devs were on drugs. Pretty strong ones may I add.
  787. * let's get how many frames are there actually, and what timestamps they have */
  788. for(j = n = 0, t = NULL; j < an->mNumChannels; j++) {
  789. na = an->mChannels[j];
  790. for(k = 0; k < na->mNumPositionKeys; k++) {
  791. for(l = 0; l < n && t[l] < na->mPositionKeys[k].mTime; l++);
  792. if(l == n || t[l] > na->mPositionKeys[k].mTime) {
  793. n++; t = (double*)realloc(t, n * sizeof(double));
  794. if(l + 1 != n) memmove(&t[l+1], &t[l], (n - l - 1) * sizeof(double));
  795. }
  796. t[l] = na->mPositionKeys[k].mTime;
  797. }
  798. for(k = 0; k < na->mNumRotationKeys; k++) {
  799. for(l = 0; l < n && t[l] < na->mRotationKeys[k].mTime; l++);
  800. if(l == n || t[l] > na->mRotationKeys[k].mTime) {
  801. n++; t = (double*)realloc(t, n * sizeof(double));
  802. if(l + 1 != n) memmove(&t[l+1], &t[l], (n - l - 1) * sizeof(double));
  803. }
  804. t[l] = na->mRotationKeys[k].mTime;
  805. }
  806. for(k = 0; k < na->mNumScalingKeys; k++) {
  807. for(l = 0; l < n && t[l] < na->mScalingKeys[k].mTime; l++);
  808. if(l == n || t[l] > na->mScalingKeys[k].mTime) {
  809. n++; t = (double*)realloc(t, n * sizeof(double));
  810. if(l + 1 != n) memmove(&t[l+1], &t[l], (n - l - 1) * sizeof(double));
  811. }
  812. t[l] = na->mScalingKeys[k].mTime;
  813. }
  814. }
  815. /* ok, now t[n] contains the timestamps in a sorted list */
  816. /* reset skeleton to bind-pose on animation start */
  817. for(j = 0; j < numnodes; j++) {
  818. if(nodes[j].boneid != -1U) {
  819. nodes[j].pos = nodes[j].lpos = m3d->bone[nodes[j].boneid].pos;
  820. nodes[j].ori = nodes[j].lori = m3d->bone[nodes[j].boneid].ori;
  821. }
  822. }
  823. /* iterate on frames */
  824. for(i = 0; i < n; i++) {
  825. /* reset skeleton transformation matrices on every frame start */
  826. for(j = 0; j < numnodes; j++)
  827. memcpy(&nodes[j].node->mTransformation, &nodes[j].mt, sizeof(struct aiMatrix4x4));
  828. /* one does not simply get an animation-pose from assimp... */
  829. for(j = l = 0; j < an->mNumChannels; j++) {
  830. na = an->mChannels[j];
  831. node = NULL;
  832. for(k = 0; k < numnodes; k++)
  833. if(!strcmp(nodes[k].node->mName.data, na->mNodeName.data)) {
  834. if(nodes[k].boneid != -1U) node = nodes[k].node;
  835. else {
  836. l = 1;
  837. fprintf(stderr, "m3dconv: mesh transform for '%s' in '%s' frame %d\n",
  838. na->mNodeName.data, an->mName.data, n + 1);
  839. }
  840. break;
  841. }
  842. if(!node) continue;
  843. aiDecomposeMatrix(&node->mTransformation, &scaling, &rot, &pos);
  844. for(k = 0; k < na->mNumPositionKeys && na->mPositionKeys[k].mTime <= t[i]; k++)
  845. if(na->mPositionKeys[k].mTime == t[i]) {
  846. memcpy(&pos, &na->mPositionKeys[k].mValue, sizeof(struct aiVector3D));
  847. break;
  848. }
  849. for(k = 0; k < na->mNumRotationKeys && na->mRotationKeys[k].mTime <= t[i]; k++)
  850. if(na->mRotationKeys[k].mTime == t[i]) {
  851. memcpy(&rot, &na->mRotationKeys[k].mValue, sizeof(struct aiQuaternion));
  852. break;
  853. }
  854. for(k = 0; k < na->mNumScalingKeys && na->mScalingKeys[k].mTime <= t[i]; k++)
  855. if(na->mScalingKeys[k].mTime == t[i]) {
  856. memcpy(&scaling, &na->mScalingKeys[k].mValue, sizeof(struct aiVector3D));
  857. break;
  858. }
  859. _assimp_composematrix(&node->mTransformation, &pos, &rot, &scaling);
  860. }
  861. /* dirty hack. we try to compensate for mesh transforms in skeletal animation... by multiplying the
  862. * affected bones with the mesh transform. We have to do this in a second round, since matrix
  863. * multiplication is not commutative. */
  864. if(l) {
  865. for(j = 0; j < an->mNumChannels; j++) {
  866. na = an->mChannels[j];
  867. node = NULL;
  868. for(k = 0; k < numnodes; k++)
  869. if(!strcmp(nodes[k].node->mName.data, na->mNodeName.data) && nodes[k].boneid == -1U) {
  870. node = nodes[k].node;
  871. break;
  872. }
  873. if(node) {
  874. memcpy(&ma, &node->mTransformation, sizeof(struct aiMatrix4x4));
  875. aiTransposeMatrix4(&ma);
  876. for(k = 0; k < node->mNumMeshes; k++) {
  877. mesh = scene->mMeshes[node->mMeshes[k]];
  878. if(mesh)
  879. for(l = 0; l < mesh->mNumBones; l++) {
  880. bone = mesh->mBones[l];
  881. if(bone) {
  882. for(m = 0; m < numnodes; m++)
  883. if(!strcmp(nodes[m].node->mName.data, bone->mName.data)) {
  884. aiMultiplyMatrix4(&nodes[m].node->mTransformation, &ma);
  885. break;
  886. }
  887. }
  888. }
  889. }
  890. }
  891. }
  892. }
  893. /* now get the animation-pose skeleton */
  894. j = _assimp_skeleton(m3d);
  895. /* if we have changed bones */
  896. if(j) {
  897. /* add a new frame */
  898. m = anim->numframe++;
  899. anim->frame = (m3dfr_t*)realloc(anim->frame, anim->numframe * sizeof(m3dfr_t));
  900. if(!anim->frame) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  901. anim->frame[m].transform = (m3dtr_t*)malloc(j * sizeof(m3dtr_t));
  902. if(!anim->frame[m].transform) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  903. anim->frame[m].msec = t[i] / an->mTicksPerSecond * 1000.0 * arg_framedelay;
  904. if(anim->frame[m].msec > anim->durationmsec)
  905. anim->durationmsec = anim->frame[m].msec;
  906. anim->frame[m].numtransform = j;
  907. /* add changed bones transforms to this frame */
  908. for(k = j = 0; k < numnodes; k++)
  909. if(nodes[k].boneid != -1U && (nodes[k].pos != nodes[k].lpos || nodes[k].ori != nodes[k].lori)) {
  910. anim->frame[m].transform[j].boneid = nodes[k].boneid;
  911. anim->frame[m].transform[j].pos = nodes[k].lpos = nodes[k].pos;
  912. anim->frame[m].transform[j].ori = nodes[k].lori = nodes[k].ori;
  913. j++;
  914. }
  915. }
  916. }
  917. free(t);
  918. }
  919. }
  920. /**
  921. * Fix materials if there's a texture next to the model by the same name
  922. */
  923. void _assimp_fixmaterials(m3d_t *m3d, char *fn)
  924. {
  925. unsigned char *data;
  926. char *tfn, *ext;
  927. unsigned int i, j, o, mi, s;
  928. /* first, look for modelname.png */
  929. tfn = malloc(strlen(fn) + 512);
  930. if(!tfn) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); return; }
  931. strcpy(tfn, fn);
  932. ext = strrchr(tfn, '.');
  933. if(ext) *ext = 0;
  934. strcat(tfn, ".png");
  935. ext = tfn + strlen(tfn) - 4;
  936. /* check if file exists, and read it into inlined array if inline requested */
  937. data = readfile(tfn, &s);
  938. if(!data) { memcpy(ext, ".PNG", 4); data = readfile(tfn, &s); }
  939. if(!data) { free(tfn); return; }
  940. /* file exists */
  941. if(!storeinline) free(data);
  942. *ext = 0;
  943. ext = strrchr(tfn, '/');
  944. if(!ext) ext = strrchr(tfn, '\\');
  945. if(!ext) ext = tfn; else ext++;
  946. /* is this texture already defined in the model? */
  947. for(i = 0, o = -1U; i < m3d->numtexture; i++)
  948. if(!strcmp(ext, m3d->texture[i].name)) { o = i; break; }
  949. if(o == -1U) {
  950. /* add texture */
  951. o = m3d->numtexture++;
  952. m3d->texture = (m3dtx_t*)realloc(m3d->texture, m3d->numtexture * sizeof(m3dtx_t));
  953. if(!m3d->texture) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  954. m3d->texture[o].name = (char*)malloc(strlen(ext)+1);
  955. if(!m3d->texture[o].name) { free(tfn); return; }
  956. strcpy(m3d->texture[o].name, ext);
  957. m3d->texture[o].w = 0;
  958. m3d->texture[o].h = 0;
  959. m3d->texture[o].d = NULL;
  960. /* add a material with this texture as diffuse color map */
  961. mi = m3d->nummaterial++;
  962. m3d->material = (m3dm_t*)realloc(m3d->material, m3d->nummaterial * sizeof(m3dm_t));
  963. if(!m3d->material) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  964. m3d->material[mi].name = _m3d_safestr("Default", 0);
  965. m3d->material[mi].numprop = 0;
  966. m3d->material[mi].prop = NULL;
  967. _assimp_addprop(&m3d->material[mi], m3dp_map_Kd, o);
  968. /* replace materialid to this new material in face for triangles which have UV coordinates */
  969. for(i = 0; i < m3d->numface; i++) {
  970. if(m3d->face[i].materialid == -1U && m3d->face[i].texcoord[0] != -1U)
  971. m3d->face[i].materialid = mi;
  972. }
  973. }
  974. /* now let's look for materialname.png */
  975. for(i = 0; i < m3d->nummaterial; i++) {
  976. /* does this material have a Kd map? */
  977. for(j = 0, o = -1U; j < m3d->material[i].numprop; j++)
  978. if(m3d->material[i].prop[j].type == m3dp_map_Kd) { o = j; break; }
  979. if(o == -1U) {
  980. /* no, and is there a materialname.png? */
  981. strcpy(ext, m3d->material[i].name);
  982. strcat(ext, ".png");
  983. data = readfile(tfn, &s);
  984. if(data) {
  985. /* file exists */
  986. if(!storeinline) free(data);
  987. for(j = 0, o = -1U; j < m3d->numtexture; j++)
  988. if(!strcmp(m3d->material[i].name, m3d->texture[j].name)) { o = j; break; }
  989. if(o == -1U) {
  990. /* add texture */
  991. o = m3d->numtexture++;
  992. m3d->texture = (m3dtx_t*)realloc(m3d->texture, m3d->numtexture * sizeof(m3dtx_t));
  993. if(!m3d->texture) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  994. m3d->texture[o].name = (char*)malloc(strlen(m3d->material[i].name)+1);
  995. if(!m3d->texture[o].name) { free(tfn); return; }
  996. strcpy(m3d->texture[o].name, m3d->material[i].name);
  997. m3d->texture[o].w = 0;
  998. m3d->texture[o].h = 0;
  999. m3d->texture[o].d = NULL;
  1000. }
  1001. _assimp_addprop(&m3d->material[i], m3dp_map_Kd, o);
  1002. }
  1003. }
  1004. }
  1005. free(tfn);
  1006. }
  1007. /**
  1008. * Load a model and convert it's structures into a Model 3D in-memory format
  1009. */
  1010. m3d_t *assimp_load(char *fn)
  1011. {
  1012. m3d_t *m3d;
  1013. unsigned int i;
  1014. char *name = strrchr(fn, '/');
  1015. if(!name) name = strrchr(fn, '\\');
  1016. m3d = (m3d_t*)malloc(sizeof(m3d_t));
  1017. if(!m3d) return NULL;
  1018. memset(m3d, 0, sizeof(m3d_t));
  1019. m3d->flags = M3D_FLG_FREESTR;
  1020. if(verbose>1) printf(" aiImportFile\n");
  1021. scene = aiImportFile(fn, aiProcess_Triangulate | aiProcess_FindInstances | aiProcess_RemoveRedundantMaterials |
  1022. #ifdef EXPINLINE
  1023. aiProcess_EmbedTextures |
  1024. #endif
  1025. (withoutnorm ? 0 : aiProcess_GenSmoothNormals) | (withoutuv ? 0 : aiProcess_GenUVCoords |
  1026. aiProcess_TransformUVCoords));
  1027. if(!scene) {
  1028. free(m3d);
  1029. errstr = (char*)aiGetErrorString();
  1030. return NULL;
  1031. }
  1032. m3d->name = _m3d_safestr( arg_name && *arg_name ? arg_name : ( strcmp(scene->mRootNode->mName.data, "ROOT") &&
  1033. strcmp(scene->mRootNode->mName.data, "Root") && strcmp(scene->mRootNode->mName.data, "root") ?
  1034. scene->mRootNode->mName.data : (name ? name + 1 : fn)), 2);
  1035. /* convert assimp node structure into something we can actually work with */
  1036. if(verbose>1) printf(" Converting nodes\n");
  1037. _assimp_nodes(scene->mRootNode);
  1038. _assimp_fixnodes();
  1039. #ifdef EXPINLINE
  1040. /* convert assimp inlined textures */
  1041. if(verbose>1) printf(" Converting inlined textures\n");
  1042. _assimp_textures(m3d);
  1043. #endif
  1044. /* convert assimp meshes into m3d_t */
  1045. if(verbose>1) printf(" Converting meshes\n");
  1046. _assimp_mesh(m3d, fn);
  1047. if(!domesh && numskeleton) {
  1048. if(verbose>1) printf(" Converting bones\n");
  1049. _assimp_bones(m3d);
  1050. if(m3d->numvertex && m3d->numbone) {
  1051. if(verbose>1) printf(" Converting skins\n");
  1052. _assimp_skin(m3d);
  1053. if(verbose>1) printf(" Converting animations\n");
  1054. _assimp_anim(m3d);
  1055. }
  1056. }
  1057. if(verbose>1) printf(" Fix materials\n");
  1058. _assimp_fixmaterials(m3d, fn);
  1059. for(i = 0; i < scene->mNumMeshes; i++)
  1060. if(scene->mMeshes[i]->mBitangents) { free(scene->mMeshes[i]->mBitangents); scene->mMeshes[i]->mBitangents = NULL; }
  1061. free(nodes);
  1062. if(verbose>1) printf(" aiReleaseImport\n");
  1063. aiReleaseImport(scene);
  1064. scene = NULL;
  1065. return m3d;
  1066. }