]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_vmanip.cpp
Light calculation: New bulk node lighting code
[dragonfireclient.git] / src / script / lua_api / l_vmanip.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20
21 #include "lua_api/l_vmanip.h"
22 #include "lua_api/l_internal.h"
23 #include "common/c_content.h"
24 #include "common/c_converter.h"
25 #include "emerge.h"
26 #include "environment.h"
27 #include "map.h"
28 #include "server.h"
29 #include "mapgen.h"
30 #include "voxelalgorithms.h"
31
32 // garbage collector
33 int LuaVoxelManip::gc_object(lua_State *L)
34 {
35         LuaVoxelManip *o = *(LuaVoxelManip **)(lua_touserdata(L, 1));
36         delete o;
37
38         return 0;
39 }
40
41 int LuaVoxelManip::l_read_from_map(lua_State *L)
42 {
43         MAP_LOCK_REQUIRED;
44
45         LuaVoxelManip *o = checkobject(L, 1);
46         MMVManip *vm = o->vm;
47
48         v3s16 bp1 = getNodeBlockPos(check_v3s16(L, 2));
49         v3s16 bp2 = getNodeBlockPos(check_v3s16(L, 3));
50         sortBoxVerticies(bp1, bp2);
51
52         vm->initialEmerge(bp1, bp2);
53
54         push_v3s16(L, vm->m_area.MinEdge);
55         push_v3s16(L, vm->m_area.MaxEdge);
56
57         return 2;
58 }
59
60 int LuaVoxelManip::l_get_data(lua_State *L)
61 {
62         NO_MAP_LOCK_REQUIRED;
63
64         LuaVoxelManip *o = checkobject(L, 1);
65         bool use_buffer  = lua_istable(L, 2);
66
67         MMVManip *vm = o->vm;
68
69         u32 volume = vm->m_area.getVolume();
70
71         if (use_buffer)
72                 lua_pushvalue(L, 2);
73         else
74                 lua_newtable(L);
75
76         for (u32 i = 0; i != volume; i++) {
77                 lua_Integer cid = vm->m_data[i].getContent();
78                 lua_pushinteger(L, cid);
79                 lua_rawseti(L, -2, i + 1);
80         }
81
82         return 1;
83 }
84
85 int LuaVoxelManip::l_set_data(lua_State *L)
86 {
87         NO_MAP_LOCK_REQUIRED;
88
89         LuaVoxelManip *o = checkobject(L, 1);
90         MMVManip *vm = o->vm;
91
92         if (!lua_istable(L, 2))
93                 return 0;
94
95         u32 volume = vm->m_area.getVolume();
96         for (u32 i = 0; i != volume; i++) {
97                 lua_rawgeti(L, 2, i + 1);
98                 content_t c = lua_tointeger(L, -1);
99
100                 vm->m_data[i].setContent(c);
101
102                 lua_pop(L, 1);
103         }
104
105         return 0;
106 }
107
108 int LuaVoxelManip::l_write_to_map(lua_State *L)
109 {
110         MAP_LOCK_REQUIRED;
111
112         LuaVoxelManip *o = checkobject(L, 1);
113         GET_ENV_PTR;
114         ServerMap *map = &(env->getServerMap());
115         if (o->is_mapgen_vm) {
116                 o->vm->blitBackAll(&(o->modified_blocks));
117         } else {
118                 voxalgo::blit_back_with_light(map, o->vm,
119                         &(o->modified_blocks));
120         }
121
122         MapEditEvent event;
123         event.type = MEET_OTHER;
124         for (std::map<v3s16, MapBlock *>::iterator it = o->modified_blocks.begin();
125                         it != o->modified_blocks.end(); ++it)
126                 event.modified_blocks.insert(it->first);
127
128         map->dispatchEvent(&event);
129
130         o->modified_blocks.clear();
131         return 0;
132 }
133
134 int LuaVoxelManip::l_get_node_at(lua_State *L)
135 {
136         NO_MAP_LOCK_REQUIRED;
137
138         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
139
140         LuaVoxelManip *o = checkobject(L, 1);
141         v3s16 pos        = check_v3s16(L, 2);
142
143         pushnode(L, o->vm->getNodeNoExNoEmerge(pos), ndef);
144         return 1;
145 }
146
147 int LuaVoxelManip::l_set_node_at(lua_State *L)
148 {
149         NO_MAP_LOCK_REQUIRED;
150
151         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
152
153         LuaVoxelManip *o = checkobject(L, 1);
154         v3s16 pos        = check_v3s16(L, 2);
155         MapNode n        = readnode(L, 3, ndef);
156
157         o->vm->setNodeNoEmerge(pos, n);
158
159         return 0;
160 }
161
162 int LuaVoxelManip::l_update_liquids(lua_State *L)
163 {
164         GET_ENV_PTR;
165
166         LuaVoxelManip *o = checkobject(L, 1);
167
168         Map *map = &(env->getMap());
169         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
170         MMVManip *vm = o->vm;
171
172         Mapgen mg;
173         mg.vm   = vm;
174         mg.ndef = ndef;
175
176         mg.updateLiquid(&map->m_transforming_liquid,
177                         vm->m_area.MinEdge, vm->m_area.MaxEdge);
178
179         return 0;
180 }
181
182 int LuaVoxelManip::l_calc_lighting(lua_State *L)
183 {
184         NO_MAP_LOCK_REQUIRED;
185
186         LuaVoxelManip *o = checkobject(L, 1);
187         if (!o->is_mapgen_vm)
188                 return 0;
189
190         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
191         EmergeManager *emerge = getServer(L)->getEmergeManager();
192         MMVManip *vm = o->vm;
193
194         v3s16 yblock = v3s16(0, 1, 0) * MAP_BLOCKSIZE;
195         v3s16 fpmin  = vm->m_area.MinEdge;
196         v3s16 fpmax  = vm->m_area.MaxEdge;
197         v3s16 pmin   = lua_istable(L, 2) ? check_v3s16(L, 2) : fpmin + yblock;
198         v3s16 pmax   = lua_istable(L, 3) ? check_v3s16(L, 3) : fpmax - yblock;
199         bool propagate_shadow = lua_isboolean(L, 4) ? lua_toboolean(L, 4) : true;
200
201         sortBoxVerticies(pmin, pmax);
202         if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
203                 throw LuaError("Specified voxel area out of VoxelManipulator bounds");
204
205         Mapgen mg;
206         mg.vm          = vm;
207         mg.ndef        = ndef;
208         mg.water_level = emerge->mgparams->water_level;
209
210         mg.calcLighting(pmin, pmax, fpmin, fpmax, propagate_shadow);
211
212         return 0;
213 }
214
215 int LuaVoxelManip::l_set_lighting(lua_State *L)
216 {
217         NO_MAP_LOCK_REQUIRED;
218
219         LuaVoxelManip *o = checkobject(L, 1);
220         if (!o->is_mapgen_vm)
221                 return 0;
222
223         if (!lua_istable(L, 2))
224                 return 0;
225
226         u8 light;
227         light  = (getintfield_default(L, 2, "day",   0) & 0x0F);
228         light |= (getintfield_default(L, 2, "night", 0) & 0x0F) << 4;
229
230         MMVManip *vm = o->vm;
231
232         v3s16 yblock = v3s16(0, 1, 0) * MAP_BLOCKSIZE;
233         v3s16 pmin = lua_istable(L, 3) ? check_v3s16(L, 3) : vm->m_area.MinEdge + yblock;
234         v3s16 pmax = lua_istable(L, 4) ? check_v3s16(L, 4) : vm->m_area.MaxEdge - yblock;
235
236         sortBoxVerticies(pmin, pmax);
237         if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
238                 throw LuaError("Specified voxel area out of VoxelManipulator bounds");
239
240         Mapgen mg;
241         mg.vm = vm;
242
243         mg.setLighting(light, pmin, pmax);
244
245         return 0;
246 }
247
248 int LuaVoxelManip::l_get_light_data(lua_State *L)
249 {
250         NO_MAP_LOCK_REQUIRED;
251
252         LuaVoxelManip *o = checkobject(L, 1);
253         MMVManip *vm = o->vm;
254
255         u32 volume = vm->m_area.getVolume();
256
257         lua_newtable(L);
258         for (u32 i = 0; i != volume; i++) {
259                 lua_Integer light = vm->m_data[i].param1;
260                 lua_pushinteger(L, light);
261                 lua_rawseti(L, -2, i + 1);
262         }
263
264         return 1;
265 }
266
267 int LuaVoxelManip::l_set_light_data(lua_State *L)
268 {
269         NO_MAP_LOCK_REQUIRED;
270
271         LuaVoxelManip *o = checkobject(L, 1);
272         MMVManip *vm = o->vm;
273
274         if (!lua_istable(L, 2))
275                 return 0;
276
277         u32 volume = vm->m_area.getVolume();
278         for (u32 i = 0; i != volume; i++) {
279                 lua_rawgeti(L, 2, i + 1);
280                 u8 light = lua_tointeger(L, -1);
281
282                 vm->m_data[i].param1 = light;
283
284                 lua_pop(L, 1);
285         }
286
287         return 0;
288 }
289
290 int LuaVoxelManip::l_get_param2_data(lua_State *L)
291 {
292         NO_MAP_LOCK_REQUIRED;
293
294         LuaVoxelManip *o = checkobject(L, 1);
295         bool use_buffer  = lua_istable(L, 2);
296
297         MMVManip *vm = o->vm;
298
299         u32 volume = vm->m_area.getVolume();
300
301         if (use_buffer)
302                 lua_pushvalue(L, 2);
303         else
304                 lua_newtable(L);
305
306         for (u32 i = 0; i != volume; i++) {
307                 lua_Integer param2 = vm->m_data[i].param2;
308                 lua_pushinteger(L, param2);
309                 lua_rawseti(L, -2, i + 1);
310         }
311
312         return 1;
313 }
314
315 int LuaVoxelManip::l_set_param2_data(lua_State *L)
316 {
317         NO_MAP_LOCK_REQUIRED;
318
319         LuaVoxelManip *o = checkobject(L, 1);
320         MMVManip *vm = o->vm;
321
322         if (!lua_istable(L, 2))
323                 return 0;
324
325         u32 volume = vm->m_area.getVolume();
326         for (u32 i = 0; i != volume; i++) {
327                 lua_rawgeti(L, 2, i + 1);
328                 u8 param2 = lua_tointeger(L, -1);
329
330                 vm->m_data[i].param2 = param2;
331
332                 lua_pop(L, 1);
333         }
334
335         return 0;
336 }
337
338 int LuaVoxelManip::l_update_map(lua_State *L)
339 {
340         return 0;
341 }
342
343 int LuaVoxelManip::l_was_modified(lua_State *L)
344 {
345         NO_MAP_LOCK_REQUIRED;
346
347         LuaVoxelManip *o = checkobject(L, 1);
348         MMVManip *vm = o->vm;
349
350         lua_pushboolean(L, vm->m_is_dirty);
351
352         return 1;
353 }
354
355 int LuaVoxelManip::l_get_emerged_area(lua_State *L)
356 {
357         NO_MAP_LOCK_REQUIRED;
358
359         LuaVoxelManip *o = checkobject(L, 1);
360
361         push_v3s16(L, o->vm->m_area.MinEdge);
362         push_v3s16(L, o->vm->m_area.MaxEdge);
363
364         return 2;
365 }
366
367 LuaVoxelManip::LuaVoxelManip(MMVManip *mmvm, bool is_mg_vm)
368 {
369         this->vm           = mmvm;
370         this->is_mapgen_vm = is_mg_vm;
371 }
372
373 LuaVoxelManip::LuaVoxelManip(Map *map)
374 {
375         this->vm = new MMVManip(map);
376         this->is_mapgen_vm = false;
377 }
378
379 LuaVoxelManip::LuaVoxelManip(Map *map, v3s16 p1, v3s16 p2)
380 {
381         this->vm = new MMVManip(map);
382         this->is_mapgen_vm = false;
383
384         v3s16 bp1 = getNodeBlockPos(p1);
385         v3s16 bp2 = getNodeBlockPos(p2);
386         sortBoxVerticies(bp1, bp2);
387         vm->initialEmerge(bp1, bp2);
388 }
389
390 LuaVoxelManip::~LuaVoxelManip()
391 {
392         if (!is_mapgen_vm)
393                 delete vm;
394 }
395
396 // LuaVoxelManip()
397 // Creates an LuaVoxelManip and leaves it on top of stack
398 int LuaVoxelManip::create_object(lua_State *L)
399 {
400         GET_ENV_PTR;
401
402         Map *map = &(env->getMap());
403         LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ?
404                 new LuaVoxelManip(map, check_v3s16(L, 1), check_v3s16(L, 2)) :
405                 new LuaVoxelManip(map);
406
407         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
408         luaL_getmetatable(L, className);
409         lua_setmetatable(L, -2);
410         return 1;
411 }
412
413 LuaVoxelManip *LuaVoxelManip::checkobject(lua_State *L, int narg)
414 {
415         NO_MAP_LOCK_REQUIRED;
416
417         luaL_checktype(L, narg, LUA_TUSERDATA);
418
419         void *ud = luaL_checkudata(L, narg, className);
420         if (!ud)
421                 luaL_typerror(L, narg, className);
422
423         return *(LuaVoxelManip **)ud;  // unbox pointer
424 }
425
426 void LuaVoxelManip::Register(lua_State *L)
427 {
428         lua_newtable(L);
429         int methodtable = lua_gettop(L);
430         luaL_newmetatable(L, className);
431         int metatable = lua_gettop(L);
432
433         lua_pushliteral(L, "__metatable");
434         lua_pushvalue(L, methodtable);
435         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
436
437         lua_pushliteral(L, "__index");
438         lua_pushvalue(L, methodtable);
439         lua_settable(L, metatable);
440
441         lua_pushliteral(L, "__gc");
442         lua_pushcfunction(L, gc_object);
443         lua_settable(L, metatable);
444
445         lua_pop(L, 1);  // drop metatable
446
447         luaL_openlib(L, 0, methods, 0);  // fill methodtable
448         lua_pop(L, 1);  // drop methodtable
449
450         // Can be created from Lua (VoxelManip())
451         lua_register(L, className, create_object);
452 }
453
454 const char LuaVoxelManip::className[] = "VoxelManip";
455 const luaL_reg LuaVoxelManip::methods[] = {
456         luamethod(LuaVoxelManip, read_from_map),
457         luamethod(LuaVoxelManip, get_data),
458         luamethod(LuaVoxelManip, set_data),
459         luamethod(LuaVoxelManip, get_node_at),
460         luamethod(LuaVoxelManip, set_node_at),
461         luamethod(LuaVoxelManip, write_to_map),
462         luamethod(LuaVoxelManip, update_map),
463         luamethod(LuaVoxelManip, update_liquids),
464         luamethod(LuaVoxelManip, calc_lighting),
465         luamethod(LuaVoxelManip, set_lighting),
466         luamethod(LuaVoxelManip, get_light_data),
467         luamethod(LuaVoxelManip, set_light_data),
468         luamethod(LuaVoxelManip, get_param2_data),
469         luamethod(LuaVoxelManip, set_param2_data),
470         luamethod(LuaVoxelManip, was_modified),
471         luamethod(LuaVoxelManip, get_emerged_area),
472         {0,0}
473 };