Sign in to follow this  

How to send arrays/ matrices to Lua?

This topic is 3297 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Well I need to push a matrix on to the stack in lua and I can't seem to find a command to do that. I tried pushing each value in the array on to the stack like this:
int lua_Translate(lua_State *L)
{
	D3DXMATRIX Matrix;
	D3DXMatrixTranslation( &Matrix, (float)lua_tonumber(L, 1), (float)lua_tonumber(L, 2), (float)lua_tonumber(L, 3) );
	lua_pushnumber(L, (float)Matrix._11);
	lua_pushnumber(L, (float)Matrix._12);
	lua_pushnumber(L, (float)Matrix._13);
	lua_pushnumber(L, (float)Matrix._14);
	lua_pushnumber(L, (float)Matrix._21);
	lua_pushnumber(L, (float)Matrix._22);
	lua_pushnumber(L, (float)Matrix._23);
	lua_pushnumber(L, (float)Matrix._24);
	lua_pushnumber(L, (float)Matrix._31);
	lua_pushnumber(L, (float)Matrix._32);
	lua_pushnumber(L, (float)Matrix._33);
	lua_pushnumber(L, (float)Matrix._34);
	lua_pushnumber(L, (float)Matrix._41);
	lua_pushnumber(L, (float)Matrix._42);
	lua_pushnumber(L, (float)Matrix._43);
	lua_pushnumber(L, (float)Matrix._44);
	return 1;
}

I thought I could then read it with something like this:
D3DXMATRIX Matrix;
Matrix._11 = (float)lua_tonumber(L,1);
Matrix._12 = (float)lua_tonumber(L,2);
Matrix._13 = (float)lua_tonumber(L,3);
Matrix._14 = (float)lua_tonumber(L,4);
Matrix._21 = (float)lua_tonumber(L,1);
Matrix._22 = (float)lua_tonumber(L,2);
Matrix._23 = (float)lua_tonumber(L,3);
Matrix._24 = (float)lua_tonumber(L,4);
Matrix._31 = (float)lua_tonumber(L,1);
Matrix._32 = (float)lua_tonumber(L,2);
Matrix._33 = (float)lua_tonumber(L,3);
Matrix._34 = (float)lua_tonumber(L,4);
Matrix._41 = (float)lua_tonumber(L,1);
Matrix._42 = (float)lua_tonumber(L,2);
Matrix._43 = (float)lua_tonumber(L,3);
Matrix._44 = (float)lua_tonumber(L,4);

But apparently you can only push one value at a time, so how do I do that? And yes I know about pushing the pointer but if I do that when I multiply the matrix it will still keep the two matrices I multiplied in memory so after I do that a few times I think I would get an overflow.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
User defined types. Follow the -> links.

Basically, you push the pointer to matrix structure.


I'm confused, I understand kinda what it's talking about but I don't understand how to push user data. I see there is a command to read it:

D3DXMATRIX Matrix = (D3DXMATRIX)lua_touserdata(L, 1);

But I fail to understand how to push it, I would think there would be a command that would work something like this:

void lua_pushuserdata (lua_State *L, void *userdata, int size);

I don't understand how lua_newuserdata works, I've read about it but for some reason I can't understand how I would use that to push my matrix?

Share this post


Link to post
Share on other sites
One of following chapters mentions light user data.

User defined types are covered well in one of GPG books, the tutorial just mentions that light user data should be used with meta tables. There's probably other articles on google.

Custom types are basically objects, so they need to be described in a way for Lua to manipulate them. You don't really want to push D3D types directly, but pass them to Lua via some managed pointer.

There's also several libraries which provide slightly more convenient access to Lua.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
One of following chapters mentions light user data.

User defined types are covered well in one of GPG books, the tutorial just mentions that light user data should be used with meta tables. There's probably other articles on google.

Custom types are basically objects, so they need to be described in a way for Lua to manipulate them. You don't really want to push D3D types directly, but pass them to Lua via some managed pointer.

There's also several libraries which provide slightly more convenient access to Lua.


I'm racking my brains trying to understand, is there anyway you can show me a code example of what I need to do?

[Edited by - CodaKiller on December 7, 2008 9:48:03 PM]

Share this post


Link to post
Share on other sites
Have u tried using some of the automated binding libraries for Lua ? Like toLua, Mluabind or Luabind, etc.. They pretty much automate the process of binding your objects to Lua. There might be more overhead than implementing raw Lua functions and pushing/poping userdata yourself, but you'll never know until you profile it.

-ddn

Share this post


Link to post
Share on other sites
Quote:
Original post by ddn3
Have u tried using some of the automated binding libraries for Lua ? Like toLua, Mluabind or Luabind, etc.. They pretty much automate the process of binding your objects to Lua. There might be more overhead than implementing raw Lua functions and pushing/poping userdata yourself, but you'll never know until you profile it.

-ddn


Well my engine is over 5000 lines of code and it has so many raw lua functions that it would take a really long time to change them all.

Share this post


Link to post
Share on other sites
Ok I'm tired of this, I'll send $10 through Paypal to the first person who can give me a function that can push a D3DXMATRIX and then show me how to read it back out like lua_tonumber but gets the matrix instead of a number.

Share this post


Link to post
Share on other sites

int method_index2_set(lua_State *L) {
D3DXMATRIX *m;
float* cells;
float v;
int i, j;

lua_getfield(L, 1, "i");
i = (int)lua_tonumber(L, -1) - 1;
j = (int)lua_tonumber(L, 2) - 1;
v = lua_tonumber(L, 3);

if ( i >= 0 && j >= 0 && i < 4 && j < 4 )
{
lua_getfield(L, 1, "matrix");
m = luaL_checkudata(L, -1, "D3DXMATRIXForLua");
cells = (float*)m;
cells[j*4 + i] = v;
}
return 0;
}

int method_index2_get(lua_State *L) {
D3DXMATRIX *m;
int i, j;

lua_getfield(L, 1, "i");
i = (int)lua_tonumber(L, -1) - 1;
j = (int)lua_tonumber(L, 2) - 1;
if ( i < 0 || j < 0 || i > 3 || j > 3 )
return 0;

lua_getfield(L, 1, "matrix");
m = luaL_checkudata(L, -1, "D3DXMATRIXForLua");
float* cells = (float*)m;
lua_pushnumber(cells[j*4 + i]);
return 1;
}

int method_index1(lua_State *L) {
lua_createtable(L, 0, 2);
lua_pushvalue(L, 2);
lua_setfield(L, -2, "i");
lua_pushvalue(L, 1);
lua_setfield(L, -2, "matrix");
if ( luaL_newmetatable(L, "D3DXMATRIXIndexedOnce") ) {
lua_pushcfunction(L, method_index2_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, method_index2_set);
lua_setfield(L, -2, "__newindex");
}
lua_setmetatable(L, -2);
return 1;
}

