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

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