Last active
October 11, 2020 10:20
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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