1

I have C++ function (which runs some physical simulation inside my game engine) which looks like this:

void doSomePhysics( int nIters, Vec3d pos, Vec3d vel ){ /*... don't care ...*/ }

I want call this function from a lua script likes this:

doSomePhysics( 100, {1.0,-2.0,3.0}, {-8.0,7.0,-6.0} ) 

I'm trying to figure out how to make lua interface to this function.

I would like to do several general helper functions for passing 2D,3D and 4D vectors and matrices since I will heavily use them.

Here is sketch what I'm currently trying to do (But I know it is not correct):

void lua_getVec3(lua_State *L, Vec3d& vec ){
    // universal helper function to get Vec3 function argument from Lua to C++ function
    luaL_checktype(L, 1, LUA_TTABLE);
    lua_settop(L, 1);
    int a_size = lua_rawlen(L, 1);
    lua_rawgeti(L, 1, 1); vec.x = lua_tonumber(L, -1);
    lua_rawgeti(L, 2, 2); vec.y = lua_tonumber(L, -2);
    lua_rawgeti(L, 3, 3); vec.z = lua_tonumber(L, -3);
    lua_pop(L, 3);
}

int l_doSomePhysics(lua_State* L){
    // lua interface for doSomePhysics
    Vec3d pos,vel;
    int n = lua_tointeger(L, 1);
    lua_getVec3(L, pos );
    lua_getVec3(L, vel );
    doSomePhysics(n,pos,vel);
    lua_pushnumber(state, 123);
    return 1;
} 

I read several short tutorials 1 2 3 but it seems horribly complicated, confusing and error-prone ... I'm completely lost in stack indexes (what is my current position in the stack?, what is correct relative index? etc.). I'm reluctant to believe the most famous game scripting language needs sooooo much boiler-plate code and so much pain for interfacing every little function.


EDIT: With help of Vlad I was able to do it for 3D vector and matrix

void lua_getVec3(lua_State *L, int idx, Vec3d& vec){
    // universal helper function to get Vec3 function argument from Lua to C++ function
    luaL_checktype(L, idx, LUA_TTABLE);
    lua_rawgeti(L, idx, 1); vec.x = lua_tonumber(L, -1); lua_pop(L, 1);
    lua_rawgeti(L, idx, 2); vec.y = lua_tonumber(L, -1); lua_pop(L, 1);
    lua_rawgeti(L, idx, 3); vec.z = lua_tonumber(L, -1); lua_pop(L, 1);
}

void lua_getMat3(lua_State *L, int idx, Mat3d& mat){
    // universal helper function to get Mat3 function argument from Lua to C++ function
    luaL_checktype(L, idx, LUA_TTABLE);
    lua_pushinteger(L, 1); lua_gettable(L, idx); lua_getVec3(L, -1, mat.a ); lua_pop(L, 1);
    lua_pushinteger(L, 2); lua_gettable(L, idx); lua_getVec3(L, -1, mat.b ); lua_pop(L, 1);
    lua_pushinteger(L, 3); lua_gettable(L, idx); lua_getVec3(L, -1, mat.c ); lua_pop(L, 1);
}

extern "C"
int l_doSomePhysics2(lua_State* L){
    // lua interface for doSomePhysics
    Vec3d pos;
    Mat3d mat;
    int n = lua_tointeger(L, 1);
    lua_getVec3(L, 2, pos );
    lua_getMat3(L, 3, mat );
    doSomePhysics2(n,pos,mat);
    //lua_pushnumber(L, 123);
    return 3;
}

works for this lua function :

mat = {{1.1,-0.1,0.1},{-0.2,2.2,0.2},{-0.3,0.3,3.3}}
doSomePhysics2( 100, {-7.7,8.8,9.9}, mat )
Prokop Hapala
  • 2,424
  • 2
  • 30
  • 59
  • One lib tip is sol 2, single header solution and does what you want in a easier way. – Hannes Hauptmann Aug 03 '17 at 06:50
  • I was already actually looking on it (together with ten of other lua binding libraries). But using some library always add some problems (dependency hell, requirement of C++14, longer compilation time due to templates, more complicated distribution ...). So I would prefer to live without it. – Prokop Hapala Aug 03 '17 at 07:16

1 Answers1

1

Your void lua_getVec3(lua_State *L, Vec3d& vec) is missing vital info - location of argument table on a Lua stack. Rewrite it to something like:

void lua_getVec3(lua_State *L, int idx, Vec3d& vec){
    // universal helper function to get Vec3 function argument from Lua to C++ function
    luaL_checktype(L, idx, LUA_TTABLE);
    lua_rawgeti(L, idx, 1); vec.x = lua_tonumber(L, -1);
    lua_rawgeti(L, idx, 2); vec.y = lua_tonumber(L, -1);
    lua_rawgeti(L, idx, 3); vec.z = lua_tonumber(L, -1);
    lua_pop(L, 3);
}

And call it like:

int l_doSomePhysics(lua_State* L){
    // lua interface for doSomePhysics
    Vec3d pos,vel;
    int n = lua_tointeger(L, 1);
    lua_getVec3(L, 2, pos );
    lua_getVec3(L, 3, vel);
    doSomePhysics(n,pos,vel);
    lua_pushnumber(state, 123);
    return 1;
} 
Vlad
  • 5,450
  • 1
  • 12
  • 19
  • great it works. It should be also `return 3;` right? Is there something missing for safety etc ? – Prokop Hapala Aug 03 '17 at 14:42
  • hmm, sorry I did not learned much ... I don't see how to generalize it to matrix `{{1.0,-0.1,0.1},{-0.2,2.0,0.2},{-0.3,0.3,3.0}}` – Prokop Hapala Aug 03 '17 at 15:28
  • `return 3` will be needed if you return 3 values from your function. So far it is just a single number, so `return 1`. Matrix is just a table of tables. `lua_rawget()` individual vectors from that outer table, get retrieved vector's table location with `lua_gettop()`, and call `lua_getVec3()` as before. – Vlad Aug 03 '17 at 16:48
  • aha thanks. The matrix I already figured out myself and edited my question accordingly. I forgot to write comment here. – Prokop Hapala Aug 03 '17 at 17:57