void luaMakeMatrix(lua_State *L, D3DXMATRIX** handle)
{
*handle = (D3DXMATRIX*)lua_newuserdata(L, sizeof(D3DXMATRIX));
if ( luaL_newmetatable(L, "D3DXMATRIXForLua") ) {
// Add any other methods you want; I've made indexing for you.
lua_pushcfunction(L, method_index1);
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
}

void luaGetMatrix(lua_State *L, D3DXMATRIX** handle, int pos)
{
// Throws a Lua error if given stack position is not a D3DXMATRIX.
*handle = luaL_checkudata(L, pos, "D3DXMATRIXForLua");
}



C usage:

// Create a new matrix, pushing it on the stack and filling a pointer to
// the newly-allocated and garbage-collected-for-you-by-lua matrix.
D3DXMATRIX* matrix;
luaMakeMatrix(L, &matrix);
matrix->_11 = matrix->_12 = matrix->_13 = matrix->_14 = 0;

// Fill a pointer with the matrix on the lua stack; in this case,
// where the matrix is passed as argument 2 to this C implementation
// of a lua-protocol function.
void befoozle(lua_State *L)
{
D3DXMATRIX* m;
luaGetMatrix(L, &matrix, 2);
m->_13 = -m->_13;
lua_pushnumber(L, m->_33);
return 1;
}



Lua usage:

function frobnicate(matrix)
matrix[3][1] = 8
return matrix[2][0]
end



Untested, and I've assumed, possibly incorrectly, that the float[16] equivalent to a D3DXMATRIX goes [_11, _21, _31, _41, _12, _22, _32... _43, _44]. Just swap i and j in the setter and getter to fix that.

Paypal transfer not required.

Share this post


Link to post
Share on other sites
I got the functions to work a bit more like I wanted them to and I fixed some of the bugs but I need a small explanation as to what all the methods are?

Here is what I did:

int method_index2_set(lua_State *L) {
D3DXMATRIX *m;
float* cells;
float v;
int i, j;

lua_getfield(L, 1, "i");
i = (int)lua_tonumber(L, -1) - 1;
j = (int)lua_tonumber(L, 2) - 1;
v = (float)lua_tonumber(L, 3);

if ( i >= 0 && j >= 0 && i < 4 && j < 4 )
{
lua_getfield(L, 1, "matrix");
m = (D3DXMATRIX*)luaL_checkudata(L, -1, "D3DXMATRIXForLua");
cells = (float*)m;
cells[j*4 + i] = v;
}
return 0;
}

int method_index2_get(lua_State *L) {
D3DXMATRIX *m;
int i, j;

lua_getfield(L, 1, "i");
i = (int)lua_tonumber(L, -1) - 1;
j = (int)lua_tonumber(L, 2) - 1;
if ( i < 0 || j < 0 || i > 3 || j > 3 )
return 0;

lua_getfield(L, 1, "matrix");
m = (D3DXMATRIX*)luaL_checkudata(L, -1, "D3DXMATRIXForLua");
float* cells = (float*)m;
lua_pushnumber(L, cells[j*4 + i]);
return 1;
}

int method_index1(lua_State *L) {
lua_createtable(L, 0, 2);
lua_pushvalue(L, 2);
lua_setfield(L, -2, "i");
lua_pushvalue(L, 1);
lua_setfield(L, -2, "matrix");
if ( luaL_newmetatable(L, "D3DXMATRIXIndexedOnce") ) {
lua_pushcfunction(L, method_index2_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, method_index2_set);
lua_setfield(L, -2, "__newindex");
}
lua_setmetatable(L, -2);
return 1;
}

void lua_pushmatrix(lua_State *L, D3DXMATRIX* Matrix)
{
D3DXMATRIX* UserData = (D3DXMATRIX*)lua_newuserdata(L, sizeof(D3DXMATRIX));
memcpy( UserData, Matrix, sizeof(D3DXMATRIX) );
if ( luaL_newmetatable(L, "D3DXMATRIXForLua") )
{
lua_pushcfunction(L, method_index1);
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
}

D3DXMATRIX lua_tomatrix(lua_State *L, int pos)
{
D3DXMATRIX Matrix;
D3DXMATRIX* LuaMatrix = (D3DXMATRIX*)luaL_checkudata(L, pos, "D3DXMATRIXForLua");
memcpy( &Matrix, LuaMatrix, sizeof(D3DXMATRIX) );
return Matrix;
}



[Edited by - CodaKiller on December 8, 2008 4:38:29 PM]

Share this post


Link to post
Share on other sites
Using your revisions...

void lua_pushmatrix(L, m) allocates a new matrix, copies matrix m over it, and pushes it on the stack. This matrix has an __index metamethod, such that in Lua, "matrix[3]" will result in a call to method_index1(L) being called with "matrix" and "3" on the stack, in that order.

method_index1(L) creates a temporary object which remembers which matrix was indexed and what the first index was. This object has __index and __newindex methods, for retrieval and assignment respectively.

method_index2_get(L) is called on __index of the temp object; the temp object is at stack 1, and the second index at stack 2. It reads the matrix for the value at that cell and returns it.

method_index2_set(L) is called on __newindex (since the temporary object has no non-nil integer indices, indexing it will result in the __newindex meta-method call). It writes the new value to the matrix.

I think that covers everything.

Share this post


Link to post
Share on other sites

This topic is 3297 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this