Skip to content

Commit

Permalink
Mapgen: Run light spread algorithm iteratively
Browse files Browse the repository at this point in the history
This approach doesn't consume valuable stack space and won't
lead to hard-to-identify segfaults.
  • Loading branch information
sfan5 committed Aug 21, 2019
1 parent ded5da7 commit f31320b
Showing 1 changed file with 42 additions and 29 deletions.
71 changes: 42 additions & 29 deletions src/mapgen/mapgen.cpp
Expand Up @@ -51,6 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen_singlenode.h"
#include "cavegen.h"
#include "dungeongen.h"
#include "util/directiontables.h"

FlagDesc flagdesc_mapgen[] = {
{"caves", MG_CAVES},
Expand Down Expand Up @@ -437,42 +438,54 @@ void Mapgen::setLighting(u8 light, v3s16 nmin, v3s16 nmax)

void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
{
if (light <= 1 || !a.contains(p))
return;
std::deque<std::pair<v3s16, u8>> queue;
queue.emplace_back(std::make_pair(p, light));

u32 vi = vm->m_area.index(p);
MapNode &n = vm->m_data[vi];
/*
The loop contains a recursive algorithm, but the wrapping
code runs it iteratively so we don't hit stack limits.
*/
while (!queue.empty()) {
{
auto &item = queue.front();
p = item.first;
light = item.second;
}
queue.pop_front();

// Decay light in each of the banks separately
u8 light_day = light & 0x0F;
if (light_day > 0)
light_day -= 0x01;
if (light <= 1 || !a.contains(p))
continue;

u8 light_night = light & 0xF0;
if (light_night > 0)
light_night -= 0x10;
u32 vi = vm->m_area.index(p);
MapNode &n = vm->m_data[vi];

// Bail out only if we have no more light from either bank to propogate, or
// we hit a solid block that light cannot pass through.
if ((light_day <= (n.param1 & 0x0F) &&
light_night <= (n.param1 & 0xF0)) ||
!ndef->get(n).light_propagates)
return;
// Decay light in each of the banks separately
u8 light_day = light & 0x0F;
if (light_day > 0)
light_day -= 0x01;

u8 light_night = light & 0xF0;
if (light_night > 0)
light_night -= 0x10;

// Bail out only if we have no more light from either bank to propogate, or
// we hit a solid block that light cannot pass through.
if ((light_day <= (n.param1 & 0x0F) &&
light_night <= (n.param1 & 0xF0)) ||
!ndef->get(n).light_propagates)
continue;

// Since this recursive function only terminates when there is no light from
// either bank left, we need to take the max of both banks into account for
// the case where spreading has stopped for one light bank but not the other.
light = MYMAX(light_day, n.param1 & 0x0F) |
MYMAX(light_night, n.param1 & 0xF0);
// Since this recursive algorithm only terminates when there is no light from
// either bank left, we need to take the max of both banks into account for
// the case where spreading has stopped for one light bank but not the other.
light = MYMAX(light_day, n.param1 & 0x0F) |
MYMAX(light_night, n.param1 & 0xF0);

n.param1 = light;
n.param1 = light;

lightSpread(a, p + v3s16(0, 0, 1), light);
lightSpread(a, p + v3s16(0, 1, 0), light);
lightSpread(a, p + v3s16(1, 0, 0), light);
lightSpread(a, p - v3s16(0, 0, 1), light);
lightSpread(a, p - v3s16(0, 1, 0), light);
lightSpread(a, p - v3s16(1, 0, 0), light);
for (const auto &dir : g_6dirs)
queue.emplace_back(std::make_pair(p + dir, light));
}
}


Expand Down

0 comments on commit f31320b

Please sign in to comment.