This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local v = Vec4() | |
v = Vec4(1, 2, 3, 4) | |
v.wzyx = Vec4(1, 2, 3, 4) | |
v = Vec4(1.111, 2.2222, 3.333, 4.444).wzyx | |
v.w = 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> | |
#include <string.h> | |
#include "af_lua_helpers.h" | |
#include "af_math.h" | |
extern lua_State *L; | |
static const char* myClassName = "Vec4"; | |
static float& vec4IndexByChar(Vec4& v, char c) | |
{ | |
switch (c) { | |
case 'x': return v.x; | |
case 'y': return v.y; | |
case 'z': return v.z; | |
case 'w': return v.w; | |
} | |
static float dummyForSafe; | |
return dummyForSafe; | |
} | |
static int Vec4GetLength(lua_State *L) | |
{ | |
Vec4* self = (Vec4*)luaL_checkudata(L, -1, myClassName); | |
float l = length(*self); | |
lua_pushnumber(L, l); | |
return 1; | |
} | |
static int Vec4ToString(lua_State *L) | |
{ | |
char buf[64]; | |
Vec4* self = (Vec4*)luaL_checkudata(L, -1, myClassName); | |
sprintf_s(buf, sizeof(buf), "(%f, %f, %f, %f)", self->x, self->y, self->z, self->w); | |
lua_pushstring(L, buf); | |
return 1; | |
} | |
static int Vec4NewIndex(lua_State *L) | |
{ | |
DumpStack(); | |
Vec4* self = (Vec4*)luaL_checkudata(L, -3, myClassName); | |
const char* key = lua_tostring(L, -2); | |
if (!self || !key) { | |
return 0; // error | |
} | |
int srcType = lua_type(L, -1); | |
Vec4 src; | |
Vec4* srcPtr; | |
switch (srcType) { | |
default: | |
return 0; // error | |
case LUA_TNUMBER: | |
src.x = src.y = src.z = src.w = (float)lua_tonumber(L, -1); | |
break; | |
case LUA_TUSERDATA: | |
if (!(srcPtr = (Vec4*)luaL_checkudata(L, -1, myClassName))) { | |
return 0; // error | |
} | |
src = *srcPtr; | |
break; | |
} | |
char key4[4] = {'\0', '\0', '\0', '\0'}; | |
memcpy(key4, key, std::min((size_t)4, strlen(key))); | |
vec4IndexByChar(*self, key4[0]) = src.x; | |
vec4IndexByChar(*self, key4[1]) = src.y; | |
vec4IndexByChar(*self, key4[2]) = src.z; | |
vec4IndexByChar(*self, key4[3]) = src.w; | |
return 1; | |
} | |
static int Vec4Index(lua_State *L) | |
{ | |
const char* key = lua_tostring(L, -1); | |
if (!strcmp(key, "GetLength")) { | |
lua_pushcfunction(L, Vec4GetLength); | |
return 1; | |
} | |
Vec4* src = (Vec4*)luaL_checkudata(L, -2, myClassName); | |
if (!key || !src) { | |
return 0; // error | |
} | |
int keyLen = strlen(key); | |
Vec4* ret = (Vec4*)lua_newuserdata(L, sizeof(Vec4)); | |
luaL_getmetatable(L, myClassName); | |
lua_setmetatable(L, -2); | |
ret->x = keyLen < 1 ? 0 : vec4IndexByChar(*src, key[0]); | |
ret->y = keyLen < 2 ? 0 : vec4IndexByChar(*src, key[1]); | |
ret->z = keyLen < 3 ? 0 : vec4IndexByChar(*src, key[2]); | |
ret->w = keyLen < 4 ? 0 : vec4IndexByChar(*src, key[3]); | |
return 1; | |
} | |
static int Vec4New(lua_State *L) | |
{ | |
int top = lua_gettop(L); | |
Vec4 v; | |
v.x = top < 4 ? 0 : (float)lua_tonumber(L, -4); | |
v.y = top < 3 ? 0 : (float)lua_tonumber(L, -3); | |
v.z = top < 2 ? 0 : (float)lua_tonumber(L, -2); | |
v.w = top < 1 ? 0 : (float)lua_tonumber(L, -1); | |
Vec4* p = (Vec4*)lua_newuserdata(L, sizeof(Vec4)); | |
*p = v; | |
luaL_getmetatable(L, myClassName); | |
lua_setmetatable(L, -2); | |
return 1; | |
} | |
void BindVec4() | |
{ | |
int r = luaL_newmetatable(L, myClassName); | |
assert(r); | |
lua_pushstring(L, "__tostring"); | |
lua_pushcfunction(L, Vec4ToString); | |
lua_settable(L, -3); | |
lua_pushstring(L, "__index"); | |
lua_pushcfunction(L, Vec4Index); | |
lua_settable(L, -3); | |
#if 0 | |
// wrong! it's never used; __index doesn't refer itself | |
lua_pushstring(L, "GetLength"); | |
lua_pushcfunction(L, Vec4GetLength); | |
DumpStack(); | |
lua_settable(L, -3); | |
DumpStack(); | |
#endif | |
lua_pushstring(L, "__newindex"); | |
lua_pushcfunction(L, Vec4NewIndex); | |
lua_settable(L, -3); | |
lua_pop(L, 1); | |
lua_register(L, "Vec4", Vec4New); | |
} |
Vec4NewIndexで、代入する値がベクトルであってもスカラーであってもいいようにLUA_TNUMBERとLUA_TUSERDATAに分岐しています。
Luaからベクトルの長さを得るGetLengthというメソッドがあります。BindVec4関数内でバインドしようとしているのはだめな例です。なぜならBindVec4で作っているのはメタテーブルであって、__で始まるメタメソッドは定義出来ても任意のメソッドは定義できません。前回のMyClassはメタテーブルの__indexにメタテーブル自身を参照させていたのでメタテーブル内に任意のメソッドを定義することができましたが、今回は__indexをswizzlingのためのC関数であるVec4Indexにつかってしまっています。
ではどうするのかというと、Vec4Index関数の中で"GetLength"を参照しようとしたかを判定してVec4GetLength関数を返しています。これでLuaからGetLengthが使えます。
テストはこれでいいかもしれませんが、実際に使えるものにするにはもうひと工夫する必要がありそうです。
No comments:
Post a Comment