[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Lua Wrapping
- From: David Morris-Oliveros <david@...>
- Date: Thu, 04 Aug 2005 12:40:43 +1000
First of all, sorry for the very very long post. If things like these
are considered bad, please let me know. Thanks
I'm trying to wrap some C++ objects in my app, and I want to, in Lua
code, be able to do this:
v = Vec2:new();
len = v.length();
v.x = 10.1;
xpos = v.x;
To this effect, i have come up with a scheme, obviously wrong. It works
under pure lua, but when i try to implement it in C++, it falls flat.
My idea is this:
I create a table (Vec2), that has a series of methods that the class
needs (length, angle, etc). Then, i create another table (annonymous)
that contains 2 metamethods: __index & __newindex. These access the raw
C++ land variables and act upon it.
My idea is thus:
When I call:
v = Vec2:new()
The table 'Vec2' contains the function 'new' and calls it. This returns
a table (in lua) or userdata (in C++) whose metatable is annonymous and
has 2 metamethods: __index & __newindex that both point to Vec2.
So, when i call this:
v.x = 1;
I expect this to happen: 'v' doesn't have something called 'x', so it
goes to its metatable and calls __index, which is Vec2, but it doesn't
have it either, so it goes to its (Vec2's) metatable, which is the
annonymous one. Since this last one has __index, it calls it. And all is
fine.
With the exception that in C++ land, i get a table instead of the
expected 'v' userdata.
This is what the pure lua code looks like:
-- lua space -----------------------------------------------------------
Vec2 =
{
length = function (self)
return math.sqrt(self.x*self.x + self.y*self.y)
end;
new = function (self, x,y)
return setmetatable({}, { __index = Vec2, __newindex = Vec2 });
end;
__tostring = function (self)
return "[Vec2]";
end;
}
setmetatable(Vec2, {
__index = function (table, key)
print ("Trying to index ", table, "with key", key);
if key == "x" then return 21; end;
if key == "y" then return 12; end;
return 0;
end;
__newindex = function (table, key, value)
print ("Trying to newindex ", table, "with key", key, " = ", value);
end;
}
);
When I try to implement this in C++ land, i do the same thing:
-- C++ space -----------------------------------------------------------
class Vec4
{
public:
Vec4() {}
Vec4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z),
w(_w) {}
Vec4(const Vec4& o) : x(o.x), y(o.y), z(o.z), w(o.w) {}
float length() { return (float)sqrtf(x*x + y*y + z*z + w*w); }
float x,y,z,w;
};
typedef struct { Vec4 *pT; } userdata_Vec4;
//----------------------------------------------------------------
int Vec4_new(lua_State* L)
{
lua_remove(L, 1); // use classname:new(), instead of classname.new()
userdata_Vec4 *ud = static_cast< userdata_Vec4* >
(lua_newuserdata(L, sizeof(userdata_Vec4))); // push 1, pop 0
int udidx = lua_gettop(L);
ud->pT = new Vec4();
luaL_getmetatable(L, "Vec4");
// sets the metatable of the new userdata_Vec4 to the
// metatable stored in the registry
lua_setmetatable (L, udidx); // push 0, pop 1
// we got still one object on the stack, the userdata_Vec4,
// which is what we return, so tell lua this.
return 1;
}
//----------------------------------------------------------------
int Vec4_gc(lua_State* L)
{
if (lua_gettop(L) != 1)
{
lua_pushstring(L, "incorrect argument to method 'Vec4_gc'");
lua_error(L);
}
userdata_Vec4 *udv4t =
static_cast<userdata_Vec4*>(luaL_checkudata(L, 1, "Vec4"));
delete udv4t->pT;
return 0;
}
//----------------------------------------------------------------
int Vec4_index(lua_State* L)
{
if (lua_gettop(L) != 2)
{
lua_pushstring(L, "incorrect argument to method 'Vec4_index'");
lua_error(L);
}
userdata_Vec4* ud =
static_cast<userdata_Vec4*>(luaL_checkudata(L, 1, "Vec4"));
const char * indexing = lua_tostring(L,2);
if (indexing[1] != 0)
{
lua_pushstring(L, "incorrect argument to method 'Vec4_index'");
lua_error(L);
}
switch(indexing[0])
{
case 'x': lua_pushnumber(L, (LUA_NUMBER) ud->pT->x); break;
case 'y': lua_pushnumber(L, (LUA_NUMBER) ud->pT->y); break;
default: {
lua_pushfstring(L, "Don't know about '%s'", indexing);
lua_error(L);
return 0;
}
}
return 1;
}
//----------------------------------------------------------------
int Vec4_newindex(lua_State* L)
{
dumpStack(L);
if (lua_gettop(L) != 3)
{
lua_pushstring(L, "incorrect argument to method 'Vec4_index'");
lua_error(L);
}
userdata_Vec4* ud =
static_cast<userdata_Vec4*>(luaL_checkudata(L, 1, "Vec4"));
const char * indexing = lua_tostring(L,2);
double value = luaL_checknumber(L,3);
if (indexing[1] != 0) // only a one letter thing
{
lua_pushfstring(L, "incorrect argument to method 'Vec4_index'
[%s]", indexing);
lua_error(L);
}
switch(indexing[0])
{
case 'x': ud->pT->x = (float) value; break;
case 'y': ud->pT->y = (float) value; break;
default: {
lua_pushfstring(L, "Don't know about '%s'", indexing);
lua_error(L);
return 0;
}
}
return 0;
}
//----------------------------------------------------------------
int Vec4_tostring(lua_State* L)
{
if (lua_gettop(L) != 1)
{
lua_pushstring(L, "incorrect argument to method 'Vec4_tostring'");
lua_error(L);
}
userdata_Vec4* ud =
static_cast<userdata_Vec4*>(luaL_checkudata(L, 1, "Vec4"));
if (ud)
{
lua_pushfstring(L, "<%f, %f, %f, %f>", ud->pT->x, ud->pT->y,
ud->pT->z, ud->pT->w);
return 1;
}
lua_pushstring(L, "Vec4 descriptor");
return 1;
}
//----------------------------------------------------------------
int Vec4_length(lua_State* L)
{
if (lua_gettop(L) != 1)
{
lua_pushstring(L, "incorrect argument to method 'Vec4_length'");
lua_error(L);
}
userdata_Vec4* ud =
static_cast<userdata_Vec4*>(luaL_checkudata(L, 1, "Vec4"));
lua_pushnumber(L, (LUA_NUMBER)ud->pT->length());
return 1;
}
//----------------------------------------------------------------
int bindLua(lua_State* L)
{
// create table
lua_newtable (L);
int Vec2_ct = lua_gettop (L);
// [anonTable] = {}
lua_newtable (L);
int Vec2_mt = lua_gettop (L);
// create a metatable
luaL_newmetatable(L, "Vec2");
int Vec2_inst_mt = lua_gettop (L);
// give the table a name
lua_pushstring (L, "Vec2");
lua_pushvalue (L, Vec2_ct);
lua_settable (L, LUA_GLOBALSINDEX);
// [anonTable].__index = Vec2_index
lua_pushstring (L, "__index");
lua_pushcfunction (L, Vec2_index);
lua_settable (L, Vec2_mt);
// [anonTable].__newindex = Vec2_newindex
lua_pushstring (L, "__newindex");
lua_pushcfunction (L, Vec2_newindex);
lua_settable (L, Vec2_mt);
// [anonTable].__gc = Vec2_gc
lua_pushliteral(L, "__gc");
lua_pushcfunction(L, Vec2_gc);
lua_settable(L, Vec2_mt);
// [anonTable].__tostring = Vec2_tostring
lua_pushliteral(L, "__tostring");
lua_pushcfunction(L, Vec2_tostring);
lua_settable(L, Vec2_mt);
lua_pushliteral (L, "new");
lua_pushcfunction (L, Vec2_new);
lua_settable (L, Vec2_ct);
// methods
lua_pushliteral (L, "length");
lua_pushcfunction (L, Vec2_length);
lua_settable (L, Vec2_ct);
// Vec2.__metatable = [anonTable]
lua_pushvalue (L, Vec2_mt);
lua_setmetatable (L, Vec2_ct);
lua_pushstring(L, "__index");
lua_pushvalue(L, Vec2_ct);
lua_settable(L, Vec2_inst_mt);
lua_pushstring(L, "__newindex");
lua_pushvalue(L, Vec2_ct);
lua_settable(L, Vec2_inst_mt);
lua_pop (L, 3);
}
And when i try to run this Lua code:
-- lua space -----------------------------------------------------------
> v = Vec2:new()
> print(v)
userdata: 0093FC48
> v.x = 1;
CRASH!
Upon inspecting the stack, i see this:
Dumping stack [3]
Arg [1][table][-]
Arg [2][string][x]
Arg [3][string][1]
So my question is:
Why is the 1st thing on the stack a table and not the userdata?
--
// David Morris-Oliveros
------------------------------------------------------------------------
Contact:
Team Bondi Pty Ltd
Level 2, 608 Harris Street
Ultimo, NSW 2007
Australia
Tel: +61 (0)2 8218 1500
Fax: +61 (0)2 8218 1507
Web: http://www.teambondi.com
------------------------------------------------------------------------
This email may contain confidential information. If you are not
the intended recipient, you may not copy or deliver this message to
anyone. In such case, you should destroy this message and kindly
notify the sender by reply email. Opinions, conclusions and other
information in this message that do not relate to the official business
of our firm shall be understood as neither given nor endorsed by it.
------------------------------------------------------------------------