X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;ds=sidebyside;f=src%2Fworld%2Fchunk.cpp;h=ef3c5fc869d80acb94d4ec054462ce2d85c9cc64;hb=46b18a88fdda816f3c2c547aba68b0a5ea7970f7;hp=a65f5c31d9b1d0081ab3204903b87cbe10bd562d;hpb=955fbb45dedb570520fc45d2ce69f420bed2ad08;p=blank.git diff --git a/src/world/chunk.cpp b/src/world/chunk.cpp index a65f5c3..ef3c5fc 100644 --- a/src/world/chunk.cpp +++ b/src/world/chunk.cpp @@ -186,6 +186,26 @@ void Chunk::SetBlock(int index, const Block &block) noexcept { } } +namespace { + +// propagate light from a's edge to b +void edge_light( + Chunk &a, const Chunk::Pos &a_pos, + Chunk &b, const Chunk::Pos &b_pos +) noexcept { + if (a.GetLight(a_pos) > 1) { + const BlockType &b_type = b.Type(Chunk::ToIndex(b_pos)); + if (!b_type.block_light) { + light_queue.emplace(&a, a_pos); + } + if (b_type.visible) { + b.Invalidate(); + } + } +} + +} + void Chunk::SetNeighbor(Chunk &other) noexcept { if (other.position == position + Pos(-1, 0, 0)) { if (neighbor[Block::FACE_LEFT] != &other) { @@ -195,12 +215,8 @@ void Chunk::SetNeighbor(Chunk &other) noexcept { for (int y = 0; y < height; ++y) { Pos my_pos(0, y, z); Pos other_pos(width - 1, y, z); - if (GetLight(my_pos) > 0) { - light_queue.emplace(this, my_pos); - } - if (other.GetLight(other_pos) > 0) { - light_queue.emplace(&other, other_pos); - } + edge_light(*this, my_pos, other, other_pos); + edge_light(other, other_pos, *this, my_pos); } } work_light(); @@ -213,12 +229,8 @@ void Chunk::SetNeighbor(Chunk &other) noexcept { for (int y = 0; y < height; ++y) { Pos my_pos(width - 1, y, z); Pos other_pos(0, y, z); - if (GetLight(my_pos) > 0) { - light_queue.emplace(this, my_pos); - } - if (other.GetLight(other_pos) > 0) { - light_queue.emplace(&other, other_pos); - } + edge_light(*this, my_pos, other, other_pos); + edge_light(other, other_pos, *this, my_pos); } } work_light(); @@ -231,12 +243,8 @@ void Chunk::SetNeighbor(Chunk &other) noexcept { for (int x = 0; x < width; ++x) { Pos my_pos(x, 0, z); Pos other_pos(x, height - 1, z); - if (GetLight(my_pos) > 0) { - light_queue.emplace(this, my_pos); - } - if (other.GetLight(other_pos) > 0) { - light_queue.emplace(&other, other_pos); - } + edge_light(*this, my_pos, other, other_pos); + edge_light(other, other_pos, *this, my_pos); } } work_light(); @@ -249,12 +257,8 @@ void Chunk::SetNeighbor(Chunk &other) noexcept { for (int x = 0; x < width; ++x) { Pos my_pos(x, height - 1, z); Pos other_pos(x, 0, z); - if (GetLight(my_pos) > 0) { - light_queue.emplace(this, my_pos); - } - if (other.GetLight(other_pos) > 0) { - light_queue.emplace(&other, other_pos); - } + edge_light(*this, my_pos, other, other_pos); + edge_light(other, other_pos, *this, my_pos); } } work_light(); @@ -267,12 +271,8 @@ void Chunk::SetNeighbor(Chunk &other) noexcept { for (int x = 0; x < width; ++x) { Pos my_pos(x, y, 0); Pos other_pos(x, y, depth - 1); - if (GetLight(my_pos) > 0) { - light_queue.emplace(this, my_pos); - } - if (other.GetLight(other_pos) > 0) { - light_queue.emplace(&other, other_pos); - } + edge_light(*this, my_pos, other, other_pos); + edge_light(other, other_pos, *this, my_pos); } } work_light(); @@ -285,12 +285,8 @@ void Chunk::SetNeighbor(Chunk &other) noexcept { for (int x = 0; x < width; ++x) { Pos my_pos(x, y, depth - 1); Pos other_pos(x, y, 0); - if (GetLight(my_pos) > 0) { - light_queue.emplace(this, my_pos); - } - if (other.GetLight(other_pos) > 0) { - light_queue.emplace(&other, other_pos); - } + edge_light(*this, my_pos, other, other_pos); + edge_light(other, other_pos, *this, my_pos); } } work_light(); @@ -299,23 +295,10 @@ void Chunk::SetNeighbor(Chunk &other) noexcept { } void Chunk::ClearNeighbors() noexcept { - for (int i = 0; i < Block::FACE_COUNT; ++i) { - neighbor[i] = nullptr; - } -} - -void Chunk::Unlink() noexcept { for (int face = 0; face < Block::FACE_COUNT; ++face) { if (neighbor[face]) { neighbor[face]->neighbor[Block::Opposite(Block::Face(face))] = nullptr; - } - } -} - -void Chunk::Relink() noexcept { - for (int face = 0; face < Block::FACE_COUNT; ++face) { - if (neighbor[face]) { - neighbor[face]->neighbor[Block::Opposite(Block::Face(face))] = this; + neighbor[face] = nullptr; } } } @@ -764,8 +747,15 @@ void ChunkLoader::Insert(Chunk &chunk) noexcept { } } -void ChunkLoader::Remove(Chunk &chunk) noexcept { - chunk.Unlink(); +std::list::iterator ChunkLoader::Remove(std::list::iterator chunk) noexcept { + // fetch next entry while chunk's still in the list + std::list::iterator next = chunk; + ++next; + // unlink neighbors so they won't reference a dead chunk + chunk->ClearNeighbors(); + // and move it from loaded to free list + to_free.splice(to_free.end(), loaded, chunk); + return next; } Chunk *ChunkLoader::Loaded(const Chunk::Pos &pos) noexcept { @@ -822,10 +812,7 @@ void ChunkLoader::Rebase(const Chunk::Pos &new_base) { // unload far away chunks for (auto iter(loaded.begin()), end(loaded.end()); iter != end;) { if (OutOfRange(*iter)) { - auto saved = iter; - Remove(*saved); - ++iter; - to_free.splice(to_free.end(), loaded, saved); + iter = Remove(iter); } else { ++iter; } @@ -848,27 +835,35 @@ void ChunkLoader::GenerateSurrounding(const Chunk::Pos &pos) { } void ChunkLoader::Update(int dt) { + // check if a chunk generation is scheduled for this frame + // and if there's a chunk waiting to be generated gen_timer.Update(dt); if (!gen_timer.Hit() || to_generate.empty()) { return; } + // take position of next chunk in queue Chunk::Pos pos(to_generate.front()); to_generate.pop_front(); + // look if the same chunk was already generated and still lingering for (auto iter(to_free.begin()), end(to_free.end()); iter != end; ++iter) { if (iter->Position() == pos) { - iter->Relink(); loaded.splice(loaded.end(), to_free, iter); + Insert(loaded.back()); + return; } } + // if the free list is empty, allocate a new chunk + // otherwise clear an unused one if (to_free.empty()) { loaded.emplace_back(reg); } else { to_free.front().ClearNeighbors(); loaded.splice(loaded.end(), to_free, to_free.begin()); } + Chunk &chunk = loaded.back(); chunk.Position(pos); gen(chunk);