Requirments:
- - A C++ IDE
- Lua setup up with your IDE
- A Brain (Optional)
To use the class make a header file and paste the following code in:
Code: Select all
template<class T> class Luna {
public:
static void Register(lua_State *L) {
lua_pushcfunction(L, &Luna<T>::constructor);
lua_setglobal(L, T::className);
luaL_newmetatable(L, T::className);
lua_pushstring(L, "__gc");
lua_pushcfunction(L, &Luna<T>::gc_obj);
lua_settable(L, -3);
}
static int constructor(lua_State *L) {
T* obj = new T(L);
lua_newtable(L);
lua_pushnumber(L, 0);
T** a = (T**)lua_newuserdata(L, sizeof(T*));
*a = obj;
luaL_getmetatable(L, T::className);
lua_setmetatable(L, -2);
lua_settable(L, -3); // table[0] = obj;
for (int i = 0; T::Register[i].name; i++) {
lua_pushstring(L, T::Register[i].name);
lua_pushnumber(L, i);
lua_pushcclosure(L, &Luna<T>::thunk, 1);
lua_settable(L, -3);
}
return 1;
}
static int thunk(lua_State *L) {
int i = (int)lua_tonumber(L, lua_upvalueindex(1));
lua_pushnumber(L, 0);
lua_gettable(L, 1);
T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className));
lua_remove(L, -1);
return ((*obj)->*(T::Register[i].mfunc))(L);
}
static int gc_obj(lua_State *L) {
T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className));
delete (*obj);
return 0;
}
struct RegType {
const char *name;
int(T::*mfunc)(lua_State*);
};
// Directly add the new class
static T* RegisterTable(lua_State *L)
{
luaL_newmetatable(L, T::className);
lua_pushstring(L, "__gc");
lua_pushcfunction(L, &Luna<T>::gc_obj);
lua_settable(L, -3);
T* obj = new T(L);
lua_newtable(L);
lua_pushnumber(L, 0);
T** a = (T**)lua_newuserdata(L, sizeof(T*));
*a = obj;
luaL_getmetatable(L, T::className);
lua_setmetatable(L, -2);
lua_settable(L, -3); // table[0] = obj;
for (int i = 0; T::Register[i].name; i++)
{
lua_pushstring(L, T::Register[i].name);
lua_pushnumber(L, i);
lua_pushcclosure(L, &Luna<T>::thunk, 1);
lua_settable(L, -3);
}
lua_setglobal(L, T::className);
return obj;
}
};
The code may look a bit complicated but essentially, it is quite simple, the 'Register' function takes your class and all it's functions and passes them into a metatable. The 'contructor' function is used to let lua know what your classes contructor is.
The functions 'thunk' and 'RegisterTable' I have not used yet, you may experiment with them at your own will.
Now this is the important part, you must now setup a lua class, here is an example of a class I am using to draw a sprite from lua:
Code: Select all
class LuaSprite {
private:
SDL_Surface* surface;
SDL_Rect rect;
int xvel, yvel;
std::string tag;
int alpha;
public:
LuaSprite(lua_State* L) {
}
int GetSurface(lua_State *L) {
lua_pushlightuserdata(L, (void*)surface);
return 1;
}
int GetRect(lua_State *L) {
lua_pushlightuserdata(L, (void*)&rect);
return 1;
}
int GetWidth(lua_State *L) {
lua_pushnumber(L, rect.w);
return 1;
}
int GetHeight(lua_State *L) {
lua_pushnumber(L, rect.h);
return 1;
}
int GetAlpha(lua_State *L) {
lua_pushnumber(L, alpha);
return 1;
}
//~LuaSprite() {
// SDL_FreeSurface(surface);
//}
int Update(lua_State *L);
int Show(lua_State *L)
{
SDL_SetAlpha(surface, SDL_SRCALPHA, alpha);
SDL_BlitSurface(surface, NULL, SDL_GetVideoSurface(), &rect);
return 1;
}
int LuaSprite::LoadImage(lua_State* L)
{
SDL_Surface* o;
o = IMG_Load(luaL_checkstring(L, 2));
SDL_DisplayFormatAlpha(o);
SDL_SetColorKey(o, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0xFF00FF);
alpha = 255;
surface = o;
return 1;
}
int SetX(lua_State *L) {
rect.x = (int)luaL_checknumber(L, 2);
return 1;
}
int SetY(lua_State *L) {
rect.y = (int)luaL_checknumber(L, 2);
return 1;
}
int SetAlpha(lua_State *L) {
alpha = (int)luaL_checknumber(L, 2);
return 1;
}
int SetTag(lua_State* L) {
tag = luaL_checkstring(L, 2);
return 1;
}
int GetX(lua_State *L) {
lua_pushnumber(L, rect.x);
return 1;
}
int GetY(lua_State *L) {
lua_pushnumber(L, rect.y);
return 1;
}
int GetTag(lua_State *L) {
lua_pushstring(L, tag.c_str());
return 1;
}
static const char className[];
static const Luna<LuaSprite>::RegType Register[];
};
Code: Select all
static const char className[];
static const Luna<LuaSprite>::RegType Register[];
So now we need to move onto telling lua what are class does, I recommend putting this in your main.cpp are where you have setup lua, also you do not need to put it in a function like 'main'. The following snippet tells lua the functions of the class above:
Code: Select all
const char LuaSprite::className[] = "Sprite";
const Luna<LuaSprite>::RegType LuaSprite::Register[] = {
{ "GetX", &LuaSprite::GetX },
{ "GetY", &LuaSprite::GetY },
{ "GetWidth", &LuaSprite::GetWidth },
{ "GetHeight", &LuaSprite::GetHeight },
{ "GetAlpha", &LuaSprite::GetAlpha },
{ "GetTag", &LuaSprite::GetTag },
{ "SetX", &LuaSprite::SetX },
{ "SetY", &LuaSprite::SetY },
{ "SetAlpha", &LuaSprite::SetAlpha },
{ "SetTag", &LuaSprite::SetTag },
{ "GetRect", &LuaSprite::GetRect },
{ "Show", &LuaSprite::Show },
{ "LoadImage", &LuaSprite::LoadImage },
{ 0 }
};
Code: Select all
{ "GetX", &LuaSprite::GetX },
Dont worry, we are almost there!
Now in a function, preferably 'main' and after you have setup a 'lua_State', we need to register our class, this will send the 'Register[]' array, from the snippet above, to lua. Here is the line of code:
Code: Select all
Luna<LuaSprite>::Register(L);
Finally (Yes!) I will show you how to use our class in lua, before hand make sure you are calling your script from C++ using 'luaL_dofile' before doing this:
Code: Select all
mysprite = Sprite() --Make a Sprite object
function SomeFunction()
mysprite:LoadImage("imagepath")
mysprite:SetX(45)
--etc...
end
That's it! Also, please note the class example I have given you may work, I am not sure, it would be best to use your own. Hope this helps!