How do I manipulate C++ vectors of C structs in Lua?

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

How do I manipulate C++ vectors of C structs in Lua?

Nolan Check
This may seem like a question that has been answered dozens of times with "use metatables". However, I'm having trouble figuring out how to apply that to the problem I have right now. I'll try to explain...

I need to manipulate sprites with Lua (I am embedding Lua in my own simple video game engine). A sprite is just a graphic that can be placed anywhere on the screen. I have this C structure for a sprite:

struct SPRITE_USERDATA
{
	bool Enabled; // Should this sprite be drawn?
	lua_Number X; // X position
	lua_Number Y; // Y position
};

This structure can't specify which graphic to use. It doesn't need to because there is only one graphic available at the moment.

My program keeps a C++ vector of sprites. On each frame, it goes through the vector and draws all of the sprites in it:

vector<SPRITE_USERDATA*> g_SpriteVector;

A C function "Sprite_New" is exported to Lua. It adds a SPRITE_USERDATA to the end of the vector. I'm not worried about any "Sprite_Delete" function yet. I need to get this working first.

All I need is a way to access the elements of g_SpriteVector from Lua. Then, I need to be able to manipulate the "Enabled", "X", and "Y" fields of the structure. In other words, I want to be able to access g_SpriteVector in Lua just like I can in my C++ code.

I hope this is all understandable. I was thinking of using Lua Userdata objects to represent the sprite vector and each sprite. Then, I could give them metatables which let me access g_SpriteVector like an array and the SPRITE_USERDATA elements like tables. I need help figuring out how to do it, if it is possible.

- Checkmate



Reply | Threaded
Open this post in threaded view
|

Re: How do I manipulate C++ vectors of C structs in Lua?

mark gossage
Hello there,

To get your access to the vector, should be the same as getting access to the elements of the SPRITE_USERDATA, ie "use metatables".

I will give you an idea of how SWIG does its wrapperings:
The g_SpriteVector will be accessible within Lua via a userdata which holds a pointer to the g_SpriteVector and a metatable which holds all the methods.
When you call g_SpriteVector[0] from lua, what happens is this is routed (via the metatable) to a function
SPRITE_USERDATA* g_SpriteVector_get(int idx){return g_SpriteVector[idx];}
(or something like this), which will return a pointer to the sprite (again wrappered as a usedata)

And so, hey presto, you get your sprite which you can then manipulate.

If you don't want to mess about with the metatables, you can easily write a SpriteVector_get() fn which you can call.

Alternatively, you can look at one of the autobinders (SWIG, tolua, tolua++, luabind, luna). I recomend SWIG, but them I'm biased :-)

Hope this helps,
Mark Gossage

> 
> This may seem like a question that has been answered dozens of times with 
> "use metatables". However, I'm having trouble figuring out how to
> apply that 
> to the problem I have right now. I'll try to explain...
> 
> I need to manipulate sprites with Lua (I am embedding Lua in my own simple 
> video game engine). A sprite is just a graphic that can be placed anywhere 
> on the screen. I have this C structure for a sprite:
> 
> struct SPRITE_USERDATA
> {
> 	bool Enabled; // Should this sprite be drawn?
> 	lua_Number X; // X position
> 	lua_Number Y; // Y position
> };
> 
> This structure can't specify which graphic to use. It doesn't need to 
> because there is only one graphic available at the moment.
> 
> My program keeps a C++ vector of sprites. On each frame, it goes through the
> 
> vector and draws all of the sprites in it:
> 
> vector<SPRITE_USERDATA*> g_SpriteVector;
> 
> A C function "Sprite_New" is exported to Lua. It adds a
> SPRITE_USERDATA to 
> the end of the vector. I'm not worried about any "Sprite_Delete"
> function 
> yet. I need to get this working first.
> 
> All I need is a way to access the elements of g_SpriteVector from Lua. Then,
> 
> I need to be able to manipulate the "Enabled", "X", and
> "Y" fields of the 
> structure. In other words, I want to be able to access g_SpriteVector in Lua
> 
> just like I can in my C++ code.
> 
> I hope this is all understandable. I was thinking of using Lua Userdata 
> objects to represent the sprite vector and each sprite. Then, I could give 
> them metatables which let me access g_SpriteVector like an array and the 
> SPRITE_USERDATA elements like tables. I need help figuring out how to do it,
> 
> if it is possible.
> 
> - Checkmate




