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

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