LuaBindingGuide

From SfzWiki
Jump to: navigation, search

luabindings for global functions

  • lua can call 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_pushstring(L,"hello world !");
  • 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(...)