// Copyright (C) 2012-2014 ChaosForge Ltd // 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/lua/lua_raw.hh" #include "nv/core/string.hh" #include "nv/core/random.hh" static size_t nlua_swizzel_lookup[256]; using nv::lua::detail::is_vec; using nv::lua::detail::to_vec; using nv::lua::detail::to_pvec; using nv::lua::detail::push_vec; inline bool nlua_is_swizzel( const unsigned 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 unit() { return T(); } static inline T construct( lua_State*, int ) { return T(); } }; template < typename T > struct nlua_vec_constructor< T, 1 > { static inline T unit() { return 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 unit() { return T( 1, 1 ); } static inline T construct( lua_State* L, int index ) { if ( lua_type( L, index ) == LUA_TUSERDATA ) return 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 unit() { return T( 1, 1, 1 ); } static inline T construct( lua_State* L, int index ) { typedef glm::detail::tvec2 vec2; if ( lua_type( L, index ) == LUA_TUSERDATA ) { if ( is_vec( L, index ) ) return to_vec( L, index ); else return T( to_vec( L, index ), lua_tonumber( L, index + 1 ) ); } else { if ( lua_type( L, index+1 ) == LUA_TUSERDATA ) return T( lua_tonumber( L, index ), 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 unit() { return T( 1, 1, 1, 1 ); } 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 ( is_vec( L, index ) ) return to_vec( L, index ); else { if ( is_vec( L, index ) ) return T( to_vec( L, index ), lua_tonumber( L, index + 1 ) ); else { if ( lua_type( L, index+1 ) == LUA_TUSERDATA ) return T( to_vec( L, index ), to_vec( L, index + 1 ) ); else return T( to_vec( L, index ), lua_tonumber( L, index + 1 ), lua_tonumber( L, index + 2 ) ); } } } else { if ( lua_type( L, index+1 ) == LUA_TUSERDATA ) { if ( is_vec( L, index+1 ) ) return T( lua_tonumber( L, index ), to_vec( L, index+1 ) ); else return T( lua_tonumber( L, index ), 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 ), 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 ) { push_vec( L, nlua_vec_constructor::construct( L, 1 ) ); return 1; } template< typename T > int nlua_vec_random( lua_State* L ) { push_vec( L, nv::random::get().range( to_vec( L, 1 ), to_vec( L, 2 ) ) ); return 1; } template< typename T > int nlua_vec_clone( lua_State* L ) { push_vec( L, to_vec( L, 1 ) ); return 1; } template< typename T > int nlua_vec_call( lua_State* L ) { push_vec( L, nlua_vec_constructor::construct( L, 2 ) ); return 1; } template< typename T > static int nlua_vec_unm( lua_State* L ) { push_vec( L, -to_vec( L, 1 ) ); return 1; } template< typename T > int nlua_vec_add( lua_State* L ) { if ( lua_type( L, 1 ) == LUA_TNUMBER ) push_vec( L, (typename T::value_type)(lua_tonumber( L, 1 )) + to_vec( L, 2 ) ); else if ( lua_type( L, 2 ) == LUA_TNUMBER ) push_vec( L, to_vec( L, 1 ) + (typename T::value_type)(lua_tonumber( L, 2 )) ); else push_vec( L, to_vec( L, 1 ) + to_vec( L, 2 ) ); return 1; } template< typename T > int nlua_vec_sub( lua_State* L ) { if ( lua_type( L, 1 ) == LUA_TNUMBER ) push_vec( L, (typename T::value_type)(lua_tonumber( L, 1 )) - to_vec( L, 2 ) ); else if ( lua_type( L, 2 ) == LUA_TNUMBER ) push_vec( L, to_vec( L, 1 ) - (typename T::value_type)(lua_tonumber( L, 2 )) ); else push_vec( L, to_vec( L, 1 ) - to_vec( L, 2 ) ); return 1; } template< typename T > int nlua_vec_mul( lua_State* L ) { if ( lua_type( L, 1 ) == LUA_TNUMBER ) push_vec( L, (typename T::value_type)(lua_tonumber( L, 1 )) * to_vec( L, 2 ) ); else if ( lua_type( L, 2 ) == LUA_TNUMBER ) push_vec( L, to_vec( L, 1 ) * (typename T::value_type)(lua_tonumber( L, 2 )) ); else push_vec( L, to_vec( L, 1 ) * to_vec( L, 2 ) ); return 1; } template< typename T > int nlua_vec_div( lua_State* L ) { if ( lua_type( L, 1 ) == LUA_TNUMBER ) push_vec( L, (typename T::value_type)(lua_tonumber( L, 1 )) / to_vec( L, 2 ) ); else if ( lua_type( L, 2 ) == LUA_TNUMBER ) push_vec( L, to_vec( L, 1 ) / (typename T::value_type)(lua_tonumber( L, 2 )) ); else push_vec( L, to_vec( L, 1 ) / to_vec( L, 2 ) ); return 1; } template< typename T > int nlua_vec_eq( lua_State* L ) { lua_pushboolean( L, to_vec( L, 1 ) == to_vec( L, 2 ) ); return 1; } template< typename T > int nlua_vec_get( lua_State* L ) { T v = 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 = to_pvec( L, 1 ); size_t len = 0; size_t vlen = v->length(); const unsigned char * key = (const unsigned char *)( 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 : push_vec( L, glm::detail::tvec2( (*v)[nlua_swizzel_lookup[key[0]]], (*v)[nlua_swizzel_lookup[key[1]]] ) ); return 1; case 3 : 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 : 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; } } luaL_getmetafield( L, 1, "__functions" ); 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 = to_pvec( L, 1 ); size_t len = 0; size_t vlen = v->length(); const unsigned char * key = (const unsigned char *)( lua_tolstring( L, 2, &len ) ); size_t idx = 255; if( len == 1 ) { idx = nlua_swizzel_lookup[ key[ 0 ] ]; if ( idx < vlen ) { (*v)[idx] = (typename 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 = 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 = 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_sf [] = { { "new", nlua_vec_new }, { "random", nlua_vec_random }, {NULL, NULL} }; static const struct luaL_Reg nlua_vec_f [] = { { "clone", nlua_vec_clone }, { "get", nlua_vec_get }, { "tostring", nlua_vec_tostring }, {NULL, NULL} }; static const struct luaL_Reg nlua_vec_sm [] = { { "__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, nv::lua::detail::glm_metatable_name() ); nlua_register( L, nlua_vec_m, -1 ); lua_createtable( L, 0, 0 ); nlua_register( L, nlua_vec_f, -1 ); lua_setfield(L, -2, "__functions" ); lua_pop( L, 1 ); lua_createtable( L, 0, 0 ); nlua_register( L, nlua_vec_sf, -1 ); lua_createtable( L, 0, 0 ); nlua_register( L, nlua_vec_sm, -1 ); lua_setmetatable( L, -2 ); nv::lua::detail::push_vec( L, T() ); lua_setfield( L, -2, "ZERO" ); nv::lua::detail::push_vec( L, nlua_vec_constructor::unit() ); lua_setfield( L, -2, "UNIT" ); return 1; } void nv::lua::register_glm( lua_State* L ) { for (size_t i = 0; i < 256; ++i ) nlua_swizzel_lookup[i] = 255; using nv::char8; nlua_swizzel_lookup[char8( 'x' )] = 0; nlua_swizzel_lookup[char8( 'r' )] = 0; nlua_swizzel_lookup[char8( 's' )] = 0; nlua_swizzel_lookup[char8( '0' )] = 0; nlua_swizzel_lookup[char8( 'y' )] = 1; nlua_swizzel_lookup[char8( 'g' )] = 1; nlua_swizzel_lookup[char8( 't' )] = 0; nlua_swizzel_lookup[char8( '1' )] = 1; nlua_swizzel_lookup[char8( 'z' )] = 2; nlua_swizzel_lookup[char8( 'b' )] = 2; nlua_swizzel_lookup[char8( 'u' )] = 0; nlua_swizzel_lookup[char8( '2' )] = 2; nlua_swizzel_lookup[char8( 'w' )] = 3; nlua_swizzel_lookup[char8( 'a' )] = 3; nlua_swizzel_lookup[char8( 'v' )] = 0; nlua_swizzel_lookup[char8( '3' )] = 3; int stack = lua_gettop( L ); luaL_requiref(L, "coord", luaopen_vec, 1); 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 ); }