I have a c++ class that organizes parts on a screen that can be drawn to, called Canvases.
I want to create those canvasses from Lua (which I already do), the C++ code keeps track of them and renders them to the screen.
But to draw into a canvas, I want to be able to make that available from LUA, so what I want is to say something like this:
local c1 = foo.createCanvas("test", 60, 60, 300, 200);
c1:onPaint = function(params)
self:clear(1, 0, 0, 1);
self:moveTo(10, 10);
self:lineTo(100, 100);
end
createCanvas are functions inside foo, clear, moveTo, lineTo are function of the canvas object that is created by createCanvas.
So now, when foo starts rendering everything, it should see that an onPaint function has been defined in canvas "test" and that this function should first be called before rendering to screen.
How should I do this?
the canvas is a lua metatable object in C++ with a __index and __newindex declared. I presume that I should take the __newindex to find out that onPaint will be defined. How can I get this function?
boost::shared_ptr<Canvas> **pppCanvas = (boost::shared_ptr<Canvas> **)luaL_checkudata(L, 1, "Canvas");
std::string key = lua_tostring(L, 2);
if (key == "onPaint")
{
// sometype x = lua_tofunction(L, 3);???
}
else
luaL_error(L, "Canvas - member '%s' is not defined", key.c_str());
return 0;
So what type should I use, what function should I use to get this function to?
And then, how will I call this lua-function? And how will I find out if the function has been defined in the first place?
EDIT:
I found this topic: click
It shows how to make a reference to a lua-function and ask it back later.
The only problem now is: luaL_ref doesn't take a stack index, so I don't know how to take the function from the stack in my above __newindex function.
My problem is solved now (can't seem to set this problem to solved because of low reputation) because I actually need the last item on the stack. But I would like to know if anyone knows how I can take another item in the stack.
Anyway: PROBLEM SOLVED
D.
Seems you can use lua_call to fulfill your need. Note that swig does not support director in lua afaik and is thus not an option.
EDIT:
Updated according to your example:
lua_getfield(L, LUA_GLOBALSINDEX, "myLuaFunctionToCall"); /* function to be called */
lua_pushinteger(L, 3); // parameter is 3
lua_call(L, 1, 1); //call with 1 parameter, 1 result
lua_getfield(L, LUA_GLOBALSINDEX, "myLuaFunctionToCall"); /* function to be called */
lua_Number result = lua_tonumber(L,1)
Related
I am trying to register a c++ function in Lua.
But getting this error:
CScript.cpp|39|error: argument of type 'int (CScript::)(lua_State*)' does not match 'int (*)(lua_State*)'|
EDIT:
int CApp::SetDisplayMode(int Width, int Height, int Depth)
{
this->Screen_Width = Width;
this->Screen_Height = Height;
this->Screen_Depth = Depth;
return 0;
}
int CScript::Lua_SetDisplayMode(lua_State* L)
{
// We need at least one parameter
int n = lua_gettop(L);
if(n < 0)
{
lua_pushstring(L, "Not enough parameter.");
lua_error(L);
}
int width = lua_tointeger(L, 1);
int height = lua_tointeger(L, 2);
int depth = lua_tointeger(L, 3);
lua_pushinteger(L, App->SetDisplayMode(width, height, depth));
return 0;
}
And in main:
lua_register(L, "setDisplayMode", Lua_SetDisplayMode);
You can not use a method of a class as a normal function, unless it is declared static. You have to define a normal function, which finds out what object you want the method to be called in, and then call the method.
The main reason it's not possible to use a class method as a callback from a C function (and remember that the Lua API is a pure C library), is because the computer doesn't know which object the method should be called on.
The answer is actually surprisingly simple; if you use lua_pushcclosure instead of lua_pushcfunction, you can pass parameters to your called function:
lua_pushlightuserdata(_state, this);
lua_pushcclosure(_state, &MyClass::lua_static_helper, 1);
int MyClass::lua_static_helper(lua_State *state) {
MyClass *klass = (MyClass *) lua_touserdata(state, lua_upvalueindex(1));
return klass->lua_member_method(state);
}
You cannot directly register a C++ non-static member function in Lua using just the basic Lua C API.
However, any of the various mechanisms that exist for easily associating C++ code with Lua will allow you to do so. toLua++, SWIG, Luabind, etc. If you're serious about using C++ objects with Lua, I suggest picking one of those and using it, rather than writing your own version. I personally use Luabind (most of the time; SWIG has its place in the toolbox), as it is the one that doesn't have some form of code generation. It's all done purely in C++, so there's no pre-pass step that generates a C++ source file.
You can work around the limitation by storing your active this pointer in a static variable as well. This introduces the problem of being unable to have two of these classes operating at the same time, but it works.
static CScript* luaThis; // This is a private variable inside CScript.
Then, inside your CScript constructor (or some kind of 'activate' function), you can just specify:
luaThis = this;
Then, when your static functions are called (they can even be private functions if they are registered from within the class), you have access to all your member information via the luaThis pointer.
lua_pushinteger(L, luaThis->App->SetDisplayMode(width, height, depth));
The problem, as I said, is that this restricts you to one active CScript at a time (since another callback from another Lua state would use luaThis while it is pointing to the wrong things). If you need multiple active instances ever, you can come up with some lookup mechanism using the incoming lua_State* as a key.
std::map<lua_State*, CScript*> lookups; // Just an idea, if it comes to this.
Hope that helps!
I'm writing a Lua library in C++ that uses callbacks for certain functionalities. For testing I have 2 Lua functions, Register and Call. They are implemented in C++ like this:
int Lua_Register(lua_State* l){
int n = lua_gettop(l);
if(n==1){
if(lua_isfunction(l, -1)){
printf("Register\n")
lua_pushvalue(l, -1);
r = luaL_ref(l, LUA_REGISTRYINDEX);
}
}
return 1;
}
int Lua_Call(lua_State* l){
lua_rawseti(l, LUA_REGISTRYINDEX, r);
lua_call(l, 0, 0);
return 1;
}
and then in Lua:
Register(function()
Log("hi!")
end)
Call()
But all I see in the console is a lot of lines containing Register, followed by the message: C stack overflow. What I assume the problem is, is that I'm storing Register, rather than the anonymous function in the argument, which would create an infinite loop. How can I solve this?
Basically, You're trying to overwrite Lua registry with non-existant value instead of executing already set value.
What are You doing in short:
--calling Register()
lua_pushvalue(l, -1); -- now 2 copies of closure on top of stack
r = luaL_ref(l, LUA_REGISTRYINDEX); --one consumed, put into registry, 1 left
--calling Call()
--this C API call has got a new piece of stack
-- which does not contain that leftover of closure copy!
lua_rawseti(l, LUA_REGISTRYINDEX, r); --overwrite Lua registry entry with what?
lua_call(l, 0, 0); --What the heck are we calling now?
Thanks siffijoe and Etab Reisner for clarification about that new piece of stack.
What You should be doing:
I still don't really understand what actually are You trying to do, but in Your Lua code sample to execute properly (closure gets called by Call(), You should retrieve the closure before executing instead of overwriting with something which does not exist on top of the Lua stack. Something like this:
int Lua_Call(lua_State* l){
lua_rawgeti(l, LUA_REGISTRYINDEX, r); // <--- retrieve closure from registry!
lua_call(l, 0, 0); // <--- consider using lua_pcall()
return 0; // <--- the call does not leave anything useful on the stack.
}
NOTE: decide, which C API functions of Yours returns something, which ones does not. And change the return value to proper one.
Reference: luaL_ref(), lua_rawgeti(), lua_pcall() and misused lua_rawseti().
In the following example a userdata value is created of type MyType and a table is created with a metafunction __tostring which calls LI_MyType__tostring. The code creates a closure-based lua OOP. My gripe with the example provided is it appears as though there is only one way to associate userdata with a method call, via upvalues. In and of itself, this isn't problematic unless I want to share the same metatable across instances.
In an ideal world - and what I'm hoping to unearth with this question - is there a way to associate an upvalue with a value (e.g. userdata) without associating it with a function call via an upvalue? I'm hoping there is a trick that will let me continue to use closure-based lua OOP and share the same metatable across instances. I'm not optimistic, but I figured I'd ask to see if someone has a suggestion or a non-obvious trick.
using FuncArray = std::vector<const ::luaL_Reg>;
static const FuncArray funcs = {
{ "__tostring", LI_MyType__tostring },
};
int LC_MyType_newInstance(lua_State* L) {
auto userdata = static_cast<MyType*>(lua_newuserdata(L, sizeof(MyType)));
new(userdata) MyType();
// Create the metatable
lua_createtable(L, 0, funcs.size()); // |userdata|table|
lua_pushvalue(L, -2); // |userdata|table|userdata|
luaL_setfuncs(L, funcs.data(), 1); // |userdata|table|
lua_setmetatable(L, -2); // |userdata|
return 1;
}
int LI_MyType__tostring(lua_State* L) {
// NOTE: Blindly assume that upvalue 1 is my userdata
const auto n = lua_upvalueindex(1);
lua_pushvalue(L, n); // |userdata|
auto myTypeInst = static_cast<MyType*>(lua_touserdata(L, -1));
lua_pushstring(L, myTypeInst->str()); // |userdata|string|
return 1; // |userdata|string|
}
I'm hoping there's a way of performing something like (this is pseudo-code!):
// Assume that arg 1 is userdata
int LI_MyType__tostring(lua_State* L) {
const int stackPosition = -1;
const int upvalueIndex = 1;
const auto n = lua_get_USERDATA_upvalue(L, stackPosition, upvalueIndex);
lua_pushvalue(L, n); // |userdata|
auto myTypeInst = static_cast<MyType*>(lua_touserdata(L, -1));
lua_pushstring(L, myTypeInst->str()); // |userdata|string|
return 1; // |userdata|string|
}
I know this is similar to how things would be for the "normal" metatable style of OOP, but I want to keep things closure based and avoid introducing the colon syntax.
Another way of asking this question would be, is there a way to share metatables across userdata instances while using a closure-based OOP? Using lua's syntax from the scripting side of things, I don't think it's possible, but I'm hoping there's something that can be done on the C side of things.
UPDATE (2013-10-10): Based on #lhf's answer to use lua_setuservalue() and lua_getuservalue() the protocol I've settled on which allows me to reuse metatables is this:
Register a single metatable object using luaL_newmetatable(). This metatable can now be shared across userdata instances because no upvalues are used when registering the metatable.
Create a userdata value (lua_newuserdata()).
Assign the correct metatable to the userdata value (lua_setmetatable()).
Create and populate an instance method calls/attributes table with one upvalue, the userdata.
Use lua_setuservalue() on userdata to store a reference to the per-instance attribute/method table.
Change various metamethods (e.g. __index) to use the userdata's uservalue table.
As a consequence:
upvalues are never used in metamethods
upvalues are only used in a value's instance methods
there is only one extra table per instance of a given class
It's still not possible to escape creating a method/attribute table per userdata, but that overhead is nominal. It would be nice if obj.myMethod() would pass obj to function myMethod() somehow without using :, but that's exactly what : does because this isn't possible another way (unless you do make use of an upvalue).
lua_setuservalue seems to be exactly what you need. There is also of course lua_getuservalue.
(I'm skipping the C++ code and answering the question in the title.)
I don't think you should be trying to do it exactly, for a few reasons.
If you call object.method(), and you try to infer the object from the instance that was created, you're blocking your ability to pass function pointers around that behave on any object given.
You have cyclic references to objects that will never get garbage collected (each instance's function pointing back to the instance).
Just get the object from slot 1, and check its type matches your userdata. (luaL_checkudata)
If its not an object and tostring is called for example, just output that its a class of object name, instead of the instance details. It makes far more sense, and may well make debugging simpler if the object reports what it actually is, rather than trying to be too clever and misleading you.
I have some lua 'objects' that are wrappers to C++ objects, they hold a local reference to the c++ object and call it.
Now i want some functions in C++ return those wrappers, so i need to call this lua function and then set the C++ object on it.
I experience crashes and i suspect that i am not handling the lua stack right. For example, if i ask for lua_top before exiting a function that creates the wrapper + c++ object, i get 5 as result, shouldn't it be 1 if i return 1 object?
So here is what i do, maybe i am doing it wrong, maybe there is a better way to do this.
c++, .h:
#define gLuaGet(L, var, type) \
if (lua_istable(L, 1)) {\
lua_getfield(L, 1, "CObj");\
lua_replace(L, 1);\
}\
type& var = *(type*)lua_touserdata(L, 1);
#define gLuaCreate(L, type) new (lua_newuserdata(L, sizeof(type))) type();
class MyObject {
public:
MyObject();
int somefunc();
};
int MyObjectCreate(lua_State *L);
int MyObjectCallSomefunc(lua_State *L);
c++, .cpp:
int MyObject::somefunc() {
std::cerr << "in c++ function" << std::endl;
return 123;
}
int MyObjectCreate(lua_State *L) {
gLuaCreate(L, MyObject);
return 1;
}
int MyObjectCallSomefunc(lua_State *L) {
gLuaGet(L, obj, MyObject);
int r = obj.somefunc();
lua_checkstack(L, 1);
lua_pushnumber(L, r);
return 1;
}
lua wrapper:
function MyObject(donotinit)
self = {}
self.CObj = nil
if (donotinit == nil) then
self.CObj = MyObjectCreate()
end
self.setCObject = function(obj)
self.CObj = obj
end
self.somefunc = function()
return MyObjectCallSomeFunc(self)
end
return self
end
Now i want some other wrapper to return a MyObject that is created within c++, so here is the c++ code that is called from the new wrapper (for better readabiliy i removed the sanity checks on lua_pcall):
int returnLuaMyObject(lua_State *L) {
gLuaGet(L, obj, MyOtherObject);
MyObject *myObject = obj.getMyObject(); // get c++ part
lua_getglobal(L, "MyObject"); // create lua part
lua_pushnumber(L, 1); // and tell it not to initialize the self.CObj
lua_pcall(L, 1, 1, 0);
lua_getfield(L, -1, "setCObject"); // call the setCObject function
lua_pushlightuserdata(L, myObject); // give c++ object as param
lua_pcall(L, 1, 0, 0);
// at this point lua_gettop(L); returns 5, can this be correct?
return 1;
}
Well, if i call this function via a lua wrapper now a couple of times, everything seems fine, but if i call it lets say 50 times in a while loop, its crashing on random times (but always on the same c++ line)
Am i doing something wrong here? Is it OK for the lua stack top to be 5 at this point, where it only returns one object?
This is what your Lua stack will look like after each function/macro call, if I'm reading this correctly
int returnLuaMyObject(lua_State *L) {
// arg
gLuaGet(L, obj, MyOtherObject); // arg.CObj
MyObject *myObject = obj.getMyObject();
lua_getglobal(L, "MyObject"); // arg.CObj _G.MyObject
lua_pushnumber(L, 1); // arg.CObj _G.MyObject 1
lua_pcall(L, 1, 1, 0); // arg.CObj obj
lua_getfield(L, -1, "setCObject"); // arg.CObj obj obj.setCObject
lua_pushlightuserdata(L, myObject); // arg.CObj obj obj.setCObject myObject
lua_pcall(L, 1, 0, 0); // arg.CObj obj
// at this point lua_gettop(L); returns 2.
// If you end this function with return 1, only obj is returned
// to Lua, everything else is discarded.
return 1;
}
(For what it's worth, when writing Lua code I religiously put comments like that on every single line that messes with the Lua stack so I always know what I'm operating on. Once you memorize the side effects of Lua function it makes bug finding very easy)
This should be fine assuming that returnLuaMyObject is being called from Lua. If you're calling it in a loop in C++ your stack is going to get messed up since it's left with two things on the stack and some of your functions are hardcoded to operate on index 1.
A better way to do this is to do what Cubic suggested and use some templates rather than macros. You should also avoid using hardcoded indexes when possible so that you can reuse your functions in situations where the object you're interested in is in a difference spot on the stack. For example, your gLuaGet should take an index as an argument so that you can use it anywhere. (I'd also get rid of the obj argument and drop the entire last line of the macro, it makes it unclear where the the variable obj is being declared.
I wrote a library for myself (coincidentally called LuaWrapper, located here) which lets you do what you want without a lot of hassle. You can use luaW_to and luaW_push to push and get pointers from
Lua just like they were numbers or strings. I'm just throwing it out there because I like it better than the suggestion of Luabind or toLua++
The top of the stack in Lua is -1, not 1 (or lua_gettop(state)). Also, you should really use templates rather than macros for this. Or better yet, unless you have a reason not to, you could use luabind or tolua++. I'm currently writing something that works essentially the same as luabind, but uses C++11 features to drop the boost dependency, although it's nowhere near completion yet.
I am trying to register a c++ function in Lua.
But getting this error:
CScript.cpp|39|error: argument of type 'int (CScript::)(lua_State*)' does not match 'int (*)(lua_State*)'|
EDIT:
int CApp::SetDisplayMode(int Width, int Height, int Depth)
{
this->Screen_Width = Width;
this->Screen_Height = Height;
this->Screen_Depth = Depth;
return 0;
}
int CScript::Lua_SetDisplayMode(lua_State* L)
{
// We need at least one parameter
int n = lua_gettop(L);
if(n < 0)
{
lua_pushstring(L, "Not enough parameter.");
lua_error(L);
}
int width = lua_tointeger(L, 1);
int height = lua_tointeger(L, 2);
int depth = lua_tointeger(L, 3);
lua_pushinteger(L, App->SetDisplayMode(width, height, depth));
return 0;
}
And in main:
lua_register(L, "setDisplayMode", Lua_SetDisplayMode);
You can not use a method of a class as a normal function, unless it is declared static. You have to define a normal function, which finds out what object you want the method to be called in, and then call the method.
The main reason it's not possible to use a class method as a callback from a C function (and remember that the Lua API is a pure C library), is because the computer doesn't know which object the method should be called on.
The answer is actually surprisingly simple; if you use lua_pushcclosure instead of lua_pushcfunction, you can pass parameters to your called function:
lua_pushlightuserdata(_state, this);
lua_pushcclosure(_state, &MyClass::lua_static_helper, 1);
int MyClass::lua_static_helper(lua_State *state) {
MyClass *klass = (MyClass *) lua_touserdata(state, lua_upvalueindex(1));
return klass->lua_member_method(state);
}
You cannot directly register a C++ non-static member function in Lua using just the basic Lua C API.
However, any of the various mechanisms that exist for easily associating C++ code with Lua will allow you to do so. toLua++, SWIG, Luabind, etc. If you're serious about using C++ objects with Lua, I suggest picking one of those and using it, rather than writing your own version. I personally use Luabind (most of the time; SWIG has its place in the toolbox), as it is the one that doesn't have some form of code generation. It's all done purely in C++, so there's no pre-pass step that generates a C++ source file.
You can work around the limitation by storing your active this pointer in a static variable as well. This introduces the problem of being unable to have two of these classes operating at the same time, but it works.
static CScript* luaThis; // This is a private variable inside CScript.
Then, inside your CScript constructor (or some kind of 'activate' function), you can just specify:
luaThis = this;
Then, when your static functions are called (they can even be private functions if they are registered from within the class), you have access to all your member information via the luaThis pointer.
lua_pushinteger(L, luaThis->App->SetDisplayMode(width, height, depth));
The problem, as I said, is that this restricts you to one active CScript at a time (since another callback from another Lua state would use luaThis while it is pointing to the wrong things). If you need multiple active instances ever, you can come up with some lookup mechanism using the incoming lua_State* as a key.
std::map<lua_State*, CScript*> lookups; // Just an idea, if it comes to this.
Hope that helps!