viewer.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. /*
  2. * m3dview/viewer.c
  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 portable Model 3D viewer - VBO version
  27. * https://gitlab.com/bztsrc/model3d
  28. *
  29. */
  30. #include "viewer.h"
  31. #include "font6.h"
  32. #define M3D_IMPLEMENTATION
  33. #define M3D_ASCII
  34. #ifdef PROFILING
  35. #include <sys/time.h>
  36. #define M3D_PROFILING
  37. #endif
  38. #include <m3d.h>
  39. #include <gl.h>
  40. #include <unistd.h>
  41. /* variables */
  42. int screenw = 800, screenh = 600;
  43. unsigned char *buff = NULL;
  44. unsigned int size, actionid = 0, frame = -1U, fpsdivisor = 1, lastframe = 0;
  45. char *wintitle = NULL, infostr[128];
  46. m3d_t *model = NULL;
  47. int mousebtn = 0, mousemove = 0, mousex = 0, mousey = 0, mousez = 0, doframe = 0, domesh = 1, doskel = 0;
  48. float mindist = 1, maxdist = 25, distance = 5.5, pitch = /*0*/-35.264, yaw = /*0*/45;
  49. float light_position[4] = { -1, 2, 2, 0 }, light_color[4] = { 0.8, 0.8, 0.8, 1 }, shadow_color[4] = { 0, 0, 0, 0 };
  50. unsigned int numtexture, texture[32];
  51. unsigned char checker_data[4*128*128];
  52. uint32_t default_color = 0xFF235580;
  53. void initmodel();
  54. #ifdef _MSC_VER
  55. #pragma pack(push)
  56. #pragma pack(1)
  57. #endif
  58. /* vertex attributes. Packing shouldn't be an issue, but be safe than sorry */
  59. typedef struct {
  60. float vertex_x;
  61. float vertex_y;
  62. float vertex_z;
  63. float normal_x;
  64. float normal_y;
  65. float normal_z;
  66. float tex_u;
  67. float tex_v;
  68. uint32_t color;
  69. uint32_t vertexid; /* needed for animation */
  70. uint32_t normalid;
  71. }
  72. #ifdef _MSC_VER
  73. #pragma pack(pop)
  74. #else
  75. __attribute__((packed))
  76. #endif
  77. vbo_t;
  78. vbo_t *vbo = NULL;
  79. /* integer triplets, material index, vbo index and vbo size */
  80. unsigned int numvbo, numvboidx = 0, *vboidx = NULL;
  81. /**
  82. * Load model from buffer
  83. */
  84. void loadbuf(unsigned char *data)
  85. {
  86. model = m3d_load(data, NULL, NULL, NULL);
  87. if(!model) error("unable to parse model");
  88. initmodel();
  89. }
  90. /**
  91. * File reader callback for the M3D SDK, also used to load the model
  92. */
  93. unsigned char *readfile(char *fn, unsigned int *size)
  94. {
  95. FILE *f;
  96. unsigned char *ret = NULL;
  97. *size = 0;
  98. f = fopen(fn, "rb");
  99. if(f) {
  100. fseek(f, 0L, SEEK_END);
  101. *size = (unsigned int)ftell(f);
  102. fseek(f, 0L, SEEK_SET);
  103. ret = (unsigned char*)malloc(*size + 1);
  104. if(ret) {
  105. fread(ret, *size, 1, f);
  106. ret[*size] = 0;
  107. } else
  108. *size = 0;
  109. fclose(f);
  110. }
  111. return ret;
  112. }
  113. /**
  114. * Parse command line and load a model
  115. */
  116. void load(int argc, char **argv)
  117. {
  118. char *fn;
  119. #ifdef PROFILING
  120. struct timeval tv0, tv1, tvd;
  121. #endif
  122. /* check arguments */
  123. if(argc < 2) {
  124. printf("Model 3D Viewer by bzt Copyright (C) 2019 MIT license\n\n"
  125. "./m3dview <m3d file>"
  126. #ifdef PREVIEW
  127. " [out.png]"
  128. #endif
  129. "\n\n");
  130. exit(0);
  131. }
  132. #ifdef PROFILING
  133. gettimeofday(&tv0, NULL);
  134. #endif
  135. /* read the file */
  136. buff = readfile(argv[1], &size);
  137. if(!buff) error("unable to load model file");
  138. #ifdef PROFILING
  139. gettimeofday(&tv1, NULL);
  140. tvd.tv_sec = tv1.tv_sec - tv0.tv_sec;
  141. tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
  142. if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
  143. printf("File read in time %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec);
  144. #endif
  145. /* decode bit-chunk into in-memory C structures */
  146. model = m3d_load(buff, readfile, free, NULL);
  147. if(!model) error("unable to parse model");
  148. /* set up window title */
  149. fn = strrchr(argv[1], '/'); if(!fn) fn = strrchr(argv[1], '\\');
  150. if(!fn) fn = argv[1]; else fn++;
  151. wintitle = (char*)malloc(strlen(fn) + strlen(model->name) + strlen(model->license) + 32);
  152. if(!wintitle) error("unable to allocate memory");
  153. strcpy(wintitle, "Model 3D Viewer: ");
  154. strcat(wintitle, fn);
  155. strcat(wintitle, " ");
  156. strcat(wintitle, model->name);
  157. if(model->license[0]) {
  158. strcat(wintitle, " (");
  159. strcat(wintitle, model->license);
  160. strcat(wintitle, ")");
  161. }
  162. #ifdef PROFILING
  163. gettimeofday(&tv0, NULL);
  164. tvd.tv_sec = tv0.tv_sec - tv1.tv_sec;
  165. tvd.tv_usec = tv0.tv_usec - tv1.tv_usec;
  166. if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
  167. printf("Model parsed in %3ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec);
  168. #endif
  169. /* initialize info string and vbo */
  170. initmodel();
  171. }
  172. /**
  173. * Initialize loaded model
  174. */
  175. void initmodel()
  176. {
  177. unsigned int i, j, k, l, last = -2U;
  178. uint32_t diffuse_color = default_color;
  179. #ifdef PROFILING
  180. struct timeval tv0, tv1, tvd;
  181. gettimeofday(&tv0, NULL);
  182. #endif
  183. sprintf(infostr, "%d triangles, %d vertices (%d bit), scale %g, %d actions",
  184. model->numface, model->numvertex, model->vc_s << 3, model->scale, model->numaction);
  185. /* count how many times we switch material context */
  186. numvbo = model->numface * 3;
  187. for(i = 0; i < model->numface; i++) {
  188. if(last != model->face[i].materialid) {
  189. last = model->face[i].materialid;
  190. numvboidx++;
  191. }
  192. }
  193. vboidx = (unsigned int*)malloc(numvboidx * 3 * sizeof(numvboidx));
  194. if(!vboidx) error("unable to allocate memory");
  195. /* set up vbo array */
  196. vbo = (vbo_t*)malloc(numvbo * sizeof(vbo_t));
  197. if(!vbo) error("unable to allocate memory");
  198. memset(vbo, 0, numvbo * sizeof(vbo_t));
  199. for(i = k = l = 0, last = -2U; i < model->numface; i++) {
  200. /* if we change material, record it in vboidx and set diffuse color in vbo.color */
  201. if(last != model->face[i].materialid) {
  202. last = model->face[i].materialid;
  203. diffuse_color = default_color;
  204. if(last < model->nummaterial)
  205. for(j = 0; j < model->material[last].numprop; j++)
  206. if(model->material[last].prop[j].type == m3dp_Kd) {
  207. diffuse_color = model->material[last].prop[j].value.color;
  208. break;
  209. }
  210. if(l)
  211. vboidx[l-1] = k - vboidx[l-2];
  212. vboidx[l] = last;
  213. vboidx[l + 1] = k;
  214. l += 3;
  215. }
  216. for(j = 0; j < 3; j++, k++) {
  217. /* fill up VBO records */
  218. memcpy(&vbo[k].vertex_x, &model->vertex[model->face[i].vertex[j]].x, 3 * sizeof(float));
  219. memcpy(&vbo[k].normal_x, &model->vertex[model->face[i].normal[j]].x, 3 * sizeof(float));
  220. if(model->tmap && model->face[i].texcoord[j] < model->numtmap) {
  221. vbo[k].tex_u = model->tmap[model->face[i].texcoord[j]].u;
  222. vbo[k].tex_v = 1.0f - model->tmap[model->face[i].texcoord[j]].v;
  223. } else
  224. vbo[k].tex_u = vbo[k].tex_v = 0.0f;
  225. /* if there's no material, use vertex color for vbo.color, may change for every vertex */
  226. vbo[k].color = (model->face[i].materialid != -1U ? diffuse_color : (
  227. model->vertex[model->face[i].vertex[j]].color ? model->vertex[model->face[i].vertex[j]].color : default_color))
  228. #ifdef PREVIEW
  229. & 0xFFFEFEFE
  230. #endif
  231. ;
  232. if(!vbo[k].color) vbo[k].color = default_color;
  233. vbo[k].vertexid = model->face[i].vertex[j];
  234. vbo[k].normalid = model->face[i].normal[j];
  235. }
  236. }
  237. if(l)
  238. vboidx[l-1] = k - vboidx[l-2];
  239. #ifdef PROFILING
  240. gettimeofday(&tv1, NULL);
  241. tvd.tv_sec = tv1.tv_sec - tv0.tv_sec;
  242. tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
  243. if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
  244. printf("VBO generated in %2ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec);
  245. #endif
  246. }
  247. /**
  248. * Multiply a vertex with a transformation matrix
  249. */
  250. void vec3_mul_mat4(m3dv_t *out, m3dv_t *v, float *mat)
  251. {
  252. out->x = mat[ 0] * v->x + mat[ 1] * v->y + mat[ 2] * v->z + mat[ 3];
  253. out->y = mat[ 4] * v->x + mat[ 5] * v->y + mat[ 6] * v->z + mat[ 7];
  254. out->z = mat[ 8] * v->x + mat[ 9] * v->y + mat[10] * v->z + mat[11];
  255. }
  256. /**
  257. * Multiply a vertex with a rotation matrix
  258. */
  259. void vec3_mul_mat3(m3dv_t *out, m3dv_t *v, float *mat)
  260. {
  261. out->x = mat[ 0] * v->x + mat[ 1] * v->y + mat[ 2] * v->z;
  262. out->y = mat[ 4] * v->x + mat[ 5] * v->y + mat[ 6] * v->z;
  263. out->z = mat[ 8] * v->x + mat[ 9] * v->y + mat[10] * v->z;
  264. }
  265. /**
  266. * Multiply a vertex with a quaternion
  267. */
  268. void vec3_mul_quat(float *out, float *q)
  269. {
  270. float vx = out[0], vy = out[1], vz = out[2];
  271. float qx = q[0], qy = q[1], qz = q[2], qw = q[3];
  272. out[0] = vx*(qx*qx + qw*qw - qy*qy - qz*qz) + vy*(2*qx*qy - 2*qw*qz) + vz*(2*qx*qz + 2*qw*qy);
  273. out[1] = vx*(2*qw*qz + 2*qx*qy) + vy*(qw*qw - qx*qx + qy*qy - qz*qz) + vz*(-2*qw*qx + 2*qy*qz);
  274. out[2] = vx*(-2*qw*qy + 2*qx*qz) + vy*(2*qw*qx + 2*qy*qz)+ vz*(qw*qw - qx*qx - qy*qy + qz*qz);
  275. }
  276. /**
  277. * Multiply quaternions
  278. */
  279. void quat_mul_quat(float *out, float *q)
  280. {
  281. float qax = q[0], qay = q[1], qaz = q[2], qaw = q[3];
  282. float qbx = out[0], qby = out[1], qbz = out[2], qbw = out[3];
  283. out[0] = qax*qbw + qaw*qbx + qay*qbz - qaz*qby;
  284. out[1] = qay*qbw + qaw*qby + qaz*qbx - qax*qbz;
  285. out[2] = qaz*qbw + qaw*qbz + qax*qby - qay*qbx;
  286. out[3] = qaw*qbw - qax*qbx - qay*qby - qaz*qbz;
  287. }
  288. /**
  289. * Convert a standard uint32_t color into OpenGL color
  290. */
  291. void set_color(uint32_t c, float *f) {
  292. if(!c) {
  293. f[0] = f[1] = f[2] = 0.0; f[3] = 1.0;
  294. } else {
  295. f[3] = ((float)((c >> 24)&0xff)) / 255;
  296. #ifndef PREVIEW
  297. f[2] = ((float)((c >> 16)&0xff)) / 255;
  298. f[1] = ((float)((c >> 8)&0xff)) / 255;
  299. f[0] = ((float)((c >> 0)&0xff)) / 255;
  300. #else
  301. f[2] = ((float)((c >> 16)&0xff)) / 256;
  302. f[1] = ((float)((c >> 8)&0xff)) / 256;
  303. f[0] = ((float)((c >> 0)&0xff)) / 256;
  304. #endif
  305. }
  306. }
  307. /**
  308. * Set material to use.
  309. */
  310. void set_material(unsigned int mi)
  311. {
  312. unsigned int i, t;
  313. float material[13];
  314. m3dm_t *m;
  315. /* reset material */
  316. memset(&material, 0, sizeof(material));
  317. material[3] = material[7] = material[11] = 1.0f; /* alpha values */
  318. glDisable(GL_TEXTURE_2D);
  319. /* update with what we have in this new material */
  320. if(mi < model->nummaterial) {
  321. m = &model->material[mi];
  322. for(i = 0; i < m->numprop; i++) {
  323. switch(m->prop[i].type) {
  324. case m3dp_Kd: /* this is already copied into the VBO */ break;
  325. case m3dp_Ka: set_color(m->prop[i].value.color, (float*)&material[0]); break;
  326. case m3dp_Ks: set_color(m->prop[i].value.color, (float*)&material[4]); break;
  327. case m3dp_Ke: set_color(m->prop[i].value.color, (float*)&material[8]); break;
  328. case m3dp_Ns: material[12] = m->prop[i].value.fnum; break;
  329. case m3dp_map_Kd:
  330. if(numtexture) {
  331. t = m->prop[i].value.textureid < numtexture ? m->prop[i].value.textureid + 1 : 0;
  332. glEnable(GL_TEXTURE_2D);
  333. glBindTexture(GL_TEXTURE_2D, texture[t]);
  334. }
  335. break;
  336. }
  337. }
  338. }
  339. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (GLfloat*)&material[0]);
  340. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat*)&material[4]);
  341. glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (GLfloat*)&material[8]);
  342. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material[12]);
  343. return;
  344. }
  345. /**
  346. * Set FPS divisor for animation debugging
  347. */
  348. void fpsdiv(int idx)
  349. {
  350. switch(idx) {
  351. case 1: fpsdivisor = 2; break;
  352. case 2: fpsdivisor = 3; break;
  353. case 3: fpsdivisor = 5; break;
  354. case 4: fpsdivisor = 10; break;
  355. case 5: fpsdivisor = 15; break;
  356. case 6: fpsdivisor = 20; break;
  357. case 7: fpsdivisor = 25; break;
  358. case 8: fpsdivisor = 30; break;
  359. case 9: fpsdivisor = 60; break;
  360. default: fpsdivisor = 1; break;
  361. }
  362. }
  363. /**
  364. * Switch to next frame
  365. */
  366. void nextframe(void)
  367. {
  368. doframe = 0; frame++;
  369. continous();
  370. }
  371. /**
  372. * Switch to previous frame
  373. */
  374. void prevframe(void)
  375. {
  376. doframe = 0; frame--;
  377. continous();
  378. }
  379. /**
  380. * Toggle continous playback
  381. */
  382. void continous(void)
  383. {
  384. doframe ^= 1;
  385. if(actionid < model->numaction) {
  386. if(frame == -1U) frame = model->action[actionid].numframe - 1;
  387. if(frame > model->action[actionid].numframe - 1) frame = 0;
  388. } else
  389. frame = 0;
  390. }
  391. /**
  392. * Zoom in
  393. */
  394. void zoomin(void)
  395. {
  396. distance -= 0.01 * distance;
  397. if(distance < 0.000001) distance = 0.000001;
  398. }
  399. /**
  400. * Zoom out
  401. */
  402. void zoomout(void)
  403. {
  404. distance += 0.01 * distance;
  405. if(distance > 100000) distance = 100000;
  406. }
  407. /**
  408. * Print an UTF-8 string
  409. */
  410. void glPrint(char *s)
  411. {
  412. unsigned int c;
  413. if(!s || !*s) return;
  414. while(*s) {
  415. if((*s & 128) != 0) {
  416. if(!(*s & 32)) { c = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); s++; } else
  417. if(!(*s & 16)) { c = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); s += 2; } else
  418. if(!(*s & 8)) { c = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); *s += 3; }
  419. else c = 0;
  420. } else c = *s;
  421. s++;
  422. if(c >= (unsigned int)(sizeof(font)/sizeof(font[0])/((FONT_WIDTH+7)/8)/FONT_HEIGHT)) c = 0;
  423. glBitmap(FONT_WIDTH, FONT_HEIGHT, 0, 0, (float)FONT_WIDTH, 0.0, ((unsigned char*)&font + c * FONT_HEIGHT));
  424. }
  425. }
  426. /**
  427. * Set up OpenGL context
  428. */
  429. void setupgl(void)
  430. {
  431. unsigned int i, j, k;
  432. glEnable(GL_NORMALIZE);
  433. glEnableClientState(GL_VERTEX_ARRAY);
  434. glEnableClientState(GL_NORMAL_ARRAY);
  435. glEnableClientState(GL_COLOR_ARRAY);
  436. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  437. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  438. glClearColor(0.4, 0.4, 0.4, 1.0);
  439. glShadeModel(GL_SMOOTH);
  440. glFrontFace(GL_CCW);
  441. glEnable(GL_LIGHT0);
  442. glLightfv(GL_LIGHT0, GL_POSITION, light_position);
  443. glLightfv(GL_LIGHT0, GL_SPECULAR, light_color);
  444. glLightfv(GL_LIGHT0, GL_AMBIENT, shadow_color);
  445. glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
  446. glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  447. glViewport(0, 0, screenw, screenh);
  448. glVertexPointer(3, GL_FLOAT, sizeof(vbo_t), &vbo[0].vertex_x);
  449. glNormalPointer(GL_FLOAT, sizeof(vbo_t), &vbo[0].normal_x);
  450. glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vbo_t), &vbo[0].color);
  451. glTexCoordPointer(2, GL_FLOAT, sizeof(vbo_t), &vbo[0].tex_u);
  452. /* set up GL textures */
  453. #ifdef GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
  454. glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, (GLint*)&numtexture);
  455. if(numtexture > 31) numtexture = 31;
  456. if(numtexture < 1) return;
  457. #else
  458. numtexture = 32;
  459. #endif
  460. memset(texture, 0, sizeof(texture));
  461. glGenTextures(numtexture, (GLuint*)&texture);
  462. for (j = k = 0; j < 128; j++)
  463. for (i = 0; i < 128; i++, k += 4) {
  464. memcpy(&checker_data[k], &default_color, 4);
  465. checker_data[k] += ((((i>>5) & 1) ^ ((j>>5) & 1)) << 5);
  466. }
  467. glBindTexture(GL_TEXTURE_2D, texture[0]);
  468. #ifdef GL_GENERATE_MIPMAP
  469. glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
  470. #endif
  471. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  472. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  473. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  474. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  475. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, checker_data);
  476. /* add textures from model */
  477. if(model->numtexture) {
  478. for(i = 0; i < numtexture && i < model->numtexture; i++) {
  479. if(!model->texture[i].w || !model->texture[i].h || !model->texture[i].d) {
  480. fprintf(stderr, "m3dview: unable to load texture '%s'\n", model->texture[i].name);
  481. texture[1 + i] = texture[0];
  482. continue;
  483. }
  484. glBindTexture(GL_TEXTURE_2D, texture[1 + i]);
  485. #ifdef GL_GENERATE_MIPMAP
  486. glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
  487. #endif
  488. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  489. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  490. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  491. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  492. switch(model->texture[i].f) {
  493. case 1: k = GL_LUMINANCE; break;
  494. case 2: k = GL_LUMINANCE_ALPHA; break;
  495. case 3: k = GL_RGB; break;
  496. default: k = GL_RGBA; break;
  497. }
  498. glTexImage2D(GL_TEXTURE_2D, 0, k, model->texture[i].w, model->texture[i].h, 0, k, GL_UNSIGNED_BYTE,
  499. model->texture[i].d);
  500. }
  501. }
  502. }
  503. /**
  504. * Animate the mesh
  505. */
  506. m3db_t *animate_model(unsigned int msec)
  507. {
  508. unsigned int i, j, s;
  509. m3db_t *animpose;
  510. m3dv_t tmp1, tmp2;
  511. if(actionid < model->numaction && doframe) {
  512. /* if we are frame debugging, use the exact timestamp of the frame as msec */
  513. if(frame == -1U) frame = 0;
  514. msec = model->action[actionid].frame[frame].msec;
  515. } else
  516. /* otherwise modify by the debugging fps divisor (is 1 by default) */
  517. msec /= fpsdivisor;
  518. /* get the animation-pose skeleton*/
  519. animpose = m3d_pose(model, actionid, msec);
  520. /* don't regenerate if we have the same timestamp as last time */
  521. if(msec == lastframe) return animpose;
  522. lastframe = msec;
  523. /* convert mesh vertices from bind-pose into animation-pose */
  524. for(i = 0; i < numvbo; i++) {
  525. s = model->vertex[vbo[i].vertexid].skinid;
  526. if(s != -1U) {
  527. /* we assume that vbo_t is packed and normals follow vertex coordinates */
  528. memset(&vbo[i].vertex_x, 0, 6 * sizeof(float));
  529. for(j = 0; j < M3D_NUMBONE && model->skin[s].weight[j] > 0.0; j++) {
  530. /* transfer from bind-pose model-space into bone-local space */
  531. vec3_mul_mat4(&tmp1, &model->vertex[vbo[i].vertexid], (float*)&model->bone[ model->skin[s].boneid[j] ].mat4);
  532. /* transfer from bone-local space into animation-pose model-space */
  533. vec3_mul_mat4(&tmp2, &tmp1, (float*)&animpose[ model->skin[s].boneid[j] ].mat4);
  534. /* multiply with weight and accumulate */
  535. vbo[i].vertex_x += tmp2.x * model->skin[s].weight[j];
  536. vbo[i].vertex_y += tmp2.y * model->skin[s].weight[j];
  537. vbo[i].vertex_z += tmp2.z * model->skin[s].weight[j];
  538. /* now again for the normal vector */
  539. vec3_mul_mat3(&tmp1, &model->vertex[vbo[i].normalid], (float*)&model->bone[ model->skin[s].boneid[j] ].mat4);
  540. vec3_mul_mat3(&tmp2, &tmp1, (float*)&animpose[ model->skin[s].boneid[j] ].mat4);
  541. vbo[i].normal_x += tmp2.x * model->skin[s].weight[j];
  542. vbo[i].normal_y += tmp2.y * model->skin[s].weight[j];
  543. vbo[i].normal_z += tmp2.z * model->skin[s].weight[j];
  544. }
  545. }
  546. }
  547. return animpose;
  548. }
  549. /**
  550. * Display the model
  551. */
  552. void display(unsigned int msec)
  553. {
  554. m3db_t *animpose = NULL, *bones;
  555. unsigned int i, j;
  556. float fov, fov2, *skel = NULL, s;
  557. char tmp[64];
  558. /* handle model rotation */
  559. if(mousemove) {
  560. yaw -= mousex * 0.3;
  561. pitch -= mousey * 0.2;
  562. if (pitch < -90) pitch = -90;
  563. if (pitch > 90) pitch = 90;
  564. if (yaw < 0) yaw += 360;
  565. if (yaw > 360) yaw -= 360;
  566. mousemove = 0;
  567. }
  568. /* switch action to animate */
  569. if(actionid == -1U) actionid = model->numaction;
  570. else if((unsigned int)actionid > model->numaction) actionid = 0;
  571. /* animate the mesh */
  572. if(model->numaction)
  573. animpose = animate_model(msec);
  574. /* display model */
  575. #ifdef PREVIEW
  576. if(!msec)
  577. glClearColor(1.0, 1.0, 1.0, 1.0);
  578. #endif
  579. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  580. glMatrixMode(GL_PROJECTION);
  581. glLoadIdentity();
  582. fov = 0.221694 * (mindist/5);
  583. fov2 = fov * (float)screenw / (float)screenh;
  584. glFrustum(-fov2, fov2, -fov, fov, mindist/5, maxdist*5);
  585. glMatrixMode(GL_MODELVIEW);
  586. glLoadIdentity();
  587. glTranslatef(0, (float)mousez/10.0f, -distance*1.1);
  588. glRotatef(-pitch, 1, 0, 0);
  589. glRotatef(-yaw, 0, 1, 0);
  590. glEnable(GL_DEPTH_TEST);
  591. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  592. /* draw the coordinate system */
  593. if(msec) {
  594. glBegin(GL_LINES);
  595. glColor4f(1.0, 0.0, 0.0, 1.0); glVertex3f(0, 0, 0); glVertex3f( 1.001, 0.0, 0.0);
  596. glColor4f(0.5, 0.4, 0.4, 1.0); glVertex3f(0, 0, 0); glVertex3f(-1.001, 0.0, 0.0);
  597. glColor4f(0.0, 1.0, 0.0, 1.0); glVertex3f(0, 0, 0); glVertex3f( 0.0, 1.001, 0.0);
  598. glColor4f(0.4, 0.5, 0.4, 1.0); glVertex3f(0, 0, 0); glVertex3f( 0.0, -1.001, 0.0);
  599. glColor4f(0.0, 0.0, 1.0, 1.0); glVertex3f(0, 0, 0); glVertex3f( 0.0, 0.0, 1.001);
  600. glColor4f(0.4, 0.4, 0.5, 1.0); glVertex3f(0, 0, 0); glVertex3f( 0.0, 0.0, -1.001);
  601. glEnd();
  602. }
  603. /* draw the skeleton */
  604. if(doskel && model->numbone) {
  605. bones = animpose ? animpose : model->bone;
  606. /* the format stores parent local bones. We need to convert those to model space if we want to draw a skeleton */
  607. skel = (float*)malloc(model->numbone * 7 * sizeof(float));
  608. if(skel) {
  609. glColor4f(1.0, 0.0, 0.0, 1.0);
  610. for(i = 0; i < model->numbone; i++) {
  611. skel[i * 7 + 0] = model->vertex[bones[i].pos].x;
  612. skel[i * 7 + 1] = model->vertex[bones[i].pos].y;
  613. skel[i * 7 + 2] = model->vertex[bones[i].pos].z;
  614. skel[i * 7 + 3] = model->vertex[bones[i].ori].x;
  615. skel[i * 7 + 4] = model->vertex[bones[i].ori].y;
  616. skel[i * 7 + 5] = model->vertex[bones[i].ori].z;
  617. skel[i * 7 + 6] = model->vertex[bones[i].ori].w;
  618. if(bones[i].parent != M3D_UNDEF) {
  619. quat_mul_quat(&skel[i * 7 + 3], &skel[bones[i].parent * 7 + 3]);
  620. vec3_mul_quat(&skel[i * 7], &skel[bones[i].parent * 7 + 3]);
  621. skel[i * 7 + 0] += skel[bones[i].parent * 7 + 0];
  622. skel[i * 7 + 1] += skel[bones[i].parent * 7 + 1];
  623. skel[i * 7 + 2] += skel[bones[i].parent * 7 + 2];
  624. /* draw a line between child and parent bone */
  625. glBegin(GL_LINES);
  626. glVertex3f(skel[bones[i].parent * 7 + 0], skel[bones[i].parent * 7 + 1], skel[bones[i].parent * 7 + 2]);
  627. glVertex3f(skel[i * 7 + 0], skel[i * 7 + 1], skel[i * 7 + 2]);
  628. glEnd();
  629. }
  630. /* draw a cube at joint */
  631. glPushMatrix();
  632. glTranslatef(skel[i * 7 + 0], skel[i * 7 + 1], skel[i * 7 + 2]);
  633. glBegin(GL_TRIANGLES);
  634. s = 0.025f;
  635. glVertex3f(-s, -s, +s); glVertex3f(+s, -s, +s); glVertex3f(-s, +s, +s);
  636. glVertex3f(+s, +s, +s); glVertex3f(-s, +s, +s); glVertex3f(+s, -s, +s);
  637. glVertex3f(-s, -s, -s); glVertex3f(-s, +s, -s); glVertex3f(+s, -s, -s);
  638. glVertex3f(+s, +s, -s); glVertex3f(+s, -s, -s); glVertex3f(-s, +s, -s);
  639. glVertex3f(-s, +s, -s); glVertex3f(-s, +s, +s); glVertex3f(+s, +s, +s);
  640. glVertex3f(+s, +s, -s); glVertex3f(-s, +s, -s); glVertex3f(+s, +s, +s);
  641. glVertex3f(-s, -s, -s); glVertex3f(+s, -s, +s); glVertex3f(-s, -s, +s);
  642. glVertex3f(+s, -s, -s); glVertex3f(+s, -s, +s); glVertex3f(-s, -s, -s);
  643. glVertex3f(+s, -s, -s); glVertex3f(+s, +s, -s); glVertex3f(+s, +s, +s);
  644. glVertex3f(+s, -s, +s); glVertex3f(+s, -s, -s); glVertex3f(+s, +s, +s);
  645. glVertex3f(-s, -s, -s); glVertex3f(-s, +s, +s); glVertex3f(-s, +s, -s);
  646. glVertex3f(-s, -s, +s); glVertex3f(-s, +s, +s); glVertex3f(-s, -s, -s);
  647. glEnd();
  648. glPopMatrix();
  649. }
  650. free(skel);
  651. }
  652. }
  653. if(animpose) {
  654. free(animpose);
  655. animpose = NULL;
  656. }
  657. /* draw the mesh */
  658. if(domesh) {
  659. glEnable(GL_COLOR_MATERIAL);
  660. glEnable(GL_LIGHTING);
  661. glEnable(GL_LIGHT0);
  662. glAlphaFunc(GL_GREATER, 0.2);
  663. glEnable(GL_ALPHA_TEST);
  664. glEnable(GL_BLEND);
  665. for(i = j = 0; i < numvboidx; i++, j += 3) {
  666. set_material(vboidx[j + 0]);
  667. glDrawArrays(GL_TRIANGLES, vboidx[j + 1], vboidx[j + 2]);
  668. }
  669. glDisable(GL_BLEND);
  670. glDisable(GL_ALPHA_TEST);
  671. glDisable(GL_LIGHTING);
  672. glDisable(GL_COLOR_MATERIAL);
  673. }
  674. glDisable(GL_DEPTH_TEST);
  675. glDisable(GL_TEXTURE_2D);
  676. /* on screen text */
  677. if(msec) {
  678. glMatrixMode(GL_PROJECTION);
  679. glLoadIdentity();
  680. glOrtho(0, screenw, screenh, 0, -1, 1);
  681. glMatrixMode(GL_MODELVIEW);
  682. glLoadIdentity();
  683. glColor4f(1, 1, 1, 1);
  684. glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT );
  685. glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE );
  686. glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE );
  687. glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
  688. glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
  689. glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
  690. glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
  691. glRasterPos2f(0.0, (float)FONT_HEIGHT);
  692. glPrint(model->name);
  693. glPrint(" (");
  694. glPrint(model->license[0] ? model->license : "no license");
  695. glPrint(", ");
  696. glPrint(model->author[0] ? model->author : "no author");
  697. glPrint(")");
  698. glRasterPos2f(0.0, (float)(FONT_HEIGHT*2));
  699. glPrint(infostr);
  700. if(model->numaction) {
  701. glPrint(", current: ");
  702. glPrint(actionid < model->numaction ? model->action[actionid].name : "(bind-pose)");
  703. }
  704. if(doframe) {
  705. sprintf(tmp, "frame %4d / %4d",
  706. actionid < model->numaction ? frame + 1 : 1,
  707. actionid < model->numaction ? model->action[actionid].numframe : 1);
  708. glRasterPos2f(0.0, (float)(FONT_HEIGHT*3));
  709. glPrint(tmp);
  710. }
  711. glRasterPos2f(0.0, (float)(screenh - 2));
  712. glPrint("[M]: toggle mesh, [S]: toggle skeleton, [PgUp]/[PgDn]: change action");
  713. glPopClientAttrib();
  714. }
  715. }
  716. /**
  717. * Print an error message and quit
  718. */
  719. void error(char *msg)
  720. {
  721. fprintf(stderr, "m3dview: %s\n", msg);
  722. cleanup();
  723. exit(1);
  724. }
  725. /**
  726. * Clean up on exit
  727. */
  728. void cleanup()
  729. {
  730. if(model) m3d_free(model);
  731. if(vbo) free(vbo);
  732. if(buff) free(buff);
  733. }