Reply | Threaded
Open this post in threaded view
|

Re: How do I manipulate C++ vectors of C structs in Lua?

Nolan Check
Thanks! The fact is, I've never worked with Lua metatables before. I'm glad it
turned out to be as simple as it is.

I am currently storing pointers to Lua userdata in g_SpriteVector. Do I have to
watch out for the Lua garbage collector? Could it free the memory of a sprite
structure while I still have a pointer to it?

- Checkmate



Reply | Threaded
Open this post in threaded view
|

Re: How do I manipulate C++ vectors of C structs in Lua?

mark gossage
In reply to this post by Nolan Check
Hello Again,

This is a matter of how you want to manage your code.
For the g_SpriteVector, I would have this as a global held in C++, that menas there is no mem-managing to do.
For the object held in the vector, thats a little harder.
I am assuming that you are holding fairly plain C/C++ code in the vector (as per you previous mail). And when Lua requests it you wrapper it and pass it back to Lua.
In this case, the C++ should be managing the code. And its C++'s job to delete the objects when required.
The issue is that if someone within Lua requests a sprite, and then C++ deletes it, the lua object is still valid, but it points to dead memory (core dump anyone?).
So I suggest that you document this behaviour and tell people not to keep references to a sprite within lua, but get them as they need it.

As an alternative (there are always so many ways to solve the problem), you could let Lua manage the data, this menas you will need a __gc method in your metatable to delete the C++ object & probably tell the vector to remove it as well.

If you asked for an opinion, I would use the former, rather than the latter.

Regards,
Mark

> Thanks! The fact is, I've never worked with Lua metatables before. I'm glad
> it
> turned out to be as simple as it is.
> 
> I am currently storing pointers to Lua userdata in g_SpriteVector. Do I have
> to
> watch out for the Lua garbage collector? Could it free the memory of a
> sprite
> structure while I still have a pointer to it?
> 




Reply | Threaded
Open this post in threaded view
|

Re: How do I manipulate C++ vectors of C structs in Lua?

Zé Pedro
Hi,
I have a similar problem, instead of a Vector a have a matrix of strings that I have in C that I want to send to Lua for manipulation in there. I'm aware that I can do it with metatables but I just don't know how. Imagine I have the following function:

int LArena::getMatrix(lua_State *L)
{   
    luaL_checktype(L, 1, LUA_TSTRING);
    const char *name = luaL_checkstring(L,1);
   
    try
    {
        std::string** matrix = ArenaContainer::getArenaContainerPtr()->getMatrix(name);
        //now I want to send the matrix to Lua. How????
    } catch(...)
    {
        luaL_error(L,"object class not found");
        return 0;
    }
    return 0;
}
Can you help what to return or how to construct the metatable so the matrix colud be manipulated in Lua?
Just to check I have a similar function that return a list of objects. It seems to be working but I don't know if it's the best way to do it:

int LArena::getObjectsByClass(lua_State *L)
{   
    luaL_checktype(L, 1, LUA_TSTRING);
    const char *classe = luaL_checkstring(L,1);
   
    try
    {
        ObjectKey classId = "">        vector<Object*> objs = ArenaContainer::getArenaContainerPtr()->getObjectsByClass(classId);
        int size = objs.size();
        Object *tmp;
        ObjectKey key;
        char *buf;
       
        for (int i=0; i<size; i++)
        {
            tmp = objs.at(i);
           
            buf = (char *)lua_newuserdata(L,sizeof(ObjectKey));   
            key = tmp->getID();
            memcpy(buf,(char*)&key,sizeof(ObjectKey));
            luaL_getmetatable(L,"Zara.object ");
            lua_setmetatable(L, -2);
        }
       
        return size;
    } catch(...)
    {
        luaL_error(L,"object class not found");
        return 0;
    }
    return 0;
}

