Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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 : #include "voxel.h"
21 : #include "map.h"
22 : #include "gettime.h"
23 : #include "nodedef.h"
24 : #include "util/timetaker.h"
25 : #include <string.h> // memcpy, memset
26 :
27 : /*
28 : Debug stuff
29 : */
30 : u32 addarea_time = 0;
31 : u32 emerge_time = 0;
32 : u32 emerge_load_time = 0;
33 : u32 clearflag_time = 0;
34 : //u32 getwaterpressure_time = 0;
35 : //u32 spreadwaterpressure_time = 0;
36 : u32 updateareawaterpressure_time = 0;
37 : u32 flowwater_pre_time = 0;
38 :
39 :
40 3549 : VoxelManipulator::VoxelManipulator():
41 : m_data(NULL),
42 3549 : m_flags(NULL)
43 : {
44 3549 : }
45 :
46 7098 : VoxelManipulator::~VoxelManipulator()
47 : {
48 3549 : clear();
49 3549 : }
50 :
51 7098 : void VoxelManipulator::clear()
52 : {
53 : // Reset area to volume=0
54 7098 : m_area = VoxelArea();
55 7098 : delete[] m_data;
56 7098 : m_data = NULL;
57 7098 : delete[] m_flags;
58 7098 : m_flags = NULL;
59 7098 : }
60 :
61 0 : void VoxelManipulator::print(std::ostream &o, INodeDefManager *ndef,
62 : VoxelPrintMode mode)
63 : {
64 0 : v3s16 em = m_area.getExtent();
65 0 : v3s16 of = m_area.MinEdge;
66 0 : o<<"size: "<<em.X<<"x"<<em.Y<<"x"<<em.Z
67 0 : <<" offset: ("<<of.X<<","<<of.Y<<","<<of.Z<<")"<<std::endl;
68 :
69 0 : for(s32 y=m_area.MaxEdge.Y; y>=m_area.MinEdge.Y; y--)
70 : {
71 0 : if(em.X >= 3 && em.Y >= 3)
72 : {
73 0 : if (y==m_area.MinEdge.Y+2) o<<"^ ";
74 0 : else if(y==m_area.MinEdge.Y+1) o<<"| ";
75 0 : else if(y==m_area.MinEdge.Y+0) o<<"y x-> ";
76 0 : else o<<" ";
77 : }
78 :
79 0 : for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
80 : {
81 0 : for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
82 : {
83 0 : u8 f = m_flags[m_area.index(x,y,z)];
84 : char c;
85 0 : if(f & VOXELFLAG_NO_DATA)
86 0 : c = 'N';
87 : else
88 : {
89 0 : c = 'X';
90 0 : MapNode n = m_data[m_area.index(x,y,z)];
91 0 : content_t m = n.getContent();
92 0 : u8 pr = n.param2;
93 0 : if(mode == VOXELPRINT_MATERIAL)
94 : {
95 0 : if(m <= 9)
96 0 : c = m + '0';
97 : }
98 0 : else if(mode == VOXELPRINT_WATERPRESSURE)
99 : {
100 0 : if(ndef->get(m).isLiquid())
101 : {
102 0 : c = 'w';
103 0 : if(pr <= 9)
104 0 : c = pr + '0';
105 : }
106 0 : else if(m == CONTENT_AIR)
107 : {
108 0 : c = ' ';
109 : }
110 : else
111 : {
112 0 : c = '#';
113 : }
114 : }
115 0 : else if(mode == VOXELPRINT_LIGHT_DAY)
116 : {
117 0 : if(ndef->get(m).light_source != 0)
118 0 : c = 'S';
119 0 : else if(ndef->get(m).light_propagates == false)
120 0 : c = 'X';
121 : else
122 : {
123 0 : u8 light = n.getLight(LIGHTBANK_DAY, ndef);
124 0 : if(light < 10)
125 0 : c = '0' + light;
126 : else
127 0 : c = 'a' + (light-10);
128 : }
129 : }
130 : }
131 0 : o<<c;
132 : }
133 0 : o<<' ';
134 : }
135 0 : o<<std::endl;
136 : }
137 0 : }
138 :
139 17914543 : void VoxelManipulator::addArea(const VoxelArea &area)
140 : {
141 : // Cancel if requested area has zero volume
142 17914543 : if (area.hasEmptyExtent())
143 17911023 : return;
144 :
145 : // Cancel if m_area already contains the requested area
146 17914482 : if(m_area.contains(area))
147 17911023 : return;
148 :
149 7098 : TimeTaker timer("addArea", &addarea_time);
150 :
151 : // Calculate new area
152 3549 : VoxelArea new_area;
153 : // New area is the requested area if m_area has zero volume
154 3549 : if(m_area.hasEmptyExtent())
155 : {
156 3549 : new_area = area;
157 : }
158 : // Else add requested area to m_area
159 : else
160 : {
161 0 : new_area = m_area;
162 0 : new_area.addArea(area);
163 : }
164 :
165 3549 : s32 new_size = new_area.getVolume();
166 :
167 : /*dstream<<"adding area ";
168 : area.print(dstream);
169 : dstream<<", old area ";
170 : m_area.print(dstream);
171 : dstream<<", new area ";
172 : new_area.print(dstream);
173 : dstream<<", new_size="<<new_size;
174 : dstream<<std::endl;*/
175 :
176 : // Allocate new data and clear flags
177 3549 : MapNode *new_data = new MapNode[new_size];
178 : assert(new_data);
179 3549 : u8 *new_flags = new u8[new_size];
180 : assert(new_flags);
181 3549 : memset(new_flags, VOXELFLAG_NO_DATA, new_size);
182 :
183 : // Copy old data
184 3549 : s32 old_x_width = m_area.MaxEdge.X - m_area.MinEdge.X + 1;
185 3549 : for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
186 0 : for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
187 : {
188 0 : unsigned int old_index = m_area.index(m_area.MinEdge.X,y,z);
189 0 : unsigned int new_index = new_area.index(m_area.MinEdge.X,y,z);
190 :
191 0 : memcpy(&new_data[new_index], &m_data[old_index],
192 0 : old_x_width * sizeof(MapNode));
193 0 : memcpy(&new_flags[new_index], &m_flags[old_index],
194 0 : old_x_width * sizeof(u8));
195 : }
196 :
197 : // Replace area, data and flags
198 :
199 3549 : m_area = new_area;
200 :
201 3549 : MapNode *old_data = m_data;
202 3549 : u8 *old_flags = m_flags;
203 :
204 : /*dstream<<"old_data="<<(int)old_data<<", new_data="<<(int)new_data
205 : <<", old_flags="<<(int)m_flags<<", new_flags="<<(int)new_flags<<std::endl;*/
206 :
207 3549 : m_data = new_data;
208 3549 : m_flags = new_flags;
209 :
210 3549 : delete[] old_data;
211 3549 : delete[] old_flags;
212 :
213 : //dstream<<"addArea done"<<std::endl;
214 : }
215 :
216 56321 : void VoxelManipulator::copyFrom(MapNode *src, const VoxelArea& src_area,
217 : v3s16 from_pos, v3s16 to_pos, v3s16 size)
218 : {
219 : /* The reason for this optimised code is that we're a member function
220 : * and the data type/layout of m_data is know to us: it's stored as
221 : * [z*h*w + y*h + x]. Therefore we can take the calls to m_area index
222 : * (which performs the preceding mapping/indexing of m_data) out of the
223 : * inner loop and calculate the next index as we're iterating to gain
224 : * performance.
225 : *
226 : * src_step and dest_step is the amount required to be added to our index
227 : * every time y increments. Because the destination area may be larger
228 : * than the source area we need one additional variable (otherwise we could
229 : * just continue adding dest_step as is done for the source data): dest_mod.
230 : * dest_mod is the difference in size between a "row" in the source data
231 : * and a "row" in the destination data (I am using the term row loosely
232 : * and for illustrative purposes). E.g.
233 : *
234 : * src <-------------------->|'''''' dest mod ''''''''
235 : * dest <--------------------------------------------->
236 : *
237 : * dest_mod (it's essentially a modulus) is added to the destination index
238 : * after every full iteration of the y span.
239 : *
240 : * This method falls under the category "linear array and incrementing
241 : * index".
242 : */
243 :
244 56321 : s32 src_step = src_area.getExtent().X;
245 56321 : s32 dest_step = m_area.getExtent().X;
246 56321 : s32 dest_mod = m_area.index(to_pos.X, to_pos.Y, to_pos.Z + 1)
247 56321 : - m_area.index(to_pos.X, to_pos.Y, to_pos.Z)
248 56321 : - dest_step * size.Y;
249 :
250 56321 : s32 i_src = src_area.index(from_pos.X, from_pos.Y, from_pos.Z);
251 56321 : s32 i_local = m_area.index(to_pos.X, to_pos.Y, to_pos.Z);
252 :
253 957489 : for (s16 z = 0; z < size.Z; z++) {
254 15321392 : for (s16 y = 0; y < size.Y; y++) {
255 14420224 : memcpy(&m_data[i_local], &src[i_src], size.X * sizeof(*m_data));
256 14420224 : memset(&m_flags[i_local], 0, size.X);
257 14420224 : i_src += src_step;
258 14420224 : i_local += dest_step;
259 : }
260 901168 : i_local += dest_mod;
261 : }
262 56321 : }
263 :
264 0 : void VoxelManipulator::copyTo(MapNode *dst, const VoxelArea& dst_area,
265 : v3s16 dst_pos, v3s16 from_pos, v3s16 size)
266 : {
267 0 : for(s16 z=0; z<size.Z; z++)
268 0 : for(s16 y=0; y<size.Y; y++)
269 : {
270 0 : s32 i_dst = dst_area.index(dst_pos.X, dst_pos.Y+y, dst_pos.Z+z);
271 0 : s32 i_local = m_area.index(from_pos.X, from_pos.Y+y, from_pos.Z+z);
272 0 : for (s16 x = 0; x < size.X; x++) {
273 0 : if (m_data[i_local].getContent() != CONTENT_IGNORE)
274 0 : dst[i_dst] = m_data[i_local];
275 0 : i_dst++;
276 0 : i_local++;
277 : }
278 : }
279 0 : }
280 :
281 : /*
282 : Algorithms
283 : -----------------------------------------------------
284 : */
285 :
286 0 : void VoxelManipulator::clearFlag(u8 flags)
287 : {
288 : // 0-1ms on moderate area
289 0 : TimeTaker timer("clearFlag", &clearflag_time);
290 :
291 : //v3s16 s = m_area.getExtent();
292 :
293 : /*dstream<<"clearFlag clearing area of size "
294 : <<""<<s.X<<"x"<<s.Y<<"x"<<s.Z<<""
295 : <<std::endl;*/
296 :
297 : //s32 count = 0;
298 :
299 : /*for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
300 : for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
301 : for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
302 : {
303 : u8 f = m_flags[m_area.index(x,y,z)];
304 : m_flags[m_area.index(x,y,z)] &= ~flags;
305 : if(m_flags[m_area.index(x,y,z)] != f)
306 : count++;
307 : }*/
308 :
309 0 : s32 volume = m_area.getVolume();
310 0 : for(s32 i=0; i<volume; i++)
311 : {
312 0 : m_flags[i] &= ~flags;
313 : }
314 :
315 : /*s32 volume = m_area.getVolume();
316 : for(s32 i=0; i<volume; i++)
317 : {
318 : u8 f = m_flags[i];
319 : m_flags[i] &= ~flags;
320 : if(m_flags[i] != f)
321 : count++;
322 : }
323 :
324 : dstream<<"clearFlag changed "<<count<<" flags out of "
325 : <<volume<<" nodes"<<std::endl;*/
326 0 : }
327 :
328 0 : void VoxelManipulator::unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
329 : std::set<v3s16> & light_sources, INodeDefManager *nodemgr)
330 : {
331 : v3s16 dirs[6] = {
332 : v3s16(0,0,1), // back
333 : v3s16(0,1,0), // top
334 : v3s16(1,0,0), // right
335 : v3s16(0,0,-1), // front
336 : v3s16(0,-1,0), // bottom
337 : v3s16(-1,0,0), // left
338 0 : };
339 :
340 0 : VoxelArea voxel_area(p - v3s16(1,1,1), p + v3s16(1,1,1));
341 0 : addArea(voxel_area);
342 :
343 : // Loop through 6 neighbors
344 0 : for(u16 i=0; i<6; i++)
345 : {
346 : // Get the position of the neighbor node
347 0 : v3s16 n2pos = p + dirs[i];
348 :
349 0 : u32 n2i = m_area.index(n2pos);
350 :
351 0 : if(m_flags[n2i] & VOXELFLAG_NO_DATA)
352 0 : continue;
353 :
354 0 : MapNode &n2 = m_data[n2i];
355 :
356 : /*
357 : If the neighbor is dimmer than what was specified
358 : as oldlight (the light of the previous node)
359 : */
360 0 : u8 light2 = n2.getLight(bank, nodemgr);
361 0 : if(light2 < oldlight)
362 : {
363 : /*
364 : And the neighbor is transparent and it has some light
365 : */
366 0 : if(nodemgr->get(n2).light_propagates && light2 != 0)
367 : {
368 : /*
369 : Set light to 0 and add to queue
370 : */
371 :
372 0 : n2.setLight(bank, 0, nodemgr);
373 :
374 0 : unspreadLight(bank, n2pos, light2, light_sources, nodemgr);
375 :
376 : /*
377 : Remove from light_sources if it is there
378 : NOTE: This doesn't happen nearly at all
379 : */
380 : /*if(light_sources.find(n2pos))
381 : {
382 : std::cout<<"Removed from light_sources"<<std::endl;
383 : light_sources.remove(n2pos);
384 : }*/
385 : }
386 : }
387 : else{
388 0 : light_sources.insert(n2pos);
389 : }
390 : }
391 0 : }
392 :
393 : #if 1
394 : /*
395 : Goes recursively through the neighbours of the node.
396 :
397 : Alters only transparent nodes.
398 :
399 : If the lighting of the neighbour is lower than the lighting of
400 : the node was (before changing it to 0 at the step before), the
401 : lighting of the neighbour is set to 0 and then the same stuff
402 : repeats for the neighbour.
403 :
404 : The ending nodes of the routine are stored in light_sources.
405 : This is useful when a light is removed. In such case, this
406 : routine can be called for the light node and then again for
407 : light_sources to re-light the area without the removed light.
408 :
409 : values of from_nodes are lighting values.
410 : */
411 0 : void VoxelManipulator::unspreadLight(enum LightBank bank,
412 : std::map<v3s16, u8> & from_nodes,
413 : std::set<v3s16> & light_sources, INodeDefManager *nodemgr)
414 : {
415 0 : if(from_nodes.empty())
416 0 : return;
417 :
418 0 : for(std::map<v3s16, u8>::iterator j = from_nodes.begin();
419 0 : j != from_nodes.end(); ++j)
420 : {
421 0 : unspreadLight(bank, j->first, j->second, light_sources, nodemgr);
422 : }
423 : }
424 : #endif
425 :
426 : #if 0
427 : /*
428 : Goes recursively through the neighbours of the node.
429 :
430 : Alters only transparent nodes.
431 :
432 : If the lighting of the neighbour is lower than the lighting of
433 : the node was (before changing it to 0 at the step before), the
434 : lighting of the neighbour is set to 0 and then the same stuff
435 : repeats for the neighbour.
436 :
437 : The ending nodes of the routine are stored in light_sources.
438 : This is useful when a light is removed. In such case, this
439 : routine can be called for the light node and then again for
440 : light_sources to re-light the area without the removed light.
441 :
442 : values of from_nodes are lighting values.
443 : */
444 : void VoxelManipulator::unspreadLight(enum LightBank bank,
445 : core::map<v3s16, u8> & from_nodes,
446 : core::map<v3s16, bool> & light_sources)
447 : {
448 : v3s16 dirs[6] = {
449 : v3s16(0,0,1), // back
450 : v3s16(0,1,0), // top
451 : v3s16(1,0,0), // right
452 : v3s16(0,0,-1), // front
453 : v3s16(0,-1,0), // bottom
454 : v3s16(-1,0,0), // left
455 : };
456 :
457 : if(from_nodes.size() == 0)
458 : return;
459 :
460 : core::map<v3s16, u8> unlighted_nodes;
461 : core::map<v3s16, u8>::Iterator j;
462 : j = from_nodes.getIterator();
463 :
464 : for(; j.atEnd() == false; j++)
465 : {
466 : v3s16 pos = j.getNode()->getKey();
467 :
468 : addArea(VoxelArea(pos - v3s16(1,1,1), pos + v3s16(1,1,1)));
469 :
470 : //MapNode &n = m_data[m_area.index(pos)];
471 :
472 : u8 oldlight = j.getNode()->getValue();
473 :
474 : // Loop through 6 neighbors
475 : for(u16 i=0; i<6; i++)
476 : {
477 : // Get the position of the neighbor node
478 : v3s16 n2pos = pos + dirs[i];
479 :
480 : u32 n2i = m_area.index(n2pos);
481 :
482 : if(m_flags[n2i] & VOXELFLAG_NO_DATA)
483 : continue;
484 :
485 : MapNode &n2 = m_data[n2i];
486 :
487 : /*
488 : If the neighbor is dimmer than what was specified
489 : as oldlight (the light of the previous node)
490 : */
491 : if(n2.getLight(bank, nodemgr) < oldlight)
492 : {
493 : /*
494 : And the neighbor is transparent and it has some light
495 : */
496 : if(nodemgr->get(n2).light_propagates && n2.getLight(bank, nodemgr) != 0)
497 : {
498 : /*
499 : Set light to 0 and add to queue
500 : */
501 :
502 : u8 current_light = n2.getLight(bank, nodemgr);
503 : n2.setLight(bank, 0);
504 :
505 : unlighted_nodes.insert(n2pos, current_light);
506 :
507 : /*
508 : Remove from light_sources if it is there
509 : NOTE: This doesn't happen nearly at all
510 : */
511 : /*if(light_sources.find(n2pos))
512 : {
513 : std::cout<<"Removed from light_sources"<<std::endl;
514 : light_sources.remove(n2pos);
515 : }*/
516 : }
517 : }
518 : else{
519 : light_sources.insert(n2pos, true);
520 : }
521 : }
522 : }
523 :
524 : /*dstream<<"unspreadLight(): Changed block "
525 : <<blockchangecount<<" times"
526 : <<" for "<<from_nodes.size()<<" nodes"
527 : <<std::endl;*/
528 :
529 : if(unlighted_nodes.size() > 0)
530 : unspreadLight(bank, unlighted_nodes, light_sources);
531 : }
532 : #endif
533 :
534 0 : void VoxelManipulator::spreadLight(enum LightBank bank, v3s16 p,
535 : INodeDefManager *nodemgr)
536 : {
537 : const v3s16 dirs[6] = {
538 : v3s16(0,0,1), // back
539 : v3s16(0,1,0), // top
540 : v3s16(1,0,0), // right
541 : v3s16(0,0,-1), // front
542 : v3s16(0,-1,0), // bottom
543 : v3s16(-1,0,0), // left
544 0 : };
545 :
546 0 : VoxelArea voxel_area(p - v3s16(1,1,1), p + v3s16(1,1,1));
547 0 : addArea(voxel_area);
548 :
549 0 : u32 i = m_area.index(p);
550 :
551 0 : if(m_flags[i] & VOXELFLAG_NO_DATA)
552 0 : return;
553 :
554 0 : MapNode &n = m_data[i];
555 :
556 0 : u8 oldlight = n.getLight(bank, nodemgr);
557 0 : u8 newlight = diminish_light(oldlight);
558 :
559 : // Loop through 6 neighbors
560 0 : for(u16 i=0; i<6; i++)
561 : {
562 : // Get the position of the neighbor node
563 0 : v3s16 n2pos = p + dirs[i];
564 :
565 0 : u32 n2i = m_area.index(n2pos);
566 :
567 0 : if(m_flags[n2i] & VOXELFLAG_NO_DATA)
568 0 : continue;
569 :
570 0 : MapNode &n2 = m_data[n2i];
571 :
572 0 : u8 light2 = n2.getLight(bank, nodemgr);
573 :
574 : /*
575 : If the neighbor is brighter than the current node,
576 : add to list (it will light up this node on its turn)
577 : */
578 0 : if(light2 > undiminish_light(oldlight))
579 : {
580 0 : spreadLight(bank, n2pos, nodemgr);
581 : }
582 : /*
583 : If the neighbor is dimmer than how much light this node
584 : would spread on it, add to list
585 : */
586 0 : if(light2 < newlight)
587 : {
588 0 : if(nodemgr->get(n2).light_propagates)
589 : {
590 0 : n2.setLight(bank, newlight, nodemgr);
591 0 : spreadLight(bank, n2pos, nodemgr);
592 : }
593 : }
594 : }
595 : }
596 :
597 : #if 0
598 : /*
599 : Lights neighbors of from_nodes, collects all them and then
600 : goes on recursively.
601 :
602 : NOTE: This is faster on small areas but will overflow the
603 : stack on large areas. Thus it is not used.
604 : */
605 : void VoxelManipulator::spreadLight(enum LightBank bank,
606 : core::map<v3s16, bool> & from_nodes)
607 : {
608 : if(from_nodes.size() == 0)
609 : return;
610 :
611 : core::map<v3s16, bool> lighted_nodes;
612 : core::map<v3s16, bool>::Iterator j;
613 : j = from_nodes.getIterator();
614 :
615 : for(; j.atEnd() == false; j++)
616 : {
617 : v3s16 pos = j.getNode()->getKey();
618 :
619 : spreadLight(bank, pos);
620 : }
621 : }
622 : #endif
623 :
624 1 : const MapNode VoxelManipulator::ContentIgnoreNode = MapNode(CONTENT_IGNORE);
625 :
626 : #if 1
627 : /*
628 : Lights neighbors of from_nodes, collects all them and then
629 : goes on recursively.
630 : */
631 0 : void VoxelManipulator::spreadLight(enum LightBank bank,
632 : std::set<v3s16> & from_nodes, INodeDefManager *nodemgr)
633 : {
634 : const v3s16 dirs[6] = {
635 : v3s16(0,0,1), // back
636 : v3s16(0,1,0), // top
637 : v3s16(1,0,0), // right
638 : v3s16(0,0,-1), // front
639 : v3s16(0,-1,0), // bottom
640 : v3s16(-1,0,0), // left
641 0 : };
642 :
643 0 : if(from_nodes.empty())
644 0 : return;
645 :
646 0 : std::set<v3s16> lighted_nodes;
647 :
648 0 : for(std::set<v3s16>::iterator j = from_nodes.begin();
649 0 : j != from_nodes.end(); ++j)
650 : {
651 0 : v3s16 pos = *j;
652 :
653 0 : VoxelArea voxel_area(pos - v3s16(1,1,1), pos + v3s16(1,1,1));
654 0 : addArea(voxel_area);
655 :
656 0 : u32 i = m_area.index(pos);
657 :
658 0 : if(m_flags[i] & VOXELFLAG_NO_DATA)
659 0 : continue;
660 :
661 0 : MapNode &n = m_data[i];
662 :
663 0 : u8 oldlight = n.getLight(bank, nodemgr);
664 0 : u8 newlight = diminish_light(oldlight);
665 :
666 : // Loop through 6 neighbors
667 0 : for(u16 i=0; i<6; i++)
668 : {
669 : // Get the position of the neighbor node
670 0 : v3s16 n2pos = pos + dirs[i];
671 :
672 : try
673 : {
674 0 : u32 n2i = m_area.index(n2pos);
675 :
676 0 : if(m_flags[n2i] & VOXELFLAG_NO_DATA)
677 0 : continue;
678 :
679 0 : MapNode &n2 = m_data[n2i];
680 :
681 0 : u8 light2 = n2.getLight(bank, nodemgr);
682 :
683 : /*
684 : If the neighbor is brighter than the current node,
685 : add to list (it will light up this node on its turn)
686 : */
687 0 : if(light2 > undiminish_light(oldlight))
688 : {
689 0 : lighted_nodes.insert(n2pos);
690 : }
691 : /*
692 : If the neighbor is dimmer than how much light this node
693 : would spread on it, add to list
694 : */
695 0 : if(light2 < newlight)
696 : {
697 0 : if(nodemgr->get(n2).light_propagates)
698 : {
699 0 : n2.setLight(bank, newlight, nodemgr);
700 0 : lighted_nodes.insert(n2pos);
701 : }
702 : }
703 : }
704 0 : catch(InvalidPositionException &e)
705 : {
706 0 : continue;
707 : }
708 : }
709 : }
710 :
711 : /*dstream<<"spreadLight(): Changed block "
712 : <<blockchangecount<<" times"
713 : <<" for "<<from_nodes.size()<<" nodes"
714 : <<std::endl;*/
715 :
716 0 : if(!lighted_nodes.empty())
717 0 : spreadLight(bank, lighted_nodes, nodemgr);
718 3 : }
719 : #endif
720 :
721 : //END
|