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

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