X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fchunk.cpp;h=04c64f26738170a98b64345ddfc9712463ce70d5;hb=374843f5b3ae60c0d02704a8da5100ac8abe7f1a;hp=e52a19f81d2c4898681f2213adfa4dc0e2b6fde2;hpb=7caa2326d25d4fc5ba98318dfccb508bb3e16820;p=blank.git diff --git a/src/chunk.cpp b/src/chunk.cpp index e52a19f..04c64f2 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -1,5 +1,7 @@ #include "chunk.hpp" +#include "generator.hpp" + #include #include @@ -111,20 +113,28 @@ glm::mat4 Chunk::Transform(const Pos &offset) const { } -int Chunk::VertexCount() const { - int count = 0; - for (const auto &block : blocks) { - count += Type(block).shape->VertexCount(); +void Chunk::CheckUpdate() { + if (dirty) { + Update(); } - return count; + model.CheckUpdate(); } void Chunk::Update() { + int vtx_count = 0, idx_count = 0; + for (const auto &block : blocks) { + const Shape *shape = Type(block).shape; + vtx_count += shape->VertexCount(); + idx_count += shape->VertexIndexCount(); + } model.Clear(); - model.Reserve(VertexCount()); + model.Reserve(vtx_count, idx_count); + Model::Index vtx_counter = 0; for (size_t i = 0; i < Size(); ++i) { - Type(blocks[i]).FillModel(ToCoords(i), model); + const BlockType &type = Type(blocks[i]); + type.FillModel(model, ToCoords(i), vtx_counter); + vtx_counter += type.shape->VertexCount(); } model.Invalidate(); @@ -132,4 +142,145 @@ void Chunk::Update() { } +ChunkLoader::ChunkLoader(const BlockTypeRegistry ®, const Generator &gen) +: base(0, 0, 0) +, reg(reg) +, gen(gen) +, loaded() +, to_generate() +, to_free() +, load_dist(4) +, unload_dist(5) { + +} + +namespace { + +struct ChunkLess { + + explicit ChunkLess(const Chunk::Pos &base) + : base(base) { } + + bool operator ()(const Chunk &a, const Chunk &b) const { + Chunk::Pos da(base - a.Position()); + Chunk::Pos db(base - b.Position()); + return + da.x * da.x + da.y * da.y + da.z * da.z < + db.x * db.x + db.y * db.y + db.z * db.z; + } + + Chunk::Pos base; + +}; + +} + +void ChunkLoader::Generate(const Chunk::Pos &from, const Chunk::Pos &to) { + for (int z = from.z; z < to.z; ++z) { + for (int y = from.y; y < to.y; ++y) { + for (int x = from.x; x < to.x; ++x) { + Chunk::Pos pos(x, y, z); + if (Known(pos)) { + continue; + } else if (x == 0 && y == 0 && z == 0) { + loaded.emplace_back(reg); + loaded.back().Position(pos); + gen(loaded.back()); + } else { + to_generate.emplace_back(reg); + to_generate.back().Position(pos); + } + } + } + } + to_generate.sort(ChunkLess(base)); +} + +Chunk *ChunkLoader::Loaded(const Chunk::Pos &pos) { + for (Chunk &chunk : loaded) { + if (chunk.Position() == pos) { + return &chunk; + } + } + return nullptr; +} + +Chunk *ChunkLoader::Queued(const Chunk::Pos &pos) { + for (Chunk &chunk : to_generate) { + if (chunk.Position() == pos) { + return &chunk; + } + } + return nullptr; +} + +Chunk *ChunkLoader::Known(const Chunk::Pos &pos) { + Chunk *chunk = Loaded(pos); + if (chunk) return chunk; + + return Queued(pos); +} + +Chunk &ChunkLoader::ForceLoad(const Chunk::Pos &pos) { + Chunk *chunk = Loaded(pos); + if (chunk) { + return *chunk; + } + + chunk = Queued(pos); + if (chunk) { + gen(*chunk); + return *chunk; + } + + loaded.emplace_back(reg); + loaded.back().Position(pos); + gen(loaded.back()); + return loaded.back(); +} + +void ChunkLoader::Rebase(const Chunk::Pos &new_base) { + if (new_base == base) { + return; + } + base = 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; + ++iter; + to_free.splice(to_free.end(), loaded, saved); + } 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->Position().x) > unload_dist + || std::abs(base.y - iter->Position().y) > unload_dist + || std::abs(base.z - iter->Position().z) > unload_dist) { + iter = to_generate.erase(iter); + } else { + ++iter; + } + } + // add missing new chunks + const Chunk::Pos offset(load_dist, load_dist, load_dist); + Generate(base - offset, base + offset); +} + +void ChunkLoader::Update() { + if (!to_generate.empty()) { + gen(to_generate.front()); + loaded.splice(loaded.end(), to_generate, to_generate.begin()); + } + + if (!to_free.empty()) { + to_free.pop_front(); + } +} + }