[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Two indexing methods of a vector. How to ?
- From: Sean Conner <sean@...>
- Date: Mon, 5 Jan 2015 18:41:18 -0500
It was thus said that the Great Charles Melice once stated:
> I defined (with the C API) a Vector object based on full user data.
>
> static Vec4 *Vget(lua_State *L, int i)
> {
> if (luaL_checkudata(L,i,MYTYPE)==NULL) ERROR(MYTYPE);
> return (Vec4*)lua_touserdata(L,i);
> }
>
> Now, I'm interested to be able to index the 'x, y, z, t' coordinates with
> numeric indexes (1,2,3,4). For instance :
>
> local v = Vec4(11,22,33,44)
> print(v.y) -- 22
> v:normalize()
> print(v) -- Vec4(0.27, 0.53, 0.80, 1.07)
> print(v[2]) -- 0.53 ???
>
> v[2]=22.22 -- ???
> print(v.y) -- 22.22
>
> I don't see how to do that ?
First, you need to create a metatable to associate with your userdata.
When you register the module, you create the metatable:
#define MY_VEC4_TYPE "Some String to denote a Vec4"
/*----------------------------------------------------------------
; I'm not sure how you actually define this, but this is a sample
; anyway.
;-----------------------------------------------------------------*/
typedef struct
{
double data[4];
} Vec4;
/*--------------------------------------------------------------------
; This function will handle references in an expression. The naming
; convention I use is <modname>meta_<method>, so for instance, the
; Lua method __index, for this example, will end up being named
; vec4meta___index(). You don't have to follow this convention, but
; I find it nice.
;
; Also, luaL_checkudata() will throw an error if the type is
; incorrect, so you don't need to check the return code.
;---------------------------------------------------------------------*/
static int vec4meta___index(lua_State *L)
{
Vec4 *vec = luaL_checkudata(L,1,MY_VEC_TYPE);
int idx;
if (lua_type(L,2) == LUA_TSTRING)
{
const char *name = lua_tostring(L,2);
if (strcmp(name,"x") == 0)
idx = 0;
else if (strcmp(name,"y") == 0)
idx = 1;
else if (strcmp(name,"z") == 0)
idx = 2;
else if (strcmp(name,"t") == 0)
idx = 3;
else
idx = -1;
}
else if (lua_type(L,2) == LUA_TNUMBER)
idx = lua_tointeger(L,2);
else
idx = -1;
if ((idx < 0) || (idx > 3))
lua_pushnil(L);
else
lua_pushnumber(L,vec->data[idx]);
return 1;
}
/*------------------------------------------------------------------
; This function will handle assignments. It looks quite a bit like
; the __index function.
;-----------------------------------------------------------------*/
static int vec4meta___newindex(lua_State *L)
{
Vec4 *vec = luaL_checkudata(L,1,MY_VEC_TYPE);
int idx;
if (lua_type(L,2) == LUA_TSTRING)
{
const char *name = lua_tostring(L,2);
if (strcmp(name,"x") == 0)
idx = 0;
else if (strcmp(name,"y") == 0)
idx = 1;
else if (strcmp(name,"z") == 0)
idx = 2;
else if (strcmp(name,"t") == 0)
idx = 3;
else
idx = -1;
}
else if (lua_type(L,2) == LUA_TNUMBER)
idx = lua_tointeger(L,2);
else
idx = -1;
if ((idx >= 0) && (idx <= 3))
vec->data[idx] = luaL_checknumber(L,3);
return 0;
}
static const luaL_Reg vec4meta[] =
{
{ "__index" , vec4meta___index },
{ "__newindex" , vec4meta___newindex },
{ NULL , NULL }
};
int luaopen_vec4(lua_State *L) /* rename as appropriate */
{
luaL_newmetatable(L,MY_VEC4_TYPE);
#if LUA_VERSION_NUM == 501
/* Lua 5.1 */
luaL_register(L,NULL,vec4meta);
#else
/* Lua 5.2 or 5.3 */
luaL_setfuncs(L,vec4meta,0);
#endif
/* rest of initialization */
}
Then, when you create a new userdata, you associate the metatable you
created with it:
Vec4* vec = lua_newuserdata(L,sizeof(Vec4));
luaL_getmetatable(L,MY_VEC4_TYPE);
lua_setmetatable(L,-2);
And that's pretty much it.
-spc