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

Last change on this file since 510 was 503, checked in by epyon, 9 years ago
  • nv::random - support for different rng sources
  • nv::types - fixes and better support
  • nv::mesh_creator - full range transform
  • nv::context - buffer mask as separate type
  • nv::lua - initializations from lua::state instead of lua_State
  • nv::lua - initial support for rtti
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_math.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        nlua_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_buffer code( nv::trimmed( lua_tostring( L, 1 ) ) );
58        nv::string_view chars( " \r\t" );
59        code.erase( nv::remove_if( code.begin(), code.end(),
60                [&chars] ( const char& c )
61        {
62                return chars.find( c ) != nv::string_view::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 = reinterpret_cast<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        nv::raw_copy_n( old_tile->data, size, new_tile->data );
121        if ( old_tile->ascii ) nv::raw_copy_n( 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        nv::vector< nv::uint8 > sizes_x = nlua_tobytearray( L, 2 );
240        nv::vector< nv::uint8 > sizes_y;
241        if ( lua_istable( L, 3 ) )
242                sizes_y = nlua_tobytearray( L, 2 );
243        else
244                sizes_y.assign( sizes_x );
245
246        nv::uint16 org_x = tile->size_x;
247        nv::uint16 org_y = tile->size_y;
248        nv::uint16 new_x = nv::uint16( nv::accumulate( sizes_x.begin(), sizes_x.end(), 0 ) );
249        nv::uint16 new_y = nv::uint16( nv::accumulate( sizes_y.begin(), sizes_y.end(), 0 ) );
250
251        nv::uint8* data = new nv::uint8[ new_x * new_y ];
252
253        nv::uint16 line_count = 0;
254        for ( nv::uint16 line = 0; line < org_y; ++line )
255                for ( nv::uint16 count = 0; count < sizes_y[ line ]; ++count )
256                {
257                        nv::uint16 px = 0;
258                        for ( nv::uint16 x = 0; x < org_x; ++x )
259                                for ( nv::uint16 c = 0; c < sizes_x[ x ]; ++c )
260                                {
261                                        data[ px + line_count * new_x ] = tile->data[ x + line * org_x ];
262                                        px++;
263                                }
264                        line_count++;
265                }
266
267        delete tile->data;
268        tile->size_x = new_x;
269        tile->size_y = new_y;
270        tile->data   = data;
271        return 0;
272}
273
274static int nlua_map_tile_raw_get( lua_State* L )
275{
276        map_tile* tile = reinterpret_cast<map_tile*>( lua_touserdata( L, 1 ) );
277        if ( lua_type( L, 2 ) == LUA_TNUMBER )
278        {
279                lua_pushinteger( L, tile->data[ ( lua_tointeger( L, 2 ) - 1 ) + ( lua_tointeger( L, 3 ) - 1 ) * tile->size_x ] );
280        }
281        else
282        {
283                nv::ivec2 coord = nv::lua::detail::to_coord( L, 2 );
284                lua_pushinteger( L, tile->data[ ( coord.x - 1 ) + ( coord.y - 1 ) * tile->size_x ] );
285        }
286        return 1;
287}
288
289static int nlua_map_tile_raw_set( lua_State* L )
290{
291        map_tile* tile = reinterpret_cast<map_tile*>( lua_touserdata( L, 1 ) );
292        if ( lua_type( L, 2 ) == LUA_TNUMBER )
293        {
294                tile->data[ ( lua_tointeger( L, 2 ) - 1 ) + ( lua_tointeger( L, 3 ) - 1 ) * tile->size_x ] = nv::uint8( lua_tointeger( L, 3 ) );
295        }
296        else
297        {
298                nv::ivec2 coord = nv::lua::detail::to_coord( L, 2 );
299                tile->data[ ( coord.x - 1 ) + ( coord.y - 1 ) * tile->size_x ] = nv::uint8( lua_tointeger( L, 3 ) );
300        }
301        return 0;
302}
303
304static int nlua_map_tile_ascii_get( lua_State* L )
305{
306        map_tile* tile = reinterpret_cast<map_tile*>( lua_touserdata( L, 1 ) );
307        if ( lua_type( L, 2 ) == LUA_TNUMBER )
308        {
309                lua_pushinteger( L, tile->ascii[ ( lua_tointeger( L, 2 ) - 1 ) + ( lua_tointeger( L, 3 ) - 1 ) * tile->size_x ] );
310        }
311        else
312        {
313                nv::ivec2 coord = nv::lua::detail::to_coord( L, 2 );
314                lua_pushinteger( L, tile->ascii[ ( coord.x - 1 ) + ( coord.y - 1 ) * tile->size_x ] );
315        }
316        return 1;
317}
318
319static int nlua_map_tile_ascii_set( lua_State* L )
320{
321        map_tile* tile = reinterpret_cast<map_tile*>( lua_touserdata( L, 1 ) );
322        if ( lua_type( L, 2 ) == LUA_TNUMBER )
323        {
324                tile->ascii[ ( lua_tointeger( L, 2 ) - 1 ) + ( lua_tointeger( L, 3 ) - 1 ) * tile->size_x ] = nv::uint8( lua_tointeger( L, 3 ) );
325        }
326        else
327        {
328                nv::ivec2 coord = nv::lua::detail::to_coord( L, 2 );
329                tile->ascii[ ( coord.x - 1 ) + ( coord.y - 1 ) * tile->size_x ] = nv::uint8( lua_tointeger( L, 3 ) );
330        }
331        return 0;
332}
333
334static int nlua_map_tile_gc( lua_State* L )
335{
336        map_tile* tile = reinterpret_cast<map_tile*>( lua_touserdata( L, 1 ) );
337        if ( tile != nullptr )
338        {
339                delete tile->data;
340                if ( tile->ascii ) delete tile->ascii;
341        }
342        return 0;
343}
344
345static const luaL_Reg nlua_map_tile_sf[] = {
346        { "new",   nlua_map_tile_new },
347        { NULL, NULL }
348};
349
350static const luaL_Reg nlua_map_tile_f[] = {
351        { "place",      nlua_map_tile_place },
352        { "clone",      nlua_map_tile_clone },
353        { "flip_x",     nlua_map_tile_flip_x },
354        { "flip_y",     nlua_map_tile_flip_y },
355        { "flip_xy",    nlua_map_tile_flip_xy },
356        { "flip_random",nlua_map_tile_flip_random },
357        { "get_size",   nlua_map_tile_get_size },
358        { "get_area",   nlua_map_tile_get_area },
359        { "expand",     nlua_map_tile_expand },
360        { "raw_get",    nlua_map_tile_raw_get },
361        { "raw_set",    nlua_map_tile_raw_set },
362        { "get_ascii",  nlua_map_tile_ascii_get },
363        { "set_ascii",  nlua_map_tile_ascii_set },
364        { "__gc",       nlua_map_tile_gc },
365        { NULL, NULL }
366};
367
368void nv::lua::register_map_tile( lua::state* state )
369{
370        // TODO: check if __gc is used!
371        lua_State* L = state->get_raw();
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.