// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz // http://chaosforge.org/ // // This file is part of NV Libraries. // For conditions of distribution and use, see copyright notice in nv.hh #include "nv/lua/lua_glm.hh" #include "nv/string.hh" static size_t nlua_swizzel_lookup[256]; inline bool nlua_is_swizzel( const char* str, size_t max ) { while (*str) { if (nlua_swizzel_lookup[*str] > max) return false; str++; } return true; } template < typename T, size_t k > struct nlua_vec_constructor { static inline T construct( lua_State* L, int index ) { return T(); } }; template < typename T > struct nlua_vec_constructor< T, 1 > { static inline T construct( lua_State* L, int index ) { return T( lua_tonumber( L, index ) ); } }; template < typename T > struct nlua_vec_constructor< T, 2 > { static inline T construct( lua_State* L, int index ) { if ( lua_type( L, index ) == LUA_TUSERDATA ) return nlua_to_vec( L, index ); else return T( lua_tonumber( L, index ), lua_tonumber( L, index + 1 ) ); } }; template < typename T > struct nlua_vec_constructor< T, 3 > { static inline T construct( lua_State* L, int index ) { typedef glm::detail::tvec2 vec2; if ( lua_type( L, index ) == LUA_TUSERDATA ) { if ( nlua_is_vec( L, index ) ) return nlua_to_vec( L, index ); else return T( nlua_to_vec( L, index ), lua_tonumber( L, index + 1 ) ); } else { if ( lua_type( L, index+1 ) == LUA_TUSERDATA ) return T( lua_tonumber( L, index ), nlua_to_vec( L, index+1 ) ); else return T( lua_tonumber( L, index ), lua_tonumber( L, index + 1 ), lua_tonumber( L, index + 2 ) ); } } }; template < typename T > struct nlua_vec_constructor< T, 4 > { static inline T construct( lua_State* L, int index ) { typedef glm::detail::tvec2 vec2; typedef glm::detail::tvec3 vec3; if ( lua_type( L, index ) == LUA_TUSERDATA ) { if ( nlua_is_vec( L, index ) ) return nlua_to_vec( L, index ); else { if ( nlua_is_vec( L, index ) ) return T( nlua_to_vec( L, index ), lua_tonumber( L, index + 1 ) ); else { if ( lua_type( L, index+1 ) == LUA_TUSERDATA ) return T( nlua_to_vec( L, index ), nlua_to_vec( L, index + 1 ) ); else return T( nlua_to_vec( L, index ), lua_tonumber( L, index + 1 ), lua_tonumber( L, index + 2 ) ); } } } else { if ( lua_type( L, index+1 ) == LUA_TUSERDATA ) { if ( nlua_is_vec( L, index+1 ) ) return T( lua_tonumber( L, index ), nlua_to_vec( L, index+1 ) ); else return T( lua_tonumber( L, index ), nlua_to_vec( L, index+1 ), lua_tonumber( L, index + 2 ) ); } else { if ( lua_type( L, index+2 ) == LUA_TUSERDATA ) return T( lua_tonumber( L, index ), lua_tonumber( L, index + 1 ), nlua_to_vec( L, index+2 ) ); else return T( lua_tonumber( L, index ), lua_tonumber( L, index + 1 ), lua_tonumber( L, index + 2 ), lua_tonumber( L, index + 3 ) ); } } } }; template< typename T > int nlua_vec_new( lua_State* L ) { nlua_push_vec( L, nlua_vec_constructor::construct( L, 1 ) ); return 1; } template< typename T > int nlua_vec_call( lua_State* L ) { nlua_push_vec( L, nlua_vec_constructor::construct( L, 2 ) ); return 1; } template< typename T > static int nlua_vec_unm( lua_State* L ) { nlua_push_vec( L, -nlua_to_vec( L, 1 ) ); return 1; } template< typename T > int nlua_vec_add( lua_State* L ) { if ( lua_type( L, 1 ) == LUA_TNUMBER ) nlua_push_vec( L, (T::value_type)(lua_tonumber( L, 1 )) + nlua_to_vec( L, 2 ) ); else if ( lua_type( L, 2 ) == LUA_TNUMBER ) nlua_push_vec( L, nlua_to_vec( L, 1 ) + (T::value_type)(lua_tonumber( L, 2 )) ); else nlua_push_vec( L, nlua_to_vec( L, 1 ) + nlua_to_vec( L, 2 ) ); return 1; } template< typename T > int nlua_vec_sub( lua_State* L ) { if ( lua_type( L, 1 ) == LUA_TNUMBER ) nlua_push_vec( L, (T::value_type)(lua_tonumber( L, 1 )) - nlua_to_vec( L, 2 ) ); else if ( lua_type( L, 2 ) == LUA_TNUMBER ) nlua_push_vec( L, nlua_to_vec( L, 1 ) - (T::value_type)(lua_tonumber( L, 2 )) ); else nlua_push_vec( L, nlua_to_vec( L, 1 ) - nlua_to_vec( L, 2 ) ); return 1; } template< typename T > int nlua_vec_mul( lua_State* L ) { if ( lua_type( L, 1 ) == LUA_TNUMBER ) nlua_push_vec( L, (T::value_type)(lua_tonumber( L, 1 )) * nlua_to_vec( L, 2 ) ); else if ( lua_type( L, 2 ) == LUA_TNUMBER ) nlua_push_vec( L, nlua_to_vec( L, 1 ) * (T::value_type)(lua_tonumber( L, 2 )) ); else nlua_push_vec( L, nlua_to_vec( L, 1 ) * nlua_to_vec( L, 2 ) ); return 1; } template< typename T > int nlua_vec_div( lua_State* L ) { if ( lua_type( L, 1 ) == LUA_TNUMBER ) nlua_push_vec( L, (T::value_type)(lua_tonumber( L, 1 )) / nlua_to_vec( L, 2 ) ); else if ( lua_type( L, 2 ) == LUA_TNUMBER ) nlua_push_vec( L, nlua_to_vec( L, 1 ) / (T::value_type)(lua_tonumber( L, 2 )) ); else nlua_push_vec( L, nlua_to_vec( L, 1 ) / nlua_to_vec( L, 2 ) ); return 1; } template< typename T > int nlua_vec_eq( lua_State* L ) { lua_pushboolean( L, nlua_to_vec( L, 1 ) == nlua_to_vec( L, 2 ) ); return 1; } template< typename T > int nlua_vec_get( lua_State* L ) { T v = nlua_to_vec( L, 1 ); for ( size_t i = 0; i < v.length(); ++i ) { lua_pushnumber( L, v[i] ); } return v.length(); } template< typename T > int nlua_vec_index( lua_State* L ) { T* v = nlua_to_pvec( L, 1 ); size_t len = 0; size_t vlen = v->length(); const char * key = lua_tolstring( L, 2, &len ); size_t idx = 255; if( len == 1 ) { idx = nlua_swizzel_lookup[ key[ 0 ] ]; if ( idx < vlen ) { lua_pushnumber( L, (*v)[idx] ); return 1; } } else if ( len < 4 && nlua_is_swizzel(key,vlen-1) ) { switch (len) { case 2 : nlua_push_vec( L, glm::detail::tvec2( (*v)[nlua_swizzel_lookup[key[0]]], (*v)[nlua_swizzel_lookup[key[1]]] ) ); return 1; case 3 : nlua_push_vec( L, glm::detail::tvec3( (*v)[nlua_swizzel_lookup[key[0]]], (*v)[nlua_swizzel_lookup[key[1]]], (*v)[nlua_swizzel_lookup[key[2]]] ) ); return 1; case 4 : nlua_push_vec( L, glm::detail::tvec4( (*v)[nlua_swizzel_lookup[key[0]]], (*v)[nlua_swizzel_lookup[key[1]]], (*v)[nlua_swizzel_lookup[key[2]]], (*v)[nlua_swizzel_lookup[key[3]]] ) ); return 1; default: break; } } lua_getmetatable( L, 1 ); lua_getfield( L, -1, "__base" ); lua_pushvalue( L, 2 ); lua_rawget( L, -2 ); return 1; } template< typename T > int nlua_vec_newindex( lua_State* L ) { typedef glm::detail::tvec2 vec2; typedef glm::detail::tvec3 vec3; typedef glm::detail::tvec4 vec4; T* v = nlua_to_pvec( L, 1 ); size_t len = 0; size_t vlen = v->length(); const char * key = lua_tolstring( L, 2, &len ); size_t idx = 255; if( len == 1 ) { idx = nlua_swizzel_lookup[ key[ 0 ] ]; if ( idx < vlen ) { (*v)[idx] = (T::value_type)luaL_checknumber( L, 3 ); return 0; } } else if ( len < 4 && nlua_is_swizzel(key,vlen-1) ) { switch (len) { case 2 : { vec2 v2 = nlua_to_vec(L,3); for (size_t i = 0; i(L,3); for (size_t i = 0; i(L,3); for (size_t i = 0; i static int nlua_vec_tostring( lua_State* L ) { T v = nlua_to_vec( L, 1 ); std::string s = "("; for ( size_t i = 0; i < v.length(); ++i ) { if (i > 0) s += ","; s += nv::to_string(v[i]); } s+=")"; lua_pushstring( L, s.c_str() ); return 1; } template< typename T > int luaopen_vec( lua_State * L ) { static const struct luaL_Reg nlua_vec_f [] = { { "new", nlua_vec_new }, { "get", nlua_vec_get }, {NULL, NULL} }; static const struct luaL_Reg nlua_vec_fm [] = { { "__call", nlua_vec_call }, {NULL, NULL} }; static const struct luaL_Reg nlua_vec_m [] = { { "__add", nlua_vec_add }, { "__sub", nlua_vec_sub }, { "__unm", nlua_vec_unm }, { "__mul", nlua_vec_mul }, { "__div", nlua_vec_div }, { "__eq", nlua_vec_eq }, { "__index", nlua_vec_index }, { "__newindex", nlua_vec_newindex }, { "__tostring", nlua_vec_tostring }, {NULL, NULL} }; luaL_newmetatable( L, nlua_metatable_name() ); luaL_setfuncs( L, nlua_vec_m, 0 ); luaL_newlib(L, nlua_vec_f); lua_pushvalue(L, -1); lua_setfield(L, -3, "__base" ); lua_replace(L, -2); lua_newtable( L ); luaL_setfuncs( L, nlua_vec_fm, 0 ); lua_setmetatable( L, -2 ); return 1; } void nlua_register_glm( lua_State* L ) { for (size_t i = 0; i < 256; ++i ) nlua_swizzel_lookup[i] = 255; nlua_swizzel_lookup['x'] = 0; nlua_swizzel_lookup['r'] = 0; nlua_swizzel_lookup['s'] = 0; nlua_swizzel_lookup['0'] = 0; nlua_swizzel_lookup['y'] = 1; nlua_swizzel_lookup['g'] = 1; nlua_swizzel_lookup['t'] = 0; nlua_swizzel_lookup['1'] = 1; nlua_swizzel_lookup['z'] = 2; nlua_swizzel_lookup['b'] = 2; nlua_swizzel_lookup['u'] = 0; nlua_swizzel_lookup['2'] = 2; nlua_swizzel_lookup['w'] = 3; nlua_swizzel_lookup['a'] = 3; nlua_swizzel_lookup['v'] = 0; nlua_swizzel_lookup['3'] = 3; int stack = lua_gettop( L ); luaL_requiref(L, "ivec2", luaopen_vec, 1); luaL_requiref(L, "ivec3", luaopen_vec, 1); luaL_requiref(L, "ivec4", luaopen_vec, 1); luaL_requiref(L, "vec2", luaopen_vec, 1); luaL_requiref(L, "vec3", luaopen_vec, 1); luaL_requiref(L, "vec4", luaopen_vec, 1); lua_settop( L, stack ); }