LuaBindingGuide
From SfzWiki
Revision as of 12:52, 9 August 2007 by Ghoulsblade (Talk | contribs)
luabindings for global functions
- lua can call special c functions that have a special prototype/parameter layout
- to call arbitrary c functions from lua wrappers that match the prototype have to be created, we call those lua-bindings
- global functions that can be called by lua all have this prototype : static int l_MyFunction (lua_State *L) { ... }
- arguments from lua are passed on a stack and can be read using luaL_checkstring(L,1)
- index is one-based, eg starting from 1, 1st paramter is 1, 2nd is 2 etc, left to right.
- the functions can return any number of values, including 0 or multiple
- to add a return value to lua you push it onto the stack like this : lua_pushnumber(L,1);
- the c functions c-return value is the number of lua-return-values pushed
luabindings for c++ classes
- you can also create lua-bindings for entire c++ classes
- if you want to create a lua-binding for the class cMyClass,
- this class has to inherit from cSmartPointable
- then you create a wrapper-class cMyClass_L that inherits cLuaBind<cMyClass> (you need luabind.h)
- those wrapper classes are usually in extra files named _L.cpp
- wrapped methods look like this : static int MyMethod (lua_State *L) { ... }
- parameter access is similar to global functions, except that parameter indices start at 2, as 1 is for the implicit self
- you cannot use this as the wrapper-methods have to be static, but you can get the implicit self by checkudata_alive(L)
- checkudata_alive(L) = checkudata_alive(L,1) (you can also retrieve parameters that are objects with that)
- all class-bindins have to have a unique typename : virtual const char* GetLuaTypeName () { return "sfz.objcontroller"; }
- create new instances like this : return CreateUData(L,new cMyClass()); (pushes a lua-udata and returns 1)
- method wrappers must be registered in the overridden RegisterMethods() method, usually via macro REGISTER_METHOD, see examples
- you can also register member variables in some cases if you don't like manually implementing getter/setter, see gfx3D_L.cpp
- the wrapper class has to be registered at startup : call from lua-plugin : static void LuaRegister (lua_State *L);
- where LuaRegister is a method that calls cLuaBind<cMyClass>::GetSingletonPtr(new cMyClass_L())->LuaRegister(L);
tips and tricks
- for variable argument count, you can use lua_gettop(L) = c (-1 for methods due to implicit self)
- for default argument value you can use this : int a = (lua_gettop(L) >= 2 && !lua_isnil(L,2)) ? luaL_checkint(L,2) : 0;
- luaL_checkstring(L,2) returns const char* and is not valid for long, so you best assign it to an std::string
- see l_GetAllKeyNames() in lugre_scripting.general.cpp for an example of how to return an array/table
- you can call lua from c, but avoid that if possible (the application should be lua driven), search for examples similar to this :
- cScripting::GetSingletonPtr()->LuaCall("NotifyMainWindowResized","ii",w,h);
- it uses a variable argument-count syntax with format string remotely similar to printf
- it does support multiple returns by passing pointers and return format e
- e.g. LuaCall("MyLuaFun","i>ff",3,&fA,&fB) takes one integer and "returns" two doubles
- warning, there is no typechecking on the params, erros will lead to undefined behaviour :
- input/parameter values : i:int,f:double,s:char*
- output/return values : i:int*,f:double*,s:std::string*
- it only supports primitive parameter and return types, not tables/arrays
- you better avoid calling lua from c
- if you absolutely have to have to, please at least try to avoid using those ugly returnvalues
- lua uses floats internally for all numbers
- there have been problems on some computers with 32 bit integer precision with compiler optimisation turned on in vs
- so if you need 32 bits you might want to use the pointertype lua_pushlightuserdata(...)