1 /*
2 Copyright (c) 2010 Peter "Corsix" Cawley
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22
23 #ifndef CORSIX_TH_TH_LUA_INTERNAL_H_
24 #define CORSIX_TH_TH_LUA_INTERNAL_H_
25 #include "config.h"
26
27 #include <string>
28
29 #include "th_lua.h"
30
31 enum class lua_metatable {
32 map,
33 palette,
34 sheet,
35 font,
36 bitmap_font,
37 #ifdef CORSIX_TH_USE_FREETYPE2
38 freetype_font,
39 #endif
40 layers,
41 anims,
42 anim,
43 pathfinder,
44 surface,
45 bitmap,
46 cursor,
47 lfs_ext,
48 sound_archive,
49 sound_fx,
50 movie,
51 string,
52 window_base,
53 sprite_list,
54 string_proxy,
55 line,
56 iso_fs,
57
58 count
59 };
60
61 struct lua_register_state {
62 lua_State* L;
63 int metatables[static_cast<size_t>(lua_metatable::count)];
64 int main_table;
65 int top;
66 };
67
68 void luaT_setclosure(const lua_register_state* pState, lua_CFunction fn,
69 int iUps);
70
71 template <typename... Args>
luaT_setclosure(const lua_register_state * pState,lua_CFunction fn,int iUps,lua_metatable eMetatable1,Args...args)72 void luaT_setclosure(const lua_register_state* pState, lua_CFunction fn,
73 int iUps, lua_metatable eMetatable1, Args... args) {
74 lua_pushvalue(pState->L,
75 pState->metatables[static_cast<size_t>(eMetatable1)]);
76 luaT_setclosure(pState, fn, iUps + 1, args...);
77 }
78
79 template <typename... Args>
luaT_setclosure(const lua_register_state * pState,lua_CFunction fn,int iUps,const char * str,Args...args)80 void luaT_setclosure(const lua_register_state* pState, lua_CFunction fn,
81 int iUps, const char* str, Args... args) {
82 lua_pushstring(pState->L, str);
83 luaT_setclosure(pState, fn, iUps + 1, args...);
84 }
85
86 /**
87 * Add a c++ function to the lua state.
88 *
89 * @param pState Lua state for the game
90 * @param fn The C/C++ function to register
91 * @param name The name to use for the function in lua
92 * @param args The upvalues to associate with the function in lua
93 */
94 template <typename... Args>
add_lua_function(const lua_register_state * pState,lua_CFunction fn,const char * name,Args...args)95 void add_lua_function(const lua_register_state* pState, lua_CFunction fn,
96 const char* name, Args... args) {
97 luaT_setclosure(pState, fn, 0, args...);
98 lua_setfield(pState->L, -2, name);
99 }
100
101 /**
102 * Create a lua 'class' bound to a C++ class.
103 *
104 * This class should be immediately destructed after adding all of it's
105 * functions, metamethods and constants to complete the creation of the bind.
106 */
107 template <typename T>
108 class lua_class_binding final {
109 public:
110 lua_class_binding() = delete;
111 lua_class_binding(const lua_class_binding&) = delete;
112 lua_class_binding(lua_class_binding&&) = delete;
113 lua_class_binding& operator=(const lua_class_binding&) = delete;
114 lua_class_binding operator=(lua_class_binding&&) = delete;
115
116 /**
117 * Initiate class bindings for lua.
118 *
119 * @param pState The lua environment to bind to.
120 * @param name The name to give this lua 'class'.
121 * @param new_fn The function to call when a new class is created.
122 * @param mt The metatable id for the class
123 */
lua_class_binding(const lua_register_state * pState,const char * name,lua_CFunction new_fn,lua_metatable mt)124 lua_class_binding(const lua_register_state* pState, const char* name,
125 lua_CFunction new_fn, lua_metatable mt)
126 : pState(pState),
127 class_name(name),
128 class_metatable(pState->metatables[static_cast<size_t>(mt)]) {
129 lua_settop(pState->L, pState->top);
130 /* Make metatable the environment for registered functions */
131 lua_pushvalue(pState->L, class_metatable);
132 lua_replace(pState->L, luaT_environindex);
133 /* Set the __gc metamethod to C++ destructor */
134 luaT_pushcclosure(pState->L, luaT_stdgc<T, luaT_environindex>, 0);
135 lua_setfield(pState->L, class_metatable, "__gc");
136 /* Set the depersist size */
137 lua_pushinteger(pState->L, sizeof(T));
138 lua_setfield(pState->L, class_metatable, "__depersist_size");
139 /* Create the methods table; call it -> new instance */
140 luaT_pushcclosuretable(pState->L, new_fn, 0);
141 /* Set __class_name on the methods metatable */
142 lua_getmetatable(pState->L, -1);
143 lua_pushstring(pState->L, class_name);
144 lua_setfield(pState->L, -2, "__class_name");
145 lua_pop(pState->L, 1);
146 /* Set __index to the methods table */
147 lua_pushvalue(pState->L, -1);
148 lua_setfield(pState->L, class_metatable, "__index");
149 }
150
151 /**
152 * Set another class as the superclass of this class.
153 *
154 * @param super_mt The metatable id of the super class.
155 */
set_superclass(lua_metatable super_mt)156 void set_superclass(lua_metatable super_mt) {
157 lua_getmetatable(pState->L, -1);
158 lua_getfield(pState->L, pState->metatables[static_cast<size_t>(super_mt)],
159 "__index");
160 lua_setfield(pState->L, -2, "__index");
161 lua_pop(pState->L, 1);
162 /* Set metatable[1] to super_mt */
163 lua_pushvalue(pState->L, pState->metatables[static_cast<size_t>(super_mt)]);
164 lua_rawseti(pState->L, class_metatable, 1);
165 }
166
167 /**
168 * Add a named constant to the lua interface.
169 *
170 * @param name (string literal) Name of the constant.
171 * @param value (tested with int) Value of the constant.
172 */
173 template <typename V>
add_constant(const char * name,V value)174 void add_constant(const char* name, V value) {
175 luaT_push(pState->L, value);
176 lua_setfield(pState->L, -2, name);
177 }
178
179 /**
180 * Add a C++ metamethod to the lua class.
181 *
182 * @param fn The C++ function to call.
183 * @param name The name of the metamethod (without the __ prefix).
184 * @param args The upvalues for the function.
185 */
186 template <typename... Args>
add_metamethod(lua_CFunction fn,const char * name,Args...args)187 void add_metamethod(lua_CFunction fn, const char* name, Args... args) {
188 luaT_setclosure(pState, fn, 0, args...);
189 lua_setfield(pState->L, class_metatable,
190 std::string("__").append(name).c_str());
191 }
192
193 /**
194 * Add a C++ function to the lua class.
195 *
196 * @param fn The C++ function.
197 * @param name The name of the function in lua.
198 * @param args The upvalues for the function
199 */
200 template <typename... Args>
add_function(lua_CFunction fn,const char * name,Args...args)201 void add_function(lua_CFunction fn, const char* name, Args... args) {
202 add_lua_function(pState, fn, name, args...);
203 }
204
205 /**
206 * Destructor which finalizes the lua binding
207 */
~lua_class_binding()208 ~lua_class_binding() {
209 lua_setfield(pState->L, pState->main_table, class_name);
210 }
211
212 private:
213 const lua_register_state* pState;
214 const char* class_name;
215 int class_metatable;
216 };
217
218 #endif
219