Skip to content

Instantly share code, notes, and snippets.

@JuanDiegoMontoya
Last active October 11, 2020 10:20
Show Gist options
  • Save JuanDiegoMontoya/383bf2cc2ad3d1b8717a42b1f0bc6a7b to your computer and use it in GitHub Desktop.
Save JuanDiegoMontoya/383bf2cc2ad3d1b8717a42b1f0bc6a7b to your computer and use it in GitHub Desktop.
Flood fill (addition) in a voxel world. The code is ugly but should be somewhat self-explanatory.
// ref https://www.seedofandromeda.com/blogs/29-fast-flood-fill-lighting-in-a-blocky-voxel-game-pt-1
// wpos: world position
// nLight: new lighting value
// skipself: chunk updating thing
void ChunkManager::lightPropagateAdd(glm::ivec3 wpos, Light nLight, bool skipself)
{
// get existing light at the position
LightPtr L = GetLightPtr(wpos);
if (L)
{
// if there is already light in the spot,
// combine the two by taking the max values only
glm::u8vec4 t = glm::max(L->Get(), nLight.Get());
L->Set(t); //*L = t;
}
// queue of world positions, rather than chunk + local index (they are equivalent)
std::queue<glm::ivec3> lightQueue;
lightQueue.push(wpos);
while (!lightQueue.empty())
{
glm::ivec3 lightp = lightQueue.front(); // light position
lightQueue.pop();
Light lightLevel = GetLight(lightp); // node that will be giving light to others
constexpr glm::ivec3 dirs[] =
{
{ 1, 0, 0 },
{-1, 0, 0 },
{ 0, 1, 0 },
{ 0,-1, 0 },
{ 0, 0, 1 },
{ 0, 0,-1 },
};
// update each neighbor
for (const auto& dir : dirs)
{
Block block = GetBlock(lightp + dir); // neighboring block
LightPtr light = GetLightPtr(lightp + dir); // neighboring light (pointer)
// add chunk to update queue if it exists
if (Chunk::chunks[Chunk::worldBlockToLocalPos(lightp + dir).chunk_pos] != nullptr)
delayed_update_queue_.insert(Chunk::chunks[Chunk::worldBlockToLocalPos(lightp + dir).chunk_pos]);
// invalid light check (should be impossible)
ASSERT(light != nullptr);
// if neighbor is solid block, skip dat boi
if (Block::PropertiesTable[block.GetTypei()].color.a == 1)
continue;
// iterate over R, G, B
bool enqueue = false;
for (int ci = 0; ci < 3; ci++)
{
// skip blocks that are too bright to be affected by this light
if (light->Get()[ci] + 2 > lightLevel.Get()[ci])
continue;
// TODO: light propagation through transparent materials
// get all light components (R, G, B, Sun) and modify ONE of them,
// then push the position of that light into the queue
glm::u8vec4 val = light->Get();
val[ci] = (lightLevel.Get()[ci] - 1);// *Block::PropertiesTable[block.GetTypei()].color[ci];
light->Set(val);
enqueue = true;
}
if (enqueue) // enqueue if any lighting component changed
lightQueue.push(lightp + dir);
}
}
// do not update this chunk again if it contained the placed light
if (skipself)
delayed_update_queue_.erase(Chunk::chunks[Chunk::worldBlockToLocalPos(wpos).chunk_pos]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment