ms3d.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. * m3dconv/ms3d.h
  3. *
  4. * Copyright (C) 2022 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 ASCII MilkShape importer
  27. * https://gitlab.com/bztsrc/model3d
  28. *
  29. */
  30. /**
  31. * Get next valid (non-empty, non-comment) line
  32. */
  33. char *ms3d_nextline(char *data)
  34. {
  35. if(!*data) return data;
  36. do {
  37. data = _m3d_findnl(data);
  38. } while(*data == '/');
  39. return data;
  40. }
  41. /**
  42. * Add to animation frame
  43. */
  44. void ms3d_addframe(m3d_t *m3d, uint32_t t, unsigned int bone, unsigned int pos, unsigned int ori)
  45. {
  46. m3da_t *action;
  47. /* find action (there should be only one for MS3D) */
  48. if(!m3d->action) {
  49. m3d->action = action = (m3da_t*)malloc(sizeof(m3da_t));
  50. if(!m3d->action) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  51. memset(m3d->action, 0, sizeof(m3da_t));
  52. m3d->action[0].name = (char*)malloc(5);
  53. if(!m3d->action[0].name) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  54. strcpy(m3d->action[0].name, "Anim");
  55. m3d->numaction = 1;
  56. } else
  57. action = &m3d->action[m3d->numaction - 1];
  58. /* add to frame */
  59. _m3d_addframe(action, t, bone, pos, ori);
  60. }
  61. /**
  62. * Load a model and convert it's structures into a Model 3D in-memory format
  63. */
  64. m3d_t *ms3d_ascii_load(char *data)
  65. {
  66. m3d_t *m3d;
  67. m3dm_t *m;
  68. uint32_t j, n, num, nv, nn, nf;
  69. char *s, *e, *d, *path, *bn;
  70. unsigned int i, l;
  71. int mi, mt[4] = { m3dp_Ka, m3dp_Kd, m3dp_Ks, m3dp_Ke };
  72. float r,g,b,a, t,x,y,z;
  73. m3d = (m3d_t*)malloc(sizeof(m3d_t));
  74. if(!m3d) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  75. memset(m3d, 0, sizeof(m3d_t));
  76. m3d->flags = M3D_FLG_FREESTR;
  77. /* add default position and orientation, may be needed by bones in group statements */
  78. m3d->numvertex = 2;
  79. m3d->vertex = (m3dv_t*)malloc(m3d->numvertex * sizeof(m3dv_t));
  80. if(!m3d->vertex) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  81. memset(m3d->vertex, 0, 2 * sizeof(m3dv_t));
  82. m3d->vertex[0].skinid = -1U;
  83. m3d->vertex[0].type = VT_WORLD;
  84. m3d->vertex[1].skinid = -2U;
  85. m3d->vertex[1].type = VT_QUATERN;
  86. while(*data) {
  87. /* skip until chunk found */
  88. while(*data && (*data < 'A' || *data > 'Z'))
  89. data = ms3d_nextline(data);
  90. if(!*data) break;
  91. s = data;
  92. data = _m3d_findarg(data);
  93. data = _m3d_getint(data, &num);
  94. data = ms3d_nextline(data);
  95. if(!memcmp(s, "Meshes:", 7)) {
  96. for(n = 0; n < num; n++) {
  97. /* first line: name, flags, material index */
  98. for(++data; *data && *data != '\"'; data++);
  99. data = _m3d_findarg(data);
  100. data = _m3d_getint(data, (uint32_t*)&mi);
  101. data = ms3d_nextline(data);
  102. /* second: number of vertex */
  103. data = _m3d_getint(data, &nv);
  104. data = ms3d_nextline(data);
  105. m3d->vertex = (m3dv_t*)realloc(m3d->vertex, (m3d->numvertex + nv) * sizeof(m3dv_t));
  106. if(!m3d->vertex) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  107. memset(&m3d->vertex[m3d->numvertex], 0, nv * sizeof(m3dv_t));
  108. m3d->tmap = (m3dti_t*)realloc(m3d->tmap, (m3d->numtmap + nv) * sizeof(m3dti_t));
  109. if(!m3d->tmap) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  110. memset(&m3d->tmap[m3d->numtmap], 0, nv * sizeof(m3dti_t));
  111. for(i = 0; i < nv; i++) {
  112. /* vertex: flags, x, y, z, u, v, bone index */
  113. data = _m3d_findarg(data);
  114. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex + i].x);
  115. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex + i].y);
  116. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex + i].z);
  117. data = _m3d_getfloat(data, &m3d->tmap[m3d->numtmap + i].u);
  118. data = _m3d_getfloat(data, &x); m3d->tmap[m3d->numtmap + i].v = (M3D_FLOAT)1.0 - x;
  119. data = _m3d_getint(data, &j); m3d->vertex[m3d->numvertex + i].skinid = j;
  120. data = ms3d_nextline(data);
  121. }
  122. /* next: number of normals */
  123. data = _m3d_getint(data, &nn);
  124. data = ms3d_nextline(data);
  125. m3d->vertex = (m3dv_t*)realloc(m3d->vertex, (m3d->numvertex + nv + nn) * sizeof(m3dv_t));
  126. if(!m3d->vertex) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  127. memset(&m3d->vertex[m3d->numvertex + nv], 0, nn * sizeof(m3dv_t));
  128. for(i = 0; i < nn; i++) {
  129. /* normal: x, y, z */
  130. m3d->vertex[m3d->numvertex + nv + i].skinid = -1U;
  131. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex + nv + i].x);
  132. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex + nv + i].y);
  133. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex + nv + i].z);
  134. data = ms3d_nextline(data);
  135. }
  136. /* next: number of faces */
  137. data = _m3d_getint(data, &nf);
  138. data = ms3d_nextline(data);
  139. m3d->face = (m3df_t*)realloc(m3d->face, (m3d->numface + nf) * sizeof(m3df_t));
  140. if(!m3d->face) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  141. memset(&m3d->face[m3d->numface], 255, nf * sizeof(m3df_t));
  142. for(i = 0; i < nf; i++) {
  143. /* triangle: flags, v1, v2, v3, n1, n2, n3, smoothing group */
  144. m3d->face[m3d->numface + i].materialid = mi;
  145. data = _m3d_findarg(data);
  146. data = _m3d_getint(data, &j);
  147. data = _m3d_findarg(data);
  148. m3d->face[m3d->numface + i].vertex[0] = m3d->numvertex + j;
  149. m3d->face[m3d->numface + i].texcoord[0] = m3d->numtmap + j;
  150. data = _m3d_getint(data, &j);
  151. data = _m3d_findarg(data);
  152. m3d->face[m3d->numface + i].vertex[2] = m3d->numvertex + j;
  153. m3d->face[m3d->numface + i].texcoord[2] = m3d->numtmap + j;
  154. data = _m3d_getint(data, &j);
  155. data = _m3d_findarg(data);
  156. m3d->face[m3d->numface + i].vertex[1] = m3d->numvertex + j;
  157. m3d->face[m3d->numface + i].texcoord[1] = m3d->numtmap + j;
  158. data = _m3d_getint(data, &j); m3d->face[m3d->numface + i].normal[0] = m3d->numvertex + nv + j;
  159. data = _m3d_findarg(data);
  160. data = _m3d_getint(data, &j); m3d->face[m3d->numface + i].normal[2] = m3d->numvertex + nv + j;
  161. data = _m3d_findarg(data);
  162. data = _m3d_getint(data, &j); m3d->face[m3d->numface + i].normal[1] = m3d->numvertex + nv + j;
  163. data = ms3d_nextline(data);
  164. }
  165. m3d->numvertex += nv + nn;
  166. m3d->numtmap += nv;
  167. m3d->numface += nf;
  168. }
  169. } else
  170. if(!memcmp(s, "Materials:", 10)) {
  171. m3d->material = (m3dm_t*)realloc(m3d->material, (m3d->nummaterial + num) * sizeof(m3dm_t));
  172. if(!m3d->material) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  173. memset(&m3d->material[m3d->nummaterial], 0, num * sizeof(m3dm_t));
  174. for(n = 0; n < num; n++) {
  175. /* first line: name */
  176. for(e = ++data; *e && *e != '\"'; e++);
  177. *e++ = 0;
  178. s = _m3d_safestr(data, 0);
  179. data = ms3d_nextline(e);
  180. m = &m3d->material[m3d->nummaterial++];
  181. m->name = s;
  182. m->numprop = 0;
  183. m->prop = (m3dp_t*)malloc(8 * sizeof(m3dp_t));
  184. if(!m->prop) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  185. memset(m->prop, 0, 8 * sizeof(m3dp_t));
  186. /* next 4 lines: colors */
  187. for(i = 0; i < 4; i++) {
  188. r = g = b = a = 0.0f;
  189. data = _m3d_getfloat(data, &r);
  190. data = _m3d_getfloat(data, &g);
  191. data = _m3d_getfloat(data, &b);
  192. data = _m3d_getfloat(data, &a);
  193. data = ms3d_nextline(data);
  194. if(a > 0.0) {
  195. m->prop[m->numprop].type = mt[i];
  196. m->prop[m->numprop].value.color =
  197. ((uint32_t)(a*255.0) << 24L) |
  198. ((uint32_t)(b*255.0) << 16L) |
  199. ((uint32_t)(g*255.0) << 8L) |
  200. ((uint32_t)(r*255.0) << 0L);
  201. m->numprop++;
  202. }
  203. }
  204. /* next: shininess value */
  205. m->prop[m->numprop].type = m3dp_Ns;
  206. data = _m3d_getfloat(data, &m->prop[m->numprop++].value.fnum);
  207. data = ms3d_nextline(data);
  208. /* next: transparency, we don't use it, we have alpha in colors */
  209. data = ms3d_nextline(data);
  210. /* next: diffuse texture map */
  211. if(data[1] != '\"') {
  212. for(e = ++data; *e && *e != '\"'; e++);
  213. for(d = e; d > data && *d != '.'; d--);
  214. *d = 0;
  215. for(s = e; s[-1] != '\"' && s[-1] != '\\' && s[-1] != '/'; s--);
  216. m->prop[m->numprop].type = m3dp_map_Kd;
  217. e = s;
  218. s = _m3d_safestr(s, 0);
  219. for(i = 0, l = -1U; i < m3d->numtexture; i++) {
  220. if(!strcmp(s, m3d->texture[i].name)) { l = i; free(s); break; }
  221. }
  222. if(l == -1U) {
  223. if(storeinline) {
  224. path = bn = (char*)malloc(strlen(e) + 5);
  225. strcpy(path, e);
  226. bn += strlen(e);
  227. strcpy(bn, ".png");
  228. if(!(readfile(path, &l))) {
  229. strcpy(bn, ".PNG");
  230. if(!(readfile(path, &l))) {
  231. for(l = strlen(path)-1; l > 0; l--)
  232. if(path[l] >= 'A' && path[l] <= 'Z') path[l] += 'a'-'A';
  233. readfile(path, &l);
  234. }
  235. }
  236. if(l) {
  237. if(verbose > 1) printf(" Inlining '%s'\n", s);
  238. } else
  239. if(verbose > 2) printf(" Texture '%s' not found\n", path);
  240. free(path);
  241. }
  242. l = m3d->numtexture++;
  243. m3d->texture = (m3dtx_t*)realloc(m3d->texture, m3d->numtexture * sizeof(m3dtx_t));
  244. if(!m3d->texture) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  245. m3d->texture[l].name = s;
  246. m3d->texture[l].w = m3d->texture[l].h = 0;
  247. m3d->texture[l].d = NULL;
  248. }
  249. *d = '.';
  250. m->prop[m->numprop++].value.textureid = l;
  251. }
  252. data = ms3d_nextline(data);
  253. /* next: alpha texture map, we don't use it, we have alpha in diffuse texture */
  254. data = ms3d_nextline(data);
  255. }
  256. } else
  257. if(!memcmp(s, "Bones:", 6)) {
  258. m3d->bone = (m3db_t*)realloc(m3d->bone, (m3d->numbone + num) * sizeof(m3db_t));
  259. if(!m3d->bone) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  260. memset(&m3d->bone[m3d->numbone], 0, num * sizeof(m3db_t));
  261. m3d->skin = (m3ds_t*)realloc(m3d->skin, (m3d->numskin + num) * sizeof(m3ds_t));
  262. if(!m3d->skin) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  263. memset(&m3d->skin[m3d->numskin], 0, num * sizeof(m3ds_t));
  264. for(n = 0; n < num; n++) {
  265. m3d->skin[m3d->numskin + n].boneid[0] = m3d->numbone + n;
  266. m3d->skin[m3d->numskin + n].weight[0] = 1.0;
  267. for(i = 1; i < M3D_NUMBONE; i++) m3d->skin[m3d->numskin + n].boneid[i] = -1U;
  268. m3d->bone[m3d->numbone + n].parent = -1U;
  269. /* first line: name */
  270. for(e = ++data; *e && *e != '\"'; e++);
  271. *e++ = 0;
  272. m3d->bone[m3d->numbone + n].name = _m3d_safestr(data, 0);
  273. data = ms3d_nextline(e);
  274. /* second line: parent */
  275. for(e = ++data; *e && *e != '\"'; e++);
  276. *e++ = 0;
  277. bn = _m3d_safestr(data, 0);
  278. if(bn) {
  279. /* find parent index by name */
  280. for(i = 0; i < n; i++)
  281. if(!strcmp(m3d->bone[m3d->numbone + i].name, bn)) {
  282. m3d->bone[m3d->numbone + n].parent = i;
  283. break;
  284. }
  285. free(bn);
  286. }
  287. data = ms3d_nextline(e);
  288. /* third line bind-pose: (flags) (x) (y) (z) (roll) (pitch) (yaw) */
  289. m3d->vertex = (m3dv_t*)realloc(m3d->vertex, (m3d->numvertex + 2) * sizeof(m3dv_t));
  290. if(!m3d->vertex) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  291. memset(&m3d->vertex[m3d->numvertex], 0, 2 * sizeof(m3dv_t));
  292. m3d->vertex[m3d->numvertex + 0].skinid = -1U;
  293. m3d->vertex[m3d->numvertex + 1].skinid = -2U;
  294. m3d->vertex[m3d->numvertex + 1].type = VT_QUATERN;
  295. data = _m3d_findarg(data);
  296. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex].x);
  297. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex].y);
  298. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex].z);
  299. data = _m3d_getfloat(data, &r);
  300. data = _m3d_getfloat(data, &g);
  301. data = _m3d_getfloat(data, &y);
  302. _m3d_euler_to_quat(r, g, y, &m3d->vertex[m3d->numvertex + 1]);
  303. data = ms3d_nextline(data);
  304. m3d->bone[m3d->numbone + n].pos = m3d->numvertex;
  305. m3d->bone[m3d->numbone + n].ori = m3d->numvertex + 1;
  306. m3d->numvertex += 2;
  307. /* fourth line: number of animation keyframes (position) */
  308. data = _m3d_getint(data, &nv);
  309. data = ms3d_nextline(data);
  310. m3d->vertex = (m3dv_t*)realloc(m3d->vertex, (m3d->numvertex + nv) * sizeof(m3dv_t));
  311. if(!m3d->vertex) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  312. memset(&m3d->vertex[m3d->numvertex], 0, nv * sizeof(m3dv_t));
  313. for(i = 0; i < nv; i++) {
  314. m3d->vertex[m3d->numvertex + i].skinid = -1U;
  315. data = _m3d_getfloat(data, &t);
  316. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex + i].x);
  317. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex + i].y);
  318. data = _m3d_getfloat(data, &m3d->vertex[m3d->numvertex + i].z);
  319. ms3d_addframe(m3d, (uint32_t)(t*1000.0), m3d->numbone + n, m3d->numvertex + i, m3d->bone[m3d->numbone + n].ori);
  320. data = ms3d_nextline(data);
  321. }
  322. m3d->numvertex += nv;
  323. /* next: number of animation keyframes (rotations) */
  324. data = _m3d_getint(data, &nv);
  325. data = ms3d_nextline(data);
  326. m3d->vertex = (m3dv_t*)realloc(m3d->vertex, (m3d->numvertex + nv) * sizeof(m3dv_t));
  327. if(!m3d->vertex) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  328. memset(&m3d->vertex[m3d->numvertex], 0, nv * sizeof(m3dv_t));
  329. for(i = 0; i < nv; i++) {
  330. m3d->vertex[m3d->numvertex + i].skinid = -2U;
  331. m3d->vertex[m3d->numvertex + i].type = VT_QUATERN;
  332. data = _m3d_getfloat(data, &t);
  333. data = _m3d_getfloat(data, &x);
  334. data = _m3d_getfloat(data, &b);
  335. data = _m3d_getfloat(data, &z);
  336. _m3d_euler_to_quat(r + x, g + b, y + z, &m3d->vertex[m3d->numvertex + i]);
  337. ms3d_addframe(m3d, (uint32_t)(t*1000.0), m3d->numbone + n, m3d->bone[m3d->numbone + n].pos, m3d->numvertex + i);
  338. data = ms3d_nextline(data);
  339. }
  340. m3d->numvertex += nv;
  341. }
  342. m3d->numbone += num;
  343. m3d->numskin += num;
  344. } else
  345. if(verbose > 2) {
  346. for(e = s; *e && *e != ':' && *e != ' '; e++);
  347. if(*e) { *e = 0; printf(" Unknown chunk: '%s'\n", s); *e = ' '; }
  348. }
  349. }
  350. return m3d;
  351. }
  352. #if 0
  353. /* MAYBE implement this. For now, binary MS3D supported via assimp */
  354. /**
  355. * Load a model and convert it's structures into a Model 3D in-memory format
  356. */
  357. m3d_t *ms3d_bin_load(unsigned char *data, unsigned int size)
  358. {
  359. m3d_t *m3d;
  360. int mi, mt[4] = { m3dp_Ka, m3dp_Kd, m3dp_Ks, m3dp_Ke };
  361. m3d = (m3d_t*)malloc(sizeof(m3d_t));
  362. if(!m3d) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  363. memset(m3d, 0, sizeof(m3d_t));
  364. m3d->flags = M3D_FLG_FREESTR;
  365. /* add default position and orientation, may be needed by bones in group statements */
  366. m3d->numvertex = 2;
  367. m3d->vertex = (m3dv_t*)malloc(m3d->numvertex * sizeof(m3dv_t));
  368. if(!m3d->vertex) { fprintf(stderr, "m3dconv: unable to allocate memory\n"); exit(1); }
  369. memset(m3d->vertex, 0, 2 * sizeof(m3dv_t));
  370. m3d->vertex[0].skinid = -1U;
  371. m3d->vertex[0].type = VT_WORLD;
  372. m3d->vertex[1].skinid = -2U;
  373. m3d->vertex[1].type = VT_QUATERN;
  374. return m3d;
  375. }
  376. #endif