source: trunk/src/lua/lua_area.cc @ 368

Last change on this file since 368 was 368, checked in by epyon, 10 years ago
  • massive restructuring
  • detail::data_base class for container/reference class base
File size: 11.3 KB
RevLine 
[319]1// Copyright (C) 2012-2014 ChaosForge Ltd
[176]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_area.hh"
8
9#include "nv/lua/lua_raw.hh"
[368]10#include "nv/stl/string.hh"
[319]11#include "nv/core/random.hh"
[176]12
[207]13const char* nv::lua::detail::AREA_METATABLE = "area";
[176]14
[207]15using nv::lua::detail::is_coord;
16using nv::lua::detail::to_coord;
17using nv::lua::detail::to_pcoord;
18using nv::lua::detail::push_coord;
[176]19
[207]20using nv::lua::detail::is_area;
21using nv::lua::detail::to_area;
22using nv::lua::detail::to_parea;
23using nv::lua::detail::push_area;
[176]24
[198]25static void nlua_area_construct( lua_State* L, int sidx )
[176]26{
[207]27        if ( is_coord( L, sidx ) )
[176]28        {
[207]29                if ( is_coord( L, sidx+1 ) )
[176]30                {
[207]31                        nv::rectangle a( to_coord( L, sidx ), to_coord( L, sidx+1 ) );
32                        push_area( L, a );
[176]33                        return;
34                }
35                // TODO: coord, width, height
36        }
37
38        nv::rectangle a(
39                nv::ivec2( lua_tointeger( L, sidx   ), lua_tointeger( L, sidx+1 ) ),
40                nv::ivec2( lua_tointeger( L, sidx+2 ), lua_tointeger( L, sidx+3 ) )
41                );
[207]42        push_area( L, a );
[176]43}
44
45
46static int nlua_area_new( lua_State* L )
47{
48        nlua_area_construct( L, 1 );
49        return 1;
50}
51
52static int nlua_area_call( lua_State* L )
53{
54        nlua_area_construct( L, 2 );
55        return 1;
56}
57
58static int nlua_area_eq( lua_State* L )
59{
[207]60        lua_pushboolean( L, to_area( L, 1 ) == to_area( L, 2 ) );
[176]61        return 1;
62}
63
64static int nlua_area_get( lua_State* L )
65{
[207]66        nv::rectangle r( to_area( L, 1 ) );
67        push_coord( L, r.ul );
68        push_coord( L, r.lr );
[176]69        return 2;
70}
71
72static int nlua_area_clone( lua_State* L )
73{
[207]74        push_area( L, *to_parea( L, 1 ) );
[176]75        return 1;
76}
77
78static int nlua_area_index( lua_State* L )
79{
[207]80        nv::rectangle* a = to_parea( L, 1 );
[176]81        std::size_t l;
82        const char* index = lua_tolstring( L, 2, &l );
83        if ( l == 1 && index[0] == 'a' )
84        {
[207]85                push_coord( L, a->ul );
[176]86        }
87        else if ( l == 1 && index[0] == 'b' )
88        {
[207]89                push_coord( L, a->lr );
[176]90        }
91        else
92        {
[179]93                luaL_getmetafield( L, 1, "__functions" );
[176]94                lua_pushvalue( L, 2 );
95                lua_rawget( L, -2 );
96        }
97        return 1;
98}
99
100static int nlua_area_newindex( lua_State* L )
101{
[207]102        nv::rectangle* a = to_parea( L, 1 );
[176]103        std::size_t l;
104        const char* index = lua_tolstring( L, 2, &l );
[207]105        nv::ivec2 value( to_coord( L, 3 ) );
[176]106        if ( l == 1 && index[0] == 'a' )
107        {
108                a->ul = value;
109        }
110        else if ( l == 1 && index[0] == 'b' )
111        {
112                a->lr = value;
113        }
114        return 0;
115}
116
117static int lua_area_coords_closure( lua_State* L )
118{
[207]119        nv::rectangle* a( to_parea( L, lua_upvalueindex(1) ) );
120        nv::ivec2*     c( to_pcoord( L, lua_upvalueindex(2) ) );
[176]121
122        c->x++;
123
124        if ( c->x > a->lr.x )
125        {
126                c->x = a->ul.x;
127                c->y++;
128                if (c->y > a->lr.y)
129                {
130                        lua_pushnil( L );
131                        return 1;
132                }
133        }
134
[207]135        push_coord( L, *c );
[176]136        return 1;
137}
138
139static int nlua_area_coords( lua_State* L )
140{
[207]141        nv::rectangle* a( to_parea( L, 1 ) );
[176]142        nv::ivec2      c( a->ul );
143        c.x--;
[207]144        push_coord( L, c );
[176]145        lua_pushcclosure( L, lua_area_coords_closure, 2 );
146        return 1;
147}
148
149static int nlua_area_edges_closure( lua_State* L )
150{
[207]151        nv::rectangle* a( to_parea( L, lua_upvalueindex(1) ) );
152        nv::ivec2*     c( to_pcoord( L, lua_upvalueindex(2) ) );
[176]153
154        c->x++;
155
156        if ( c->x > a->lr.x )
157        {
158                c->x = a->ul.x;
159                c->y++;
160                if (c->y > a->lr.y)
161                {
162                        lua_pushnil( L );
163                        return 1;
164                }
165        }
166        if (c->y != a->ul.y && c->y != a->lr.y && c->x == a->ul.x + 1 ) c->x = a->ul.x;
167
168
[207]169        push_coord( L, *c );
[176]170        return 1;
171}
172
173static int nlua_area_edges( lua_State* L )
174{
[207]175        nv::rectangle*   a( to_parea( L, 1 ) );
[176]176        nv::ivec2 c( a->ul );
177        c.x--;
[207]178        push_coord( L, c );
[176]179        lua_pushcclosure( L, nlua_area_edges_closure, 2 );
180        return 1;
181}
182
183static int nlua_area_corners_closure( lua_State* L )
184{
[204]185        int index = static_cast< int >( lua_tointeger( L, lua_upvalueindex(2) ) + 1 );
[176]186        lua_pushinteger( L, index );
187        lua_replace( L, lua_upvalueindex(2) ); // update
188        lua_rawgeti( L, lua_upvalueindex(1), index ); // get value
189        return 1;   
190}
191
192static int nlua_area_corners( lua_State* L )
193{
[207]194        nv::rectangle* a = to_parea( L, 1 );
[176]195
196        lua_createtable(L, 4, 0);
[207]197        push_coord( L, a->ul );
[176]198        lua_rawseti( L, -2, 1 );
[207]199        push_coord( L, a->ur() );
[176]200        lua_rawseti( L, -2, 2 );
[207]201        push_coord( L, a->ll() );
[176]202        lua_rawseti( L, -2, 3 );
[207]203        push_coord( L, a->lr );
[176]204        lua_rawseti( L, -2, 4 );
205
206        lua_pushinteger(L, 0);
207        lua_pushcclosure( L, nlua_area_corners_closure, 2 );
208        return 1;
209}
210
211static int nlua_area_shrink( lua_State* L )
212{
[207]213        nv::rectangle* a = to_parea( L, 1 );
[204]214        a->shrink( static_cast< int >( lua_tointeger( L, 2 ) ) );
[176]215        return 0;
216}
217
218static int nlua_area_shrinked( lua_State* L )
219{
[207]220        nv::rectangle* a = to_parea( L, 1 );
221        push_area( L, a->shrinked( static_cast< int >( lua_tointeger( L, 2 ) ) ) );
[176]222        return 1;
223}
224
225static int nlua_area_expand( lua_State* L )
226{
[207]227        nv::rectangle* a = to_parea( L, 1 );
[204]228        a->expand( static_cast< int >( lua_tointeger( L, 2 ) ) );
[176]229        return 0;
230}
231
232static int nlua_area_expanded( lua_State* L )
233{
[207]234        nv::rectangle* a = to_parea( L, 1 );
235        push_area( L, a->expanded( static_cast< int >( lua_tointeger( L, 2 ) ) ) );
[176]236        return 1;
237}
238
239static int nlua_area_clamp( lua_State* L )
240{
[207]241        nv::rectangle* a1 = to_parea( L, 1 );
242        nv::rectangle* a2 = to_parea( L, 2 );
[176]243        a1->clamp_to( *a2 );
244        return 0;
245}
246
247static int nlua_area_clamped( lua_State* L )
248{
[207]249        nv::rectangle  a1 = to_area( L, 1 );
250        nv::rectangle* a2 = to_parea( L, 2 );
[176]251        a1.clamp_to( *a2 );
[207]252        push_area( L, a1 );
[176]253        return 1;
254}
255
256static int nlua_area_clamp_coord( lua_State* L )
257{
[207]258        nv::rectangle* a = to_parea( L, 1 );
259        nv::ivec2*     c = to_pcoord( L, 2 );
[176]260        *c = glm::clamp( *c, a->ul, a->lr );
261        return 0;
262}
263
264static int nlua_area_clamped_coord( lua_State* L )
265{
[207]266        nv::rectangle* a = to_parea( L, 1 );
267        nv::ivec2*     c = to_pcoord( L, 2 );
268        push_coord( L, glm::clamp( *c, a->ul, a->lr ) );
[176]269        return 0;
270}
271
272static int nlua_area_fix( lua_State* L )
273{
[207]274        nv::rectangle* a = to_parea( L, 1 );
[176]275        if ( a->ul.x > a->lr.x ) a->ul.x = a->lr.x;
276        if ( a->ul.y > a->lr.y ) a->ul.y = a->lr.y;
277        return 0;
278}
279
280static int nlua_area_proper( lua_State* L )
281{
[207]282        nv::rectangle* a = to_parea( L, 1 );
[176]283        lua_pushboolean( L, a->ul.x <= a->lr.x && a->ul.y <= a->lr.y );
284        return 1;
285}
286
287static int nlua_area_dim( lua_State* L )
288{
[207]289        nv::rectangle* a = to_parea( L, 1 );
290        push_coord( L, a->ul - a->lr + nv::ivec2(1,1) );
[176]291        return 1;
292}
293
294static int nlua_area_size( lua_State* L )
295{
[207]296        nv::rectangle* a = to_parea( L, 1 );
[176]297        lua_pushinteger( L, a->get_enclosed_area() );
298        return 1;
299}
300
301static int nlua_area_contains( lua_State* L )
302{
[207]303        lua_pushboolean( L, to_parea( L, 1 )->contains( to_coord( L, 2 ) ) );
[176]304        return 1;
305}
306
307static int nlua_area_is_edge( lua_State* L )
308{
[207]309        nv::rectangle a = to_area( L, 1 );
310        nv::ivec2     c = to_coord( L, 2 );
[176]311        lua_pushboolean( L, a.contains( c ) && ( c.x == a.ul.x || c.x == a.lr.x || c.y == a.ul.y || c.y == a.lr.y ) );
312        return 1;
313}
314
315static int nlua_area_around( lua_State* L )
316{
[207]317        nv::ivec2 c = to_coord( L, 1 );
[204]318        int amount = static_cast< int >( lua_tointeger( L, 1 ) );
[176]319        nv::ivec2 shift( amount, amount );
[207]320        push_area( L, nv::rectangle( c - shift, c + shift ) );
[176]321        return 1;
322}
323
324static int nlua_area_tostring( lua_State* L )
325{
[207]326        nv::rectangle a = to_area( L, 1 );
[176]327        std::string s = "(";
328        s += nv::to_string(a.ul.x);
329        s += ",";
330        s += nv::to_string(a.ul.y);
331        s += "x";
332        s += nv::to_string(a.lr.x);
333        s += ",";
334        s += nv::to_string(a.lr.y);
335        s += ")";
336        lua_pushstring( L, s.c_str() );
337        return 1;
338}
339
340static int nlua_area_random_edge_coord( lua_State* L )
341{
[207]342        nv::rectangle area = to_area( L, 1 );
[176]343        nv::ivec2 a   = area.ul;
344        nv::ivec2 b   = area.lr;
345        nv::sint32 xs = ( b.x - a.x ) + 1;
346        nv::sint32 ys = ( b.y - a.y ) - 1;
347        nv::sint32 roll = nv::random::get().srand( 2 * xs + 2 * ys );
348        nv::ivec2 result;
349
350        if ( roll < 2 * xs )
351        {
352                result = ( roll < xs ) ? nv::ivec2( a.x + roll, a.y ) : nv::ivec2( a.x + roll - xs, b.y );
353        }
354        else
355        {
356                roll -= 2 * xs;
357                result = ( roll < ys ) ? nv::ivec2( a.x, a.y + roll + 1 ) : nv::ivec2( b.x, a.y + roll - ys + 1);
358        }
[207]359        push_coord( L, result );
[176]360        return 1;
361}
362
363static int nlua_area_random_inner_edge_coord( lua_State* L )
364{
[207]365        nv::rectangle area = to_area( L, 1 );
[176]366        nv::ivec2 a   = area.ul;
367        nv::ivec2 b   = area.lr;
368        nv::sint32 xs = ( b.x - a.x ) - 1;
369        nv::sint32 ys = ( b.y - a.y ) - 1;
370        nv::sint32 roll = nv::random::get().srand( 2 * xs + 2 * ys );
371        nv::ivec2 result;
372
373        if ( roll < 2 * xs )
374        {
375                result = ( roll < xs ) ? nv::ivec2( a.x + roll + 1, a.y ) : nv::ivec2( a.x + roll - xs + 1, b.y );
376        }
377        else
378        {
379                roll -= 2 * xs;
380                result = ( roll < ys ) ? nv::ivec2( a.x, a.y + roll + 1 ) : nv::ivec2( b.x, a.y + roll - ys + 1);
381        }
[207]382        push_coord( L, result );
[176]383        return 1;
384}
385
386static int nlua_area_random_coord( lua_State* L )
387{
[207]388        nv::rectangle area = to_area( L, 1 );
389        push_coord( L, nv::random::get().range( area.ul, area.lr ) );
[176]390        return 1;
391}
392
393static int nlua_area_random_subarea( lua_State* L )
394{
[207]395        nv::rectangle area  = to_area( L, 1 );
396        nv::ivec2     dim   = to_coord( L, 2 );
[176]397        nv::ivec2     start = nv::random::get().range( area.ul, area.lr - dim );
[207]398        push_area( L, nv::rectangle( start, start + dim ) );
[176]399        return 1;
400}
401
402
[198]403static int luaopen_area( lua_State * L )
[176]404{
[335]405        NV_LUA_STACK_ASSERT( L, 1 );
[176]406        static const struct luaL_Reg nlua_area_sf [] = {
407                { "new",            nlua_area_new },
408                { "around",         nlua_area_around },
409                {NULL, NULL}
410        };
411
412        static const struct luaL_Reg nlua_area_f [] = {
413                { "get",            nlua_area_get },
414                { "clone",          nlua_area_clone },
415
416                { "coords",         nlua_area_coords },
417                { "edges",          nlua_area_edges },
418                { "corners",        nlua_area_corners },
419
420                { "tostring",       nlua_area_tostring },
421                { "shrink",         nlua_area_shrink },
422                { "shrinked",       nlua_area_shrinked },
423                { "expand",         nlua_area_expand },
424                { "expanded",       nlua_area_expanded },
425                { "clamp",          nlua_area_clamp },
426                { "clamped",        nlua_area_clamped },
427                { "clamp_coord",    nlua_area_clamp_coord },
428                { "clamped_coord",  nlua_area_clamped_coord },
429                { "fix",            nlua_area_fix },
430                { "proper",         nlua_area_proper },
431                { "dim",            nlua_area_dim },
432                { "size",           nlua_area_size },
433                { "contains",       nlua_area_contains },
434                { "is_edge",        nlua_area_is_edge },
435
436                { "random_subarea",          nlua_area_random_subarea },
437                { "random_coord",            nlua_area_random_coord },
438                { "random_edge_coord",       nlua_area_random_edge_coord },
439                { "random_inner_edge_coord", nlua_area_random_inner_edge_coord },
440
441                {NULL, NULL}
442        };
443
444        static const struct luaL_Reg nlua_area_sm [] = {
445                { "__call",         nlua_area_call },
446                {NULL, NULL}
447        };
448
449        static const struct luaL_Reg nlua_area_m [] = {
450                { "__eq",       nlua_area_eq },
451                { "__call",     nlua_area_coords },
452                { "__index",    nlua_area_index },
453                { "__newindex", nlua_area_newindex },
454                { "__tostring", nlua_area_tostring },
455                {NULL, NULL}
456        };
457
[207]458        luaL_newmetatable( L, nv::lua::detail::AREA_METATABLE );
[176]459        nlua_register( L, nlua_area_m, -1 );
460        lua_createtable( L, 0, 0 );
461        nlua_register( L, nlua_area_f, -1 );
462        lua_setfield(L, -2, "__functions" );
463        lua_pop( L, 1 );
464
465        lua_createtable( L, 0, 0 );
466        nlua_register( L, nlua_area_sf, -1 );
467        lua_createtable( L, 0, 0 );
468        nlua_register( L, nlua_area_sm, -1 );
469        lua_setmetatable( L, -2 );
470        return 1;
471}
472
[207]473void nv::lua::register_area( lua_State* L )
[176]474{
475        int stack = lua_gettop( L );
476        luaL_requiref(L, "area", luaopen_area, 1);
477        lua_settop( L, stack );
478}
479
Note: See TracBrowser for help on using the repository browser.