X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fworld%2Fchunk.cpp;h=190fe3d7b9e4c4aa25d4fbaf6745845c97b0565b;hb=5998b18978bd8e7a0c9deb516474634e1d3521c9;hp=50595f4856526220a44eb069c4ab9b6374a0d2b9;hpb=b7d09e1e35ef90282c97509e0020b20db3c7ea9f;p=blank.git diff --git a/src/world/chunk.cpp b/src/world/chunk.cpp index 50595f4..190fe3d 100644 --- a/src/world/chunk.cpp +++ b/src/world/chunk.cpp @@ -3,8 +3,10 @@ #include "ChunkLoader.hpp" #include "Generator.hpp" +#include "WorldCollision.hpp" #include +#include #include #include @@ -63,9 +65,13 @@ struct SetNode { int Get() const noexcept { return chunk->GetLight(pos); } void Set(int level) noexcept { chunk->SetLight(pos, level); } + const BlockType &GetType() const noexcept { return chunk->Type(Chunk::ToIndex(pos)); } + bool HasNext(Block::Face face) noexcept { + const BlockType &type = GetType(); + if (type.block_light && !type.luminosity) return false; const BlockLookup next(chunk, pos, face); - return next && !next.GetType().block_light; + return next; } SetNode GetNext(Block::Face face) noexcept { const BlockLookup next(chunk, pos, face); @@ -169,20 +175,41 @@ void Chunk::SetBlock(int index, const Block &block) noexcept { } else if (!new_type.block_light && old_type.block_light) { // obstacle removed int level = 0; + Pos pos(ToPos(index)); for (int face = 0; face < Block::FACE_COUNT; ++face) { - BlockLookup next_block(this, ToPos(index), Block::Face(face)); + BlockLookup next_block(this, pos, Block::Face(face)); if (next_block) { - level = std::min(level, next_block.GetLight()); + level = std::max(level, next_block.GetLight()); } } if (level > 1) { SetLight(index, level - 1); - light_queue.emplace(this, ToPos(index)); + light_queue.emplace(this, pos); work_light(); } } } +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) { @@ -192,12 +219,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(); @@ -210,12 +233,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(); @@ -228,12 +247,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(); @@ -246,12 +261,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(); @@ -264,12 +275,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(); @@ -282,12 +289,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(); @@ -296,23 +299,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; } } } @@ -329,7 +319,7 @@ int Chunk::GetLight(int index) const noexcept { return light[index]; } -float Chunk::GetVertexLight(const Pos &pos, const BlockModel::Position &vtx, const Model::Normal &norm) const noexcept { +float Chunk::GetVertexLight(const Pos &pos, const BlockModel::Position &vtx, const EntityModel::Normal &norm) const noexcept { int index = ToIndex(pos); float light = GetLight(index); @@ -449,7 +439,6 @@ bool Chunk::Intersection( float &dist, glm::vec3 &normal ) const noexcept { - // TODO: should be possible to heavily optimize this int idx = 0; blkid = -1; dist = std::numeric_limits::infinity(); @@ -481,6 +470,36 @@ bool Chunk::Intersection( } } +bool Chunk::Intersection( + const AABB &box, + const glm::mat4 &Mbox, + const glm::mat4 &Mchunk, + std::vector &col +) const noexcept { + bool any = false; + float penetration; + glm::vec3 normal; + + if (!blank::Intersection(box, Mbox, Bounds(), Mchunk, penetration, normal)) { + return false; + } + for (int idx = 0, z = 0; z < depth; ++z) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x, ++idx) { + const BlockType &type = Type(idx); + if (!type.collision) { + continue; + } + if (type.shape->Intersects(Mchunk * ToTransform(Pos(x, y, z), idx), box, Mbox, penetration, normal)) { + col.emplace_back(this, idx, penetration, normal); + any = true; + } + } + } + } + return any; +} + namespace { @@ -627,9 +646,10 @@ ChunkLoader::ChunkLoader(const Config &config, const BlockTypeRegistry ®, con , loaded() , to_generate() , to_free() +, gen_timer(config.gen_limit) , load_dist(config.load_dist) , unload_dist(config.unload_dist) { - + gen_timer.Start(); } namespace { @@ -731,8 +751,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 { @@ -750,7 +777,7 @@ bool ChunkLoader::Queued(const Chunk::Pos &pos) noexcept { return true; } } - return nullptr; + return false; } bool ChunkLoader::Known(const Chunk::Pos &pos) noexcept { @@ -774,6 +801,12 @@ Chunk &ChunkLoader::ForceLoad(const Chunk::Pos &pos) { return Generate(pos); } +bool ChunkLoader::OutOfRange(const Chunk::Pos &pos) const noexcept { + return std::abs(base.x - pos.x) > unload_dist + || std::abs(base.y - pos.y) > unload_dist + || std::abs(base.z - pos.z) > unload_dist; +} + void ChunkLoader::Rebase(const Chunk::Pos &new_base) { if (new_base == base) { return; @@ -782,22 +815,15 @@ void ChunkLoader::Rebase(const Chunk::Pos &new_base) { // unload far away chunks for (auto iter(loaded.begin()), end(loaded.end()); iter != end;) { - if (std::abs(base.x - iter->Position().x) > unload_dist - || std::abs(base.y - iter->Position().y) > unload_dist - || std::abs(base.z - iter->Position().z) > unload_dist) { - auto saved = iter; - Remove(*saved); - ++iter; - to_free.splice(to_free.end(), loaded, saved); + if (OutOfRange(*iter)) { + iter = Remove(iter); } else { ++iter; } } // abort far away queued chunks for (auto iter(to_generate.begin()), end(to_generate.end()); iter != end;) { - if (std::abs(base.x - iter->x) > unload_dist - || std::abs(base.y - iter->y) > unload_dist - || std::abs(base.z - iter->z) > unload_dist) { + if (OutOfRange(*iter)) { iter = to_generate.erase(iter); } else { ++iter; @@ -812,28 +838,36 @@ void ChunkLoader::GenerateSurrounding(const Chunk::Pos &pos) { Generate(pos - offset, pos + offset); } -void ChunkLoader::Update() { - if (to_generate.empty()) { +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);