b2l_material_editor.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  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 "glsl_parser.h"
  15. #include "glsl_ast.h"
  16. #include "mesh.h"
  17. #include "geometry.h"
  18. #include "program.h"
  19. #include "texture.h"
  20. extern char *metalval;
  21. #include <gdk-pixbuf/gdk-pixbuf.h>
  22. #include <glib.h>
  23. #include <glib-unix.h>
  24. #define MAX_TEXTURE_UNITS 8
  25. #define USE_SLERP 1
  26. #define NEW_STRUCT(TYPE) ((struct TYPE *)malloc(sizeof(struct TYPE), sizeof(intptr_t)))
  27. static int set_b2l_file(lua_State *L);
  28. static int need_redraw(lua_State *L);
  29. static int get_shader_uniforms(lua_State *L);
  30. static int filter_shader_text(lua_State *L);
  31. static int make_path_relative(lua_State *L);
  32. static int directory_name(lua_State *L);
  33. static int create_glwin(lua_State *L);
  34. luaL_Reg lua_b2l_material_editor_capi[] = {
  35. { "directory_name", directory_name },
  36. { "make_path_relative", make_path_relative },
  37. { "set_b2l_file", set_b2l_file},
  38. { "need_redraw", need_redraw},
  39. { "get_shader_uniforms", get_shader_uniforms},
  40. { "filter_shader_text", filter_shader_text},
  41. { "create_glwin", create_glwin},
  42. { NULL, NULL }
  43. };
  44. static glplatform_gl_context_t g_ctx;
  45. static struct glplatform_win *g_win;
  46. static lua_State *g_L;
  47. static bool g_need_redraw = true;
  48. static GSource *g_src;
  49. static int g_dx[3];
  50. static int g_dy[3];
  51. static float g_log_zoom = 0.3;
  52. static bool g_mouse_down[3] = {false, false, false};
  53. static void on_expose(struct glplatform_win *win);
  54. static void on_destroy(struct glplatform_win *win);
  55. static void on_mouse_button_up(struct glplatform_win *, int, int, int);
  56. static void on_mouse_button_down(struct glplatform_win *, int, int, int);
  57. static void on_mouse_move(struct glplatform_win *, int, int);
  58. static void on_resize(struct glplatform_win *);
  59. static void on_mouse_wheel(struct glplatform_win *, int, int, int);
  60. static void redraw(struct glplatform_win *win);
  61. static struct math3d_quaternion q_cur = {0,0,0,1};
  62. static struct math3d_quaternion q_delta = {0,0,0,1};
  63. static struct math3d_vec3 g_offset = {{0,0,0}};
  64. static struct math3d_vec3 g_offset_next = {{0,0,0}};
  65. static void on_mouse_button_up(struct glplatform_win *win, int button, int x, int y)
  66. {
  67. if (g_mouse_down[0] && button == 1) {
  68. struct math3d_quaternion next;
  69. math3d_quaternion_mul(&q_delta, &q_cur, &next);
  70. q_cur = next;
  71. q_delta.x = 0;
  72. q_delta.y = 0;
  73. q_delta.z = 0;
  74. q_delta.w = 1;
  75. need_redraw(g_L);
  76. }
  77. if (g_mouse_down[2] && button == 3) {
  78. g_offset.v[0] += g_offset_next.v[0];
  79. g_offset.v[1] += g_offset_next.v[1];
  80. g_offset.v[2] += g_offset_next.v[2];
  81. g_offset_next.v[0] = 0;
  82. g_offset_next.v[1] = 0;
  83. g_offset_next.v[2] = 0;
  84. need_redraw(g_L);
  85. }
  86. g_mouse_down[button -1] = false;
  87. on_mouse_move(win, x, y);
  88. }
  89. static void on_mouse_button_down(struct glplatform_win *win, int button, int x, int y)
  90. {
  91. g_mouse_down[button -1] = true;
  92. g_dx[button - 1] = x;
  93. g_dy[button - 1] = y;
  94. on_mouse_move(win, x, y);
  95. }
  96. static void on_mouse_move(struct glplatform_win *win, int x, int y)
  97. {
  98. struct math3d_quaternion next;
  99. math3d_quaternion_mul(&q_delta, &q_cur, &next);
  100. if (g_mouse_down[0]) {
  101. struct math3d_vec3 axis;
  102. axis.v[0] = g_dy[0] - y;
  103. axis.v[1] = g_dx[0] - x;
  104. axis.v[2] = 0;
  105. float length = math3d_vec3_length(&axis);
  106. math3d_vec3_normalize(&axis);
  107. math3d_quaternion_from_axis_angle(&q_delta, &axis, length * 3 / win->width);
  108. need_redraw(g_L);
  109. }
  110. if (g_mouse_down[2]) {
  111. struct math3d_vec3 delta;
  112. delta.v[0] = (g_dx[2] - x) * 2.0 / win->width;
  113. delta.v[1] = -(g_dy[2] - y) * 2.0 / win->height;
  114. delta.v[2] = 0;
  115. math3d_quaternion_unit_inv_mul_vec3(&next, &delta, &g_offset_next);
  116. g_offset_next.v[0] = -g_offset_next.v[0];
  117. g_offset_next.v[1] = -g_offset_next.v[1];
  118. g_offset_next.v[2] = -g_offset_next.v[2];
  119. need_redraw(g_L);
  120. }
  121. }
  122. static void on_expose(struct glplatform_win *win)
  123. {
  124. need_redraw(g_L);
  125. }
  126. static void on_mouse_wheel(struct glplatform_win *win, int x, int y, int direction)
  127. {
  128. g_log_zoom += direction * 0.1;
  129. need_redraw(g_L);
  130. }
  131. static int lua_backtrace_string(lua_State *L)
  132. {
  133. static lua_Debug ar;
  134. int i = 0;
  135. while (lua_getstack(L, i++, &ar)) {
  136. lua_getinfo(L, "Sl", &ar);
  137. char *str = g_strdup_printf("%s:%d\n", ar.source, ar.currentline);
  138. lua_pushstring(L, str);
  139. g_free(str);
  140. }
  141. lua_concat(L, i -1);
  142. return 1;
  143. }
  144. static int make_path_relative(lua_State *L)
  145. {
  146. if (!lua_isstring(L, -1) || !lua_isstring(L, -2)) {
  147. lua_pushnil(L);
  148. return 1;
  149. }
  150. const char *x = lua_tostring(L, -1); //file
  151. const char *y = lua_tostring(L, -2); //origin path (with trailing '/')
  152. int strings = 1;
  153. while (*x && *x == *y) {
  154. x++;
  155. y++;
  156. }
  157. while (*y) {
  158. if (*(y++) == '/') {
  159. lua_pushstring(L, "../");
  160. strings++;
  161. }
  162. }
  163. lua_pushstring(L, x);
  164. lua_concat(L, strings);
  165. return 1;
  166. }
  167. static void truncate_to_dirname(char *str)
  168. {
  169. char *x = str;
  170. char *y = NULL;
  171. while (*x) {
  172. if (*x == '/')
  173. y = x;
  174. x++;
  175. }
  176. if (y)
  177. *(++y) = 0;
  178. else
  179. *str = 0;
  180. }
  181. static int directory_name(lua_State *L)
  182. {
  183. char *filename = strdup(lua_tostring(L, -1));
  184. truncate_to_dirname(filename);
  185. lua_pushstring(L, filename);
  186. free(filename);
  187. return 1;
  188. }
  189. static void on_resize(struct glplatform_win *win)
  190. {
  191. need_redraw(g_L);
  192. }
  193. static void on_destroy(struct glplatform_win *win)
  194. {
  195. exit(0);
  196. }
  197. struct glplatform_win_callbacks cb;
  198. static uint8_t *get_file_buffer(const char *fname, size_t *size)
  199. {
  200. FILE *f = fopen(fname, "rb");
  201. if (!f) {
  202. return NULL;
  203. }
  204. fseek(f, 0, SEEK_END);
  205. *size = ftell(f);
  206. fseek(f, 0, SEEK_SET);
  207. uint8_t *ret = (uint8_t *)malloc(*size);
  208. if (fread(ret, *size, 1, f) != 1) {
  209. free(ret);
  210. ret = NULL;
  211. }
  212. fclose(f);
  213. return ret;
  214. }
  215. struct gl_state {
  216. const uint8_t *blob;
  217. size_t blob_size;
  218. bool initialized;
  219. GLuint vao;
  220. } g_gl_state;
  221. static bool recompile_shaders();
  222. static void init_gl_state();
  223. static gboolean dispatch(gpointer user_data)
  224. {
  225. glplatform_get_events(false);
  226. return glplatform_process_events();
  227. }
  228. int luaopen_material_editor_capi(lua_State *L)
  229. {
  230. lua_newtable(L);
  231. luaL_setfuncs(L, lua_b2l_material_editor_capi, 0);
  232. g_L = L;
  233. cb.on_expose = on_expose;
  234. cb.on_destroy = on_destroy;
  235. cb.on_resize = on_resize;
  236. cb.on_mouse_button_up = on_mouse_button_up;
  237. cb.on_mouse_button_down = on_mouse_button_down;
  238. cb.on_mouse_move = on_mouse_move;
  239. cb.on_mouse_wheel = on_mouse_wheel;
  240. cb.on_resize = on_resize;
  241. glplatform_init();
  242. GMainContext *ctx = g_main_context_default();
  243. g_src = g_unix_fd_source_new(glplatform_epoll_fd, G_IO_IN);
  244. g_source_attach(g_src, ctx);
  245. g_source_set_callback(g_src, dispatch, NULL, NULL);
  246. return 1;
  247. }
  248. static int create_glwin(lua_State *L)
  249. {
  250. int xid = lua_tointeger(L, -1);
  251. g_win = glplatform_create_window("B2L 3D View", &cb, NULL, 512, 512);
  252. if (!g_win)
  253. exit(-1);
  254. glplatform_set_win_type(g_win, GLWIN_UTILITY);
  255. glplatform_set_win_transient_for(g_win, xid);
  256. glplatform_show_window(g_win);
  257. g_ctx = glplatform_create_context(g_win, 3, 3);
  258. if (!g_ctx)
  259. exit(-1);
  260. glplatform_make_current(g_win, g_ctx);
  261. need_redraw(L);
  262. return 0;
  263. }
  264. static int need_redraw(lua_State *L)
  265. {
  266. g_need_redraw = true;
  267. return 0;
  268. }
  269. struct insert_shader_uniforms_state {
  270. const char *tag;
  271. const char *name;
  272. int type_code;
  273. bool uniform;
  274. lua_State *L;
  275. int uniform_table_idx;
  276. };
  277. static void insert_shader_uniforms_enter(struct glsl_ast_walk_data *data, struct glsl_node *n, intptr_t state_)
  278. {
  279. int i;
  280. struct insert_shader_uniforms_state *state = (struct insert_shader_uniforms_state *) state_;
  281. switch(n->code) {
  282. case TRANSLATION_UNIT:
  283. case DECLARATION_STATEMENT_LIST:
  284. for (i = n->child_count - 1; i >= 0; i--) {
  285. glsl_ast_walk_push_node(data, n->children[i]); //DECLARATION_STATEMENT
  286. }
  287. break;
  288. case TYPE_QUALIFIER_LIST:
  289. for (i = 0; i < n->child_count; i++) {
  290. if (n->children[i]->code == UNIFORM) {
  291. state->uniform = true;
  292. }
  293. }
  294. break;
  295. case DECLARATION:
  296. glsl_ast_walk_push_node(data, n->children[0]); //declaration
  297. break;
  298. case SECTION_STATEMENT:
  299. state->tag = n->children[0]->data.str; //IDENTIFIER
  300. glsl_ast_walk_push_node(data, n->children[1]);
  301. break;
  302. case SINGLE_DECLARATION:
  303. state->name = n->children[1]->data.str; //IDENTIFIER
  304. glsl_ast_walk_push_node(data, n->children[0]);
  305. break;
  306. case FULLY_SPECIFIED_TYPE:
  307. glsl_ast_walk_push_node(data, n->children[1]); //TYPE_SPECIFIER
  308. glsl_ast_walk_push_node(data, n->children[0]); //TYPE_QUALIFIER_LIST
  309. break;
  310. case TYPE_SPECIFIER:
  311. state->type_code = n->children[0]->code; //type_specifier_nonarray
  312. break;
  313. }
  314. }
  315. static void insert_shader_uniforms_exit(struct glsl_ast_walk_data *data, struct glsl_node *n, intptr_t state_)
  316. {
  317. struct insert_shader_uniforms_state *state = (struct insert_shader_uniforms_state *) state_;
  318. switch (n->code) {
  319. case SECTION_STATEMENT:
  320. state->tag = NULL;
  321. break;
  322. case DECLARATION: {
  323. const char *type_string;
  324. switch (state->type_code) {
  325. case FLOAT:
  326. type_string = "float";
  327. break;
  328. case VEC3:
  329. type_string = "vec3";
  330. break;
  331. case MAT4:
  332. type_string = "mat4";
  333. break;
  334. case BOOL:
  335. type_string = "bool";
  336. break;
  337. case SAMPLER2D:
  338. type_string = "sampler2D";
  339. break;
  340. default:
  341. type_string = NULL;
  342. }
  343. if (state->uniform && type_string && state->name) {
  344. lua_getfield(state->L, state->uniform_table_idx, state->name);
  345. if (lua_isnil(state->L, -1)) {
  346. lua_newtable(state->L);
  347. lua_pushstring(state->L, type_string);
  348. lua_setfield(state->L, -2, "datatype");
  349. if (state->tag) {
  350. lua_pushstring(state->L, state->tag);
  351. lua_setfield(state->L, -2, "tag");
  352. }
  353. lua_setfield(state->L, state->uniform_table_idx, state->name);
  354. }
  355. lua_pushstring(state->L, state->name);
  356. lua_rawseti(state->L, state->uniform_table_idx, lua_rawlen(state->L, state->uniform_table_idx) + 1);
  357. lua_pop(state->L, 1);
  358. }
  359. state->uniform = false;
  360. state->type_code = -1;
  361. state->name = NULL;
  362. } break;
  363. }
  364. }
  365. int insert_shader_uniforms(lua_State *L, int text_idx, int uniform_table_idx)
  366. {
  367. const char *temp = lua_tostring(L, text_idx);
  368. struct glsl_parse_context context;
  369. glsl_parse_context_init(&context);
  370. glsl_parse_string(&context, temp);
  371. struct insert_shader_uniforms_state lstate;
  372. //Data we need during traversal
  373. lstate.L = L;
  374. lstate.uniform_table_idx = uniform_table_idx;
  375. lstate.type_code = -1;
  376. lstate.uniform = false;
  377. lstate.name = NULL;
  378. lstate.tag = NULL;
  379. struct glsl_ast_walk_data wd;
  380. glsl_ast_walk_init(&wd);
  381. glsl_ast_walk_push_node(&wd, context.root);
  382. glsl_ast_walk(&wd, (intptr_t)&lstate, insert_shader_uniforms_enter, insert_shader_uniforms_exit);
  383. glsl_parse_context_destroy(&context);
  384. return 0;
  385. }
  386. //
  387. // Strip meta-data from shader text
  388. //
  389. int filter_shader_text(lua_State *L)
  390. {
  391. const char *input = lua_tostring(L, -1);
  392. char *output;
  393. struct glsl_parse_context context;
  394. glsl_parse_context_init(&context);
  395. glsl_parse_string(&context, input);
  396. output = glsl_ast_generate_glsl(context.root);
  397. glsl_parse_context_destroy(&context);
  398. lua_pushstring(L, "#version 330\n"); //TODO: we need to grab the actual text for this
  399. lua_pushstring(L, output);
  400. lua_concat(L, 2);
  401. //glsl_ast_print(context.root, 0);
  402. //printf("%s\n", output);
  403. free(output);
  404. return 1;
  405. }
  406. static int get_shader_uniforms(lua_State *L)
  407. {
  408. int vertex_text_index = lua_gettop(L) - 1;
  409. int fragment_text_index = lua_gettop(L);
  410. lua_newtable(L);
  411. if (insert_shader_uniforms(L, vertex_text_index, lua_gettop(L))) {
  412. lua_pop(L, 1);
  413. lua_pushnil(L);
  414. return 1;
  415. }
  416. if (insert_shader_uniforms(L, fragment_text_index, lua_gettop(L))) {
  417. lua_pop(L, 1);
  418. lua_pushnil(L);
  419. return 1;
  420. }
  421. return 1;
  422. }
  423. static void init_gl_state()
  424. {
  425. printf("OpenGL version %s\n", glGetString(GL_VERSION));
  426. glGenVertexArrays(1, &g_gl_state.vao);
  427. glBindVertexArray(g_gl_state.vao);
  428. g_gl_state.initialized = true;
  429. }
  430. static void redraw(struct glplatform_win *win)
  431. {
  432. struct glplatform_thread_state thread_state;
  433. glplatform_get_thread_state(&thread_state);
  434. glplatform_make_current(win, g_ctx);
  435. lua_State *L = g_L;
  436. static bool gl_init_attempted = false;
  437. static bool gl_init_result = false;
  438. if (!gl_init_attempted) {
  439. gl_init_result = glplatform_glcore_init(3, 3);
  440. }
  441. if (!gl_init_result) {
  442. fprintf(stderr, "Failed to initialize OpenGL bindings\n");
  443. exit(-1);
  444. return;
  445. }
  446. if (!GLPLATFORM_GL_ARB_buffer_storage) {
  447. fprintf(stderr, "Missing GL extension: GL_ARB_buffer_storage\n");
  448. exit(-1);
  449. }
  450. if (!GLPLATFORM_GL_ARB_vertex_attrib_binding) {
  451. fprintf(stderr, "Missing GL extension: GL_ARB_vertex_attrib_binding\n");
  452. exit(-1);
  453. }
  454. glViewport(0, 0, win->width, win->height);
  455. glClearColor(0, 0, 0, 0);
  456. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  457. glEnable(GL_DEPTH_TEST);
  458. int top_idx = lua_gettop(L);
  459. if (!g_gl_state.initialized)
  460. init_gl_state();
  461. if (!g_gl_state.initialized) {
  462. goto end;
  463. }
  464. lua_getglobal(L, "b2l_data"); //1
  465. if (!lua_istable(L, -1)) {
  466. lua_pop(L, 1);
  467. goto end;
  468. }
  469. int b2l_data_idx = lua_gettop(L);
  470. lua_getglobal(L, "current_object");
  471. if (!lua_isstring(L, -1)) {
  472. goto end;
  473. }
  474. const char *current_object = lua_tostring(L, -1);
  475. lua_getglobal(L, "current_scene");
  476. if (!lua_isstring(L, -1)) {
  477. goto end;
  478. }
  479. const char *current_scene = lua_tostring(L, -1);
  480. double frame;
  481. int frame_start;
  482. lua_getglobal(L, "frame_start");
  483. frame_start = lua_tointeger(L, -1);
  484. lua_getglobal(L, "frame_delta");
  485. frame = frame_start + lua_tonumber(L, -1);
  486. struct math3d_mat4 view;
  487. struct math3d_mat4 model;
  488. struct math3d_mat4 proj;
  489. struct math3d_quaternion next;
  490. math3d_quaternion_mul(&q_delta, &q_cur, &next);
  491. math3d_quaternion_to_mat4(&next, &view);
  492. view.v[3][3] = 1;
  493. math3d_mat4_identity(&model);
  494. model.v[3][0] = g_offset.v[0] + g_offset_next.v[0];
  495. model.v[3][1] = g_offset.v[1] + g_offset_next.v[1];
  496. model.v[3][2] = g_offset.v[2] + g_offset_next.v[2];
  497. float zoom = exp(g_log_zoom);
  498. float zr = 100;
  499. math3d_mat4_zero(&proj);
  500. proj.v[0][0] = 1.0/zoom;
  501. proj.v[1][1] = 1.0*win->width/(zoom*win->height);
  502. proj.v[2][2] = 1.0/zr;
  503. proj.v[3][3] = 1.0;
  504. lua_getglobal(L, "materials");
  505. int materials_idx = lua_gettop(L);
  506. if (lua_isnil(L, -1))
  507. goto end;
  508. lua_pushnil(L);
  509. while(lua_next(L, -2)) {
  510. int material_idx = lua_gettop(L);
  511. lua_getfield(L, material_idx, "program");
  512. //
  513. // Create material program object if it's missing
  514. //
  515. if (!lua_isuserdata(L, -1)) {
  516. lprogram_create(L);
  517. lua_setfield(L, material_idx, "program");
  518. }
  519. lua_getfield(L, material_idx, "program");
  520. int program_idx = lua_gettop(L);
  521. struct program *program = lua_touserdata(L, program_idx);
  522. //
  523. // Assign shaders to the program. The shaders
  524. // will be compiled and the program will be linked
  525. // if the values are different than previously
  526. // specified
  527. //
  528. lua_getfield(L, material_idx, "shaders");
  529. lua_getfield(L, -1, "_vs_text");
  530. lua_getfield(L, -2, "_fs_text");
  531. const char *vs_text = lua_tostring(L, -2);
  532. const char *fs_text = lua_tostring(L, -1);
  533. lua_pushvalue(L, program_idx);
  534. if (!lprogram_set_shaders(L, vs_text, fs_text)) {
  535. goto end;
  536. }
  537. glUseProgram(program->program);
  538. //
  539. // Upload textures if neccisary
  540. //
  541. lua_getfield(L, material_idx, "params");
  542. lua_pushnil(L); /* first key */
  543. int texunit = 0;
  544. while (lua_next(L, -2)) {
  545. int variable_idx = lua_gettop(L);
  546. lua_getfield(L, variable_idx, "datatype");
  547. const char *datatype = lua_tostring(L, -1);
  548. if (!strcmp(datatype,"sampler2D")) {
  549. lua_getfield(L, variable_idx, "_texture");
  550. if (!lua_isuserdata(L, -1)) {
  551. lua_getfield(L, variable_idx, "_pbuf");
  552. if (lua_isuserdata(L, -1)) {
  553. GdkPixbuf *pbuf;
  554. lua_getfield(L, -1, "_native");
  555. pbuf = (GdkPixbuf *)lua_touserdata(L, -1);
  556. ltexture_create(L, pbuf);
  557. lua_setfield(L, variable_idx, "_texture");
  558. }
  559. }
  560. texunit++;
  561. }
  562. lua_settop(L, variable_idx - 1);
  563. }
  564. lua_settop(L, material_idx - 1);
  565. }
  566. render_mesh(L, b2l_data_idx, materials_idx, g_gl_state.blob,
  567. current_scene,
  568. current_object, frame,
  569. &model,
  570. &view,
  571. &proj);
  572. end:
  573. lua_settop(L, top_idx);
  574. {
  575. GLenum err = glGetError();
  576. if (err)
  577. printf("render_scene GL error = %d\n", err);
  578. }
  579. glplatform_swap_buffers(g_win);
  580. glplatform_set_thread_state(&thread_state);
  581. g_need_redraw = false;
  582. return;
  583. }
  584. static int set_b2l_file(lua_State *L)
  585. {
  586. size_t blob_size;
  587. uint8_t *blob = get_file_buffer(lua_tostring(L, -1), &blob_size);
  588. if (blob == NULL) {
  589. printf("failed to load blob file %s\n",lua_tostring(L, -1));
  590. return -1;
  591. }
  592. g_gl_state.blob = blob;
  593. g_gl_state.blob_size = blob_size;
  594. return 0;
  595. }
  596. static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize)
  597. {
  598. (void)ud;
  599. (void)osize; /* not used */
  600. if (nsize == 0) {
  601. free(ptr);
  602. return NULL;
  603. } else {
  604. return realloc(ptr, nsize);
  605. }
  606. }
  607. int luaopen_lgi_corelgilua (lua_State* L);
  608. int lua_message_handler (lua_State* L)
  609. {
  610. lua_pushvalue(L, -1);
  611. lua_pushstring(L, "\n");
  612. lua_backtrace_string(L);
  613. lua_concat(L, 3);
  614. return 1;
  615. }
  616. int lua_panic_handler (lua_State* L)
  617. {
  618. lua_pushvalue(L, -1);
  619. lua_pushstring(L, "\n");
  620. lua_backtrace_string(L);
  621. lua_concat(L, 3);
  622. fprintf(stderr, "%s\n", lua_tostring(L, -1));
  623. return 1;
  624. }
  625. static void print_help(const char *program_name)
  626. {
  627. printf("Usage: %s [OPTION]...\n", program_name);
  628. printf("\n"
  629. "Options:\n"
  630. " -d,--data-dir <path> Path to application data. Overrides B2L_DATA_DIR.\n"
  631. " -h,--help Print this page.\n");
  632. }
  633. int main(int argc, char **argv)
  634. {
  635. /*
  636. char exe_path[200];
  637. ssize_t sz = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
  638. if (sz < 0)
  639. return -1;
  640. exe_path[sz] = '\0';
  641. truncate_to_dirname(exe_path);
  642. */
  643. const char *b2l_data_dir = NULL;
  644. const char *b2l_file_name = NULL;
  645. static struct option options [] = {
  646. {"data-dir" , 1, 0, 'd' },
  647. {"help" , 0, 0, 'h' }
  648. };
  649. while (1) {
  650. int option_index;
  651. int c = getopt_long(argc, argv, "d:h", options, &option_index);
  652. if (c == -1) {
  653. break;
  654. }
  655. switch(c) {
  656. case 'd':
  657. b2l_data_dir = optarg;
  658. break;
  659. case 'h':
  660. print_help(argv[0]);
  661. exit(0);
  662. break;
  663. }
  664. }
  665. if (!b2l_data_dir) {
  666. b2l_data_dir = getenv("B2L_DATA_DIR");
  667. }
  668. if (!b2l_data_dir) {
  669. b2l_data_dir = DATA_DIR;
  670. }
  671. if (optind < argc) {
  672. b2l_file_name = argv[optind];
  673. }
  674. lua_State *L = lua_newstate(l_alloc, NULL);
  675. luaL_openlibs(L);
  676. lua_atpanic(L, lua_panic_handler);
  677. lua_getglobal(L, "package"); //1
  678. lua_getfield(L, -1, "preload"); //2
  679. lua_pushcfunction(L, luaopen_material_editor_capi);
  680. lua_setfield(L, -2, "material_editor_capi");
  681. lua_pushcfunction(L, luaopen_lgi_corelgilua);
  682. lua_setfield(L, -2, "lgi.corelgilua");
  683. lua_pushstring(L, b2l_data_dir);
  684. lua_pushstring(L, "/?.lua;");
  685. lua_pushstring(L, b2l_data_dir);
  686. lua_pushstring(L, "/lgi/?.lua");
  687. lua_concat(L, 4);
  688. lua_setfield(L, -3, "path");
  689. lua_pushstring(L, b2l_data_dir);
  690. lua_pushstring(L, "/lib/?.so;");
  691. lua_pushstring(L, b2l_data_dir);
  692. lua_pushstring(L, "/lgi/lib/?.so");
  693. lua_concat(L, 4);
  694. lua_setfield(L, -3, "cpath");
  695. lua_pushcfunction(L, lua_message_handler);
  696. int msgh = lua_gettop(L);
  697. lua_pushstring(L, b2l_data_dir);
  698. lua_pushstring(L, "/material_editor.lua");
  699. lua_concat(L, 2);
  700. int err;
  701. err = luaL_loadfile(L, lua_tostring(L, -1));
  702. if (err != LUA_OK) {
  703. fprintf(stderr, "Error loading script: %s\n", lua_tostring(L, -1));
  704. return 0;
  705. }
  706. if (!b2l_file_name) {
  707. lua_pushnil(L);
  708. } else {
  709. lua_pushstring(L, b2l_file_name);
  710. }
  711. lua_setglobal(L, "b2l_filename");
  712. err = lua_pcall(L, 0, 0, msgh);
  713. switch (err) {
  714. case LUA_ERRRUN:
  715. fprintf(stderr, "Lua runtime error: ");
  716. break;
  717. case LUA_ERRMEM:
  718. fprintf(stderr, "Lua memory allocation error: ");
  719. break;
  720. case LUA_ERRERR:
  721. fprintf(stderr, "Lua internal error: ");
  722. break;
  723. case LUA_ERRGCMM:
  724. fprintf(stderr, "Lua garbage collection error: ");
  725. break;
  726. }
  727. if (err != LUA_OK) {
  728. fprintf(stderr, "%s\n", lua_tostring(L, -1));
  729. return -1;
  730. }
  731. bool shutdown = false;
  732. bool block = true;
  733. bool animation_playing = false;
  734. while (!shutdown) {
  735. while ((gtk_events_pending() || block) && !shutdown) {
  736. gtk_main_iteration_do(block);
  737. block = false;
  738. lua_getglobal(g_L, "shutdown");
  739. shutdown = lua_toboolean(g_L, -1);
  740. lua_pop(g_L, 1);
  741. lua_getglobal(g_L, "playing_animation");
  742. animation_playing = lua_toboolean(g_L, -1);
  743. lua_pop(g_L, 1);
  744. }
  745. if (animation_playing) {
  746. lua_getglobal(g_L, "animation_update");
  747. lua_call(g_L, 0, 0);
  748. g_need_redraw = true;
  749. }
  750. if (g_win && g_need_redraw) {
  751. redraw(g_win);
  752. }
  753. block = !animation_playing;
  754. if (!block) {
  755. glplatform_get_events(false);
  756. glplatform_process_events();
  757. }
  758. lua_gc(g_L, LUA_GCCOLLECT, 0);
  759. }
  760. return 0;
  761. }