m3d_lua.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /*
  2. * m3d_lua.h
  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 Lua bindings for procedural 3D models
  27. * https://gitlab.com/bztsrc/model3d/blob/master/docs/procedural.md
  28. *
  29. */
  30. #ifndef _M3D_LUA_H_
  31. #define _M3D_LUA_H_
  32. /**
  33. * This header provides two main functions. Both receiving a Lua script stored in a Model 3D.
  34. * - m3d_tx_lua() executes a script and converts its output into a texture to be used in a material
  35. * - m3d_pr_lua() executes a script but first adds a lua library which is used by the script to generate procedural surface
  36. *
  37. * Use like this:
  38. * #include <m3d_lua.h>
  39. * #include M3D_IMPLEMENTATION
  40. * #include <m3d.h>
  41. */
  42. #ifdef __cplusplus
  43. extern "C" {
  44. #endif
  45. /* "register" M3D interpreter callbacks */
  46. #define M3D_TX_INTERP m3d_tx_lua
  47. #define M3D_PR_INTERP m3d_pr_lua
  48. #include <m3d.h>
  49. #undef _M3D_H_
  50. #include <string.h>
  51. #define LUA_C89_NUMBERS
  52. #include <lua.h>
  53. #include <lauxlib.h>
  54. #include <lualib.h>
  55. /**
  56. * M3D script callback for procedural texture generation
  57. */
  58. int m3d_tx_lua(const char *name, const void *script, uint32_t len, m3dtx_t *output)
  59. {
  60. uint32_t i, n, p;
  61. lua_State *L = luaL_newstate();
  62. luaL_openlibs(L);
  63. if(luaL_loadbuffer(L, script, len, name)) return M3D_ERR_UNKIMG;
  64. lua_call(L, 0, 1);
  65. if(lua_istable(L, -1)) {
  66. /* returns an int array table, ret[0] = width, ret[1] = height, ret[2] = numcomponent, ret[3...] = pixels */
  67. lua_pushnil(L);
  68. lua_next(L, -2);
  69. output->w = (uint16_t)lua_tointeger(L, -1);
  70. lua_pop(L, 1);
  71. lua_next(L, -2);
  72. output->h = (uint16_t)lua_tointeger(L, -1);
  73. lua_pop(L, 1);
  74. lua_next(L, -2);
  75. output->f = (uint8_t)lua_tointeger(L, -1);
  76. lua_pop(L, 1);
  77. if(output->w && output->h && output->f >= 1 && output->f <= 4)
  78. output->d = M3D_MALLOC(output->w * output->h * output->f);
  79. if(!output->d) {
  80. lua_close(L);
  81. return M3D_ERR_ALLOC;
  82. }
  83. /* fill up pixel data */
  84. n = output->w * output->h;
  85. for(i = 0; i < n && lua_next(L, -2);) {
  86. p = (uint32_t)lua_tointeger(L, -1);
  87. switch(output->f) {
  88. case 1: output->d[i] = p; i++; break;
  89. case 2: *((uint16_t*)&output->d[i]) = (uint16_t)p; i += 2; break;
  90. case 3: *((uint32_t*)&output->d[i]) = (uint32_t)p; i += 3; break;
  91. case 4: *((uint32_t*)&output->d[i]) = (uint32_t)p; i += 4; break;
  92. }
  93. lua_pop(L, 1);
  94. }
  95. }
  96. lua_close(L);
  97. return M3D_SUCCESS;
  98. }
  99. /* C values stored in Lua registry for the Lua callbacks */
  100. const char *_m3d_lua_key = "m3dmodel", *_m3d_lua_mat = "m3dmaterial";
  101. /* Lua callbacks */
  102. int _m3d_lua_getvertex(lua_State *L);
  103. int _m3d_lua_getuv(lua_State *L);
  104. int _m3d_lua_usematerial(lua_State *L);
  105. int _m3d_lua_addtriangle(lua_State *L);
  106. int _m3d_lua_addtriangleuv(lua_State *L);
  107. int _m3d_lua_addtrianglen(lua_State *L);
  108. int _m3d_lua_addtriangleuvn(lua_State *L);
  109. /**
  110. * M3D script callback for procedural surface generation
  111. */
  112. int m3d_pr_lua(const char *name, const void *script, uint32_t len, m3d_t *model)
  113. {
  114. static const struct luaL_Reg m3dlib[] = {
  115. { "getVertex", _m3d_lua_getvertex }, /* returns the vertex index for the given coordinates */
  116. { "getUV", _m3d_lua_getuv }, /* returns the UV index for the given coordinates */
  117. { "useMaterial", _m3d_lua_usematerial }, /* sets the material for the given material name */
  118. { "addTriangle", _m3d_lua_addtriangle }, /* adds a simple triangle */
  119. { "addTriangleUV", _m3d_lua_addtriangleuv }, /* adds triangle with UV coordinates */
  120. { "addTriangleN", _m3d_lua_addtrianglen }, /* adds triangle with normals */
  121. { "addTriangleUVN", _m3d_lua_addtriangleuvn }, /* adds triangle with UV coordinates and normals */
  122. { NULL, NULL }
  123. };
  124. lua_State *L = luaL_newstate();
  125. luaL_openlibs(L);
  126. luaL_newmetatable(L, "m3d");
  127. luaL_setfuncs(L, m3dlib, 0);
  128. if(luaL_loadbuffer(L, script, len, name)) {
  129. lua_close(L);
  130. return M3D_ERR_UNIMPL;
  131. }
  132. lua_pushlightuserdata(L, (void*)&_m3d_lua_key);
  133. lua_pushlightuserdata(L, (void*)model);
  134. lua_settable(L, LUA_REGISTRYINDEX);
  135. lua_pushlightuserdata(L, (void*)&_m3d_lua_mat);
  136. lua_pushinteger(L, -1);
  137. lua_settable(L, LUA_REGISTRYINDEX);
  138. lua_call(L, 0, 0);
  139. lua_close(L);
  140. return M3D_SUCCESS;
  141. }
  142. int _m3d_lua_getvertex(lua_State *L)
  143. {
  144. uint32_t i, idx = (uint32_t)-1U;
  145. m3d_t *model;
  146. /* called with: vertexIndex = m3d.getVertex(color, x, y, z, w) */
  147. uint32_t c = (uint32_t)luaL_checkinteger(L, 1);
  148. M3D_FLOAT x = (M3D_FLOAT)luaL_checknumber(L, 2);
  149. M3D_FLOAT y = (M3D_FLOAT)luaL_checknumber(L, 3);
  150. M3D_FLOAT z = (M3D_FLOAT)luaL_checknumber(L, 4);
  151. M3D_FLOAT w = (M3D_FLOAT)luaL_checknumber(L, 5);
  152. if(x >= (M3D_FLOAT)-1.0 && x <= (M3D_FLOAT)1.0 && y >= (M3D_FLOAT)-1.0 && y <= (M3D_FLOAT)1.0 &&
  153. z >= (M3D_FLOAT)-1.0 && z <= (M3D_FLOAT)1.0 && w >= (M3D_FLOAT)-1.0 && w <= (M3D_FLOAT)1.0) {
  154. lua_pushlightuserdata(L, (void*)&_m3d_lua_key);
  155. lua_gettable(L, LUA_REGISTRYINDEX);
  156. model = (m3d_t*)lua_touserdata(L, -1);
  157. /* check if vertex exists, get it's index */
  158. for(i = 0; i < model->numvertex; i++)
  159. if(model->vertex[i].color == c && model->vertex[i].x == x && model->vertex[i].y == y &&
  160. model->vertex[i].z == z && model->vertex[i].w == w) { idx = i; break; }
  161. /* if not, add to model->vertex */
  162. if(idx == (uint32_t)-1U) {
  163. idx = model->numvertex++;
  164. model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t));
  165. if(!model->vertex) idx = (uint32_t)-1U;
  166. else {
  167. model->vertex[idx].color = c;
  168. model->vertex[idx].x = x;
  169. model->vertex[idx].y = y;
  170. model->vertex[idx].z = z;
  171. model->vertex[idx].w = w;
  172. }
  173. }
  174. }
  175. /* return vertex index */
  176. lua_pushinteger(L, idx);
  177. return 1;
  178. }
  179. int _m3d_lua_getuv(lua_State *L)
  180. {
  181. uint32_t i, idx = (uint32_t)-1U;
  182. m3d_t *model;
  183. /* called with: uvIndex = m3d.getUV(u, v) */
  184. M3D_FLOAT u = (M3D_FLOAT)luaL_checknumber(L, 1);
  185. M3D_FLOAT v = (M3D_FLOAT)luaL_checknumber(L, 2);
  186. if(u >= (M3D_FLOAT)-1.0 && u <= (M3D_FLOAT)1.0 && v >= (M3D_FLOAT)-1.0 && v <= (M3D_FLOAT)1.0) {
  187. lua_pushlightuserdata(L, (void*)&_m3d_lua_key);
  188. lua_gettable(L, LUA_REGISTRYINDEX);
  189. model = (m3d_t*)lua_touserdata(L, -1);
  190. /* check if tmap exists, get it's index */
  191. for(i = 0; i < model->numtmap; i++)
  192. if(model->tmap[i].u == u && model->tmap[i].v == v) { idx = i; break; }
  193. /* if not, add to model->tmap */
  194. if(idx == (uint32_t)-1U) {
  195. idx = model->numtmap++;
  196. model->tmap = (m3dti_t*)M3D_REALLOC(model->tmap, model->numtmap * sizeof(m3dti_t));
  197. if(!model->tmap) idx = (uint32_t)-1U;
  198. else {
  199. model->tmap[idx].u = u;
  200. model->tmap[idx].v = v;
  201. }
  202. }
  203. }
  204. /* return tmap index */
  205. lua_pushinteger(L, idx);
  206. return 1;
  207. }
  208. int _m3d_lua_usematerial(lua_State *L)
  209. {
  210. uint32_t i;
  211. m3d_t *model;
  212. uint32_t materialid = (uint32_t)-1U;
  213. /* called with: m3d.useMaterial(material name) */
  214. const char *material = luaL_checkstring(L, 1);
  215. if(!material || !*material) return 0;
  216. lua_pushlightuserdata(L, (void*)&_m3d_lua_key);
  217. lua_gettable(L, LUA_REGISTRYINDEX);
  218. model = (m3d_t*)lua_touserdata(L, -1);
  219. for(i = 0; i < model->nummaterial; i++)
  220. if(!strcmp(material, model->material[i].name)) {
  221. materialid = i;
  222. break;
  223. }
  224. /* set material index in registry */
  225. lua_pushlightuserdata(L, (void*)&_m3d_lua_mat);
  226. lua_pushinteger(L, materialid);
  227. lua_settable(L, LUA_REGISTRYINDEX);
  228. lua_pushinteger(L, materialid);
  229. return 1;
  230. }
  231. int _m3d_lua_addtriangle(lua_State *L)
  232. {
  233. m3d_t *model;
  234. uint32_t i, materialid = (uint32_t)-1U;
  235. /* called with: m3d.addTriangle(v1, v2, v3) */
  236. uint32_t v1 = (uint32_t)luaL_checkinteger(L, 1);
  237. uint32_t v2 = (uint32_t)luaL_checkinteger(L, 2);
  238. uint32_t v3 = (uint32_t)luaL_checkinteger(L, 3);
  239. lua_pushlightuserdata(L, (void*)&_m3d_lua_key);
  240. lua_gettable(L, LUA_REGISTRYINDEX);
  241. model = (m3d_t*)lua_touserdata(L, -1);
  242. if(v1 < model->numvertex && v2 < model->numvertex && v3 < model->numvertex) {
  243. lua_pushlightuserdata(L, (void*)&_m3d_lua_mat);
  244. lua_gettable(L, LUA_REGISTRYINDEX);
  245. materialid = (uint32_t)lua_tointeger(L, -1);
  246. /* add to model->face */
  247. i = model->numface++;
  248. model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t));
  249. if(model->face) {
  250. memset(&model->face[i], 255, sizeof(m3df_t)); /* set all index to -1 by default */
  251. model->face[i].materialid = materialid;
  252. model->face[i].vertex[0] = v1;
  253. model->face[i].vertex[1] = v2;
  254. model->face[i].vertex[2] = v3;
  255. }
  256. }
  257. return 0;
  258. }
  259. int _m3d_lua_addtriangleuv(lua_State *L)
  260. {
  261. m3d_t *model;
  262. uint32_t i, materialid = (uint32_t)-1U;
  263. /* called with: m3d.addTriangleUV(v1, uv1, v2, uv2, v3, uv3) */
  264. uint32_t v1 = (uint32_t)luaL_checkinteger(L, 1);
  265. uint32_t uv1= (uint32_t)luaL_checkinteger(L, 2);
  266. uint32_t v2 = (uint32_t)luaL_checkinteger(L, 3);
  267. uint32_t uv2= (uint32_t)luaL_checkinteger(L, 4);
  268. uint32_t v3 = (uint32_t)luaL_checkinteger(L, 5);
  269. uint32_t uv3= (uint32_t)luaL_checkinteger(L, 6);
  270. lua_pushlightuserdata(L, (void*)&_m3d_lua_key);
  271. lua_gettable(L, LUA_REGISTRYINDEX);
  272. model = (m3d_t*)lua_touserdata(L, -1);
  273. if(v1 < model->numvertex && v2 < model->numvertex && v3 < model->numvertex &&
  274. uv1 < model->numtmap && uv2 < model->numtmap && uv3 < model->numtmap) {
  275. lua_pushlightuserdata(L, (void*)&_m3d_lua_mat);
  276. lua_gettable(L, LUA_REGISTRYINDEX);
  277. materialid = (uint32_t)lua_tointeger(L, -1);
  278. /* add to model->face */
  279. i = model->numface++;
  280. model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t));
  281. if(model->face) {
  282. memset(&model->face[i], 255, sizeof(m3df_t)); /* set all index to -1 by default */
  283. model->face[i].materialid = materialid;
  284. model->face[i].vertex[0] = v1;
  285. model->face[i].vertex[1] = v2;
  286. model->face[i].vertex[2] = v3;
  287. model->face[i].texcoord[0] = uv1;
  288. model->face[i].texcoord[1] = uv2;
  289. model->face[i].texcoord[2] = uv3;
  290. }
  291. }
  292. return 0;
  293. }
  294. int _m3d_lua_addtrianglen(lua_State *L)
  295. {
  296. m3d_t *model;
  297. uint32_t i, materialid = (uint32_t)-1U;
  298. /* called with: m3d.addTriangleN(v1, n1, v2, n2, v3, n3) */
  299. uint32_t v1 = (uint32_t)luaL_checkinteger(L, 1);
  300. uint32_t n1 = (uint32_t)luaL_checkinteger(L, 2);
  301. uint32_t v2 = (uint32_t)luaL_checkinteger(L, 3);
  302. uint32_t n2 = (uint32_t)luaL_checkinteger(L, 4);
  303. uint32_t v3 = (uint32_t)luaL_checkinteger(L, 5);
  304. uint32_t n3 = (uint32_t)luaL_checkinteger(L, 6);
  305. lua_pushlightuserdata(L, (void*)&_m3d_lua_key);
  306. lua_gettable(L, LUA_REGISTRYINDEX);
  307. model = (m3d_t*)lua_touserdata(L, -1);
  308. if(v1 < model->numvertex && v2 < model->numvertex && v3 < model->numvertex &&
  309. n1 < model->numvertex && n2 < model->numvertex && n3 < model->numvertex) {
  310. lua_pushlightuserdata(L, (void*)&_m3d_lua_mat);
  311. lua_gettable(L, LUA_REGISTRYINDEX);
  312. materialid = (uint32_t)lua_tointeger(L, -1);
  313. /* add to model->face */
  314. i = model->numface++;
  315. model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t));
  316. if(model->face) {
  317. memset(&model->face[i], 255, sizeof(m3df_t)); /* set all index to -1 by default */
  318. model->face[i].materialid = materialid;
  319. model->face[i].vertex[0] = v1;
  320. model->face[i].vertex[1] = v2;
  321. model->face[i].vertex[2] = v3;
  322. model->face[i].normal[0] = n1;
  323. model->face[i].normal[1] = n2;
  324. model->face[i].normal[2] = n3;
  325. }
  326. }
  327. return 0;
  328. }
  329. int _m3d_lua_addtriangleuvn(lua_State *L)
  330. {
  331. m3d_t *model;
  332. uint32_t i, materialid = (uint32_t)-1U;
  333. /* called with: m3d.addTriangleUVN(v1, uv1, n1, v2, uv2, n2, v3, uv3, n3) */
  334. uint32_t v1 = (uint32_t)luaL_checkinteger(L, 1);
  335. uint32_t uv1= (uint32_t)luaL_checkinteger(L, 2);
  336. uint32_t n1 = (uint32_t)luaL_checkinteger(L, 3);
  337. uint32_t v2 = (uint32_t)luaL_checkinteger(L, 4);
  338. uint32_t uv2= (uint32_t)luaL_checkinteger(L, 5);
  339. uint32_t n2 = (uint32_t)luaL_checkinteger(L, 6);
  340. uint32_t v3 = (uint32_t)luaL_checkinteger(L, 7);
  341. uint32_t uv3= (uint32_t)luaL_checkinteger(L, 8);
  342. uint32_t n3 = (uint32_t)luaL_checkinteger(L, 9);
  343. lua_pushlightuserdata(L, (void*)&_m3d_lua_key);
  344. lua_gettable(L, LUA_REGISTRYINDEX);
  345. model = (m3d_t*)lua_touserdata(L, -1);
  346. if(v1 < model->numvertex && v2 < model->numvertex && v3 < model->numvertex &&
  347. n1 < model->numvertex && n2 < model->numvertex && n3 < model->numvertex &&
  348. uv1 < model->numtmap && uv2 < model->numtmap && uv3 < model->numtmap) {
  349. lua_pushlightuserdata(L, (void*)&_m3d_lua_mat);
  350. lua_gettable(L, LUA_REGISTRYINDEX);
  351. materialid = (uint32_t)lua_tointeger(L, -1);
  352. /* add to model->face */
  353. i = model->numface++;
  354. model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t));
  355. if(model->face) {
  356. memset(&model->face[i], 255, sizeof(m3df_t)); /* set all index to -1 by default */
  357. model->face[i].materialid = materialid;
  358. model->face[i].vertex[0] = v1;
  359. model->face[i].vertex[1] = v2;
  360. model->face[i].vertex[2] = v3;
  361. model->face[i].texcoord[0] = uv1;
  362. model->face[i].texcoord[1] = uv2;
  363. model->face[i].texcoord[2] = uv3;
  364. model->face[i].normal[0] = n1;
  365. model->face[i].normal[1] = n2;
  366. model->face[i].normal[2] = n3;
  367. }
  368. }
  369. return 0;
  370. }
  371. #ifdef __cplusplus
  372. }
  373. #endif /* __cplusplus */
  374. #endif