b2l_model_viewer.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. #include <stdlib.h>
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <math.h>
  6. #include <getopt.h>
  7. #include <gtk/gtk.h>
  8. #include "lua.h"
  9. #include "lualib.h"
  10. #include "lauxlib.h"
  11. #include <glplatform/glplatform-glcore.h>
  12. #include <glplatform/math3d.h>
  13. #include <glplatform/glplatform.h>
  14. #include "b2l.h"
  15. #include <glib.h>
  16. #include "mesh.h"
  17. static int g_dx[3];
  18. static int g_dy[3];
  19. static float g_log_zoom = 0.3;
  20. static bool g_mouse_down[3] = {false, false, false};
  21. static void on_expose(struct glplatform_win *win);
  22. static void on_destroy(struct glplatform_win *win);
  23. static void on_mouse_button_up(struct glplatform_win *, int, int, int);
  24. static void on_mouse_button_down(struct glplatform_win *, int, int, int);
  25. static void on_mouse_move(struct glplatform_win *, int, int);
  26. static void on_resize(struct glplatform_win *);
  27. static void on_mouse_wheel(struct glplatform_win *, int, int, int);
  28. static struct math3d_quaternion q_cur = {0,0,0,1};
  29. static struct math3d_quaternion q_delta = {0,0,0,1};
  30. static struct math3d_vec3 g_offset = {{0,0,0}};
  31. static struct math3d_vec3 g_offset_next = {{0,0,0}};
  32. static void on_mouse_button_up(struct glplatform_win *win, int button, int x, int y)
  33. {
  34. if (g_mouse_down[0] && button == 1) {
  35. struct math3d_quaternion next;
  36. math3d_quaternion_mul(&q_delta, &q_cur, &next);
  37. q_cur = next;
  38. q_delta.x = 0;
  39. q_delta.y = 0;
  40. q_delta.z = 0;
  41. q_delta.w = 1;
  42. }
  43. if (g_mouse_down[2] && button == 3) {
  44. g_offset.v[0] += g_offset_next.v[0];
  45. g_offset.v[1] += g_offset_next.v[1];
  46. g_offset.v[2] += g_offset_next.v[2];
  47. g_offset_next.v[0] = 0;
  48. g_offset_next.v[1] = 0;
  49. g_offset_next.v[2] = 0;
  50. }
  51. g_mouse_down[button -1] = false;
  52. on_mouse_move(win, x, y);
  53. }
  54. static void on_mouse_button_down(struct glplatform_win *win, int button, int x, int y)
  55. {
  56. g_mouse_down[button -1] = true;
  57. g_dx[button - 1] = x;
  58. g_dy[button - 1] = y;
  59. on_mouse_move(win, x, y);
  60. }
  61. static void on_mouse_move(struct glplatform_win *win, int x, int y)
  62. {
  63. struct math3d_quaternion next;
  64. math3d_quaternion_mul(&q_delta, &q_cur, &next);
  65. if (g_mouse_down[0]) {
  66. struct math3d_vec3 axis;
  67. axis.v[0] = g_dy[0] - y;
  68. axis.v[1] = g_dx[0] - x;
  69. axis.v[2] = 0;
  70. float length = math3d_vec3_length(&axis);
  71. math3d_vec3_normalize(&axis);
  72. math3d_quaternion_from_axis_angle(&q_delta, &axis, length * 3 / win->width);
  73. }
  74. if (g_mouse_down[2]) {
  75. struct math3d_vec3 delta;
  76. delta.v[0] = (g_dx[2] - x) * 2.0 / win->width;
  77. delta.v[1] = -(g_dy[2] - y) * 2.0 / win->height;
  78. delta.v[2] = 0;
  79. math3d_quaternion_unit_inv_mul_vec3(&next, &delta, &g_offset_next);
  80. g_offset_next.v[0] = -g_offset_next.v[0];
  81. g_offset_next.v[1] = -g_offset_next.v[1];
  82. g_offset_next.v[2] = -g_offset_next.v[2];
  83. }
  84. }
  85. static void on_expose(struct glplatform_win *win)
  86. {
  87. }
  88. static void on_mouse_wheel(struct glplatform_win *win, int x, int y, int direction)
  89. {
  90. g_log_zoom += direction * 0.1;
  91. }
  92. static int lua_backtrace_string(lua_State *L)
  93. {
  94. static lua_Debug ar;
  95. int i = 0;
  96. while (lua_getstack(L, i++, &ar)) {
  97. lua_getinfo(L, "Sl", &ar);
  98. char *str = g_strdup_printf("%s:%d\n", ar.source, ar.currentline);
  99. lua_pushstring(L, str);
  100. g_free(str);
  101. }
  102. lua_concat(L, i -1);
  103. return 1;
  104. }
  105. static void on_resize(struct glplatform_win *win)
  106. {
  107. }
  108. static void on_destroy(struct glplatform_win *win)
  109. {
  110. exit(0);
  111. }
  112. struct glplatform_win_callbacks cb;
  113. static void *l_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
  114. {
  115. (void)ud;
  116. (void)osize; /* not used */
  117. if (nsize == 0) {
  118. free(ptr);
  119. return NULL;
  120. } else {
  121. return realloc(ptr, nsize);
  122. }
  123. }
  124. int lua_panic_handler (lua_State* L)
  125. {
  126. lua_pushvalue(L, -1);
  127. lua_pushstring(L, "\n");
  128. lua_backtrace_string(L);
  129. lua_concat(L, 3);
  130. fprintf(stderr, "%s\n", lua_tostring(L, -1));
  131. return 1;
  132. }
  133. int lua_message_handler (lua_State* L)
  134. {
  135. lua_pushvalue(L, -1);
  136. lua_pushstring(L, "\n");
  137. lua_backtrace_string(L);
  138. lua_concat(L, 3);
  139. return 1;
  140. }
  141. static void print_help(const char *program_name)
  142. {
  143. printf("Usage: %s [OPTION]... filename\n", program_name);
  144. printf("\n"
  145. "Options:\n"
  146. " -f,--frame Frame number to render.\n"
  147. " -s,--scene name Scene to use.\n"
  148. " -o,--object name Object to render.\n"
  149. " -h,--help Print this page.\n");
  150. }
  151. int main(int argc, char **argv)
  152. {
  153. const char *b2l_file_name = NULL;
  154. const char *object_name = NULL;
  155. const char *scene_name = NULL;
  156. static struct option options [] = {
  157. {"help" , 0, 0, 'h' },
  158. {"frame" , 1, 0, 'f' },
  159. {"object" , 1, 0, 'o' },
  160. {"scene" , 1, 0, 's' }
  161. };
  162. float frame = 1;
  163. char *temp;
  164. while (1) {
  165. int option_index;
  166. int c = getopt_long(argc, argv, "hf:o:s:", options, &option_index);
  167. if (c == -1) {
  168. break;
  169. }
  170. switch(c) {
  171. case '?':
  172. case ':':
  173. print_help(argv[0]);
  174. exit(-1);
  175. break;
  176. case 'h':
  177. print_help(argv[0]);
  178. exit(0);
  179. break;
  180. case 'f':
  181. temp = optarg;
  182. frame = strtod(optarg, &temp);
  183. if (temp == optarg || *temp != 0) {
  184. fprintf(stderr, "Invalid frame number: %s\n", optarg);
  185. print_help(argv[0]);
  186. exit(-1);
  187. }
  188. break;
  189. case 'o':
  190. object_name = optarg;
  191. break;
  192. case 's':
  193. scene_name = optarg;
  194. break;
  195. }
  196. }
  197. if (optind < argc) {
  198. b2l_file_name = argv[optind];
  199. } else {
  200. fprintf(stderr, "Missing B2L filename\n");
  201. print_help(argv[0]);
  202. exit(-1);
  203. }
  204. cb.on_expose = on_expose;
  205. cb.on_destroy = on_destroy;
  206. cb.on_resize = on_resize;
  207. cb.on_mouse_button_up = on_mouse_button_up;
  208. cb.on_mouse_button_down = on_mouse_button_down;
  209. cb.on_mouse_move = on_mouse_move;
  210. cb.on_mouse_wheel = on_mouse_wheel;
  211. cb.on_resize = on_resize;
  212. glplatform_init();
  213. lua_State *L = lua_newstate(l_alloc, NULL);
  214. luaL_openlibs(L);
  215. lua_atpanic(L, lua_panic_handler);
  216. lua_checkstack(L, 4096);
  217. size_t blob_size;
  218. void *blob;
  219. if (!b2l_load(L, b2l_file_name, &blob, &blob_size)) {
  220. exit(-1);
  221. }
  222. int b2l_data_idx = lua_gettop(L) - 1;
  223. int materials_idx = lua_gettop(L);
  224. lua_getfield(L, b2l_data_idx, "scenes");
  225. int scenes_idx = lua_gettop(L);
  226. if (object_name && !b2l_is_mesh_object(L, b2l_data_idx, object_name)) {
  227. fprintf(stderr, "Object '%s' is not a mesh object\n", object_name);
  228. exit(-1);
  229. }
  230. if (!scene_name) {
  231. lua_getfield(L, b2l_data_idx, "scenes");
  232. lua_pushnil(L);
  233. bool object_found = false;
  234. while (lua_next(L, -2)) {
  235. int scene_idx = lua_gettop(L);
  236. const char *tmp_scene_name = lua_tostring(L, -2);
  237. lua_getfield(L, scene_idx, "objects");
  238. if (object_name) {
  239. lua_getfield(L, -1, object_name);
  240. if (lua_istable(L, -1)) {
  241. object_found = true;
  242. scene_name = tmp_scene_name;
  243. break;
  244. }
  245. } else {
  246. lua_pushnil(L);
  247. while (lua_next(L, -2)) {
  248. const char *tmp_object_name = lua_tostring(L, -2);
  249. if (b2l_is_mesh_object(L, b2l_data_idx, tmp_object_name)) {
  250. object_found = true;
  251. object_name = tmp_object_name;
  252. break;
  253. }
  254. lua_pop(L, 1);
  255. }
  256. if (object_found) {
  257. scene_name = tmp_scene_name;
  258. break;
  259. }
  260. }
  261. lua_settop(L, scene_idx - 1);
  262. }
  263. if (!object_found) {
  264. fprintf(stderr, "No renderable scenes in file\n");
  265. exit(-1);
  266. }
  267. } else {
  268. lua_getfield(L, scenes_idx, scene_name);
  269. if (!lua_istable(L, -1)) {
  270. fprintf(stderr, "Scene '%s' not found\n", scene_name);
  271. exit(-1);
  272. }
  273. int scene_idx = lua_gettop(L);
  274. if (!object_name) {
  275. lua_getfield(L, scene_idx, "objects");
  276. lua_pushnil(L);
  277. while (lua_next(L, -2)) {
  278. int object_idx = lua_gettop(L);
  279. const char *tmp_object_name = lua_tostring(L, -2);
  280. if (b2l_is_mesh_object(L, b2l_data_idx, tmp_object_name)) {
  281. object_name = tmp_object_name;
  282. break;
  283. }
  284. lua_settop(L, object_idx -1);
  285. }
  286. if (!object_name) {
  287. fprintf(stderr, "No mesh objects found in scene '%s'\n", scene_name);
  288. exit(-1);
  289. }
  290. }
  291. }
  292. struct glplatform_win *win = glplatform_create_window("B2L Model viewer", &cb, NULL, 512, 512);
  293. if (!win) {
  294. fprintf(stderr, "Unable to create GL enabled window\n");
  295. exit(-1);
  296. }
  297. glplatform_show_window(win);
  298. glplatform_gl_context_t ctx = glplatform_create_context(win, 3, 3);
  299. if (!ctx)
  300. exit(-1);
  301. glplatform_make_current(win, ctx);
  302. if (!glplatform_glcore_init(3, 3)) {
  303. fprintf(stderr, "Failed to initialize OpenGL bindings\n");
  304. exit(-1);
  305. }
  306. if (!GLPLATFORM_GL_ARB_buffer_storage) {
  307. fprintf(stderr, "Missing GL extension: GL_ARB_buffer_storage\n");
  308. exit(-1);
  309. }
  310. if (!GLPLATFORM_GL_ARB_vertex_attrib_binding) {
  311. fprintf(stderr, "Missing GL extension: GL_ARB_vertex_attrib_binding\n");
  312. exit(-1);
  313. }
  314. printf("OpenGL version %s\n", glGetString(GL_VERSION));
  315. if (!b2l_materials_gl_setup(L, b2l_file_name, materials_idx)) {
  316. fprintf(stderr, "Failed to initialize GL state for B2L file\n");
  317. exit(-1);
  318. }
  319. while (glplatform_process_events()) {
  320. glViewport(0, 0, win->width, win->height);
  321. glClearColor(0, 0, 0, 0);
  322. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  323. glEnable(GL_DEPTH_TEST);
  324. struct math3d_mat4 view;
  325. struct math3d_mat4 model;
  326. struct math3d_mat4 proj;
  327. struct math3d_quaternion next;
  328. math3d_quaternion_mul(&q_delta, &q_cur, &next);
  329. math3d_quaternion_to_mat4(&next, &view);
  330. view.v[3][3] = 1;
  331. math3d_mat4_identity(&model);
  332. model.v[3][0] = g_offset.v[0] + g_offset_next.v[0];
  333. model.v[3][1] = g_offset.v[1] + g_offset_next.v[1];
  334. model.v[3][2] = g_offset.v[2] + g_offset_next.v[2];
  335. float zoom = exp(g_log_zoom);
  336. float zr = 100;
  337. math3d_mat4_zero(&proj);
  338. proj.v[0][0] = 1.0/zoom;
  339. proj.v[1][1] = 1.0*win->width/(zoom*win->height);
  340. proj.v[2][2] = 1.0/zr;
  341. proj.v[3][3] = 1.0;
  342. render_mesh(L, b2l_data_idx, materials_idx, blob,
  343. scene_name,
  344. object_name,
  345. frame,
  346. &model,
  347. &view,
  348. &proj);
  349. GLenum err = glGetError();
  350. if (err)
  351. printf("render_scene GL error: %d\n", err);
  352. glplatform_swap_buffers(win);
  353. lua_gc(L, LUA_GCCOLLECT, 0);
  354. glplatform_get_events(true);
  355. }
  356. return 0;
  357. }