source: trunk/src/lua/lua_glm.cc @ 74

Last change on this file since 74 was 74, checked in by epyon, 12 years ago
  • lua::state - removed notion of global state
  • lua_glm - fixed stack pollution at registration
  • lualib_test - made use of lua::state
File size: 10.1 KB
Line 
1// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
2// http://chaosforge.org/
3//
4// This file is part of NV Libraries.
5// For conditions of distribution and use, see copyright notice in nv.hh
6
7#include "nv/lua/lua_glm.hh"
8#include "nv/types.hh"
9#include "nv/string.hh"
10#include <new>
11
12static size_t nlua_swizzel_lookup[256];
13
14inline bool nlua_is_swizzel( const char* str, size_t max )
15{
16        while (*str)
17        {
18                if (nlua_swizzel_lookup[*str] > max) return false;
19                str++;
20        }
21        return true;
22}
23
24template < typename T, size_t k >
25struct nlua_vec_constructor {
26        static inline T construct( lua_State* L, int index ) {
27                return T();
28        }
29};
30
31template < typename T > struct nlua_vec_constructor< T, 1 > {
32        static inline T construct( lua_State* L, int index ) {
33                return T( lua_tonumber( L, index ) );
34        }
35};
36
37template < typename T > struct nlua_vec_constructor< T, 2 > {
38        static inline T construct( lua_State* L, int index ) {
39                if ( lua_type( L, index ) == LUA_TUSERDATA )
40                        return nlua_to_vec<T>( L, index );
41                else
42                        return T( lua_tonumber( L, index ), lua_tonumber( L, index + 1 ) );
43        }
44};
45
46template < typename T > struct nlua_vec_constructor< T, 3 > {
47        static inline T construct( lua_State* L, int index ) {
48                typedef glm::detail::tvec2<T::value_type> vec2;
49                if ( lua_type( L, index ) == LUA_TUSERDATA )
50                {
51                        if ( nlua_is_vec<T>( L, index ) )
52                                return nlua_to_vec<T>( L, index );
53                        else
54                                return T( nlua_to_vec<vec2>( L, index ), lua_tonumber( L, index + 1 ) );
55                }
56                else
57                {
58                        if ( lua_type( L, index+1 ) == LUA_TUSERDATA )
59                                return T( lua_tonumber( L, index ), nlua_to_vec<vec2>( L, index+1 ) );
60                        else
61                                return T( lua_tonumber( L, index ), lua_tonumber( L, index + 1 ), lua_tonumber( L, index + 2 ) );
62                }
63        }
64};
65
66template < typename T > struct nlua_vec_constructor< T, 4 > {
67        static inline T construct( lua_State* L, int index ) {
68                typedef glm::detail::tvec2<T::value_type> vec2;
69                typedef glm::detail::tvec3<T::value_type> vec3;
70                if ( lua_type( L, index ) == LUA_TUSERDATA )
71                {
72                        if ( nlua_is_vec<T>( L, index ) )
73                                return nlua_to_vec<T>( L, index );
74                        else
75                        {
76                                if ( nlua_is_vec<vec3>( L, index ) )
77                                        return T( nlua_to_vec<vec3>( L, index ), lua_tonumber( L, index + 1 ) );
78                                else
79                                {
80                                        if ( lua_type( L, index+1 ) == LUA_TUSERDATA )
81                                                return T( nlua_to_vec<vec2>( L, index ), nlua_to_vec<vec2>( L, index + 1 ) );
82                                        else
83                                                return T( nlua_to_vec<vec2>( L, index ), lua_tonumber( L, index + 1 ), lua_tonumber( L, index + 2 ) );
84                                }
85                        }
86                }
87                else
88                {
89                        if ( lua_type( L, index+1 ) == LUA_TUSERDATA )
90                        {
91                                if ( nlua_is_vec<vec3>( L, index+1 ) )
92                                        return T( lua_tonumber( L, index ), nlua_to_vec<vec3>( L, index+1 ) );
93                                else
94                                        return T( lua_tonumber( L, index ), nlua_to_vec<vec2>( L, index+1 ), lua_tonumber( L, index + 2 ) );
95                        }
96                        else
97                        {
98                                if ( lua_type( L, index+2 ) == LUA_TUSERDATA )
99                                        return T( lua_tonumber( L, index ), lua_tonumber( L, index + 1 ), nlua_to_vec<vec2>( L, index+2 ) );
100                                else
101                                        return T( lua_tonumber( L, index ), lua_tonumber( L, index + 1 ), lua_tonumber( L, index + 2 ), lua_tonumber( L, index + 3 ) );
102                        }
103                }
104        }
105};
106
107template< typename T >
108int nlua_vec_new( lua_State* L )
109{
110        nlua_push_vec( L, nlua_vec_constructor<T,sizeof( T ) / sizeof( T::value_type )>::construct( L, 1 ) );
111        return 1;
112}
113
114template< typename T >
115int nlua_vec_call( lua_State* L )
116{
117        nlua_push_vec( L, nlua_vec_constructor<T,sizeof( T ) / sizeof( T::value_type )>::construct( L, 2 ) );
118        return 1;
119}
120
121template< typename T >
122static int nlua_vec_unm( lua_State* L )
123{
124        nlua_push_vec<T>( L, -nlua_to_vec<T>( L, 1 ) );
125        return 1;
126}
127
128template< typename T >
129int nlua_vec_add( lua_State* L )
130{
131        if ( lua_type( L, 1 ) == LUA_TNUMBER )
132                nlua_push_vec<T>( L, (T::value_type)(lua_tonumber( L, 1 )) + nlua_to_vec<T>( L, 2 ) );
133        else
134                if ( lua_type( L, 2 ) == LUA_TNUMBER )
135                        nlua_push_vec<T>( L, nlua_to_vec<T>( L, 1 ) + (T::value_type)(lua_tonumber( L, 2 )) );
136                else
137                        nlua_push_vec<T>( L, nlua_to_vec<T>( L, 1 ) + nlua_to_vec<T>( L, 2 ) );
138        return 1;
139}
140
141template< typename T >
142int nlua_vec_sub( lua_State* L )
143{
144        if ( lua_type( L, 1 ) == LUA_TNUMBER )
145                nlua_push_vec<T>( L, (T::value_type)(lua_tonumber( L, 1 )) - nlua_to_vec<T>( L, 2 ) );
146        else
147                if ( lua_type( L, 2 ) == LUA_TNUMBER )
148                        nlua_push_vec<T>( L, nlua_to_vec<T>( L, 1 ) - (T::value_type)(lua_tonumber( L, 2 )) );
149                else
150                        nlua_push_vec<T>( L, nlua_to_vec<T>( L, 1 ) - nlua_to_vec<T>( L, 2 ) );
151        return 1;
152}
153
154template< typename T >
155int nlua_vec_mul( lua_State* L )
156{
157        if ( lua_type( L, 1 ) == LUA_TNUMBER )
158                nlua_push_vec<T>( L, (T::value_type)(lua_tonumber( L, 1 )) * nlua_to_vec<T>( L, 2 ) );
159        else
160                if ( lua_type( L, 2 ) == LUA_TNUMBER )
161                        nlua_push_vec<T>( L, nlua_to_vec<T>( L, 1 ) * (T::value_type)(lua_tonumber( L, 2 )) );
162                else
163                        nlua_push_vec<T>( L, nlua_to_vec<T>( L, 1 ) * nlua_to_vec<T>( L, 2 ) );
164        return 1;
165}
166
167template< typename T >
168int nlua_vec_div( lua_State* L )
169{
170        if ( lua_type( L, 1 ) == LUA_TNUMBER )
171                nlua_push_vec<T>( L, (T::value_type)(lua_tonumber( L, 1 )) / nlua_to_vec<T>( L, 2 ) );
172        else
173                if ( lua_type( L, 2 ) == LUA_TNUMBER )
174                        nlua_push_vec<T>( L, nlua_to_vec<T>( L, 1 ) / (T::value_type)(lua_tonumber( L, 2 )) );
175                else
176                        nlua_push_vec<T>( L, nlua_to_vec<T>( L, 1 ) / nlua_to_vec<T>( L, 2 ) );
177        return 1;
178}
179
180template< typename T >
181int nlua_vec_eq( lua_State* L )
182{
183        lua_pushboolean( L, nlua_to_vec<T>( L, 1 ) == nlua_to_vec<T>( L, 2 ) );
184        return 1;
185}
186
187template< typename T >
188int nlua_vec_get( lua_State* L )
189{
190        T v = nlua_to_vec<T>( L, 1 );
191        for ( size_t i = 0; i < v.length(); ++i )
192        {
193                lua_pushnumber( L, v[i] );
194        }
195        return v.length();
196}
197
198template< typename T >
199int nlua_vec_index( lua_State* L )
200{
201        T* v = nlua_to_pvec<T>( L, 1 );
202        size_t len  = 0;
203        size_t vlen = v->length();
204        const char * key = lua_tolstring( L, 2, &len );
205        size_t idx = 255;
206
207        if( len == 1 )
208        {
209                idx = nlua_swizzel_lookup[ key[ 0 ] ];
210                if ( idx < vlen )
211                {
212                        lua_pushnumber( L, (*v)[idx] );
213                        return 1;
214                }
215        }
216        else if ( len < 4 && nlua_is_swizzel(key,vlen-1) )
217        {
218                switch (len) {
219                case 2 : nlua_push_vec( L, glm::detail::tvec2<T::value_type>( (*v)[nlua_swizzel_lookup[key[0]]], (*v)[nlua_swizzel_lookup[key[1]]] ) ); return 1;
220                case 3 : nlua_push_vec( L, glm::detail::tvec3<T::value_type>( (*v)[nlua_swizzel_lookup[key[0]]], (*v)[nlua_swizzel_lookup[key[1]]], (*v)[nlua_swizzel_lookup[key[2]]] ) ); return 1;
221                case 4 : nlua_push_vec( L, glm::detail::tvec4<T::value_type>( (*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;
222                default: break;
223                }
224        }
225
226        lua_getglobal( L, nv::get_type_name<T>() );
227        lua_pushvalue( L, -2 );
228        lua_rawget( L, -2 );
229
230        return 1;
231}
232
233template< typename T >
234int nlua_vec_newindex( lua_State* L )
235{
236        typedef glm::detail::tvec2<T::value_type> vec2;
237        typedef glm::detail::tvec3<T::value_type> vec3;
238        typedef glm::detail::tvec4<T::value_type> vec4;
239
240        T* v = nlua_to_pvec<T>( L, 1 );
241        size_t len  = 0;
242        size_t vlen = v->length();
243        const char * key = lua_tolstring( L, 2, &len );
244        size_t idx = 255;
245        if( len == 1 )
246        {
247                idx = nlua_swizzel_lookup[ key[ 0 ] ];
248                if ( idx < vlen )
249                {
250                        (*v)[idx] = (T::value_type)luaL_checknumber( L, 3 );
251                        return 0;
252                }
253        }
254        else if ( len < 4 && nlua_is_swizzel(key,vlen-1) )
255        {
256                switch (len) {
257                case 2 : { vec2 v2 = nlua_to_vec<vec2>(L,3); for (size_t i = 0; i<len; ++i) (*v)[nlua_swizzel_lookup[key[i]]] = v2[i]; } return 0;
258                case 3 : { vec3 v3 = nlua_to_vec<vec3>(L,3); for (size_t i = 0; i<len; ++i) (*v)[nlua_swizzel_lookup[key[i]]] = v3[i]; } return 0;
259                case 4 : { vec4 v4 = nlua_to_vec<vec4>(L,3); for (size_t i = 0; i<len; ++i) (*v)[nlua_swizzel_lookup[key[i]]] = v4[i]; } return 0;
260                default: break;
261                }
262        }
263        return 0;
264}
265
266template< typename T >
267static int nlua_vec_tostring( lua_State* L )
268{
269        T v = nlua_to_vec<T>( L, 1 );
270        std::string s = "(";
271        for ( size_t i = 0; i < v.length(); ++i )
272        {
273                if (i > 0) s += ",";
274                s += nv::to_string(v[i]);
275        }
276        s+=")";
277        lua_pushstring( L, s.c_str() );
278        return 1;
279}
280
281template< typename T >
282int luaopen_vec( lua_State * L )
283{
284        static const struct luaL_Reg nlua_vec_f [] = {
285                { "new",            nlua_vec_new<T> },
286                { "get",            nlua_vec_get<T> },
287                {NULL, NULL}
288        };
289
290        static const struct luaL_Reg nlua_vec_fm [] = {
291                { "__call",         nlua_vec_call<T> },
292                {NULL, NULL}
293        };
294
295        static const struct luaL_Reg nlua_vec_m [] = {
296                { "__add",      nlua_vec_add<T> },
297                { "__sub",      nlua_vec_sub<T> },
298                { "__unm",      nlua_vec_unm<T> },
299                { "__mul",      nlua_vec_mul<T> },
300                { "__div",      nlua_vec_div<T> },
301                { "__eq",       nlua_vec_eq<T> },
302                { "__index",    nlua_vec_index<T> },
303                { "__newindex", nlua_vec_newindex<T> },
304                { "__tostring", nlua_vec_tostring<T> },
305                {NULL, NULL}
306        };
307
308        luaL_newmetatable( L, nv::get_type_name<T>() );
309        luaL_setfuncs( L, nlua_vec_m, 0 );
310        lua_pop(L,1);
311        luaL_newlib(L, nlua_vec_f);
312        lua_newtable( L );
313        luaL_setfuncs( L, nlua_vec_fm, 0 );
314        lua_setmetatable( L, -2 );
315        return 1;
316}
317
318void nlua_register_glm( lua_State* L )
319{
320        for (size_t i = 0; i < 256; ++i ) nlua_swizzel_lookup[i] = 255;
321        nlua_swizzel_lookup['x'] = 0;
322        nlua_swizzel_lookup['r'] = 0;
323        nlua_swizzel_lookup['s'] = 0;
324        nlua_swizzel_lookup['0'] = 0;
325        nlua_swizzel_lookup['y'] = 1;
326        nlua_swizzel_lookup['g'] = 1;
327        nlua_swizzel_lookup['t'] = 0;
328        nlua_swizzel_lookup['1'] = 1;
329        nlua_swizzel_lookup['z'] = 2;
330        nlua_swizzel_lookup['b'] = 2;
331        nlua_swizzel_lookup['u'] = 0;
332        nlua_swizzel_lookup['2'] = 2;
333        nlua_swizzel_lookup['w'] = 3;
334        nlua_swizzel_lookup['a'] = 3;
335        nlua_swizzel_lookup['v'] = 0;
336        nlua_swizzel_lookup['3'] = 3;
337        int stack = lua_gettop( L );
338        luaL_requiref(L, "ivec2", luaopen_vec<glm::ivec2>, 1);
339        luaL_requiref(L, "ivec3", luaopen_vec<glm::ivec3>, 1);
340        luaL_requiref(L, "ivec4", luaopen_vec<glm::ivec4>, 1);
341        luaL_requiref(L, "vec2", luaopen_vec<glm::vec2>, 1);
342        luaL_requiref(L, "vec3", luaopen_vec<glm::vec3>, 1);
343        luaL_requiref(L, "vec4", luaopen_vec<glm::vec4>, 1);
344        lua_settop( L, stack );
345}
346
Note: See TracBrowser for help on using the repository browser.