lua_environment.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. * Copyright (c) 2012-2017 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/dbartolini/crown/blob/master/LICENSE
  4. */
  5. #include "config.h"
  6. #include "core/error/error.h"
  7. #include "device/device.h"
  8. #include "device/log.h"
  9. #include "lua/lua_environment.h"
  10. #include "lua/lua_stack.h"
  11. #include "resource/lua_resource.h"
  12. #include "resource/resource_manager.h"
  13. #include <stdarg.h>
  14. namespace { const crown::log_internal::System LUA = { "Lua" }; }
  15. namespace crown
  16. {
  17. extern void load_api(LuaEnvironment& env);
  18. LuaEnvironment::LuaEnvironment()
  19. : L(NULL)
  20. , _vec3_used(0)
  21. , _quat_used(0)
  22. , _mat4_used(0)
  23. {
  24. L = luaL_newstate();
  25. CE_ASSERT(L, "Unable to create lua state");
  26. }
  27. LuaEnvironment::~LuaEnvironment()
  28. {
  29. lua_close(L);
  30. }
  31. void LuaEnvironment::load_libs()
  32. {
  33. lua_gc(L, LUA_GCSTOP, 0);
  34. // Open default libraries
  35. luaL_openlibs(L);
  36. // Register crown libraries
  37. load_api(*this);
  38. // Register custom loader
  39. lua_getfield(L, LUA_GLOBALSINDEX, "package");
  40. lua_getfield(L, -1, "loaders");
  41. lua_remove(L, -2);
  42. int num_loaders = 0;
  43. lua_pushnil(L);
  44. while (lua_next(L, -2) != 0)
  45. {
  46. lua_pop(L, 1);
  47. num_loaders++;
  48. }
  49. lua_pushinteger(L, num_loaders + 1);
  50. lua_pushcfunction(L, require);
  51. lua_rawset(L, -3);
  52. lua_pop(L, 1);
  53. // Create metatable for lightuserdata
  54. lua_pushlightuserdata(L, 0);
  55. lua_getfield(L, LUA_REGISTRYINDEX, "Lightuserdata_mt");
  56. lua_setmetatable(L, -2);
  57. lua_pop(L, 1);
  58. // Ensure stack is clean
  59. CE_ASSERT(lua_gettop(L) == 0, "Stack not clean");
  60. lua_gc(L, LUA_GCRESTART, 0);
  61. }
  62. LuaStack LuaEnvironment::execute(const LuaResource* lr)
  63. {
  64. LuaStack stack(L);
  65. lua_pushcfunction(L, LuaEnvironment::error);
  66. luaL_loadbuffer(L, lua_resource::program(lr), lr->size, "<unknown>");
  67. lua_pcall(L, 0, 1, -2);
  68. lua_pop(L, 1);
  69. return stack;
  70. }
  71. LuaStack LuaEnvironment::execute_string(const char* s)
  72. {
  73. LuaStack stack(L);
  74. lua_pushcfunction(L, LuaEnvironment::error);
  75. luaL_loadstring(L, s);
  76. lua_pcall(L, 0, 0, -2);
  77. lua_pop(L, 1);
  78. return stack;
  79. }
  80. void LuaEnvironment::add_module_function(const char* module, const char* name, const lua_CFunction func)
  81. {
  82. luaL_Reg entry[2];
  83. entry[0].name = name;
  84. entry[0].func = func;
  85. entry[1].name = NULL;
  86. entry[1].func = NULL;
  87. luaL_register(L, module, entry);
  88. lua_pop(L, 1);
  89. }
  90. void LuaEnvironment::add_module_function(const char* module, const char* name, const char* func)
  91. {
  92. // Create module if it does not exist
  93. luaL_Reg entry;
  94. entry.name = NULL;
  95. entry.func = NULL;
  96. luaL_register(L, module, &entry);
  97. lua_pop(L, 1);
  98. lua_getglobal(L, module);
  99. lua_getglobal(L, func);
  100. lua_setfield(L, -2, name);
  101. lua_setglobal(L, module);
  102. }
  103. void LuaEnvironment::add_module_metafunction(const char* module, const char* name, const lua_CFunction func)
  104. {
  105. // Create module if it does not exist
  106. luaL_Reg entry[2];
  107. entry[0].name = NULL;
  108. entry[0].func = NULL;
  109. luaL_register(L, module, entry);
  110. lua_pop(L, 1);
  111. luaL_newmetatable(L, module);
  112. if (func)
  113. {
  114. entry[0].name = name;
  115. entry[0].func = func;
  116. entry[1].name = NULL;
  117. entry[1].func = NULL;
  118. luaL_register(L, NULL, entry);
  119. }
  120. else
  121. {
  122. lua_pushstring(L, name);
  123. lua_pushvalue(L, -2);
  124. lua_settable(L, -3);
  125. }
  126. lua_getglobal(L, module);
  127. lua_pushvalue(L, -2);
  128. lua_setmetatable(L, -2);
  129. lua_pop(L, -1);
  130. }
  131. void LuaEnvironment::call_global(const char* func, u8 argc, ...)
  132. {
  133. CE_ENSURE(NULL != func);
  134. LuaStack stack(L);
  135. va_list vl;
  136. va_start(vl, argc);
  137. lua_pushcfunction(L, LuaEnvironment::error);
  138. lua_getglobal(L, func);
  139. for (u8 i = 0; i < argc; i++)
  140. {
  141. const int type = va_arg(vl, int);
  142. switch (type)
  143. {
  144. case ARGUMENT_FLOAT:
  145. stack.push_float(va_arg(vl, f64));
  146. break;
  147. default:
  148. CE_FATAL("Unknown argument type");
  149. break;
  150. }
  151. }
  152. va_end(vl);
  153. lua_pcall(L, argc, 0, -argc - 2);
  154. lua_pop(L, -1);
  155. CE_ASSERT(lua_gettop(L) == 0, "Stack not clean");
  156. }
  157. LuaStack LuaEnvironment::get_global(const char* global)
  158. {
  159. LuaStack stack(L);
  160. lua_getglobal(L, global);
  161. return stack;
  162. }
  163. Vector3* LuaEnvironment::next_vector3(const Vector3& v)
  164. {
  165. CE_ASSERT(_vec3_used < CROWN_MAX_LUA_VECTOR3, "Maximum number of Vector3 reached");
  166. return &(_vec3_buffer[_vec3_used++] = v);
  167. }
  168. Quaternion* LuaEnvironment::next_quaternion(const Quaternion& q)
  169. {
  170. CE_ASSERT(_quat_used < CROWN_MAX_LUA_QUATERNION, "Maximum number of Quaternion reached");
  171. return &(_quat_buffer[_quat_used++] = q);
  172. }
  173. Matrix4x4* LuaEnvironment::next_matrix4x4(const Matrix4x4& m)
  174. {
  175. CE_ASSERT(_mat4_used < CROWN_MAX_LUA_MATRIX4X4, "Maximum number of Matrix4x4 reached");
  176. return &(_mat4_buffer[_mat4_used++] = m);
  177. }
  178. bool LuaEnvironment::is_vector3(const Vector3* p) const
  179. {
  180. return p >= &_vec3_buffer[0]
  181. && p <= &_vec3_buffer[CROWN_MAX_LUA_VECTOR3 - 1];
  182. }
  183. bool LuaEnvironment::is_quaternion(const Quaternion* p) const
  184. {
  185. return p >= &_quat_buffer[0]
  186. && p <= &_quat_buffer[CROWN_MAX_LUA_QUATERNION - 1];
  187. }
  188. bool LuaEnvironment::is_matrix4x4(const Matrix4x4* p) const
  189. {
  190. return p >= &_mat4_buffer[0]
  191. && p <= &_mat4_buffer[CROWN_MAX_LUA_MATRIX4X4 - 1];
  192. }
  193. void LuaEnvironment::temp_count(u32& num_vec3, u32& num_quat, u32& num_mat4)
  194. {
  195. num_vec3 = _vec3_used;
  196. num_quat = _quat_used;
  197. num_mat4 = _mat4_used;
  198. }
  199. void LuaEnvironment::set_temp_count(u32 num_vec3, u32 num_quat, u32 num_mat4)
  200. {
  201. _vec3_used = num_vec3;
  202. _quat_used = num_quat;
  203. _mat4_used = num_mat4;
  204. }
  205. void LuaEnvironment::reset_temporaries()
  206. {
  207. _vec3_used = 0;
  208. _quat_used = 0;
  209. _mat4_used = 0;
  210. }
  211. int LuaEnvironment::error(lua_State* L)
  212. {
  213. lua_getfield(L, LUA_GLOBALSINDEX, "debug");
  214. if (!lua_istable(L, -1))
  215. {
  216. lua_pop(L, 1);
  217. return 0;
  218. }
  219. lua_getfield(L, -1, "traceback");
  220. if (!lua_isfunction(L, -1))
  221. {
  222. lua_pop(L, 2);
  223. return 0;
  224. }
  225. lua_pushvalue(L, 1); // Pass error message
  226. lua_pushinteger(L, 2);
  227. lua_call(L, 2, 1); // Call debug.traceback
  228. loge(LUA, lua_tostring(L, -1)); // Print error message
  229. lua_pop(L, 1); // Remove error message from stack
  230. lua_pop(L, 1); // Remove debug.traceback from stack
  231. device()->pause();
  232. return 0;
  233. }
  234. int LuaEnvironment::require(lua_State* L)
  235. {
  236. LuaStack stack(L);
  237. const LuaResource* lr = (LuaResource*)device()->_resource_manager->get(RESOURCE_TYPE_SCRIPT, stack.get_resource_id(1));
  238. luaL_loadbuffer(L, lua_resource::program(lr), lr->size, "");
  239. return 1;
  240. }
  241. } // namespace crown