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

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