Thanks,
José Pedro Tavares


Reply | Threaded
Open this post in threaded view
|

Re: Re: How do I manipulate C++ vectors of C structs in Lua?

Ken Smith-2
On 11/10/06, Zé Pedro <[hidden email]> wrote:
Hi,
I have a similar problem, instead of a Vector a have a matrix of strings
that I have in C that I want to send to Lua for manipulation in there. I'm
aware that I can do it with metatables but I just don't know how. Imagine I
have the following function:
[snip]

I don't even bother with metatables.  I just convert C/C++ structures
and classes to nested tables.  I set up a function that looks
something like this and its inverse if I must get the table back into
the C/C++ struct/class.

// global
static SomeClass c;

// export this to Lua
static int class_to_lua_table(lua_State* L)
{
  lua_newtable(L);

  int table_stack_pos = lua_gettop(L);

  lua_pushnumber(L, c.val1);
  lua_setfield(L, table_stack_pos, "val1");

  lua_pushnumber(L, c.val2);
  lua_setfield(L, table_stack_pos, "val2");

  subclass_to_lua_table(L, c.sub);  // implementation implied
  lua_setfield(L, table_stack_pos, "sub");

  return 1;
}

Then, once you've registered that function to Lua, you can do this, for example.

c = class_to_lua_table()

print(c.val1, c.val2, c.sub.data1, c.sub.data2)

I find this to be the simplest solution but I basically just use C/C++
to bootstrap into Lua and implement all the logic in Lua so I either
don't need or can easily wrap the methods in the classes.  YMMV.

 Ken Smith


Reply | Threaded
Open this post in threaded view
|

Re: Re: How do I manipulate C++ vectors of C structs in Lua?

Zé Pedro
Thanks for the reply, but I'm not sure if that's what I want. I already do something like that when translating C++ classes to lua, but two dimensional arrays, I'm having dificulties seeing how to do it. Taking your example would it be something like:

// export two dimensional arrays to Lua
static int class_to_lua_table(lua_State* L)
{
   string[][] matrix = getMatrix(name);

   lua_newtable(L);

   int table_stack_pos = lua_gettop(L);

   for (int i=0; i<matrix.size; i++)
      lua_pushnumber(L, matrix.i);                         //??????
      lua_setfield(L, table_stack_pos, i);      //??????
      for (int j=0; i<matrix[i].size; j++)
         lua_pushnumber(L, matrix.i.j);           //??????
         lua_setfield(L, table_stack_pos, matrix[i][j]);

   return 1;
}

It doesn't make much sense to me....

Thanks,
Jose Pedro Tavares


On 11/10/06, Ken Smith <[hidden email]> wrote:
On 11/10/06, Zé Pedro <[hidden email]> wrote:
> Hi,
> I have a similar problem, instead of a Vector a have a matrix of strings
> that I have in C that I want to send to Lua for manipulation in there. I'm
> aware that I can do it with metatables but I just don't know how. Imagine I
> have the following function:
[snip]

I don't even bother with metatables.  I just convert C/C++ structures
and classes to nested tables.  I set up a function that looks
something like this and its inverse if I must get the table back into
the C/C++ struct/class.

// global
static SomeClass c;

// export this to Lua
static int class_to_lua_table(lua_State* L)
{
   lua_newtable(L);

   int table_stack_pos = lua_gettop(L);

   lua_pushnumber(L, c.val1);
   lua_setfield(L, table_stack_pos, "val1");

   lua_pushnumber(L, c.val2);
   lua_setfield(L, table_stack_pos, "val2");

   subclass_to_lua_table(L, c.sub);  // implementation implied
   lua_setfield(L, table_stack_pos, "sub");

   return 1;
}

Then, once you've registered that function to Lua, you can do this, for example.

c = class_to_lua_table()

print(c.val1, c.val2, c.sub.data1, c.sub.data2)

