source: trunk/src/lua/lua_map_tile.cc @ 374

Last change on this file since 374 was 374, checked in by epyon, 10 years ago
  • MASSIVE commit
  • common.hh - size_t, ptrdiff_t, nv:: namespace, NV_ALIGN_OF and basic template tools
  • STL - algorithm.hh, iterator.hh, limits.hh, numeric.hh and type_info.hh
  • STL - updates to memory, array and string
File size: 10.9 KB
RevLine 
[319]1// Copyright (C) 2012-2014 ChaosForge Ltd
[221]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_map_tile.hh"
8
9#include "nv/lua/lua_map_area.hh"
[368]10#include "nv/stl/flags.hh"
[374]11#include "nv/stl/numeric.hh"
12#include "nv/stl/algorithm.hh"
[319]13#include "nv/core/random.hh"
[221]14#include "nv/lua/lua_area.hh"
15#include "nv/lua/lua_glm.hh"
16#include "nv/lua/lua_values.hh"
17#include "nv/lua/lua_raw.hh"
18
19static const char* NLUA_MAP_TILE_METATABLE = "map_tile";
20
21struct map_tile
22{
[369]23        nv::uint8*  data;
24        nv::uchar8* ascii;
25        nv::uint16  size_x;
26        nv::uint16  size_y;
[221]27};
28
29
[323]30// static bool nlua_is_map_tile( lua_State* L, int index )
31// {
32//      return luaL_testudata( L, index, NLUA_MAP_TILE_METATABLE ) != 0;
33// }
34//
35// static map_tile nlua_to_map_tile( lua_State* L, int index )
36// {
37//      return *(map_tile*)luaL_checkudata( L, index, NLUA_MAP_TILE_METATABLE );
38// }
[221]39
[323]40static map_tile* nlua_to_pmap_tile( lua_State* L, int index )
[221]41{
42        return (map_tile*)luaL_checkudata( L, index, NLUA_MAP_TILE_METATABLE );
43}
44
[323]45static void nlua_push_map_tile( lua_State* L, const map_tile& tile )
[221]46{
47        map_tile* result = (map_tile*)lua_newuserdata( L, sizeof(map_tile) );
48        *result = tile;
49        luaL_setmetatable( L, NLUA_MAP_TILE_METATABLE );
50}
51
52static int nlua_map_tile_new( lua_State* L )
53{
54        bool ascii = lua_toboolean( L, 4 ) != 0;
55        nv::map_area* map_area = nv::lua::detail::to_map_area( L, 3 );
56        lua_settop( L, 2 );
57        std::string code = nv::trimmed( lua_tostring( L, 1 ) );
58        nv::remove_chars( code, " \r\t" );
59
60        map_tile tile;
61
[374]62        tile.size_y = (nv::uint16)( nv::count( code.begin(), code.end(), '\n' ) + 1 );
[221]63        tile.size_x = (nv::uint16)( code.find( '\n' ) );
64        if ( tile.size_x == 0 )
65        {
66                tile.size_x = (nv::uint16)code.length();
67        }
68        tile.data  = new nv::uint8[ tile.size_x * tile.size_y ];
[369]69        tile.ascii = ( ascii ? new nv::uchar8[ tile.size_x * tile.size_y ] : nullptr );
[221]70
71        nv::uint8 translation[256] = { 0 };
72       
73        // TODO: error reporting
74        if ( lua_istable( L, 2 ) )
75        {
76                lua_pushnil( L );
77                while ( lua_next( L, 2 ) != 0 )
78                {
79                        // uses 'key' (at index -2) and 'value' (at index -1) */
80                        if ( lua_isstring( L, -2 ) && lua_objlen( L, -2 ) == 1 )
81                        {
[323]82                                translation[ (nv::uint8)( lua_tostring( L, -2 )[0] ) ] = nv::uint8( map_area->string_to_id( lua_tostring( L, -1 ) ) );
[221]83                        }
84                        // removes 'value'; keeps 'key' for next iteration */
85                        lua_pop( L, 1 );
86                }
87        }
88
[323]89        for ( nv::uint16 line = 0; line < tile.size_x; line++ )
90                for ( nv::uint16 row = 0; row < tile.size_y; row++ )
[221]91                {
[369]92                        nv::uchar8 gylph = (nv::uchar8)code[ row * ( tile.size_x + 1 ) + line ];
[221]93                        // TODO: check for errors
94                        tile.data[ row * tile.size_x + line ] = translation[ gylph ];
95                        if ( ascii ) tile.ascii[row * tile.size_x + line] = gylph;
96                }
97
98        nlua_push_map_tile( L, tile );
99        return 1;
100}
101
102static int nlua_map_tile_clone( lua_State* L )
103{
104        map_tile* old_tile = nlua_to_pmap_tile( L, 1 );
105        map_tile* new_tile = (map_tile*) lua_newuserdata( L, sizeof( map_tile ) );
106        new_tile->size_x = old_tile->size_x;
107        new_tile->size_y = old_tile->size_y;
108        nv::uint32 size  = new_tile->size_x * new_tile->size_y;
109        new_tile->data   = new nv::uint8[ size ];
110        new_tile->ascii  = nullptr;
111        if ( old_tile->ascii )
112        {
[369]113                new_tile->ascii = new nv::uchar8[ size ];
[221]114        }
115        std::copy( old_tile->data, old_tile->data + size, new_tile->data );
116        if ( old_tile->ascii ) std::copy( old_tile->ascii, old_tile->ascii + size, new_tile->ascii );
117
118        luaL_getmetatable( L, NLUA_MAP_TILE_METATABLE );
119        lua_setmetatable( L, -2 );
120        return 1;
121}
122
123static int nlua_map_tile_place( lua_State* L )
124{
125        map_tile* tile     = nlua_to_pmap_tile( L, 1 );
126        nv::map_area* area = nv::lua::detail::to_map_area( L, 2 );
127        nv::ivec2 coord    = nv::lua::detail::to_coord( L, 3 );
128
129        for ( nv::uint16 x = 0; x < tile->size_x; ++x )
130                for ( nv::uint16 y = 0; y < tile->size_y; ++y )
131                {
132                        nv::uint8 c = tile->data[ y * tile->size_x + x ];
[228]133                        if ( c != 0 ) area->set_cell( coord + nv::ivec2( x, y ), c );
[221]134                }
135
136        return 0;
137}
138
139static nv::uint8* nlua_map_tile_flip_x_helper( nv::uint8* src, nv::uint16 sx, nv::uint16 sy )
140{
141        if ( src == nullptr ) return nullptr;
142        nv::uint8* data = new nv::uint8[ sx * sy ];
143        for ( nv::uint16 x = 0; x < sx; ++x )
144                for ( nv::uint16 y = 0; y < sy; ++y )
145                {
146                        data[ y * sx + x ] = src[ ( y + 1 ) * sx - x - 1 ];
147                }
148        delete src;
149        return data;
150}
151
152static nv::uint8* nlua_map_tile_flip_y_helper( nv::uint8* src, nv::uint16 sx, nv::uint16 sy )
153{
154        if ( src == nullptr ) return nullptr;
155        nv::uint8* data = new nv::uint8[ sx * sy ];
156        for ( nv::uint16 x = 0; x < sx; ++x )
157                for ( nv::uint16 y = 0; y < sy; ++y )
158                {
159                        data[ y * sx + x ] = src[ ( sy - y - 1 ) * sx + x ];
160                }
161        delete src;
162        return data;
163}
164
165static nv::uint8* nlua_map_tile_flip_xy_helper( nv::uint8* src, nv::uint16 sx, nv::uint16 sy )
166{
167        if ( src == nullptr ) return nullptr;
168        nv::uint8* data = new nv::uint8[ sx * sy ];
169        for ( nv::uint16 x = 0; x < sx; ++x )
170                for ( nv::uint16 y = 0; y < sy; ++y )
171                {
172                        data[ y * sx + x ] = src[ ( sy - y ) * sx - x - 1 ];
173                }
174        delete src;
175        return data;
176}
177
178static int nlua_map_tile_flip_x( lua_State* L )
179{
180        map_tile* tile = nlua_to_pmap_tile( L, 1 );
181        tile->data     = nlua_map_tile_flip_x_helper( tile->data,  tile->size_x, tile->size_y );
182        tile->ascii    = nlua_map_tile_flip_x_helper( tile->ascii, tile->size_x, tile->size_y );
183        return 0;
184}
185
186static int nlua_map_tile_flip_y( lua_State* L )
187{
188        map_tile* tile = nlua_to_pmap_tile( L, 1 );
189        tile->data     = nlua_map_tile_flip_y_helper( tile->data,  tile->size_x, tile->size_y );
190        tile->ascii    = nlua_map_tile_flip_y_helper( tile->ascii, tile->size_x, tile->size_y );
191        return 0;
192}
193
194static int nlua_map_tile_flip_xy( lua_State* L )
195{
196        map_tile* tile = nlua_to_pmap_tile( L, 1 );
197        tile->data     = nlua_map_tile_flip_xy_helper( tile->data,  tile->size_x, tile->size_y );
198        tile->ascii    = nlua_map_tile_flip_xy_helper( tile->ascii, tile->size_x, tile->size_y );
199        return 0;
200}
201
202static int nlua_map_tile_flip_random( lua_State* L )
203{
204        switch ( nv::random::get().urand( 4 ) )
205        {
[323]206        case 1 : nlua_map_tile_flip_x( L ); break;
207        case 2 : nlua_map_tile_flip_y( L ); break;
208        case 3 : nlua_map_tile_flip_xy( L ); break;
[319]209        default:
[221]210                break;
211        }
212        return 0;
213}
214
215static int nlua_map_tile_get_size( lua_State* L )
216{
217        map_tile* tile = nlua_to_pmap_tile( L, 1 );
218        nv::lua::detail::push_coord( L, nv::ivec2( tile->size_x, tile->size_y ) );
219        return 1;
220}
221
222static int nlua_map_tile_get_area( lua_State* L )
223{
224        map_tile* tile = nlua_to_pmap_tile( L, 1 );
225        nv::lua::detail::push_area( L, nv::rectangle( nv::ivec2(1,1), nv::ivec2( tile->size_x, tile->size_y ) ) );
226        return 1;
227}
228
229static int nlua_map_tile_expand( lua_State* L )
230{
231        // TODO: lots of error checking
232        map_tile* tile = nlua_to_pmap_tile( L, 1 );
233        // assert( tile^.ascii == nullptr );
234        std::vector< nv::uint8 > sizes_x = nlua_tobytearray( L, 2 );
235        std::vector< nv::uint8 > sizes_y = ( lua_istable( L, 3 ) ? nlua_tobytearray( L, 3 ) : sizes_x );
236
237        nv::uint16 org_x = tile->size_x;
238        nv::uint16 org_y = tile->size_y;
[374]239        nv::uint16 new_x = ( nv::uint16 )nv::accumulate( sizes_x.begin(), sizes_x.end(), 0 );
240        nv::uint16 new_y = ( nv::uint16 )nv::accumulate( sizes_y.begin(), sizes_y.end(), 0 );
[221]241
242        nv::uint8* data = new nv::uint8[ new_x * new_y ];
243
244        nv::uint16 line_count = 0;
245        for ( nv::uint16 line = 0; line < org_y; ++line )
246                for ( nv::uint16 count = 0; count < sizes_y[ line ]; ++count )
247                {
248                        nv::uint16 px = 0;
249                        for ( nv::uint16 x = 0; x < org_x; ++x )
250                                for ( nv::uint16 c = 0; c < sizes_x[ x ]; ++c )
251                                {
252                                        data[ px + line_count * new_x ] = tile->data[ x + line * org_x ];
253                                        px++;
254                                }
255                        line_count++;
256                }
257
258        delete tile->data;
259        tile->size_x = new_x;
260        tile->size_y = new_y;
261        tile->data   = data;
262        return 0;
263}
264
265static int nlua_map_tile_raw_get( lua_State* L )
266{
267        map_tile* tile = (map_tile*)lua_touserdata( L, 1 );
268        if ( lua_type( L, 2 ) == LUA_TNUMBER )
269        {
270                lua_pushinteger( L, tile->data[ ( lua_tointeger( L, 2 ) - 1 ) + ( lua_tointeger( L, 3 ) - 1 ) * tile->size_x ] );
271        }
272        else
273        {
274                nv::ivec2 coord = nv::lua::detail::to_coord( L, 2 );
275                lua_pushinteger( L, tile->data[ ( coord.x - 1 ) + ( coord.y - 1 ) * tile->size_x ] );
276        }
277        return 1;
278}
279
280static int nlua_map_tile_raw_set( lua_State* L )
281{
282        map_tile* tile = (map_tile*)lua_touserdata( L, 1 );
283        if ( lua_type( L, 2 ) == LUA_TNUMBER )
284        {
285                tile->data[ ( lua_tointeger( L, 2 ) - 1 ) + ( lua_tointeger( L, 3 ) - 1 ) * tile->size_x ] = (nv::uint8)lua_tointeger( L, 3 );
286        }
287        else
288        {
289                nv::ivec2 coord = nv::lua::detail::to_coord( L, 2 );
290                tile->data[ ( coord.x - 1 ) + ( coord.y - 1 ) * tile->size_x ] = (nv::uint8)lua_tointeger( L, 3 );
291        }
292        return 0;
293}
294
295static int nlua_map_tile_ascii_get( lua_State* L )
296{
297        map_tile* tile = (map_tile*)lua_touserdata( L, 1 );
298        if ( lua_type( L, 2 ) == LUA_TNUMBER )
299        {
300                lua_pushinteger( L, tile->ascii[ ( lua_tointeger( L, 2 ) - 1 ) + ( lua_tointeger( L, 3 ) - 1 ) * tile->size_x ] );
301        }
302        else
303        {
304                nv::ivec2 coord = nv::lua::detail::to_coord( L, 2 );
305                lua_pushinteger( L, tile->ascii[ ( coord.x - 1 ) + ( coord.y - 1 ) * tile->size_x ] );
306        }
307        return 1;
308}
309
310static int nlua_map_tile_ascii_set( lua_State* L )
311{
312        map_tile* tile = (map_tile*)lua_touserdata( L, 1 );
313        if ( lua_type( L, 2 ) == LUA_TNUMBER )
314        {
315                tile->ascii[ ( lua_tointeger( L, 2 ) - 1 ) + ( lua_tointeger( L, 3 ) - 1 ) * tile->size_x ] = (nv::uint8)lua_tointeger( L, 3 );
316        }
317        else
318        {
319                nv::ivec2 coord = nv::lua::detail::to_coord( L, 2 );
320                tile->ascii[ ( coord.x - 1 ) + ( coord.y - 1 ) * tile->size_x ] = (nv::uint8)lua_tointeger( L, 3 );
321        }
322        return 0;
323}
324
325static int nlua_map_tile_gc( lua_State* L )
326{
327        map_tile* tile = (map_tile*)lua_touserdata( L, 1 );
328        if ( tile != nullptr )
329        {
330                delete tile->data;
331                if ( tile->ascii ) delete tile->ascii;
332        }
333        return 0;
334}
335
336static const luaL_Reg nlua_map_tile_sf[] = {
337        { "new",   nlua_map_tile_new },
338        { NULL, NULL }
339};
340
341static const luaL_Reg nlua_map_tile_f[] = {
342        { "place",      nlua_map_tile_place },
343        { "clone",      nlua_map_tile_clone },
344        { "flip_x",     nlua_map_tile_flip_x },
345        { "flip_y",     nlua_map_tile_flip_y },
346        { "flip_xy",    nlua_map_tile_flip_xy },
347        { "flip_random",nlua_map_tile_flip_random },
348        { "get_size",   nlua_map_tile_get_size },
349        { "get_area",   nlua_map_tile_get_area },
350        { "expand",     nlua_map_tile_expand },
351        { "raw_get",    nlua_map_tile_raw_get },
352        { "raw_set",    nlua_map_tile_raw_set },
353        { "get_ascii",  nlua_map_tile_ascii_get },
354        { "set_ascii",  nlua_map_tile_ascii_set },
355        { "__gc",       nlua_map_tile_gc },
356        { NULL, NULL }
357};
358
359void nv::lua::register_map_tile( lua_State * L )
360{
361        // TODO: check if __gc is used!
362        luaL_newmetatable( L, NLUA_MAP_TILE_METATABLE );
363        lua_pushvalue( L, -1 );
364        lua_setfield( L, -2, "__index" );
365        nlua_register( L, nlua_map_tile_f, -1 );
366
367        lua_createtable( L, 0, 0 );
368        nlua_register( L, "map_tile", nlua_map_tile_sf );
369}
Note: See TracBrowser for help on using the repository browser.