assimp.h 50 KB

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