I find this to be the simplest solution but I basically just use C/C++
to bootstrap into Lua and implement all the logic in Lua so I either
don't need or can easily wrap the methods in the classes.  YMMV.

  Ken Smith



--
Believe nothing, no matter where you read it, or who said it,
no matter if I have said it, unless it agrees with your own reason
and your common sense.
- Buda

Para quê ter olhos azuis, se a Natureza deixa os meus  vermelhos?
- Bob Marley

"Don't try to use what you learn from Buddhism to be a Buddhist;
use it to be a better whatever-you-already-are."
- His Holiness the 14th Dalai Lama

Idealism is what precedes experience; cynicism is what follows.
  - David T. Wolf

"Please don't download, because I want to get a pool in my second home."
  - Kanye West
Reply | Threaded
Open this post in threaded view
|

Re: Re: Re: How do I manipulate C++ vectors of C structs in Lua?

Ken Smith-2
On 11/14/06, Zé Pedro <[hidden email]> wrote:
Thanks for the reply, but I'm not sure if that's what I want. I already do
something like that when translating C++ classes to lua, but two dimensional
arrays, I'm having dificulties seeing how to do it. Taking your example
would it be something like:

// export two dimensional arrays to Lua

I would do it like this.

---C++ backend---
static int class_to_lua_table(lua_State* L)
{
  // Declare return table t
  lua_newtable(L);
  int table_stack_pos = lua_gettop(L);

  for (int i=0; i<10; i++)
  {
     // Declare subtable at t[i]
     lua_pushnumber(L, i);
     lua_newtable(L);
     int subtable_stack_pos = lua_gettop(L);

     for (int j=0; j<10; j++)
     {
        char tmp_str[10];
        sprintf(tmp_str, "%d,%d", i, j);

        // Set t[i][j] to tmp_str
        lua_pushnumber(L, j);
        lua_pushstring(L, tmp_str);

        // Finalize t[i][j]
        lua_settable(L, subtable_stack_pos);
     }

     // Finalize t[i]
     lua_settable(L, table_stack_pos);
  }

  // The top level table is the only thing on the stack.
  assert(lua_gettop(L) == 1);

  return 1;
}

Then the following lua will iterate through the 2d table.


---Lua---
t = mylib.class_to_lua_table()

for i,subtable in ipairs(t) do
  for j,str in ipairs(subtable) do
     print(i,j,str)
  end
end

The above will print something like the following.

1	1	1,1
1	2	1,2
1	3	1,3
1	4	1,4
1	5	1,5
1	6	1,6
1	7	1,7
1	8	1,8
1	9	1,9
2	1	2,1
2	2	2,2
2	3	2,3
2	4	2,4
2	5	2,5
2	6	2,6
2	7	2,7
2	8	2,8
2	9	2,9
3	1	3,1
3	2	3,2
3	3	3,3
3	4	3,4
3	5	3,5
3	6	3,6
3	7	3,7
3	8	3,8
3	9	3,9
4	1	4,1
4	2	4,2
4	3	4,3
4	4	4,4
4	5	4,5
4	6	4,6
4	7	4,7
4	8	4,8
4	9	4,9
5	1	5,1
5	2	5,2
5	3	5,3
5	4	5,4
5	5	5,5
5	6	5,6
5	7	5,7
5	8	5,8
5	9	5,9
6	1	6,1
6	2	6,2
6	3	6,3
6	4	6,4
6	5	6,5
6	6	6,6
6	7	6,7
6	8	6,8
6	9	6,9
7	1	7,1
7	2	7,2
7	3	7,3
7	4	7,4
7	5	7,5
7	6	7,6
7	7	7,7
7	8	7,8
7	9	7,9
8	1	8,1
8	2	8,2
8	3	8,3
8	4	8,4
8	5	8,5
8	6	8,6
8	7	8,7
8	8	8,8
8	9	8,9
9	1	9,1
9	2	9,2
9	3	9,3
9	4	9,4
9	5	9,5
9	6	9,6
9	7	9,7
9	8	9,8
9	9	9,9

 Cheers,
 Ken Smith