b2l_scene_viewer.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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. " -h,--help Print this page.\n");
  149. }
  150. static struct math3d_mat4 *object_local_transform(lua_State *L, void *blob, const char *object, const char *scene, int frame)
  151. {
  152. lua_getfield(L, -1, "scenes");
  153. lua_getfield(L, -1, scene);
  154. lua_getfield(L, -1, "objects");
  155. lua_getfield(L, -1, object);
  156. lua_getfield(L, -1, "object_transform_array_offset");
  157. int offset = lua_tointeger(L, -1);
  158. lua_pop(L, 5);
  159. return (struct math3d_mat4 *)(((uint8_t *) blob) + offset);
  160. }
  161. static int object_parent(lua_State *L)
  162. {
  163. lua_getfield(L, -1, "objects");
  164. lua_getfield(L, -1, lua_tostring(L, -3));
  165. lua_getfield(L, -1, "parent");
  166. lua_replace(L, -5);
  167. lua_pop(L, 2);
  168. return 0;
  169. }
  170. int main(int argc, char **argv)
  171. {
  172. const char *b2l_file_name = NULL;
  173. const char *scene_name = NULL;
  174. static struct option options [] = {
  175. {"help" , 0, 0, 'h' },
  176. {"frame" , 1, 0, 'f' },
  177. {"scene" , 1, 0, 's' }
  178. };
  179. float frame = 1;
  180. char *temp;
  181. while (1) {
  182. int option_index;
  183. int c = getopt_long(argc, argv, "hf:o:s:", options, &option_index);
  184. if (c == -1) {
  185. break;
  186. }
  187. switch(c) {
  188. case '?':
  189. case ':':
  190. print_help(argv[0]);
  191. exit(-1);
  192. break;
  193. case 'h':
  194. print_help(argv[0]);
  195. exit(0);
  196. break;
  197. case 'f':
  198. temp = optarg;
  199. frame = strtod(optarg, &temp);
  200. if (temp == optarg || *temp != 0) {
  201. fprintf(stderr, "Invalid frame number: %s\n", optarg);
  202. print_help(argv[0]);
  203. exit(-1);
  204. }
  205. break;
  206. case 's':
  207. scene_name = optarg;
  208. break;
  209. }
  210. }
  211. if (optind < argc) {
  212. b2l_file_name = argv[optind];
  213. } else {
  214. fprintf(stderr, "Missing B2L filename\n");
  215. print_help(argv[0]);
  216. exit(-1);
  217. }
  218. cb.on_expose = on_expose;
  219. cb.on_destroy = on_destroy;
  220. cb.on_resize = on_resize;
  221. cb.on_mouse_button_up = on_mouse_button_up;
  222. cb.on_mouse_button_down = on_mouse_button_down;
  223. cb.on_mouse_move = on_mouse_move;
  224. cb.on_mouse_wheel = on_mouse_wheel;
  225. cb.on_resize = on_resize;
  226. glplatform_init();
  227. lua_State *L = lua_newstate(l_alloc, NULL);
  228. luaL_openlibs(L);
  229. lua_atpanic(L, lua_panic_handler);
  230. lua_checkstack(L, 4096);
  231. size_t blob_size;
  232. void *blob;
  233. if (!b2l_load(L, b2l_file_name, &blob, &blob_size)) {
  234. exit(-1);
  235. }
  236. int b2l_data_idx = lua_gettop(L) - 1;
  237. int materials_idx = lua_gettop(L);
  238. lua_getfield(L, b2l_data_idx, "scenes");
  239. int scenes_idx = lua_gettop(L);
  240. int scene_idx;
  241. if (!scene_name) {
  242. lua_pushnil(L);
  243. bool object_found = false;
  244. while (lua_next(L, scenes_idx)) {
  245. scene_idx = lua_gettop(L);
  246. const char *tmp_scene_name = lua_tostring(L, -2);
  247. lua_getfield(L, scene_idx, "objects");
  248. lua_pushnil(L);
  249. while (lua_next(L, -2)) {
  250. const char *tmp_object_name = lua_tostring(L, -2);
  251. if (b2l_is_mesh_object(L, b2l_data_idx, tmp_object_name)) {
  252. object_found = true;
  253. break;
  254. }
  255. lua_pop(L, 1);
  256. }
  257. if (object_found) {
  258. scene_name = tmp_scene_name;
  259. break;
  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. scene_idx = lua_gettop(L);
  274. }
  275. struct glplatform_win *win = glplatform_create_window("B2L Model viewer", &cb, NULL, 512, 512);
  276. if (!win) {
  277. fprintf(stderr, "Unable to create GL enabled window\n");
  278. exit(-1);
  279. }
  280. glplatform_show_window(win);
  281. glplatform_gl_context_t ctx = glplatform_create_context(win, 3, 3);
  282. if (!ctx)
  283. exit(-1);
  284. glplatform_make_current(win, ctx);
  285. if (!glplatform_glcore_init(3, 3)) {
  286. fprintf(stderr, "Failed to initialize OpenGL bindings\n");
  287. exit(-1);
  288. }
  289. if (!GLPLATFORM_GL_ARB_buffer_storage) {
  290. fprintf(stderr, "Missing GL extension: GL_ARB_buffer_storage\n");
  291. exit(-1);
  292. }
  293. if (!GLPLATFORM_GL_ARB_vertex_attrib_binding) {
  294. fprintf(stderr, "Missing GL extension: GL_ARB_vertex_attrib_binding\n");
  295. exit(-1);
  296. }
  297. printf("OpenGL version %s\n", glGetString(GL_VERSION));
  298. if (!b2l_materials_gl_setup(L, b2l_file_name, materials_idx)) {
  299. fprintf(stderr, "Failed to initialize GL state for B2L file\n");
  300. exit(-1);
  301. }
  302. while (glplatform_process_events()) {
  303. glViewport(0, 0, win->width, win->height);
  304. glClearColor(0, 0, 0, 0);
  305. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  306. glEnable(GL_DEPTH_TEST);
  307. struct math3d_mat4 view;
  308. struct math3d_mat4 model;
  309. struct math3d_mat4 proj;
  310. struct math3d_mat4 view_pan;
  311. struct math3d_mat4 temp;
  312. struct math3d_quaternion next;
  313. math3d_quaternion_mul(&q_delta, &q_cur, &next);
  314. math3d_quaternion_to_mat4(&next, &view);
  315. view.v[3][3] = 1;
  316. math3d_mat4_identity(&view_pan);
  317. view_pan.v[3][0] = g_offset.v[0] + g_offset_next.v[0];
  318. view_pan.v[3][1] = g_offset.v[1] + g_offset_next.v[1];
  319. view_pan.v[3][2] = g_offset.v[2] + g_offset_next.v[2];
  320. math3d_mat4_mul(&view, &view_pan, &temp);
  321. view = temp;
  322. float zoom = exp(g_log_zoom);
  323. float zr = 100;
  324. math3d_mat4_zero(&proj);
  325. proj.v[0][0] = 1.0/zoom;
  326. proj.v[1][1] = 1.0*win->width/(zoom*win->height);
  327. proj.v[2][2] = 1.0/zr;
  328. proj.v[3][3] = 1.0;
  329. int prev_top = lua_gettop(L);
  330. lua_getfield(L, scene_idx, "objects");
  331. lua_pushnil(L);
  332. while (lua_next(L, -2)) {
  333. const char *object_name = lua_tostring(L, -2);
  334. if (b2l_is_mesh_object(L, b2l_data_idx, object_name)) {
  335. lua_pushstring(L, object_name);
  336. lua_pushvalue(L, b2l_data_idx);
  337. struct math3d_mat4 *m;
  338. math3d_mat4_identity(&model);
  339. do {
  340. m = object_local_transform(L, blob, lua_tostring(L, -2), scene_name, frame);
  341. math3d_mat4_mul(&model, m, &temp);
  342. model = temp;
  343. object_parent(L);
  344. } while(!lua_isnil(L, -2));
  345. lua_pop(L, 2);
  346. render_mesh(L, b2l_data_idx, materials_idx, blob,
  347. scene_name,
  348. object_name,
  349. frame,
  350. &model,
  351. &view,
  352. &proj);
  353. }
  354. lua_pop(L, 1);
  355. }
  356. lua_settop(L, prev_top);
  357. GLenum err = glGetError();
  358. if (err)
  359. printf("render_scene GL error: %d\n", err);
  360. glplatform_swap_buffers(win);
  361. lua_gc(L, LUA_GCCOLLECT, 0);
  362. glplatform_get_events(true);
  363. }
  364. return 0;
  365. }