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

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