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

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